feat: payment refund

This commit is contained in:
zzw
2026-10-07 09:28:12 +08:00
parent a39ab003f4
commit a4c04b9c83
17 changed files with 258 additions and 116 deletions
Binary file not shown.
+5 -4
View File
@@ -26,16 +26,16 @@ service Payment {
};
}
rpc Refund(RefundReq) returns (Response) {
rpc Notify(NotifyReq) returns (Response) {
option (google.api.http) = {
post: "/api/v3/payment/refund"
post: "/api/v3/payment/notify"
body: "*"
};
}
rpc Notify(NotifyReq) returns (Response) {
rpc Refund(RefundReq) returns (Response) {
option (google.api.http) = {
post: "/api/v3/payment/notify"
post: "/admin/v3/payment/refund"
body: "*"
};
}
@@ -51,6 +51,7 @@ message PayReq {
string order_sn = 1;
string client = 2;
string channel = 3;
string openid = 4;
}
message QueryReq {
+14 -5
View File
@@ -88,6 +88,7 @@ type PayReq struct {
OrderSn string `protobuf:"bytes,1,opt,name=order_sn,json=orderSn,proto3" json:"order_sn,omitempty"`
Client string `protobuf:"bytes,2,opt,name=client,proto3" json:"client,omitempty"`
Channel string `protobuf:"bytes,3,opt,name=channel,proto3" json:"channel,omitempty"`
Openid string `protobuf:"bytes,4,opt,name=openid,proto3" json:"openid,omitempty"` // 小程序微信支付必传,当前微信会话的openid
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -143,6 +144,13 @@ func (x *PayReq) GetChannel() string {
return ""
}
func (x *PayReq) GetOpenid() string {
if x != nil {
return x.Openid
}
return ""
}
type QueryReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
OrderSn string `protobuf:"bytes,1,opt,name=order_sn,json=orderSn,proto3" json:"order_sn,omitempty"`
@@ -383,11 +391,12 @@ const file_payment_payment_proto_rawDesc = "" +
"\bResponse\x12\x12\n" +
"\x04code\x18\x01 \x01(\x05R\x04code\x12\x10\n" +
"\x03msg\x18\x02 \x01(\tR\x03msg\x12\x12\n" +
"\x04data\x18\x03 \x01(\tR\x04data\"U\n" +
"\x04data\x18\x03 \x01(\tR\x04data\"m\n" +
"\x06PayReq\x12\x19\n" +
"\border_sn\x18\x01 \x01(\tR\aorderSn\x12\x16\n" +
"\x06client\x18\x02 \x01(\tR\x06client\x12\x18\n" +
"\achannel\x18\x03 \x01(\tR\achannel\"?\n" +
"\achannel\x18\x03 \x01(\tR\achannel\x12\x16\n" +
"\x06openid\x18\x04 \x01(\tR\x06openid\"?\n" +
"\bQueryReq\x12\x19\n" +
"\border_sn\x18\x01 \x01(\tR\aorderSn\x12\x18\n" +
"\achannel\x18\x02 \x01(\tR\achannel\"?\n" +
@@ -405,13 +414,13 @@ const file_payment_payment_proto_rawDesc = "" +
"\x04body\x18\x03 \x01(\fR\x04body\x1a:\n" +
"\fHeadersEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x012\xa8\x03\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x012\x9e\x03\n" +
"\aPayment\x12I\n" +
"\x03Pay\x12\x0f.payment.PayReq\x1a\x11.payment.Response\"\x1e\x82\xd3\xe4\x93\x02\x18:\x01*\"\x13/api/v3/payment/pay\x12O\n" +
"\x05Query\x12\x11.payment.QueryReq\x1a\x11.payment.Response\" \x82\xd3\xe4\x93\x02\x1a:\x01*\"\x15/api/v3/payment/query\x12O\n" +
"\x05Close\x12\x11.payment.CloseReq\x1a\x11.payment.Response\" \x82\xd3\xe4\x93\x02\x1a:\x01*\"\x15/api/v3/payment/close\x12R\n" +
"\x06Refund\x12\x12.payment.RefundReq\x1a\x11.payment.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\"\x16/api/v3/payment/refund\x12\\\n" +
"\x06Notify\x12\x12.payment.NotifyReq\x1a\x11.payment.Response\"+\x82\xd3\xe4\x93\x02%:\x01*\" /api/v3/payment/notify/{channel}B\x1bZ\x19lone-services/rpc/paymentb\x06proto3"
"\x06Refund\x12\x12.payment.RefundReq\x1a\x11.payment.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\"\x16/api/v3/payment/refund\x12R\n" +
"\x06Notify\x12\x12.payment.NotifyReq\x1a\x11.payment.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\"\x16/api/v3/payment/notifyB\x1bZ\x19lone-services/rpc/paymentb\x06proto3"
var (
file_payment_payment_proto_rawDescOnce sync.Once
-10
View File
@@ -30,15 +30,10 @@ const (
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type PaymentClient interface {
// 发起支付
Pay(ctx context.Context, in *PayReq, opts ...grpc.CallOption) (*Response, error)
// 查询支付状态
Query(ctx context.Context, in *QueryReq, opts ...grpc.CallOption) (*Response, error)
// 关闭支付
Close(ctx context.Context, in *CloseReq, opts ...grpc.CallOption) (*Response, error)
// 退款
Refund(ctx context.Context, in *RefundReq, opts ...grpc.CallOption) (*Response, error)
// 支付回调(由 BFF/网关转发原始 body + headers)
Notify(ctx context.Context, in *NotifyReq, opts ...grpc.CallOption) (*Response, error)
}
@@ -104,15 +99,10 @@ func (c *paymentClient) Notify(ctx context.Context, in *NotifyReq, opts ...grpc.
// All implementations must embed UnimplementedPaymentServer
// for forward compatibility.
type PaymentServer interface {
// 发起支付
Pay(context.Context, *PayReq) (*Response, error)
// 查询支付状态
Query(context.Context, *QueryReq) (*Response, error)
// 关闭支付
Close(context.Context, *CloseReq) (*Response, error)
// 退款
Refund(context.Context, *RefundReq) (*Response, error)
// 支付回调(由 BFF/网关转发原始 body + headers)
Notify(context.Context, *NotifyReq) (*Response, error)
mustEmbedUnimplementedPaymentServer()
}
+90 -40
View File
@@ -1386,6 +1386,50 @@ func (x *InternalGetUserInfoData) GetCredentialType() string {
return ""
}
type GetOpenidReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetOpenidReq) Reset() {
*x = GetOpenidReq{}
mi := &file_user_user_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetOpenidReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetOpenidReq) ProtoMessage() {}
func (x *GetOpenidReq) ProtoReflect() protoreflect.Message {
mi := &file_user_user_proto_msgTypes[21]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetOpenidReq.ProtoReflect.Descriptor instead.
func (*GetOpenidReq) Descriptor() ([]byte, []int) {
return file_user_user_proto_rawDescGZIP(), []int{21}
}
func (x *GetOpenidReq) GetCode() string {
if x != nil {
return x.Code
}
return ""
}
type InfoReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
@@ -1394,7 +1438,7 @@ type InfoReq struct {
func (x *InfoReq) Reset() {
*x = InfoReq{}
mi := &file_user_user_proto_msgTypes[21]
mi := &file_user_user_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1406,7 +1450,7 @@ func (x *InfoReq) String() string {
func (*InfoReq) ProtoMessage() {}
func (x *InfoReq) ProtoReflect() protoreflect.Message {
mi := &file_user_user_proto_msgTypes[21]
mi := &file_user_user_proto_msgTypes[22]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1419,7 +1463,7 @@ func (x *InfoReq) ProtoReflect() protoreflect.Message {
// Deprecated: Use InfoReq.ProtoReflect.Descriptor instead.
func (*InfoReq) Descriptor() ([]byte, []int) {
return file_user_user_proto_rawDescGZIP(), []int{21}
return file_user_user_proto_rawDescGZIP(), []int{22}
}
type ClientReq struct {
@@ -1433,7 +1477,7 @@ type ClientReq struct {
func (x *ClientReq) Reset() {
*x = ClientReq{}
mi := &file_user_user_proto_msgTypes[22]
mi := &file_user_user_proto_msgTypes[23]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1445,7 +1489,7 @@ func (x *ClientReq) String() string {
func (*ClientReq) ProtoMessage() {}
func (x *ClientReq) ProtoReflect() protoreflect.Message {
mi := &file_user_user_proto_msgTypes[22]
mi := &file_user_user_proto_msgTypes[23]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1458,7 +1502,7 @@ func (x *ClientReq) ProtoReflect() protoreflect.Message {
// Deprecated: Use ClientReq.ProtoReflect.Descriptor instead.
func (*ClientReq) Descriptor() ([]byte, []int) {
return file_user_user_proto_rawDescGZIP(), []int{22}
return file_user_user_proto_rawDescGZIP(), []int{23}
}
func (x *ClientReq) GetName() string {
@@ -1596,15 +1640,18 @@ const file_user_user_proto_rawDesc = "" +
"\n" +
"identifier\x18\b \x01(\tR\n" +
"identifier\x12'\n" +
"\x0fcredential_type\x18\t \x01(\tR\x0ecredentialType\"\t\n" +
"\x0fcredential_type\x18\t \x01(\tR\x0ecredentialType\"\"\n" +
"\fGetOpenidReq\x12\x12\n" +
"\x04code\x18\x01 \x01(\tR\x04code\"\t\n" +
"\aInfoReq\"V\n" +
"\tClientReq\x12\x12\n" +
"\x04name\x18\x01 \x01(\tR\x04name\x12\x12\n" +
"\x04type\x18\x02 \x01(\tR\x04type\x12!\n" +
"\fsubject_type\x18\x03 \x01(\rR\vsubjectType2\x90\b\n" +
"\fsubject_type\x18\x03 \x01(\rR\vsubjectType2\xe0\b\n" +
"\x04User\x12A\n" +
"\x05Login\x12\x0e.user.LoginReq\x1a\x0e.user.Response\"\x18\x82\xd3\xe4\x93\x02\x12:\x01*\"\r/api/v3/login\x12C\n" +
"\x04Info\x12\r.user.InfoReq\x1a\x0e.user.Response\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\x12\x11/api/v3/user/info\x12K\n" +
"\x04Info\x12\r.user.InfoReq\x1a\x0e.user.Response\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\x12\x11/api/v3/user/info\x12N\n" +
"\tGetOpenid\x12\x12.user.GetOpenidReq\x1a\x0e.user.Response\"\x1d\x82\xd3\xe4\x93\x02\x17:\x01*\"\x12/api/v3/getuseroid\x12K\n" +
"\x06Client\x12\x0f.user.ClientReq\x1a\x0e.user.Response\" \x82\xd3\xe4\x93\x02\x1a:\x01*\x12\x15/admin/v3/user/client\x12P\n" +
"\tUserItems\x12\x12.user.UserItemsReq\x1a\x0e.user.Response\"\x1f\x82\xd3\xe4\x93\x02\x19:\x01*\x12\x14/admin/v3/user/items\x12S\n" +
"\n" +
@@ -1630,7 +1677,7 @@ func file_user_user_proto_rawDescGZIP() []byte {
return file_user_user_proto_rawDescData
}
var file_user_user_proto_msgTypes = make([]protoimpl.MessageInfo, 23)
var file_user_user_proto_msgTypes = make([]protoimpl.MessageInfo, 24)
var file_user_user_proto_goTypes = []any{
(*Response)(nil), // 0: user.Response
(*LoginReq)(nil), // 1: user.LoginReq
@@ -1653,39 +1700,42 @@ var file_user_user_proto_goTypes = []any{
(*InternalUpdateData)(nil), // 18: user.InternalUpdateData
(*InternalGetUserInfoReq)(nil), // 19: user.InternalGetUserInfoReq
(*InternalGetUserInfoData)(nil), // 20: user.InternalGetUserInfoData
(*InfoReq)(nil), // 21: user.InfoReq
(*ClientReq)(nil), // 22: user.ClientReq
(*GetOpenidReq)(nil), // 21: user.GetOpenidReq
(*InfoReq)(nil), // 22: user.InfoReq
(*ClientReq)(nil), // 23: user.ClientReq
}
var file_user_user_proto_depIdxs = []int32{
7, // 0: user.InternalUsersByIdsData.items:type_name -> user.UserBriefItem
1, // 1: user.User.Login:input_type -> user.LoginReq
21, // 2: user.User.Info:input_type -> user.InfoReq
22, // 3: user.User.Client:input_type -> user.ClientReq
2, // 4: user.User.UserItems:input_type -> user.UserItemsReq
3, // 5: user.User.UserStatus:input_type -> user.UserStatusReq
4, // 6: user.User.InternalCreate:input_type -> user.InternalCreateReq
13, // 7: user.User.InternalCheckCreate:input_type -> user.InternalCheckCreateReq
15, // 8: user.User.InternalCheckUpdate:input_type -> user.InternalCheckUpdateReq
17, // 9: user.User.InternalUpdate:input_type -> user.InternalUpdateReq
6, // 10: user.User.InternalUsersByIds:input_type -> user.InternalUsersByIdsReq
9, // 11: user.User.InternalUpdateMobile:input_type -> user.InternalUpdateMobileReq
11, // 12: user.User.InternalRevokeBizClient:input_type -> user.InternalRevokeBizClientReq
19, // 13: user.User.InternalGetUserInfo:input_type -> user.InternalGetUserInfoReq
0, // 14: user.User.Login:output_type -> user.Response
0, // 15: user.User.Info:output_type -> user.Response
0, // 16: user.User.Client:output_type -> user.Response
0, // 17: user.User.UserItems:output_type -> user.Response
0, // 18: user.User.UserStatus:output_type -> user.Response
5, // 19: user.User.InternalCreate:output_type -> user.InternalCreateData
14, // 20: user.User.InternalCheckCreate:output_type -> user.InternalCheckCreateData
16, // 21: user.User.InternalCheckUpdate:output_type -> user.InternalCheckUpdateData
18, // 22: user.User.InternalUpdate:output_type -> user.InternalUpdateData
8, // 23: user.User.InternalUsersByIds:output_type -> user.InternalUsersByIdsData
10, // 24: user.User.InternalUpdateMobile:output_type -> user.InternalUpdateMobileData
12, // 25: user.User.InternalRevokeBizClient:output_type -> user.InternalRevokeBizClientData
20, // 26: user.User.InternalGetUserInfo:output_type -> user.InternalGetUserInfoData
14, // [14:27] is the sub-list for method output_type
1, // [1:14] is the sub-list for method input_type
22, // 2: user.User.Info:input_type -> user.InfoReq
21, // 3: user.User.GetOpenid:input_type -> user.GetOpenidReq
23, // 4: user.User.Client:input_type -> user.ClientReq
2, // 5: user.User.UserItems:input_type -> user.UserItemsReq
3, // 6: user.User.UserStatus:input_type -> user.UserStatusReq
4, // 7: user.User.InternalCreate:input_type -> user.InternalCreateReq
13, // 8: user.User.InternalCheckCreate:input_type -> user.InternalCheckCreateReq
15, // 9: user.User.InternalCheckUpdate:input_type -> user.InternalCheckUpdateReq
17, // 10: user.User.InternalUpdate:input_type -> user.InternalUpdateReq
6, // 11: user.User.InternalUsersByIds:input_type -> user.InternalUsersByIdsReq
9, // 12: user.User.InternalUpdateMobile:input_type -> user.InternalUpdateMobileReq
11, // 13: user.User.InternalRevokeBizClient:input_type -> user.InternalRevokeBizClientReq
19, // 14: user.User.InternalGetUserInfo:input_type -> user.InternalGetUserInfoReq
0, // 15: user.User.Login:output_type -> user.Response
0, // 16: user.User.Info:output_type -> user.Response
0, // 17: user.User.GetOpenid:output_type -> user.Response
0, // 18: user.User.Client:output_type -> user.Response
0, // 19: user.User.UserItems:output_type -> user.Response
0, // 20: user.User.UserStatus:output_type -> user.Response
5, // 21: user.User.InternalCreate:output_type -> user.InternalCreateData
14, // 22: user.User.InternalCheckCreate:output_type -> user.InternalCheckCreateData
16, // 23: user.User.InternalCheckUpdate:output_type -> user.InternalCheckUpdateData
18, // 24: user.User.InternalUpdate:output_type -> user.InternalUpdateData
8, // 25: user.User.InternalUsersByIds:output_type -> user.InternalUsersByIdsData
10, // 26: user.User.InternalUpdateMobile:output_type -> user.InternalUpdateMobileData
12, // 27: user.User.InternalRevokeBizClient:output_type -> user.InternalRevokeBizClientData
20, // 28: user.User.InternalGetUserInfo:output_type -> user.InternalGetUserInfoData
15, // [15:29] is the sub-list for method output_type
1, // [1:15] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
@@ -1702,7 +1752,7 @@ func file_user_user_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_user_user_proto_rawDesc), len(file_user_user_proto_rawDesc)),
NumEnums: 0,
NumMessages: 23,
NumMessages: 24,
NumExtensions: 0,
NumServices: 1,
},
+38 -1
View File
@@ -8,7 +8,6 @@ package user
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
@@ -22,6 +21,7 @@ const _ = grpc.SupportPackageIsVersion9
const (
User_Login_FullMethodName = "/user.User/Login"
User_Info_FullMethodName = "/user.User/Info"
User_GetOpenid_FullMethodName = "/user.User/GetOpenid"
User_Client_FullMethodName = "/user.User/Client"
User_UserItems_FullMethodName = "/user.User/UserItems"
User_UserStatus_FullMethodName = "/user.User/UserStatus"
@@ -41,6 +41,7 @@ const (
type UserClient interface {
Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*Response, error)
Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*Response, error)
GetOpenid(ctx context.Context, in *GetOpenidReq, opts ...grpc.CallOption) (*Response, error)
Client(ctx context.Context, in *ClientReq, opts ...grpc.CallOption) (*Response, error)
UserItems(ctx context.Context, in *UserItemsReq, opts ...grpc.CallOption) (*Response, error)
UserStatus(ctx context.Context, in *UserStatusReq, opts ...grpc.CallOption) (*Response, error)
@@ -82,6 +83,16 @@ func (c *userClient) Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOpt
return out, nil
}
func (c *userClient) GetOpenid(ctx context.Context, in *GetOpenidReq, opts ...grpc.CallOption) (*Response, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Response)
err := c.cc.Invoke(ctx, User_GetOpenid_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *userClient) Client(ctx context.Context, in *ClientReq, opts ...grpc.CallOption) (*Response, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Response)
@@ -198,6 +209,7 @@ func (c *userClient) InternalGetUserInfo(ctx context.Context, in *InternalGetUse
type UserServer interface {
Login(context.Context, *LoginReq) (*Response, error)
Info(context.Context, *InfoReq) (*Response, error)
GetOpenid(context.Context, *GetOpenidReq) (*Response, error)
Client(context.Context, *ClientReq) (*Response, error)
UserItems(context.Context, *UserItemsReq) (*Response, error)
UserStatus(context.Context, *UserStatusReq) (*Response, error)
@@ -225,6 +237,9 @@ func (UnimplementedUserServer) Login(context.Context, *LoginReq) (*Response, err
func (UnimplementedUserServer) Info(context.Context, *InfoReq) (*Response, error) {
return nil, status.Error(codes.Unimplemented, "method Info not implemented")
}
func (UnimplementedUserServer) GetOpenid(context.Context, *GetOpenidReq) (*Response, error) {
return nil, status.Error(codes.Unimplemented, "method GetOpenid not implemented")
}
func (UnimplementedUserServer) Client(context.Context, *ClientReq) (*Response, error) {
return nil, status.Error(codes.Unimplemented, "method Client not implemented")
}
@@ -315,6 +330,24 @@ func _User_Info_Handler(srv interface{}, ctx context.Context, dec func(interface
return interceptor(ctx, in, info, handler)
}
func _User_GetOpenid_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetOpenidReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UserServer).GetOpenid(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: User_GetOpenid_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserServer).GetOpenid(ctx, req.(*GetOpenidReq))
}
return interceptor(ctx, in, info, handler)
}
func _User_Client_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ClientReq)
if err := dec(in); err != nil {
@@ -528,6 +561,10 @@ var User_ServiceDesc = grpc.ServiceDesc{
MethodName: "Info",
Handler: _User_Info_Handler,
},
{
MethodName: "GetOpenid",
Handler: _User_GetOpenid_Handler,
},
{
MethodName: "Client",
Handler: _User_Client_Handler,
BIN
View File
Binary file not shown.
+10
View File
@@ -144,6 +144,10 @@ message InternalGetUserInfoData {
string credential_type = 9;
}
message GetOpenidReq {
string code = 1;
}
message InfoReq {}
message ClientReq {
@@ -165,6 +169,12 @@ service User {
body: "*"
};
}
rpc GetOpenid(GetOpenidReq) returns (Response) {
option (google.api.http) = {
post: "/api/v3/getuseroid"
body: "*"
};
}
rpc Client(ClientReq) returns (Response) {
option (google.api.http) = {
get: "/admin/v3/user/client"
+6 -5
View File
@@ -78,12 +78,13 @@ func (l *PayLogic) Pay(in *payment.PayReq) (*payment.Response, error) {
switch channelCode {
case pkgpay.ChannelWechat:
openid, oErr := loadOpenID(l.ctx, l.svcCtx.UserSvcName, loginUser.ID)
if oErr != nil || openid == utils.StringEmpty {
l.Errorf("pay openid: %v", oErr)
return outResponse(utils.Fail, "未绑定微信openid"), nil
if client == pkgpay.ClientApp {
break
}
prepayReq.OpenID = openid
if in.Openid == utils.StringEmpty {
return outResponse(utils.ErrorParams, "openid不能为空"), nil
}
prepayReq.OpenID = in.Openid
case pkgpay.ChannelAlipay, pkgpay.ChannelBank:
return outResponse(utils.Fail, "支付渠道暂未开通"), nil
}
@@ -1,35 +0,0 @@
package logic
import (
"context"
"fmt"
"lone-services/pkg/utils"
userpb "lone-services/rpc/user/pb"
"lone-services/services/payment/internal/svc"
)
func loadOpenID(ctx context.Context, userSvcName string, userID int64) (string, error) {
if userSvcName == utils.StringEmpty {
return utils.StringEmpty, fmt.Errorf("user service not configured")
}
if userID < utils.NumberOne {
return utils.StringEmpty, fmt.Errorf("invalid user id")
}
cli, err := svc.GetRpcClient(userSvcName)
if err != nil {
return utils.StringEmpty, err
}
info, err := userpb.NewUserClient(cli.Conn()).InternalGetUserInfo(ctx, &userpb.InternalGetUserInfoReq{
UserId: userID,
CredentialType: "openid",
})
if err != nil {
return utils.StringEmpty, err
}
if info == nil || info.Identifier == utils.StringEmpty {
return utils.StringEmpty, fmt.Errorf("openid credential not found")
}
return info.Identifier, nil
}
@@ -7,7 +7,7 @@ package server
import (
"context"
"lone-services/rpc/payment/pb"
payment "lone-services/rpc/payment/pb"
"lone-services/services/payment/internal/logic"
"lone-services/services/payment/internal/svc"
)
@@ -23,31 +23,26 @@ func NewPaymentServer(svcCtx *svc.ServiceContext) *PaymentServer {
}
}
// 发起支付
func (s *PaymentServer) Pay(ctx context.Context, in *payment.PayReq) (*payment.Response, error) {
l := logic.NewPayLogic(ctx, s.svcCtx)
return l.Pay(in)
}
// 查询支付状态
func (s *PaymentServer) Query(ctx context.Context, in *payment.QueryReq) (*payment.Response, error) {
l := logic.NewQueryLogic(ctx, s.svcCtx)
return l.Query(in)
}
// 关闭支付
func (s *PaymentServer) Close(ctx context.Context, in *payment.CloseReq) (*payment.Response, error) {
l := logic.NewCloseLogic(ctx, s.svcCtx)
return l.Close(in)
}
// 退款
func (s *PaymentServer) Refund(ctx context.Context, in *payment.RefundReq) (*payment.Response, error) {
l := logic.NewRefundLogic(ctx, s.svcCtx)
return l.Refund(in)
}
// 支付回调(由 BFF/网关转发原始 body + headers)
func (s *PaymentServer) Notify(ctx context.Context, in *payment.NotifyReq) (*payment.Response, error) {
l := logic.NewNotifyLogic(ctx, s.svcCtx)
return l.Notify(in)
-10
View File
@@ -22,15 +22,10 @@ type (
Response = payment.Response
Payment interface {
// 发起支付
Pay(ctx context.Context, in *PayReq, opts ...grpc.CallOption) (*Response, error)
// 查询支付状态
Query(ctx context.Context, in *QueryReq, opts ...grpc.CallOption) (*Response, error)
// 关闭支付
Close(ctx context.Context, in *CloseReq, opts ...grpc.CallOption) (*Response, error)
// 退款
Refund(ctx context.Context, in *RefundReq, opts ...grpc.CallOption) (*Response, error)
// 支付回调(由 BFF/网关转发原始 body + headers)
Notify(ctx context.Context, in *NotifyReq, opts ...grpc.CallOption) (*Response, error)
}
@@ -45,31 +40,26 @@ func NewPayment(cli zrpc.Client) Payment {
}
}
// 发起支付
func (m *defaultPayment) Pay(ctx context.Context, in *PayReq, opts ...grpc.CallOption) (*Response, error) {
client := payment.NewPaymentClient(m.cli.Conn())
return client.Pay(ctx, in, opts...)
}
// 查询支付状态
func (m *defaultPayment) Query(ctx context.Context, in *QueryReq, opts ...grpc.CallOption) (*Response, error) {
client := payment.NewPaymentClient(m.cli.Conn())
return client.Query(ctx, in, opts...)
}
// 关闭支付
func (m *defaultPayment) Close(ctx context.Context, in *CloseReq, opts ...grpc.CallOption) (*Response, error) {
client := payment.NewPaymentClient(m.cli.Conn())
return client.Close(ctx, in, opts...)
}
// 退款
func (m *defaultPayment) Refund(ctx context.Context, in *RefundReq, opts ...grpc.CallOption) (*Response, error) {
client := payment.NewPaymentClient(m.cli.Conn())
return client.Refund(ctx, in, opts...)
}
// 支付回调(由 BFF/网关转发原始 body + headers)
func (m *defaultPayment) Notify(ctx context.Context, in *NotifyReq, opts ...grpc.CallOption) (*Response, error) {
client := payment.NewPaymentClient(m.cli.Conn())
return client.Notify(ctx, in, opts...)
+5
View File
@@ -6,6 +6,11 @@ type Token struct {
Info UserLoginSession `json:"info"`
}
type OpenidResult struct {
Openid string `json:"openid"`
Unionid string `json:"unionid"`
}
type UserLoginSession struct {
Id int64 `json:"id"`
Name string `json:"name"`
@@ -0,0 +1,66 @@
package logic
import (
"context"
"lone-services/pkg/utils"
"lone-services/pkg/validate"
user "lone-services/rpc/user/pb"
userconfig "lone-services/services/user/internal/config"
"lone-services/services/user/internal/dao"
"lone-services/services/user/internal/svc"
"lone-services/services/user/validator"
"github.com/zeromicro/go-zero/core/logx"
)
type GetOpenidLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewGetOpenidLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetOpenidLogic {
return &GetOpenidLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *GetOpenidLogic) GetOpenid(in *user.GetOpenidReq) (*user.Response, error) {
loginUser := utils.GetUserFromCtx(l.ctx)
if loginUser.ID < utils.NumberOne {
return failResponse(utils.ErrorNoLoginInfo), nil
}
var req validator.GetOpenidValidator
if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty {
return outResponse(utils.ErrorParams, msg), nil
}
if loginUser.ClientCode == utils.StringEmpty {
return outResponse(utils.ErrorParams, "端编码不能为空"), nil
}
if _, err := loadEnabledClient(loginUser.ClientCode); err != nil {
l.Errorf("get openid load client: %v", err)
return failResponse(utils.Fail), nil
}
wxClient, cfgErr := userconfig.NewWechatClient(loginUser.ClientCode)
if cfgErr != nil {
l.Errorf("get openid wechat config: %v", cfgErr)
return outResponse(utils.Fail, "微信配置缺失"), nil
}
session, wxErr := wxClient.Code2Session(req.Code)
if wxErr != nil {
l.Errorf("get openid code2session: %v", wxErr)
return outResponse(utils.Fail, "获取openid失败"), nil
}
return okResponse(dao.OpenidResult{
Openid: session.OpenID,
Unionid: session.UnionID,
}), nil
}
@@ -33,6 +33,11 @@ func (s *UserServer) Info(ctx context.Context, in *user.InfoReq) (*user.Response
return l.Info(in)
}
func (s *UserServer) GetOpenid(ctx context.Context, in *user.GetOpenidReq) (*user.Response, error) {
l := logic.NewGetOpenidLogic(ctx, s.svcCtx)
return l.GetOpenid(in)
}
func (s *UserServer) Client(ctx context.Context, in *user.ClientReq) (*user.Response, error) {
l := logic.NewClientLogic(ctx, s.svcCtx)
return l.Client(in)
+7
View File
@@ -15,6 +15,7 @@ import (
type (
ClientReq = user.ClientReq
GetOpenidReq = user.GetOpenidReq
InfoReq = user.InfoReq
InternalCheckCreateData = user.InternalCheckCreateData
InternalCheckCreateReq = user.InternalCheckCreateReq
@@ -41,6 +42,7 @@ type (
User interface {
Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*Response, error)
Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*Response, error)
GetOpenid(ctx context.Context, in *GetOpenidReq, opts ...grpc.CallOption) (*Response, error)
Client(ctx context.Context, in *ClientReq, opts ...grpc.CallOption) (*Response, error)
UserItems(ctx context.Context, in *UserItemsReq, opts ...grpc.CallOption) (*Response, error)
UserStatus(ctx context.Context, in *UserStatusReq, opts ...grpc.CallOption) (*Response, error)
@@ -75,6 +77,11 @@ func (m *defaultUser) Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOp
return client.Info(ctx, in, opts...)
}
func (m *defaultUser) GetOpenid(ctx context.Context, in *GetOpenidReq, opts ...grpc.CallOption) (*Response, error) {
client := user.NewUserClient(m.cli.Conn())
return client.GetOpenid(ctx, in, opts...)
}
func (m *defaultUser) Client(ctx context.Context, in *ClientReq, opts ...grpc.CallOption) (*Response, error) {
client := user.NewUserClient(m.cli.Conn())
return client.Client(ctx, in, opts...)
+11
View File
@@ -24,6 +24,17 @@ func (p LoginValidator) GetMessage() validate.ValidatorMessages {
}
}
type GetOpenidValidator struct {
Code string `validate:"required,max=128"`
}
func (p GetOpenidValidator) GetMessage() validate.ValidatorMessages {
return validate.ValidatorMessages{
"Code.required": "Code 不能为空",
"Code.max": "Code 过长",
}
}
type UserItemsValidator struct {
Mobile string
Page int32 `validate:"omitempty,min=1"`