From 214e087197f0e7766c284f714f19bbfcecf21456 Mon Sep 17 00:00:00 2001 From: liangzai <2440983361@qq.com> Date: Tue, 15 Apr 2025 22:52:02 +0800 Subject: [PATCH] add agent vip activateagent --- app/user/cmd/api/desc/agent.api | 27 +-- app/user/cmd/api/desc/pay.api | 13 +- app/user/cmd/api/etc/main.dev.yaml | 14 +- app/user/cmd/api/etc/main.yaml | 2 +- .../handler/pay/paymentcheckhandler.go | 29 +++ app/user/cmd/api/internal/handler/routes.go | 17 +- .../agent/activateagentmembershiplogic.go | 154 ++++++++----- .../logic/agent/agentwithdrawallogic.go | 2 +- .../internal/logic/pay/alipaycallbacklogic.go | 155 ++++++++++++- .../internal/logic/pay/paymentchecklogic.go | 49 ++++ .../api/internal/logic/pay/paymentlogic.go | 200 +++++++++++------ .../internal/logic/query/queryservicelogic.go | 4 +- .../api/internal/queue/paySuccessNotify.go | 4 +- .../cmd/api/internal/service/alipayService.go | 16 +- app/user/cmd/api/internal/types/cache.go | 7 + app/user/cmd/api/internal/types/types.go | 23 +- .../agentMembershipRechargeOrderModel_gen.go | 126 ++++++++--- app/user/model/vars.go | 16 ++ deploy/script/genModel.ps1 | 25 --- deploy/script/gen_models.ps1 | 4 +- gen_api.ps1 | 2 + temp/agent/agent.api | 211 ------------------ temp/app/app.api | 17 -- temp/auth/auth.api | 16 -- temp/pay/pay.api | 28 --- temp/product/product.api | 36 --- temp/query/query.api | 127 ----------- temp/user/user.api | 101 --------- 28 files changed, 633 insertions(+), 792 deletions(-) create mode 100644 app/user/cmd/api/internal/handler/pay/paymentcheckhandler.go create mode 100644 app/user/cmd/api/internal/logic/pay/paymentchecklogic.go delete mode 100644 deploy/script/genModel.ps1 create mode 100644 gen_api.ps1 delete mode 100644 temp/agent/agent.api delete mode 100644 temp/app/app.api delete mode 100644 temp/auth/auth.api delete mode 100644 temp/pay/pay.api delete mode 100644 temp/product/product.api delete mode 100644 temp/query/query.api delete mode 100644 temp/user/user.api diff --git a/app/user/cmd/api/desc/agent.api b/app/user/cmd/api/desc/agent.api index bcfdc95..f6098b3 100644 --- a/app/user/cmd/api/desc/agent.api +++ b/app/user/cmd/api/desc/agent.api @@ -141,6 +141,9 @@ service main { @handler AgentWithdrawal post /withdrawal (WithdrawalReq) returns (WithdrawalResp) + + @handler ActivateAgentMembership + post /membership/activate (AgentActivateMembershipReq) returns (AgentActivateMembershipResp) } type ( @@ -231,6 +234,15 @@ type ( Status int64 `json:"status"` // 1申请中 2成功 3失败 failMsg string `json:"fail_msg"` } + + // 开通代理会员请求参数 + AgentActivateMembershipReq { + Type string `json:"type,oneof=VIP SVIP"` // 会员类型:vip/svip + } + // 开通代理会员响应 + AgentActivateMembershipResp { + Id string `json:"id"` + } ) @server ( @@ -246,8 +258,6 @@ service main { @handler GetLinkData get /link (GetLinkDataReq) returns (GetLinkDataResp) - @handler ActivateAgentMembership - post /membership/activate (AgentActivateMembershipReq) returns (AgentActivateMembershipResp) } type ( @@ -270,18 +280,5 @@ type ( GetLinkDataResp { Product } - // 开通代理会员请求参数 - AgentActivateMembershipReq { - Mobile string `json:"mobile"` - Type string `json:"type,oneof=VIP SVIP"` // 会员类型:vip/svip - Amount float64 `json:"amount"` - PaymentMethod string `json:"payment_method"` - TransactionId string `json:"transaction_id"` - } - // 开通代理会员响应 - AgentActivateMembershipResp { - MembershipType string `json:"membership_type"` // 最终开通的会员类型 - ExpireTime string `json:"expire_time"` // 到期时间 - } ) diff --git a/app/user/cmd/api/desc/pay.api b/app/user/cmd/api/desc/pay.api index e01b333..5f363ab 100644 --- a/app/user/cmd/api/desc/pay.api +++ b/app/user/cmd/api/desc/pay.api @@ -39,17 +39,28 @@ service main { @handler IapCallback post /pay/iap_callback (IapCallbackReq) + + @handler PaymentCheck + post /pay/check (PaymentCheckReq) returns (PaymentCheckResp) } type ( PaymentReq { Id string `json:"id"` PayMethod string `json:"pay_method"` + PayType string `json:"pay_type" validate:"required,oneof=query agent_vip"` } PaymentResp { PrepayData interface{} `json:"prepay_data"` PrepayId string `json:"prepay_id"` - OrderID int64 `json:"order_id"` + OrderNo string `json:"order_no"` + } + PaymentCheckReq { + OrderNo string `json:"order_no" validate:"required"` + } + PaymentCheckResp { + Type string `json:"type"` + Status string `json:"status"` } ) diff --git a/app/user/cmd/api/etc/main.dev.yaml b/app/user/cmd/api/etc/main.dev.yaml index 7bf8bd3..2dc81a2 100644 --- a/app/user/cmd/api/etc/main.dev.yaml +++ b/app/user/cmd/api/etc/main.dev.yaml @@ -32,21 +32,21 @@ Alipay: AppID: "2021004165608254" PrivateKey: "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCPsXuwFJeHAL8CwI0QdD9GP7xQ8eejIoQKg6J3/peu26su68JCtGSRhlDm/7vbLHJcFR6h7at+INoz2juc7SqlmNO7i9wKc3+Ua0487y1G2fCsneRNxTTqbceBZwqjj9/AAN0u5/4nSl0bcqTeMddofdpTGOvwGvIJh6CZgCglnhMZnH4D6H6yiIyZf7Q6k2d/qBpVGK8kluYEtSnf/vEQCHhxRx+/DgTL7V1LjbA3BYoPTELZ15JAj0uIzuxextAtxOm4+Huli0RJFAN3q/to2L1Zs8yYY1gKJyTaPWKsJWBx8zI+gZcC/e45k6CZnGgh1Fn3+Xqkf7eGxJGGHs1fAgMBAAECggEAM2rkApbrvdBDiV2TXK7sMVv/K8vUAmkIbKa7zUpZxqUuNSUBp1LbpcM1UeNyujPGXDLmejUMp55j1igiKr4nA4iTQ0oBm+/GWDqpjV5cijzURUBegIGvtK9Bs4lGok6KVy839l/nbvHKLVcxrZySIv7dz9xcGNfbghN5IVRdiU/kOokNbtwQNC837piG5q4PHL6bzwIUGbrLED/RDmw/IwVMMmZovcQQ2JAuWJBo9CS9LB0Nc3I4MOPNx/0Rl+5URSSfmJAriL5ihlWckocQCUHwhRpSGQ6Q4xAXFYvb8OsApAQG3WU9SciBfs2wg/QfGNFzwQgGFofPcTQg3DTeuQKBgQDUHBTsgoe3WXnGo6qZKw1zA4OtF67IJJoltHo5JtkBRKCNVU3BJ+q+6i/fn0MBwScKQ1mhPjWe3h+qTRT207RRxGaxb6ljATOiU+BxmpHvu6jP+DVYtP5F3M7MCAGqpDAEoXgoAWttxmijqk+5YuLOLe0j/btCmpzuH7zwxSnqlQKBgQCtbTvaS/g+Jeu4Ml6iv7xi5//JCjeTn2wUJpXnNmN0jn+riRwEO81z4GWuOI8WukZHHAnufI6qWk2sLH0gcdLQ/STsMnl2L3NbeUyO8o5w2JSAlnZDYfaFfasGqFkGJrBLqG6bh/Bk1DP3/Bl6iMEwDbmu7Ptoy8ihokng9dEPIwKBgBHdi6WgGO5IiwlAH85m4eseEKkzpXUWICWs3d6SdxS0QxGkbbgnNI6ACyg6sdoj+rXSlmoOY1XOP7yIYYuoqTd542xui0XbhA3YIr9u1XvrwnxB27xtAj3AK2rkAb/ttF2ve/9inznPzGB8p9plidTz6VVuuacSfsVPxwpAkRdBAoGAR7c9Ifd6b1DFGkWSBuEc6RWhG6Si+OPbELYoFRXTqNZoiynGsSV9v2ZTBemTmkVrXGqG3N0bLezr47/9+lW3ZP7ZrubsfWf/3xrZAt/g8V9OgaI2w4SWKfuepsElFzsWeiLroltjmH58Axd3/cjhgpqaZ3DOQjbK/7QZsvJUAlsCgYEAqTQVhKLizM7BvXu1N6Z2K8trfJbiN+f90XhZIRPkIIcom0PnOfXhRtT76MCxz9n+lwf+alOKOfbQFy0pZtWG/eaFSYroQlXL+EfmqlFPXZR6D0NQLeygWAKH8161IQUh2VF3Qkhle6g6ZkyJA3Ev4RmqH2BYGv8hcZTTHsZ3Ic4=" AlipayPublicKey: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2CqoCp95w/JV3RT/gzF4/8QmVT1HQNaeW7yUp+mA7x9AbjvlTW/+eRn6oGAL/XhZLjvHD0XjKLVKX0MJVS1aUQHEHEbOJN4Eu8II45OavD4iZISa7Kp9V6AM+i4qTyaeV2wNDnGxHQBaLVUGCfMR+56EK2YpORdE1H9uy72SSQseVb3bmpsV9EW/IJNmcVL/ut3uA1JWAoRmzlQ7ekxg7p8AYXzYPEHQr1tl7W+M4zv9wO9GKZCxIqMA8U3RP5npPfRaCfIRGzXzCqFEEUvWuidOB7frsvN4jiPD07qpL2Bi9LM1X/ee2kC/oM8Uhd7ERZhG8MbZfijZKxgrsDKBcwIDAQAB" - AppCertPath: "app/user/cmd/api/etc/merchant/appCertPublicKey_2021004165608254.crt" - AlipayCertPath: "app/user/cmd/api/etc/merchant/alipayCertPublicKey_RSA2.crt" - AlipayRootCertPath: "app/user/cmd/api/etc/merchant/alipayRootCert.crt" + AppCertPath: "etc/merchant/appCertPublicKey_2021004165608254.crt" + AlipayCertPath: "etc/merchant/alipayCertPublicKey_RSA2.crt" + AlipayRootCertPath: "etc/merchant/alipayRootCert.crt" IsProduction: true NotifyUrl: "https://6m4685017o.goho.co/api/v1/pay/alipay/callback" - ReturnURL: "http://localhost:5678/inquire" + ReturnURL: "http://192.168.10.13:5679/payment/result" Wxpay: AppID: "wxa581992dc74d860e" MchID: "1704330055" MchPublicKeyID: "PUB_KEY_ID_0117043300552025010900447500000187" - MchPublicKeyPath: "app/user/cmd/api/etc/merchant/pub_key.pem" + MchPublicKeyPath: "etc/merchant/pub_key.pem" MchCertificateSerialNumber: "434FE8C0FC8CFEF28B76B3EF35DD2297E977A3CB" MchApiv3Key: "h6Jk9Qm7W1pXyFzA4bL2V8CzH0K3wDqw" - MchPrivateKeyPath: "app/user/cmd/api/etc/merchant/apiclient_key.pem" + MchPrivateKeyPath: "etc/merchant/apiclient_key.pem" NotifyUrl: "https://6m4685017o.goho.co/api/v1/pay/wechat/callback" RefundNotifyUrl: "https://6m4685017o.goho.co/api/v1/wechat/refund_callback" Applepay: @@ -56,7 +56,7 @@ Applepay: BundleID: "com.allinone.check" IssuerID: "bf828d85-5269-4914-9660-c066e09cd6ef" KeyID: "LAY65829DQ" - LoadPrivateKeyPath: "app/user/cmd/api/etc/merchant/AuthKey_LAY65829DQ.p8" + LoadPrivateKeyPath: "etc/merchant/AuthKey_LAY65829DQ.p8" Ali: Code: "d55b58829efb41c8aa8e86769cba4844" SystemConfig: diff --git a/app/user/cmd/api/etc/main.yaml b/app/user/cmd/api/etc/main.yaml index 25d85ea..50683db 100644 --- a/app/user/cmd/api/etc/main.yaml +++ b/app/user/cmd/api/etc/main.yaml @@ -39,7 +39,7 @@ Alipay: AlipayRootCertPath: "etc/merchant/alipayRootCert.crt" IsProduction: true NotifyUrl: "https://www.quannengcha.com/api/v1/pay/alipay/callback" - ReturnURL: "https://www.quannengcha.com/report" + ReturnURL: "https://www.quannengcha.com/payment/result" Wxpay: AppID: "wxa581992dc74d860e" MchID: "1704330055" diff --git a/app/user/cmd/api/internal/handler/pay/paymentcheckhandler.go b/app/user/cmd/api/internal/handler/pay/paymentcheckhandler.go new file mode 100644 index 0000000..ce5db47 --- /dev/null +++ b/app/user/cmd/api/internal/handler/pay/paymentcheckhandler.go @@ -0,0 +1,29 @@ +package pay + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "qnc-server/app/user/cmd/api/internal/logic/pay" + "qnc-server/app/user/cmd/api/internal/svc" + "qnc-server/app/user/cmd/api/internal/types" + "qnc-server/common/result" + "qnc-server/pkg/lzkit/validator" +) + +func PaymentCheckHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.PaymentCheckReq + if err := httpx.Parse(r, &req); err != nil { + result.ParamErrorResult(r, w, err) + return + } + if err := validator.Validate(req); err != nil { + result.ParamValidateErrorResult(r, w, err) + return + } + l := pay.NewPaymentCheckLogic(r.Context(), svcCtx) + resp, err := l.PaymentCheck(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/user/cmd/api/internal/handler/routes.go b/app/user/cmd/api/internal/handler/routes.go index a282967..92d9028 100644 --- a/app/user/cmd/api/internal/handler/routes.go +++ b/app/user/cmd/api/internal/handler/routes.go @@ -1,6 +1,4 @@ // Code generated by goctl. DO NOT EDIT. -// goctl 1.7.3 - package handler import ( @@ -71,6 +69,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/commission", Handler: agent.GetAgentCommissionHandler(serverCtx), }, + { + Method: http.MethodPost, + Path: "/membership/activate", + Handler: agent.ActivateAgentMembershipHandler(serverCtx), + }, { Method: http.MethodGet, Path: "/revenue", @@ -108,11 +111,6 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/link", Handler: agent.GetLinkDataHandler(serverCtx), }, - { - Method: http.MethodPost, - Path: "/membership/activate", - Handler: agent.ActivateAgentMembershipHandler(serverCtx), - }, }, rest.WithPrefix("/api/v1/agent"), ) @@ -183,6 +181,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { rest.WithMiddlewares( []rest.Middleware{serverCtx.SourceInterceptor}, []rest.Route{ + { + Method: http.MethodPost, + Path: "/pay/check", + Handler: pay.PaymentCheckHandler(serverCtx), + }, { Method: http.MethodPost, Path: "/pay/iap_callback", diff --git a/app/user/cmd/api/internal/logic/agent/activateagentmembershiplogic.go b/app/user/cmd/api/internal/logic/agent/activateagentmembershiplogic.go index f366ebf..58258f0 100644 --- a/app/user/cmd/api/internal/logic/agent/activateagentmembershiplogic.go +++ b/app/user/cmd/api/internal/logic/agent/activateagentmembershiplogic.go @@ -2,17 +2,17 @@ package agent import ( "context" - "database/sql" - "qnc-server/app/user/model" + "encoding/json" + "fmt" + "qnc-server/common/ctxdata" "qnc-server/common/xerr" - "qnc-server/pkg/lzkit/crypto" "time" "github.com/pkg/errors" - "github.com/zeromicro/go-zero/core/stores/sqlx" "qnc-server/app/user/cmd/api/internal/svc" "qnc-server/app/user/cmd/api/internal/types" + "qnc-server/app/user/model" "github.com/zeromicro/go-zero/core/logx" ) @@ -30,27 +30,16 @@ func NewActivateAgentMembershipLogic(ctx context.Context, svcCtx *svc.ServiceCon svcCtx: svcCtx, } } - func (l *ActivateAgentMembershipLogic) ActivateAgentMembership(req *types.AgentActivateMembershipReq) (resp *types.AgentActivateMembershipResp, err error) { - //userID, err := ctxdata.GetUidFromCtx(l.ctx) - //if err != nil { - // return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户ID失败: %v", err) - //} - secretKey := l.svcCtx.Config.Encrypt.SecretKey - encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey) + userID, err := ctxdata.GetUidFromCtx(l.ctx) if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "加密手机号失败: %v", err) - } - userModel, err := l.svcCtx.UserModel.FindOneByMobile(l.ctx, encryptedMobile) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败: %v", err) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户ID失败: %v", err) } // 查询用户代理信息 - agentModel, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userModel.Id) - if err != nil && err != sql.ErrNoRows { + agentModel, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID) + if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败: %v", err) } - // 定义等级顺序映射 levelOrder := map[string]int{ "": 1, @@ -78,51 +67,96 @@ func (l *ActivateAgentMembershipLogic) ActivateAgentMembership(req *types.AgentA "禁止降级操作(当前等级:%s,请求等级:%s)", agentModel.LevelName, req.Type) } } - - err = l.svcCtx.AgentModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error { - agentModel.LevelName = req.Type - agentModel.MembershipExpiryTime = RenewMembership(agentModel.MembershipExpiryTime) - transErr := l.svcCtx.AgentModel.UpdateWithVersion(transCtx, session, agentModel) - if transErr != nil { - return transErr - } - agentMembershipRechargeOrder := model.AgentMembershipRechargeOrder{ - AgentId: agentModel.Id, - UserId: userModel.Id, - LevelName: req.Type, - Amount: req.Amount, - PaymentMethod: req.PaymentMethod, - TransactionId: req.TransactionId, - } - _, transErr = l.svcCtx.AgentMembershipRechargeOrderModel.Insert(transCtx, session, &agentMembershipRechargeOrder) - if transErr != nil { - return transErr - } - return nil - }) + outTradeNo := "A_" + l.svcCtx.AlipayService.GenerateOutTradeNo() + redisKey := fmt.Sprintf(types.AgentVipCacheKey, userID, outTradeNo) + agentVipCache := types.AgentVipCache{Type: req.Type} + jsonData, err := json.Marshal(agentVipCache) if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "升级代理等级失败: %s", req.Type) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "序列化代理VIP缓存失败: %v", err) + } + cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour)) + if cacheErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "设置缓存失败: %v", cacheErr) } return &types.AgentActivateMembershipResp{ - MembershipType: req.Type, - ExpireTime: agentModel.MembershipExpiryTime.Time.Format("2006-01-02 15:04:05"), + Id: outTradeNo, }, nil } -func RenewMembership(expiry sql.NullTime) sql.NullTime { - // 确定基准时间 - var baseTime time.Time - if expiry.Valid { - baseTime = expiry.Time - } else { - baseTime = time.Now() - } - // 增加一年(自动处理闰年) - newTime := baseTime.AddDate(1, 0, 0) +// func (l *ActivateAgentMembershipLogic) ActivateAgentMembership(req *types.AgentActivateMembershipReq) (resp *types.AgentActivateMembershipResp, err error) { +// //userID, err := ctxdata.GetUidFromCtx(l.ctx) +// //if err != nil { +// // return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户ID失败: %v", err) +// //} +// secretKey := l.svcCtx.Config.Encrypt.SecretKey +// encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey) +// if err != nil { +// return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "加密手机号失败: %v", err) +// } +// userModel, err := l.svcCtx.UserModel.FindOneByMobile(l.ctx, encryptedMobile) +// if err != nil { +// return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败: %v", err) +// } +// // 查询用户代理信息 +// agentModel, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userModel.Id) +// if err != nil && err != sql.ErrNoRows { +// return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败: %v", err) +// } - // 返回始终有效的 NullTime - return sql.NullTime{ - Time: newTime, - Valid: true, - } -} +// // 定义等级顺序映射 +// levelOrder := map[string]int{ +// "": 1, +// model.AgentLeveNameNormal: 1, +// model.AgentLeveNameVIP: 2, +// model.AgentLeveNameSVIP: 3, +// } + +// // 验证请求等级合法性 +// if _, valid := levelOrder[req.Type]; !valid { +// return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "无效的代理等级: %s", req.Type) +// } + +// // 如果存在代理记录,进行等级验证 +// if agentModel != nil { +// currentLevel, exists := levelOrder[agentModel.LevelName] +// if !exists { +// return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), +// "非法的当前代理等级: %s", agentModel.LevelName) +// } + +// requestedLevel := levelOrder[req.Type] +// if requestedLevel < currentLevel { +// return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), +// "禁止降级操作(当前等级:%s,请求等级:%s)", agentModel.LevelName, req.Type) +// } +// } + +// err = l.svcCtx.AgentModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error { +// agentModel.LevelName = req.Type +// agentModel.MembershipExpiryTime = RenewMembership(agentModel.MembershipExpiryTime) +// transErr := l.svcCtx.AgentModel.UpdateWithVersion(transCtx, session, agentModel) +// if transErr != nil { +// return transErr +// } +// agentMembershipRechargeOrder := model.AgentMembershipRechargeOrder{ +// AgentId: agentModel.Id, +// UserId: userModel.Id, +// LevelName: req.Type, +// Amount: req.Amount, +// PaymentMethod: req.PaymentMethod, +// TransactionId: req.TransactionId, +// } +// _, transErr = l.svcCtx.AgentMembershipRechargeOrderModel.Insert(transCtx, session, &agentMembershipRechargeOrder) +// if transErr != nil { +// return transErr +// } +// return nil +// }) +// if err != nil { +// return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "升级代理等级失败: %s", req.Type) +// } +// return &types.AgentActivateMembershipResp{ +// MembershipType: req.Type, +// ExpireTime: agentModel.MembershipExpiryTime.Time.Format("2006-01-02 15:04:05"), +// }, nil +// } diff --git a/app/user/cmd/api/internal/logic/agent/agentwithdrawallogic.go b/app/user/cmd/api/internal/logic/agent/agentwithdrawallogic.go index 7ea3a7e..77e98c2 100644 --- a/app/user/cmd/api/internal/logic/agent/agentwithdrawallogic.go +++ b/app/user/cmd/api/internal/logic/agent/agentwithdrawallogic.go @@ -80,7 +80,7 @@ func (l *AgentWithdrawalLogic) AgentWithdrawal(req *types.WithdrawalReq) (*types } // 生成交易号 - outBizNo = l.svcCtx.AlipayService.GenerateOutTradeNo() + outBizNo = "W_" + l.svcCtx.AlipayService.GenerateOutTradeNo() // 创建提现记录(初始状态为处理中) if err = l.createWithdrawalRecord(session, agentModel.Id, req, outBizNo); err != nil { diff --git a/app/user/cmd/api/internal/logic/pay/alipaycallbacklogic.go b/app/user/cmd/api/internal/logic/pay/alipaycallbacklogic.go index 4533172..9bde985 100644 --- a/app/user/cmd/api/internal/logic/pay/alipaycallbacklogic.go +++ b/app/user/cmd/api/internal/logic/pay/alipaycallbacklogic.go @@ -2,16 +2,20 @@ package pay import ( "context" + "database/sql" + "fmt" "net/http" - "os" "qnc-server/pkg/lzkit/lzUtils" + "strings" "time" "github.com/smartwalle/alipay/v3" "qnc-server/app/user/cmd/api/internal/svc" + "qnc-server/app/user/model" "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/core/stores/sqlx" ) type AlipayCallbackLogic struct { @@ -29,31 +33,46 @@ func NewAlipayCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Al } func (l *AlipayCallbackLogic) AlipayCallback(w http.ResponseWriter, r *http.Request) error { - env := os.Getenv("ENV") - if env == "development" { - return nil - } notification, err := l.svcCtx.AlipayService.HandleAliPaymentNotification(r) if err != nil { logx.Errorf("支付宝支付回调,%v", err) return nil } + + // 根据订单号前缀判断订单类型 + orderNo := notification.OutTradeNo + if strings.HasPrefix(orderNo, "Q_") { + // 查询订单处理 + return l.handleQueryOrderPayment(w, notification) + } else if strings.HasPrefix(orderNo, "A_") { + // 代理会员订单处理 + return l.handleAgentVipOrderPayment(w, notification) + } else { + // 兼容旧订单,假设没有前缀的是查询订单 + return l.handleQueryOrderPayment(w, notification) + } +} + +// 处理查询订单支付 +func (l *AlipayCallbackLogic) handleQueryOrderPayment(w http.ResponseWriter, notification *alipay.Notification) error { order, findOrderErr := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, notification.OutTradeNo) if findOrderErr != nil { logx.Errorf("支付宝支付回调,查找订单失败: %+v", findOrderErr) return nil } + if order.Status != "pending" { alipay.ACKNotification(w) return nil } + user, err := l.svcCtx.UserModel.FindOne(l.ctx, order.UserId) if err != nil { logx.Errorf("支付宝支付回调,查找用户失败: %+v", err) return nil } - amount := lzUtils.ToAlipayAmount(order.Amount) + amount := lzUtils.ToAlipayAmount(order.Amount) if user.Inside != 1 { // 确保订单金额和状态正确,防止重复更新 if amount != notification.TotalAmount { @@ -62,11 +81,6 @@ func (l *AlipayCallbackLogic) AlipayCallback(w http.ResponseWriter, r *http.Requ } } - if order.Status != "pending" { - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte("success")) // 确保只写入一次响应 - return nil - } switch notification.TradeStatus { case alipay.TradeStatusSuccess: order.Status = "paid" @@ -74,17 +88,136 @@ func (l *AlipayCallbackLogic) AlipayCallback(w http.ResponseWriter, r *http.Requ default: return nil } + order.PlatformOrderId = lzUtils.StringToNullString(notification.TradeNo) if updateErr := l.svcCtx.OrderModel.UpdateWithVersion(l.ctx, nil, order); updateErr != nil { logx.Errorf("支付宝支付回调,修改订单信息失败: %+v", updateErr) return nil } + if order.Status == "paid" { if asyncErr := l.svcCtx.AsynqService.SendQueryTask(order.Id); asyncErr != nil { logx.Errorf("异步任务调度失败: %v", asyncErr) return asyncErr } } + alipay.ACKNotification(w) return nil } + +// 处理代理会员订单支付 +func (l *AlipayCallbackLogic) handleAgentVipOrderPayment(w http.ResponseWriter, notification *alipay.Notification) error { + agentOrder, findAgentOrderErr := l.svcCtx.AgentMembershipRechargeOrderModel.FindOneByOrderNo(l.ctx, notification.OutTradeNo) + if findAgentOrderErr != nil { + logx.Errorf("支付宝支付回调,查找代理会员订单失败: %+v", findAgentOrderErr) + return nil + } + + if agentOrder.Status != "pending" { + alipay.ACKNotification(w) + return nil + } + + user, err := l.svcCtx.UserModel.FindOne(l.ctx, agentOrder.UserId) + if err != nil { + logx.Errorf("支付宝支付回调,查找用户失败: %+v", err) + return nil + } + + amount := lzUtils.ToAlipayAmount(agentOrder.Amount) + if user.Inside != 1 { + // 确保订单金额和状态正确,防止重复更新 + if amount != notification.TotalAmount { + logx.Errorf("支付宝支付回调,金额不一致") + return nil + } + } + + switch notification.TradeStatus { + case alipay.TradeStatusSuccess: + agentOrder.Status = "paid" + default: + return nil + } + + if agentOrder.Status == "paid" { + err = l.svcCtx.AgentModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error { + agentModel, err := l.svcCtx.AgentModel.FindOne(transCtx, agentOrder.AgentId) + if err != nil { + return fmt.Errorf("查找代理信息失败: %+v", err) + } + agentOrder.PlatformOrderId = lzUtils.StringToNullString(notification.TradeNo) + if updateErr := l.svcCtx.AgentMembershipRechargeOrderModel.UpdateWithVersion(l.ctx, nil, agentOrder); updateErr != nil { + return fmt.Errorf("修改代理会员订单信息失败: %+v", updateErr) + } + agentModel.LevelName = agentOrder.LevelName + agentModel.MembershipExpiryTime = RenewMembership(agentModel.MembershipExpiryTime) + if updateErr := l.svcCtx.AgentModel.UpdateWithVersion(l.ctx, nil, agentModel); updateErr != nil { + return fmt.Errorf("修改代理信息失败: %+v", updateErr) + } + return nil + }) + if err != nil { + logx.Errorf("支付宝支付回调,处理代理会员订单失败: %+v", err) + refundErr := l.handleRefund(agentOrder) + if refundErr != nil { + logx.Errorf("支付宝支付回调,退款失败: %+v", refundErr) + } + return nil + } + } + + alipay.ACKNotification(w) + return nil +} +func RenewMembership(expiry sql.NullTime) sql.NullTime { + // 确定基准时间 + var baseTime time.Time + if expiry.Valid { + baseTime = expiry.Time + } else { + baseTime = time.Now() + } + + // 增加一年(自动处理闰年) + newTime := baseTime.AddDate(1, 0, 0) + + // 返回始终有效的 NullTime + return sql.NullTime{ + Time: newTime, + Valid: true, + } +} + +func (l *AlipayCallbackLogic) handleRefund(order *model.AgentMembershipRechargeOrder) error { + ctx := context.Background() + // 退款 + if order.PaymentMethod == "wechat" { + refundErr := l.svcCtx.WechatPayService.WeChatRefund(ctx, order.OrderNo, order.Amount, order.Amount) + if refundErr != nil { + return refundErr + } + } else { + refund, refundErr := l.svcCtx.AlipayService.AliRefund(ctx, order.OrderNo, order.Amount) + if refundErr != nil { + return refundErr + } + if refund.IsSuccess() { + logx.Errorf("支付宝退款成功, orderID: %d", order.Id) + // 更新订单状态为退款 + order.Status = "refunded" + updateOrderErr := l.svcCtx.AgentMembershipRechargeOrderModel.UpdateWithVersion(ctx, nil, order) + if updateOrderErr != nil { + logx.Errorf("更新订单状态失败,订单ID: %d, 错误: %v", order.Id, updateOrderErr) + return fmt.Errorf("更新订单状态失败: %v", updateOrderErr) + } + return nil + } else { + logx.Errorf("支付宝退款失败:%v", refundErr) + return refundErr + } + // 直接成功 + } + return nil +} diff --git a/app/user/cmd/api/internal/logic/pay/paymentchecklogic.go b/app/user/cmd/api/internal/logic/pay/paymentchecklogic.go new file mode 100644 index 0000000..081b60c --- /dev/null +++ b/app/user/cmd/api/internal/logic/pay/paymentchecklogic.go @@ -0,0 +1,49 @@ +package pay + +import ( + "context" + "strings" + + "qnc-server/app/user/cmd/api/internal/svc" + "qnc-server/app/user/cmd/api/internal/types" + "qnc-server/common/xerr" + + "github.com/pkg/errors" + "github.com/zeromicro/go-zero/core/logx" +) + +type PaymentCheckLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewPaymentCheckLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentCheckLogic { + return &PaymentCheckLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *PaymentCheckLogic) PaymentCheck(req *types.PaymentCheckReq) (resp *types.PaymentCheckResp, err error) { + if strings.HasPrefix(req.OrderNo, "A_") { + order, err := l.svcCtx.AgentMembershipRechargeOrderModel.FindOneByOrderNo(l.ctx, req.OrderNo) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询订单失败: %v", err) + } + return &types.PaymentCheckResp{ + Type: "agent_vip", + Status: order.Status, + }, nil + } else { + order, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, req.OrderNo) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询订单失败: %v", err) + } + return &types.PaymentCheckResp{ + Type: "query", + Status: order.Status, + }, nil + } +} diff --git a/app/user/cmd/api/internal/logic/pay/paymentlogic.go b/app/user/cmd/api/internal/logic/pay/paymentlogic.go index c5f66d3..7758203 100644 --- a/app/user/cmd/api/internal/logic/pay/paymentlogic.go +++ b/app/user/cmd/api/internal/logic/pay/paymentlogic.go @@ -5,7 +5,6 @@ import ( "encoding/hex" "encoding/json" "fmt" - "os" "qnc-server/app/user/cmd/api/internal/svc" "qnc-server/app/user/cmd/api/internal/types" "qnc-server/app/user/model" @@ -14,6 +13,7 @@ import ( "qnc-server/pkg/lzkit/crypto" "github.com/pkg/errors" + "github.com/redis/go-redis/v9" "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/stores/sqlx" ) @@ -23,6 +23,11 @@ type PaymentLogic struct { ctx context.Context svcCtx *svc.ServiceContext } +type PaymentTypeResp struct { + amount float64 + outTradeNo string + description string +} func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLogic { return &PaymentLogic{ @@ -33,20 +38,61 @@ func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLo } func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, err error) { + var paymentTypeResp *PaymentTypeResp + var prepayData interface{} + l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error { + switch req.PayType { + case "agent_vip": + paymentTypeResp, err = l.AgentVipOrderPayment(req, session) + if err != nil { + return err + } + + case "query": + paymentTypeResp, err = l.QueryOrderPayment(req, session) + if err != nil { + return err + } + } + + var createOrderErr error + if req.PayMethod == "wechat" { + prepayData, createOrderErr = l.svcCtx.WechatPayService.CreateWechatOrder(l.ctx, paymentTypeResp.amount, paymentTypeResp.description, paymentTypeResp.outTradeNo) + } else if req.PayMethod == "alipay" { + prepayData, createOrderErr = l.svcCtx.AlipayService.CreateAlipayOrder(l.ctx, paymentTypeResp.amount, paymentTypeResp.description, paymentTypeResp.outTradeNo) + } else if req.PayMethod == "appleiap" { + prepayData = l.svcCtx.ApplePayService.GetIappayAppID(paymentTypeResp.outTradeNo) + } + if createOrderErr != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 创建支付订单失败: %+v", createOrderErr) + } + return nil + }) + if err != nil { + return nil, err + } + switch v := prepayData.(type) { + case string: + // 如果 prepayData 是字符串类型,直接返回 + return &types.PaymentResp{PrepayId: v, OrderNo: paymentTypeResp.outTradeNo}, nil + default: + return &types.PaymentResp{PrepayData: prepayData, OrderNo: paymentTypeResp.outTradeNo}, nil + } +} + +func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Session) (resp *PaymentTypeResp, err error) { userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx) if getUidErr != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取用户信息失败, %+v", getUidErr) } - - brand, ok := l.ctx.Value("brand").(string) - if !ok { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取平台失败, %+v", getUidErr) - } outTradeNo := req.Id - redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo) + redisKey := fmt.Sprintf(types.QueryCacheKey, userID, outTradeNo) cache, cacheErr := l.svcCtx.Redis.GetCtx(l.ctx, redisKey) if cacheErr != nil { - return nil, cacheErr + if cacheErr == redis.Nil { + return nil, errors.Wrapf(xerr.NewErrMsg("订单已过期"), "生成订单, 缓存不存在, %+v", cacheErr) + } + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取缓存失败, %+v", cacheErr) } var data types.QueryCacheLoad err = json.Unmarshal([]byte(cache), &data) @@ -59,9 +105,7 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 查找产品错误: %v", err) } - var prepayData interface{} var amount float64 - var orderAmount float64 user, err := l.svcCtx.UserModel.FindOne(l.ctx, userID) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取用户信息失败: %v", err) @@ -73,79 +117,95 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取代理订单失败: %+v", findAgentLinkErr) } amount = agentLinkModel.Price - orderAmount = agentLinkModel.Price } else { amount = product.SellPrice - orderAmount = product.SellPrice } if user.Inside == 1 { amount = 0.01 } - - var createOrderErr error - if req.PayMethod == "wechat" { - prepayData, createOrderErr = l.svcCtx.WechatPayService.CreateWechatOrder(l.ctx, amount, product.ProductName, outTradeNo) - } else if req.PayMethod == "alipay" { - prepayData, createOrderErr = l.svcCtx.AlipayService.CreateAlipayOrder(l.ctx, amount, product.ProductName, outTradeNo, brand) - } else if req.PayMethod == "appleiap" { - prepayData = l.svcCtx.ApplePayService.GetIappayAppID(product.ProductEn) - } - if createOrderErr != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 创建支付订单失败: %+v", createOrderErr) - } var orderID int64 - transErr := l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error { - order := model.Order{ - OrderNo: outTradeNo, - UserId: userID, - ProductId: product.Id, - PaymentPlatform: req.PayMethod, - PaymentScene: "app", - Amount: orderAmount, - Status: "pending", - } - orderInsertResult, insertOrderErr := l.svcCtx.OrderModel.Insert(ctx, session, &order) - if insertOrderErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存订单失败: %+v", insertOrderErr) - } - insertedOrderID, lastInsertIdErr := orderInsertResult.LastInsertId() - if lastInsertIdErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取保存订单ID失败: %+v", lastInsertIdErr) - } - orderID = insertedOrderID + order := model.Order{ + OrderNo: outTradeNo, + UserId: userID, + ProductId: product.Id, + PaymentPlatform: req.PayMethod, + PaymentScene: "app", + Amount: amount, + Status: "pending", + } + orderInsertResult, insertOrderErr := l.svcCtx.OrderModel.Insert(l.ctx, session, &order) + if insertOrderErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存订单失败: %+v", insertOrderErr) + } + insertedOrderID, lastInsertIdErr := orderInsertResult.LastInsertId() + if lastInsertIdErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取保存订单ID失败: %+v", lastInsertIdErr) + } + orderID = insertedOrderID - if data.AgentIdentifier != "" { - agent, parsingErr := l.agentParsing(data.AgentIdentifier) - if parsingErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 解析代理标识符失败: %+v", parsingErr) - } - var agentOrder model.AgentOrder - agentOrder.OrderId = orderID - agentOrder.AgentId = agent.AgentID - _, agentOrderInsert := l.svcCtx.AgentOrderModel.Insert(ctx, session, &agentOrder) - if agentOrderInsert != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存代理订单失败: %+v", agentOrderInsert) - } + if data.AgentIdentifier != "" { + agent, parsingErr := l.agentParsing(data.AgentIdentifier) + if parsingErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 解析代理标识符失败: %+v", parsingErr) } - return nil - }) - if transErr != nil { - return nil, transErr - } - env := os.Getenv("ENV") - if env == "development" { - if asyncErr := l.svcCtx.AsynqService.SendQueryTask(orderID); asyncErr != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 异步订单调用失败: %+v", asyncErr) + var agentOrder model.AgentOrder + agentOrder.OrderId = orderID + agentOrder.AgentId = agent.AgentID + _, agentOrderInsert := l.svcCtx.AgentOrderModel.Insert(l.ctx, session, &agentOrder) + if agentOrderInsert != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存代理订单失败: %+v", agentOrderInsert) } } - switch v := prepayData.(type) { - case string: - // 如果 prepayData 是字符串类型,直接返回 - return &types.PaymentResp{PrepayId: v, OrderID: orderID}, nil - default: - return &types.PaymentResp{PrepayData: prepayData, OrderID: orderID}, nil + return &PaymentTypeResp{amount: amount, outTradeNo: outTradeNo, description: product.ProductName}, nil +} +func (l *PaymentLogic) AgentVipOrderPayment(req *types.PaymentReq, session sqlx.Session) (resp *PaymentTypeResp, err error) { + userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx) + if getUidErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取用户信息失败, %+v", getUidErr) } + user, err := l.svcCtx.UserModel.FindOne(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取用户信息失败: %v", err) + } + // 查询用户代理信息 + agentModel, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败: %v", err) + } + redisKey := fmt.Sprintf(types.AgentVipCacheKey, userID, req.Id) + cache, cacheErr := l.svcCtx.Redis.GetCtx(l.ctx, redisKey) + if cacheErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取缓存失败, %+v", cacheErr) + } + var agentVipCache types.AgentVipCache + err = json.Unmarshal([]byte(cache), &agentVipCache) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 解析缓存内容失败, %+v", err) + } + agentMembershipConfig, err := l.svcCtx.AgentMembershipConfigModel.FindOneByLevelName(l.ctx, agentVipCache.Type) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取代理会员配置失败, %+v", err) + } + + amount := agentMembershipConfig.Price.Float64 + if user.Inside == 1 { + amount = 0.01 + } + agentMembershipRechargeOrder := model.AgentMembershipRechargeOrder{ + OrderNo: req.Id, + UserId: userID, + AgentId: agentModel.Id, + Amount: amount, + PaymentMethod: req.PayMethod, + LevelName: agentVipCache.Type, + Status: "pending", + } + _, err = l.svcCtx.AgentMembershipRechargeOrderModel.Insert(l.ctx, session, &agentMembershipRechargeOrder) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存代理会员充值订单失败: %+v", err) + } + return &PaymentTypeResp{amount: amount, outTradeNo: req.Id, description: fmt.Sprintf("%s代理会员充值", agentMembershipConfig.LevelName)}, nil } func (l *PaymentLogic) agentParsing(agentIdentifier string) (*types.AgentIdentifier, error) { key, decodeErr := hex.DecodeString("8e3e7a2f60edb49221e953b9c029ed10") diff --git a/app/user/cmd/api/internal/logic/query/queryservicelogic.go b/app/user/cmd/api/internal/logic/query/queryservicelogic.go index 6256911..d949105 100644 --- a/app/user/cmd/api/internal/logic/query/queryservicelogic.go +++ b/app/user/cmd/api/internal/logic/query/queryservicelogic.go @@ -1380,8 +1380,8 @@ func (l *QueryServiceLogic) CacheData(params map[string]interface{}, Product str if marshalErr != nil { return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 序列化参数失败: %+v", marshalErr) } - outTradeNo := l.svcCtx.AlipayService.GenerateOutTradeNo() - redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo) + outTradeNo := "Q_" + l.svcCtx.AlipayService.GenerateOutTradeNo() + redisKey := fmt.Sprintf(types.QueryCacheKey, userID, outTradeNo) cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour)) if cacheErr != nil { return "", cacheErr diff --git a/app/user/cmd/api/internal/queue/paySuccessNotify.go b/app/user/cmd/api/internal/queue/paySuccessNotify.go index 9f27ed7..1b04ed7 100644 --- a/app/user/cmd/api/internal/queue/paySuccessNotify.go +++ b/app/user/cmd/api/internal/queue/paySuccessNotify.go @@ -52,7 +52,7 @@ func (l *PaySuccessNotifyUserHandler) ProcessTask(ctx context.Context, t *asynq. if err != nil { return fmt.Errorf("找不到相关产品: orderID: %d, productID: %d", payload.OrderID, order.ProductId) } - redisKey := fmt.Sprintf("%d:%s", order.UserId, order.OrderNo) + redisKey := fmt.Sprintf(types.QueryCacheKey, order.UserId, order.OrderNo) cache, cacheErr := l.svcCtx.Redis.GetCtx(ctx, redisKey) if cacheErr != nil { return fmt.Errorf("获取缓存内容失败: %+v", cacheErr) @@ -149,7 +149,7 @@ func (l *PaySuccessNotifyUserHandler) ProcessTask(ctx context.Context, t *asynq. func (l *PaySuccessNotifyUserHandler) handleError(ctx context.Context, err error, order *model.Order, query *model.Query) error { logx.Errorf("处理任务失败,原因: %v", err) - redisKey := fmt.Sprintf("%d:%s", order.UserId, order.OrderNo) + redisKey := fmt.Sprintf(types.QueryCacheKey, order.UserId, order.OrderNo) _, delErr := l.svcCtx.Redis.DelCtx(ctx, redisKey) if delErr != nil { logx.Errorf("删除Redis缓存失败,订单ID: %d, 错误: %v", order.Id, delErr) diff --git a/app/user/cmd/api/internal/service/alipayService.go b/app/user/cmd/api/internal/service/alipayService.go index cd21fe3..20cc3e6 100644 --- a/app/user/cmd/api/internal/service/alipayService.go +++ b/app/user/cmd/api/internal/service/alipayService.go @@ -73,15 +73,7 @@ func (a *AliPayService) CreateAlipayAppOrder(amount float64, subject string, out } // CreateAlipayH5Order 创建支付宝H5支付订单 -func (a *AliPayService) CreateAlipayH5Order(amount float64, subject string, outTradeNo string, brand string) (string, error) { - var returnURL string - if brand == "tyc" { - returnURL = "https://www.tianyuancha.com/report" - } else if brand == "qnc" { - returnURL = "https://www.quannengcha.com/report" - } else { - returnURL = a.config.ReturnURL - } +func (a *AliPayService) CreateAlipayH5Order(amount float64, subject string, outTradeNo string) (string, error) { client := a.AlipayClient totalAmount := lzUtils.ToAlipayAmount(amount) // 构造H5支付请求 @@ -92,7 +84,7 @@ func (a *AliPayService) CreateAlipayH5Order(amount float64, subject string, outT TotalAmount: totalAmount, ProductCode: "QUICK_WAP_PAY", // H5支付专用产品码 NotifyURL: a.config.NotifyUrl, // 异步回调通知地址 - ReturnURL: returnURL, + ReturnURL: a.config.ReturnURL, }, } // 获取H5支付请求字符串,这里会签名 @@ -105,7 +97,7 @@ func (a *AliPayService) CreateAlipayH5Order(amount float64, subject string, outT } // CreateAlipayOrder 根据平台类型创建支付宝支付订单 -func (a *AliPayService) CreateAlipayOrder(ctx context.Context, amount float64, subject string, outTradeNo string, brand string) (string, error) { +func (a *AliPayService) CreateAlipayOrder(ctx context.Context, amount float64, subject string, outTradeNo string) (string, error) { // 根据 ctx 中的 platform 判断平台 platform, platformOk := ctx.Value("platform").(string) if !platformOk { @@ -117,7 +109,7 @@ func (a *AliPayService) CreateAlipayOrder(ctx context.Context, amount float64, s return a.CreateAlipayAppOrder(amount, subject, outTradeNo) case "h5": // 调用H5支付的创建方法,并传入 returnUrl - return a.CreateAlipayH5Order(amount, subject, outTradeNo, brand) + return a.CreateAlipayH5Order(amount, subject, outTradeNo) default: return "", fmt.Errorf("不支持的支付平台: %s", platform) } diff --git a/app/user/cmd/api/internal/types/cache.go b/app/user/cmd/api/internal/types/cache.go index 81778fe..ecd68cc 100644 --- a/app/user/cmd/api/internal/types/cache.go +++ b/app/user/cmd/api/internal/types/cache.go @@ -1,5 +1,8 @@ package types +const QueryCacheKey = "query:%d:%s" +const AgentVipCacheKey = "agentVip:%d:%s" + type QueryCache struct { Name string `json:"name"` IDCard string `json:"id_card"` @@ -11,3 +14,7 @@ type QueryCacheLoad struct { Params string `json:"params"` AgentIdentifier string `json:"agent_dentifier"` } + +type AgentVipCache struct { + Type string `json:"type"` +} diff --git a/app/user/cmd/api/internal/types/types.go b/app/user/cmd/api/internal/types/types.go index 24024d4..5828cc3 100644 --- a/app/user/cmd/api/internal/types/types.go +++ b/app/user/cmd/api/internal/types/types.go @@ -1,6 +1,4 @@ // Code generated by goctl. DO NOT EDIT. -// goctl 1.7.3 - package types type ActiveReward struct { @@ -18,16 +16,11 @@ type ActiveRewardData struct { } type AgentActivateMembershipReq struct { - Mobile string `json:"mobile"` - Type string `json:"type,oneof=VIP SVIP"` // 会员类型:vip/svip - Amount float64 `json:"amount"` - PaymentMethod string `json:"payment_method"` - TransactionId string `json:"transaction_id"` + Type string `json:"type,oneof=VIP SVIP"` // 会员类型:vip/svip } type AgentActivateMembershipResp struct { - MembershipType string `json:"membership_type"` // 最终开通的会员类型 - ExpireTime string `json:"expire_time"` // 到期时间 + Id string `json:"id"` } type AgentApplyReq struct { @@ -228,15 +221,25 @@ type Notification struct { EndTime string `json:"endTime"` // 每天通知结束时间,格式 "HH:MM:SS" } +type PaymentCheckReq struct { + OrderNo string `json:"order_no" validate:"required"` +} + +type PaymentCheckResp struct { + Type string `json:"type"` + Status string `json:"status"` +} + type PaymentReq struct { Id string `json:"id"` PayMethod string `json:"pay_method"` + PayType string `json:"pay_type" validate:"required,oneof=query agent_vip"` } type PaymentResp struct { PrepayData interface{} `json:"prepay_data"` PrepayId string `json:"prepay_id"` - OrderID int64 `json:"order_id"` + OrderNo string `json:"order_no"` } type Product struct { diff --git a/app/user/model/agentMembershipRechargeOrderModel_gen.go b/app/user/model/agentMembershipRechargeOrderModel_gen.go index acb0df8..3ccc924 100644 --- a/app/user/model/agentMembershipRechargeOrderModel_gen.go +++ b/app/user/model/agentMembershipRechargeOrderModel_gen.go @@ -26,13 +26,17 @@ var ( agentMembershipRechargeOrderRowsExpectAutoSet = strings.Join(stringx.Remove(agentMembershipRechargeOrderFieldNames, "`id`", "`create_time`", "`update_time`"), ",") agentMembershipRechargeOrderRowsWithPlaceHolder = strings.Join(stringx.Remove(agentMembershipRechargeOrderFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?" - cacheQncAgentMembershipRechargeOrderIdPrefix = "cache:qnc:agentMembershipRechargeOrder:id:" + cacheQncAgentMembershipRechargeOrderIdPrefix = "cache:qnc:agentMembershipRechargeOrder:id:" + cacheQncAgentMembershipRechargeOrderOrderNoPrefix = "cache:qnc:agentMembershipRechargeOrder:orderNo:" + cacheQncAgentMembershipRechargeOrderPlatformOrderIdPrefix = "cache:qnc:agentMembershipRechargeOrder:platformOrderId:" ) type ( agentMembershipRechargeOrderModel interface { Insert(ctx context.Context, session sqlx.Session, data *AgentMembershipRechargeOrder) (sql.Result, error) FindOne(ctx context.Context, id int64) (*AgentMembershipRechargeOrder, error) + FindOneByOrderNo(ctx context.Context, orderNo string) (*AgentMembershipRechargeOrder, error) + FindOneByPlatformOrderId(ctx context.Context, platformOrderId sql.NullString) (*AgentMembershipRechargeOrder, error) Update(ctx context.Context, session sqlx.Session, data *AgentMembershipRechargeOrder) (sql.Result, error) UpdateWithVersion(ctx context.Context, session sqlx.Session, data *AgentMembershipRechargeOrder) error Trans(ctx context.Context, fn func(context context.Context, session sqlx.Session) error) error @@ -54,19 +58,20 @@ type ( } AgentMembershipRechargeOrder struct { - Id int64 `db:"id"` - UserId int64 `db:"user_id"` // 用户ID - AgentId int64 `db:"agent_id"` // 代理ID - LevelName string `db:"level_name"` // 会员级别,如 VIP,SVIP,normal - Amount float64 `db:"amount"` // 充值金额 - PaymentMethod string `db:"payment_method"` // 支付方式:支付宝,微信,苹果支付,其他 - TransactionId string `db:"transaction_id"` // 交易号 - Status int64 `db:"status"` // 充值状态:1 成功,0 失败 - CreateTime time.Time `db:"create_time"` - UpdateTime time.Time `db:"update_time"` // 更新时间 - DeleteTime sql.NullTime `db:"delete_time"` // 删除时间 - DelState int64 `db:"del_state"` // 删除状态,0 未删除,1 已删除 - Version int64 `db:"version"` // 版本号 + Id int64 `db:"id"` + UserId int64 `db:"user_id"` // 用户ID + AgentId int64 `db:"agent_id"` // 代理ID + LevelName string `db:"level_name"` // 会员级别,如 VIP,SVIP,normal + Amount float64 `db:"amount"` // 充值金额 + PaymentMethod string `db:"payment_method"` // 支付方式:支付宝,微信,苹果支付,其他 + OrderNo string `db:"order_no"` // 交易号 + PlatformOrderId sql.NullString `db:"platform_order_id"` + Status string `db:"status"` // 充值状态:1 成功,0 失败 + CreateTime time.Time `db:"create_time"` + UpdateTime time.Time `db:"update_time"` // 更新时间 + DeleteTime sql.NullTime `db:"delete_time"` // 删除时间 + DelState int64 `db:"del_state"` // 删除状态,0 未删除,1 已删除 + Version int64 `db:"version"` // 版本号 } ) @@ -80,13 +85,15 @@ func newAgentMembershipRechargeOrderModel(conn sqlx.SqlConn, c cache.CacheConf) func (m *defaultAgentMembershipRechargeOrderModel) Insert(ctx context.Context, session sqlx.Session, data *AgentMembershipRechargeOrder) (sql.Result, error) { data.DelState = globalkey.DelStateNo qncAgentMembershipRechargeOrderIdKey := fmt.Sprintf("%s%v", cacheQncAgentMembershipRechargeOrderIdPrefix, data.Id) + qncAgentMembershipRechargeOrderOrderNoKey := fmt.Sprintf("%s%v", cacheQncAgentMembershipRechargeOrderOrderNoPrefix, data.OrderNo) + qncAgentMembershipRechargeOrderPlatformOrderIdKey := fmt.Sprintf("%s%v", cacheQncAgentMembershipRechargeOrderPlatformOrderIdPrefix, data.PlatformOrderId) return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { - query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, agentMembershipRechargeOrderRowsExpectAutoSet) + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, agentMembershipRechargeOrderRowsExpectAutoSet) if session != nil { - return session.ExecCtx(ctx, query, data.UserId, data.AgentId, data.LevelName, data.Amount, data.PaymentMethod, data.TransactionId, data.Status, data.DeleteTime, data.DelState, data.Version) + return session.ExecCtx(ctx, query, data.UserId, data.AgentId, data.LevelName, data.Amount, data.PaymentMethod, data.OrderNo, data.PlatformOrderId, data.Status, data.DeleteTime, data.DelState, data.Version) } - return conn.ExecCtx(ctx, query, data.UserId, data.AgentId, data.LevelName, data.Amount, data.PaymentMethod, data.TransactionId, data.Status, data.DeleteTime, data.DelState, data.Version) - }, qncAgentMembershipRechargeOrderIdKey) + return conn.ExecCtx(ctx, query, data.UserId, data.AgentId, data.LevelName, data.Amount, data.PaymentMethod, data.OrderNo, data.PlatformOrderId, data.Status, data.DeleteTime, data.DelState, data.Version) + }, qncAgentMembershipRechargeOrderIdKey, qncAgentMembershipRechargeOrderOrderNoKey, qncAgentMembershipRechargeOrderPlatformOrderIdKey) } func (m *defaultAgentMembershipRechargeOrderModel) FindOne(ctx context.Context, id int64) (*AgentMembershipRechargeOrder, error) { @@ -106,33 +113,85 @@ func (m *defaultAgentMembershipRechargeOrderModel) FindOne(ctx context.Context, } } -func (m *defaultAgentMembershipRechargeOrderModel) Update(ctx context.Context, session sqlx.Session, data *AgentMembershipRechargeOrder) (sql.Result, error) { +func (m *defaultAgentMembershipRechargeOrderModel) FindOneByOrderNo(ctx context.Context, orderNo string) (*AgentMembershipRechargeOrder, error) { + qncAgentMembershipRechargeOrderOrderNoKey := fmt.Sprintf("%s%v", cacheQncAgentMembershipRechargeOrderOrderNoPrefix, orderNo) + var resp AgentMembershipRechargeOrder + err := m.QueryRowIndexCtx(ctx, &resp, qncAgentMembershipRechargeOrderOrderNoKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (i interface{}, e error) { + query := fmt.Sprintf("select %s from %s where `order_no` = ? and del_state = ? limit 1", agentMembershipRechargeOrderRows, m.table) + if err := conn.QueryRowCtx(ctx, &resp, query, orderNo, globalkey.DelStateNo); err != nil { + return nil, err + } + return resp.Id, nil + }, m.queryPrimary) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultAgentMembershipRechargeOrderModel) FindOneByPlatformOrderId(ctx context.Context, platformOrderId sql.NullString) (*AgentMembershipRechargeOrder, error) { + qncAgentMembershipRechargeOrderPlatformOrderIdKey := fmt.Sprintf("%s%v", cacheQncAgentMembershipRechargeOrderPlatformOrderIdPrefix, platformOrderId) + var resp AgentMembershipRechargeOrder + err := m.QueryRowIndexCtx(ctx, &resp, qncAgentMembershipRechargeOrderPlatformOrderIdKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (i interface{}, e error) { + query := fmt.Sprintf("select %s from %s where `platform_order_id` = ? and del_state = ? limit 1", agentMembershipRechargeOrderRows, m.table) + if err := conn.QueryRowCtx(ctx, &resp, query, platformOrderId, globalkey.DelStateNo); err != nil { + return nil, err + } + return resp.Id, nil + }, m.queryPrimary) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultAgentMembershipRechargeOrderModel) Update(ctx context.Context, session sqlx.Session, newData *AgentMembershipRechargeOrder) (sql.Result, error) { + data, err := m.FindOne(ctx, newData.Id) + if err != nil { + return nil, err + } qncAgentMembershipRechargeOrderIdKey := fmt.Sprintf("%s%v", cacheQncAgentMembershipRechargeOrderIdPrefix, data.Id) + qncAgentMembershipRechargeOrderOrderNoKey := fmt.Sprintf("%s%v", cacheQncAgentMembershipRechargeOrderOrderNoPrefix, data.OrderNo) + qncAgentMembershipRechargeOrderPlatformOrderIdKey := fmt.Sprintf("%s%v", cacheQncAgentMembershipRechargeOrderPlatformOrderIdPrefix, data.PlatformOrderId) return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, agentMembershipRechargeOrderRowsWithPlaceHolder) if session != nil { - return session.ExecCtx(ctx, query, data.UserId, data.AgentId, data.LevelName, data.Amount, data.PaymentMethod, data.TransactionId, data.Status, data.DeleteTime, data.DelState, data.Version, data.Id) + return session.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id) } - return conn.ExecCtx(ctx, query, data.UserId, data.AgentId, data.LevelName, data.Amount, data.PaymentMethod, data.TransactionId, data.Status, data.DeleteTime, data.DelState, data.Version, data.Id) - }, qncAgentMembershipRechargeOrderIdKey) + return conn.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id) + }, qncAgentMembershipRechargeOrderIdKey, qncAgentMembershipRechargeOrderOrderNoKey, qncAgentMembershipRechargeOrderPlatformOrderIdKey) } -func (m *defaultAgentMembershipRechargeOrderModel) UpdateWithVersion(ctx context.Context, session sqlx.Session, data *AgentMembershipRechargeOrder) error { +func (m *defaultAgentMembershipRechargeOrderModel) UpdateWithVersion(ctx context.Context, session sqlx.Session, newData *AgentMembershipRechargeOrder) error { - oldVersion := data.Version - data.Version += 1 + oldVersion := newData.Version + newData.Version += 1 var sqlResult sql.Result var err error + data, err := m.FindOne(ctx, newData.Id) + if err != nil { + return err + } qncAgentMembershipRechargeOrderIdKey := fmt.Sprintf("%s%v", cacheQncAgentMembershipRechargeOrderIdPrefix, data.Id) + qncAgentMembershipRechargeOrderOrderNoKey := fmt.Sprintf("%s%v", cacheQncAgentMembershipRechargeOrderOrderNoPrefix, data.OrderNo) + qncAgentMembershipRechargeOrderPlatformOrderIdKey := fmt.Sprintf("%s%v", cacheQncAgentMembershipRechargeOrderPlatformOrderIdPrefix, data.PlatformOrderId) sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, agentMembershipRechargeOrderRowsWithPlaceHolder) if session != nil { - return session.ExecCtx(ctx, query, data.UserId, data.AgentId, data.LevelName, data.Amount, data.PaymentMethod, data.TransactionId, data.Status, data.DeleteTime, data.DelState, data.Version, data.Id, oldVersion) + return session.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion) } - return conn.ExecCtx(ctx, query, data.UserId, data.AgentId, data.LevelName, data.Amount, data.PaymentMethod, data.TransactionId, data.Status, data.DeleteTime, data.DelState, data.Version, data.Id, oldVersion) - }, qncAgentMembershipRechargeOrderIdKey) + return conn.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion) + }, qncAgentMembershipRechargeOrderIdKey, qncAgentMembershipRechargeOrderOrderNoKey, qncAgentMembershipRechargeOrderPlatformOrderIdKey) if err != nil { return err } @@ -350,14 +409,21 @@ func (m *defaultAgentMembershipRechargeOrderModel) SelectBuilder() squirrel.Sele return squirrel.Select().From(m.table) } func (m *defaultAgentMembershipRechargeOrderModel) Delete(ctx context.Context, session sqlx.Session, id int64) error { + data, err := m.FindOne(ctx, id) + if err != nil { + return err + } + qncAgentMembershipRechargeOrderIdKey := fmt.Sprintf("%s%v", cacheQncAgentMembershipRechargeOrderIdPrefix, id) - _, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + qncAgentMembershipRechargeOrderOrderNoKey := fmt.Sprintf("%s%v", cacheQncAgentMembershipRechargeOrderOrderNoPrefix, data.OrderNo) + qncAgentMembershipRechargeOrderPlatformOrderIdKey := fmt.Sprintf("%s%v", cacheQncAgentMembershipRechargeOrderPlatformOrderIdPrefix, data.PlatformOrderId) + _, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { query := fmt.Sprintf("delete from %s where `id` = ?", m.table) if session != nil { return session.ExecCtx(ctx, query, id) } return conn.ExecCtx(ctx, query, id) - }, qncAgentMembershipRechargeOrderIdKey) + }, qncAgentMembershipRechargeOrderIdKey, qncAgentMembershipRechargeOrderOrderNoKey, qncAgentMembershipRechargeOrderPlatformOrderIdKey) return err } func (m *defaultAgentMembershipRechargeOrderModel) formatPrimary(primary interface{}) string { diff --git a/app/user/model/vars.go b/app/user/model/vars.go index 97d3b74..ce8b059 100644 --- a/app/user/model/vars.go +++ b/app/user/model/vars.go @@ -2,6 +2,7 @@ package model import ( "errors" + "github.com/zeromicro/go-zero/core/stores/sqlx" ) @@ -29,3 +30,18 @@ var AgentRewardsTypeDescendantWithdraw string = "descendant_withdraw" var AgentLeveNameNormal string = "normal" var AgentLeveNameVIP string = "VIP" var AgentLeveNameSVIP string = "SVIP" + +const ( + OrderStatusPending = "pending" + OrderStatusPaid = "paid" + OrderStatusFailed = "failed" + OrderStatusRefunded = "refunded" + OrderStatusClosed = "closed" +) + +const ( + QueryStatePending = "pending" + QueryStateFailed = "failed" + QueryStateSuccess = "success" + QueryStateProcessing = "processing" +) diff --git a/deploy/script/genModel.ps1 b/deploy/script/genModel.ps1 deleted file mode 100644 index fcec7be..0000000 --- a/deploy/script/genModel.ps1 +++ /dev/null @@ -1,25 +0,0 @@ -# 使用方法: -# .\genModel.ps1 user user -# .\genModel.ps1 user user_auth -# 再将 .\genModel 下的文件剪切到对应服务的 model 目录里面,记得改 package -# goctl model mysql datasource -url="qnc:5vg67b3UNHu8@tcp(127.0.0.1:20001)/qnc" -table="product" -dir="./model" --home="../template" -cache=true --style=goZero -param ( - [string]$database, - [string]$tables -) - -# 生成的表名 -$modeldir = "./genModel" -$templateDir = Join-Path -Path (Resolve-Path "$PSScriptRoot/..") -ChildPath "template" -# 数据库配置 -$host = "127.0.0.1" -$port = "20001" -$dbname = "$database" -$username = "qnc" -$passwd = "5vg67b3UNHu8" - -Write-Output "开始创建库:$dbname 的表:$tables" - -# 执行 goctl 命令生成 model -$command = "goctl model mysql datasource -url=`"$username`:$passwd`@tcp($host`:$port)/$dbname`" -table=`"$tables`" -dir=`"$modeldir`" --home=`"$templateDir`" -cache=true --style=goZero" -Invoke-Expression $command diff --git a/deploy/script/gen_models.ps1 b/deploy/script/gen_models.ps1 index b1faf64..ae58c1e 100644 --- a/deploy/script/gen_models.ps1 +++ b/deploy/script/gen_models.ps1 @@ -15,7 +15,7 @@ $tables = @( # "agent_commission_deduction", # "agent_link", # "agent_membership_config", - # "agent_membership_recharge_order", + "agent_membership_recharge_order" # "agent_membership_user_config", # "agent_order", # "agent_platform_deduction", @@ -29,7 +29,7 @@ $tables = @( # "product", # "product_feature", # "query", - "user" + # "user" # "user_auth" ) diff --git a/gen_api.ps1 b/gen_api.ps1 new file mode 100644 index 0000000..32eca87 --- /dev/null +++ b/gen_api.ps1 @@ -0,0 +1,2 @@ +# API生成脚本 +goctl api go --api ./app/user/cmd/api/desc/main.api --dir ./app/user/cmd/api --home ./deploy/template \ No newline at end of file diff --git a/temp/agent/agent.api b/temp/agent/agent.api deleted file mode 100644 index 92e0ca6..0000000 --- a/temp/agent/agent.api +++ /dev/null @@ -1,211 +0,0 @@ -syntax = "v1" - -info ( - title: "代理服务" - desc: "代理服务接口" - author: "Liangzai" - email: "2440983361@qq.com" - version: "v1" -) - -type AgentProductConfig { - ProductID int64 `json:"product_id"` - CostPrice float64 `json:"cost_price"` - PriceRangeMin float64 `json:"price_range_min"` - PriceRangeMax float64 `json:"price_range_max"` - PPricingStandard float64 `json:"p_pricing_standard"` - POverpricingRatio float64 `json:"p_overpricing_ratio"` - APricingStandard float64 `json:"a_pricing_standard"` - APricingEnd float64 `json:"a_pricing_end"` - AOverpricingRatio float64 `json:"a_overpricing_ratio"` -} - -type AgentMembershipUserConfig { - ProductID int64 `json:"product_id"` - PriceIncreaseAmount float64 `json:"price_increase_amount"` - PriceRangeFrom float64 `json:"price_range_from"` - PriceRangeTo float64 `json:"price_range_to"` - PriceRatio float64 `json:"price_ratio"` -} - -type ProductConfig { - ProductID int64 `json:"product_id"` - CostPrice float64 `json:"cost_price"` - PriceRangeMin float64 `json:"price_range_min"` - PriceRangeMax float64 `json:"price_range_max"` -} - -type ( - AgentInfoResp { - status int64 `json:"status"` // 0=待审核,1=审核通过,2=审核未通过,3=未申请 - isAgent bool `json:"is_agent"` - agentID int64 `json:"agent_id"` - level string `json:"level"` - region string `json:"region"` - mobile string `json:"mobile"` - wechatID string `json:"wechat_id"` - } - // 代理申请请求参数 - AgentApplyReq { - Region string `json:"region"` - Mobile string `json:"mobile"` - WechatID string `json:"wechat_id"` - Code string `json:"code"` - Ancestor string `json:"ancestor,optional"` - } - AgentApplyResp{ - AccessToken string `json:"accessToken"` - AccessExpire int64 `json:"accessExpire"` - RefreshAfter int64 `json:"refreshAfter"` - } - // 查询代理申请状态响应 - AgentAuditStatusResp { - Status int64 `json:"status"` // 0=待审核,1=审核通过,2=审核未通过 - AuditReason string `json:"audit_reason"` - } - AgentGeneratingLinkReq { - Product string `json:"product"` - Price string `json:"price"` - } - AgentGeneratingLinkResp { - LinkIdentifier string `json:"link_identifier"` - } - GetLinkDataReq { - LinkIdentifier string `form:"link_identifier"` - } - GetLinkDataResp { - Product - } - AgentProductConfigResp { - AgentProductConfig []AgentProductConfig - } - // 开通代理会员请求参数 - AgentActivateMembershipReq { - Mobile string `json:"mobile"` - Type string `json:"type,oneof=VIP SVIP"` // 会员类型:vip/svip - Amount float64 `json:"amount"` - PaymentMethod string `json:"payment_method"` - TransactionId string `json:"transaction_id"` - } - // 开通代理会员响应 - AgentActivateMembershipResp { - MembershipType string `json:"membership_type"` // 最终开通的会员类型 - ExpireTime string `json:"expire_time"` // 到期时间 - } - // 获取会员当前配置 - AgentMembershipProductConfigReq { - ProductID int64 `form:"product_id"` - } - // 获取会员当前配置 - AgentMembershipProductConfigResp { - AgentMembershipUserConfig AgentMembershipUserConfig `json:"agent_membership_user_config"` - ProductConfig ProductConfig `json:"product_config"` - PriceIncreaseMax float64 `json:"price_increase_max"` - PriceIncreaseAmount float64 `json:"price_increase_amount"` - PriceRatio float64 `json:"price_ratio"` - } - SaveAgentMembershipUserConfigReq { - ProductID int64 `json:"product_id"` - PriceIncreaseAmount float64 `json:"price_increase_amount"` - PriceRangeFrom float64 `json:"price_range_from"` - PriceRangeTo float64 `json:"price_range_to"` - PriceRatio float64 `json:"price_ratio"` - } -) - -type ( - // 收益信息 - GetAgentRevenueInfoReq {} - GetAgentRevenueInfoResp { - Balance float64 `json:"balance"` - FrozenBalance float64 `json:"frozen_balance"` - TotalEarnings float64 `json:"total_earnings"` - DirectPush DirectPushReport `json:"direct_push"` // 直推报告数据 - ActiveReward ActiveReward `json:"active_reward"` // 活跃下级奖励数据 - } - // 直推报告数据结构 - DirectPushReport { - TotalCommission float64 `json:"total_commission"` - TotalReport int `json:"total_report"` - Today TimeRangeReport `json:"today"` // 近24小时数据 - Last7D TimeRangeReport `json:"last7d"` // 近7天数据 - Last30D TimeRangeReport `json:"last30d"` // 近30天数据 - } - // 活跃下级奖励数据结构 - ActiveReward { - TotalReward float64 `json:"total_reward"` - Today ActiveRewardData `json:"today"` // 今日数据 - Last7D ActiveRewardData `json:"last7d"` // 近7天数据 - Last30D ActiveRewardData `json:"last30d"` // 近30天数据 - } - // 通用时间范围报告结构 - TimeRangeReport { - Commission float64 `json:"commission"` // 佣金 - Report int `json:"report"` // 报告量 - } - // 活跃奖励专用结构 - ActiveRewardData { - NewActiveReward float64 `json:"active_reward"` - SubPromoteReward float64 `json:"sub_promote_reward"` - SubUpgradeReward float64 `json:"sub_upgrade_reward"` - SubWithdrawReward float64 `json:"sub_withdraw_reward"` - } -) - -type ( - Commission { - ProductName string `json:"product_name"` - Amount float64 `json:"amount"` - CreateTime string `json:"create_time"` - } - GetCommissionReq { - Page int64 `form:"page"` // 页码 - PageSize int64 `form:"page_size"` // 每页数据量 - } - GetCommissionResp { - Total int64 `json:"total"` // 总记录数 - List []Commission `json:"list"` // 查询列表 - } - Rewards { - Type string `json:"type"` - Amount float64 `json:"amount"` - CreateTime string `json:"create_time"` - } - GetRewardsReq { - Page int64 `form:"page"` // 页码 - PageSize int64 `form:"page_size"` // 每页数据量 - } - GetRewardsResp { - Total int64 `json:"total"` // 总记录数 - List []Rewards `json:"list"` // 查询列表 - } - Withdrawal { - Status int64 `json:"status"` - Amount float64 `json:"amount"` - WithdrawalNo string `json:"withdrawal_no"` - Remark string `json:"remark"` - payeeAccount string `json:"payee_account"` - CreateTime string `json:"create_time"` - } - GetWithdrawalReq { - Page int64 `form:"page"` // 页码 - PageSize int64 `form:"page_size"` // 每页数据量 - } - GetWithdrawalResp { - Total int64 `json:"total"` // 总记录数 - List []Withdrawal `json:"list"` // 查询列表 - } -) - -type ( - WithdrawalReq { - Amount float64 `json:"amount"` // 提现金额 - payeeAccount string `json:"payee_account"` - payeeName string `json:"payee_name"` - } - WithdrawalResp { - Status int64 `json:"status"` // 1申请中 2成功 3失败 - failMsg string `json:"fail_msg"` - } -) - diff --git a/temp/app/app.api b/temp/app/app.api deleted file mode 100644 index 6f091d2..0000000 --- a/temp/app/app.api +++ /dev/null @@ -1,17 +0,0 @@ -syntax = "v1" - -info ( - title: "APP服务" - desc: "APP服务" - author: "Liangzai" - email: "2440983361@qq.com" - version: "v1" -) - -type ( - getAppVersionResp { - version string `json:"version"` - wgtUrl string `json:"wgtUrl"` - } -) - diff --git a/temp/auth/auth.api b/temp/auth/auth.api deleted file mode 100644 index e35c414..0000000 --- a/temp/auth/auth.api +++ /dev/null @@ -1,16 +0,0 @@ -syntax = "v1" - -info ( - title: "认证服务" - desc: "认证服务" - author: "Liangzai" - email: "2440983361@qq.com" -) - -type ( - sendSmsReq { - Mobile string `json:"mobile" validate:"required,mobile"` - ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply"` - } -) - diff --git a/temp/pay/pay.api b/temp/pay/pay.api deleted file mode 100644 index 2d80db1..0000000 --- a/temp/pay/pay.api +++ /dev/null @@ -1,28 +0,0 @@ -syntax = "v1" - -info ( - title: "产品支付服务" - desc: "产品支付服务" - author: "Liangzai" - email: "2440983361@qq.com" -) - -type ( - PaymentReq { - Id string `json:"id"` - PayMethod string `json:"pay_method"` - } - PaymentResp { - prepayData interface{} `json:"prepay_data"` - prepayId string `json:"prepay_id"` - OrderID int64 `json:"order_id"` - } -) - -type ( - IapCallbackReq { - OrderID int64 `json:"order_id" validate:"required"` - TransactionReceipt string `json:"transaction_receipt" validate:"required"` - } -) - diff --git a/temp/product/product.api b/temp/product/product.api deleted file mode 100644 index 9d69933..0000000 --- a/temp/product/product.api +++ /dev/null @@ -1,36 +0,0 @@ -syntax = "v1" - -info ( - title: "产品查询服务" - desc: "产品查询服务" - author: "Liangzai" - email: "2440983361@qq.com" -) - -type Product { - ProductName string `json:"product_name"` - ProductEn string `json:"product_en"` - Description string `json:"description"` - Notes string `json:"notes,optional"` - SellPrice float64 `json:"sell_price"` - Features []Feature `json:"features"` // 关联功能列表 -} - -type Feature { - ID int64 `json:"id"` // 功能ID - ApiID string `json:"api_id"` // API标识 - Name string `json:"name"` // 功能描述 -} - -type GetProductByIDRequest { - Id int64 `path:"id"` -} - -type GetProductByEnRequest { - ProductEn string `path:"product_en"` -} - -type ProductResponse { - Product -} - diff --git a/temp/query/query.api b/temp/query/query.api deleted file mode 100644 index 1d3d3f5..0000000 --- a/temp/query/query.api +++ /dev/null @@ -1,127 +0,0 @@ -syntax = "v1" - -info ( - title: "产品查询服务" - desc: "产品查询服务" - author: "Liangzai" - email: "2440983361@qq.com" -) - -type ( - QueryReq { - Data string `json:"data" validate:"required"` - } - QueryResp { - id string `json:"id"` - } -) - -type ( - QueryServiceReq { - Product string `path:"product"` - Data string `json:"data" validate:"required"` - AgentIdentifier string `json:"agent_identifier,optional"` - App bool `json:"app,optional"` - } - QueryServiceResp { - id string `json:"id"` - AccessToken string `json:"accessToken"` - AccessExpire int64 `json:"accessExpire"` - RefreshAfter int64 `json:"refreshAfter"` - } -) - -type Query { - Id int64 `json:"id"` // 主键ID - OrderId int64 `json:"order_id"` // 订单ID - UserId int64 `json:"user_id"` // 用户ID - ProductName string `json:"product_name"` // 产品ID - QueryParams map[string]interface{} `json:"query_params"` - QueryData []QueryItem `json:"query_data"` - CreateTime string `json:"create_time"` // 创建时间 - UpdateTime string `json:"update_time"` // 更新时间 - QueryState string `json:"query_state"` // 查询状态 -} - -type QueryItem { - Feature interface{} `json:"feature"` - Data interface{} `json:"data"` // 这里可以是 map 或 具体的 struct -} - -// 获取查询临时订单 -type ( - QueryProvisionalOrderReq { - Id string `path:"id"` - } - QueryProvisionalOrderResp { - Name string `json:"name"` - IdCard string `json:"id_card"` - Mobile string `json:"mobile"` - Product Product `json:"product"` - } -) - -type ( - QueryListReq { - Page int64 `form:"page"` // 页码 - PageSize int64 `form:"page_size"` // 每页数据量 - } - QueryListResp { - Total int64 `json:"total"` // 总记录数 - List []Query `json:"list"` // 查询列表 - } -) - -type ( - QueryExampleReq { - feature string `form:"feature"` - } - QueryExampleResp { - Query - } -) - -type ( - QueryDetailReq { - Id int64 `path:"id"` - } - QueryDetailResp { - Query - } -) - -type ( - QueryDetailByOrderIdReq { - OrderId int64 `path:"order_id"` - } - QueryDetailByOrderIdResp { - Query - } -) - -type ( - QueryDetailByOrderNoReq { - OrderNo string `path:"order_no"` - } - QueryDetailByOrderNoResp { - Query - } -) - -type ( - QueryRetryReq { - Id int64 `path:"id"` - } - QueryRetryResp {} -) - -type QuerySingleTestReq { - params map[string]interface{} `json:"params"` - Api string `json:"api"` -} - -type QuerySingleTestResp { - Data interface{} `json:"data"` - Api string `json:"api"` -} - diff --git a/temp/user/user.api b/temp/user/user.api deleted file mode 100644 index 56931e0..0000000 --- a/temp/user/user.api +++ /dev/null @@ -1,101 +0,0 @@ -syntax = "v1" - -info ( - title: "用户实例" - desc: "用户实例" - author: "Liangzai" - email: "2440983361@qq.com" -) - -type User { - Id int64 `json:"id"` - Mobile string `json:"mobile"` - NickName string `json:"nickName"` -} - -type ( - RegisterReq { - Mobile string `json:"mobile" validate:"required,mobile"` - Password string `json:"password" validate:"required,min=11,max=11,password"` - Code string `json:"code" validate:"required"` - } - RegisterResp { - AccessToken string `json:"accessToken"` - AccessExpire int64 `json:"accessExpire"` - RefreshAfter int64 `json:"refreshAfter"` - } -) - -type ( - MobileLoginReq { - Mobile string `json:"mobile" validate:"required,mobile"` - Password string `json:"password" validate:"required"` - } - MobileLoginResp { - AccessToken string `json:"accessToken"` - AccessExpire int64 `json:"accessExpire"` - RefreshAfter int64 `json:"refreshAfter"` - } -) - -type ( - MobileCodeLoginReq { - Mobile string `json:"mobile"` - Code string `json:"code" validate:"required"` - } - MobileCodeLoginResp { - AccessToken string `json:"accessToken"` - AccessExpire int64 `json:"accessExpire"` - RefreshAfter int64 `json:"refreshAfter"` - } -) - -type ( - WXMiniAuthReq { - Code string `json:"code"` - IV string `json:"iv"` - EncryptedData string `json:"encryptedData"` - } - WXMiniAuthResp { - AccessToken string `json:"accessToken"` - AccessExpire int64 `json:"accessExpire"` - RefreshAfter int64 `json:"refreshAfter"` - } -) - -type ( - WXH5AuthReq { - Code string `json:"code"` - } - WXH5AuthResp { - AccessToken string `json:"accessToken"` - AccessExpire int64 `json:"accessExpire"` - RefreshAfter int64 `json:"refreshAfter"` - } -) - -type ( - UserInfoResp { - UserInfo User `json:"userInfo"` - } -) - -//============================> notification v1 <============================ -type Notification { - Title string `json:"title"` // 通知标题 - Content string `json:"content"` // 通知内容 (富文本) - NotificationPage string `json:"notificationPage"` // 通知页面 - StartDate string `json:"startDate"` // 通知开始日期,格式 "YYYY-MM-DD" - EndDate string `json:"endDate"` // 通知结束日期,格式 "YYYY-MM-DD" - StartTime string `json:"startTime"` // 每天通知开始时间,格式 "HH:MM:SS" - EndTime string `json:"endTime"` // 每天通知结束时间,格式 "HH:MM:SS" -} - -type ( - // 获取通知响应体(分页) - GetNotificationsResp { - Notifications []Notification `json:"notifications"` // 通知列表 - Total int64 `json:"total"` // 总记录数 - } -) -