diff --git a/app/main/api/internal/logic/admin_order/adminrefundorderlogic.go b/app/main/api/internal/logic/admin_order/adminrefundorderlogic.go index e8a1c69..fffd857 100644 --- a/app/main/api/internal/logic/admin_order/adminrefundorderlogic.go +++ b/app/main/api/internal/logic/admin_order/adminrefundorderlogic.go @@ -82,7 +82,8 @@ func (l *AdminRefundOrderLogic) handleAlipayRefund(order *model.Order, req *type orderPayTime = &order.PayTime.Time } refundNo := l.generateRefundNo(order.OrderNo) - refundResp, err := l.svcCtx.AlipayService.AliRefund(l.ctx, order.OrderNo, req.RefundAmount, orderPayTime, refundNo) + // 按订单记录的商户号 payment_merchant 选择支付宝商户;老订单未写入时由 AliRefund 内部按时间区间兜底。 + refundResp, err := l.svcCtx.AlipayService.AliRefund(l.ctx, order.PaymentMerchant, order.OrderNo, req.RefundAmount, orderPayTime, refundNo) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 支付宝退款失败 err: %v", err) } @@ -146,6 +147,7 @@ func (l *AdminRefundOrderLogic) createRefundRecordAndUpdateOrder(order *model.Or OrderId: order.Id, UserId: order.UserId, ProductId: order.ProductId, + PaymentMerchant: order.PaymentMerchant, RefundAmount: req.RefundAmount, RefundReason: l.createNullString(req.RefundReason), Status: refundStatus, // 使用传入的状态,不再硬编码 @@ -174,6 +176,7 @@ func (l *AdminRefundOrderLogic) createRefundRecordOnly(order *model.Order, req * OrderId: order.Id, UserId: order.UserId, ProductId: order.ProductId, + PaymentMerchant: order.PaymentMerchant, RefundAmount: req.RefundAmount, RefundReason: l.createNullString(req.RefundReason), Status: refundStatus, diff --git a/app/main/api/internal/logic/pay/alipaycallbacklogic.go b/app/main/api/internal/logic/pay/alipaycallbacklogic.go index bf71d45..2751631 100644 --- a/app/main/api/internal/logic/pay/alipaycallbacklogic.go +++ b/app/main/api/internal/logic/pay/alipaycallbacklogic.go @@ -32,22 +32,58 @@ func NewAlipayCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Al } func (l *AlipayCallbackLogic) AlipayCallback(w http.ResponseWriter, r *http.Request) error { - notification, err := l.svcCtx.AlipayService.HandleAliPaymentNotification(r) - if err != nil { - logx.Errorf("支付宝支付回调,%v", err) + // 先解析表单,拿到 out_trade_no 用于查找订单和对应商户号 + if err := r.ParseForm(); err != nil { + logx.Errorf("支付宝支付回调,解析请求表单失败: %v", err) return nil } - // 根据订单号前缀判断订单类型 - orderNo := notification.OutTradeNo + orderNo := r.FormValue("out_trade_no") + if orderNo == "" { + logx.Errorf("支付宝支付回调,缺少 out_trade_no") + return nil + } + + // 根据订单号前缀判断订单类型,并查出对应商户标识 + var merchant string if strings.HasPrefix(orderNo, "Q_") { - // 查询订单处理 - return l.handleQueryOrderPayment(w, notification) + // 查询订单 + order, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, orderNo) + if err != nil { + logx.Errorf("支付宝支付回调,查询订单失败: %v", err) + return nil + } + merchant = order.PaymentMerchant } else if strings.HasPrefix(orderNo, "A_") { - // 代理会员订单处理 - return l.handleAgentVipOrderPayment(w, notification) + // 代理会员订单 + agentOrder, err := l.svcCtx.AgentMembershipRechargeOrderModel.FindOneByOrderNo(l.ctx, orderNo) + if err != nil { + logx.Errorf("支付宝支付回调,查询代理会员订单失败: %v", err) + return nil + } + merchant = agentOrder.PaymentMerchant } else { // 兼容旧订单,假设没有前缀的是查询订单 + order, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, orderNo) + if err != nil { + logx.Errorf("支付宝支付回调(旧订单),查询订单失败: %v", err) + return nil + } + merchant = order.PaymentMerchant + } + + notification, err := l.svcCtx.AlipayService.HandleAliPaymentNotification(merchant, r.Form) + if err != nil { + logx.Errorf("支付宝支付回调,验签失败: %v", err) + return nil + } + + // 再次根据订单号前缀分发到具体处理函数 + 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) } } @@ -218,9 +254,10 @@ func (l *AlipayCallbackLogic) handleRefund(order *model.AgentMembershipRechargeO return refundErr } } else { - // 代理会员订单以创建时间为准,仅 [2026-01-25 16:38:17, 2026-02-02 18:26) 区间内订单走 bak 商户号 + // 支付宝退款按订单记录的商户号 payment_merchant 走对应商户; + // 老订单若未写入商户号,则在 AliRefund 内按时间区间兜底。 orderPayTime := order.CreateTime - refund, refundErr := l.svcCtx.AlipayService.AliRefund(ctx, order.OrderNo, order.Amount, &orderPayTime, "") + refund, refundErr := l.svcCtx.AlipayService.AliRefund(ctx, order.PaymentMerchant, order.OrderNo, order.Amount, &orderPayTime, "") if refundErr != nil { return refundErr } diff --git a/app/main/api/internal/logic/pay/paymentlogic.go b/app/main/api/internal/logic/pay/paymentlogic.go index 9b6bf9c..e301e75 100644 --- a/app/main/api/internal/logic/pay/paymentlogic.go +++ b/app/main/api/internal/logic/pay/paymentlogic.go @@ -28,10 +28,11 @@ type PaymentLogic struct { svcCtx *svc.ServiceContext } type PaymentTypeResp struct { - amount float64 - outTradeNo string - description string - orderID int64 + amount float64 + outTradeNo string + description string + orderID int64 + payMerchantID string } func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLogic { @@ -79,7 +80,8 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, 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) + // 支付宝:按订单写入的商户标识(one/two)创建支付订单 + prepayData, createOrderErr = l.svcCtx.AlipayService.CreateAlipayOrder(l.ctx, paymentTypeResp.payMerchantID, paymentTypeResp.amount, paymentTypeResp.description, paymentTypeResp.outTradeNo) } else if req.PayMethod == "appleiap" { prepayData = l.svcCtx.ApplePayService.GetIappayAppID(paymentTypeResp.outTradeNo) } @@ -186,12 +188,24 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses amount = 0.01 } var orderID int64 + + // 默认支付宝商户号为 one;若为代理推广订单(存在 AgentIdentifier),则使用 two。 + paymentMerchant := "" + if req.PayMethod == "alipay" { + if data.AgentIdentifier != "" { + paymentMerchant = "two" + } else { + paymentMerchant = "one" + } + } + order := model.Order{ OrderNo: outTradeNo, UserId: userID, ProductId: product.Id, PaymentPlatform: req.PayMethod, PaymentScene: "app", + PaymentMerchant: paymentMerchant, Amount: amount, Status: "pending", } @@ -228,7 +242,13 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存代理订单失败: %+v", agentOrderInsert) } } - return &PaymentTypeResp{amount: amount, outTradeNo: outTradeNo, description: product.ProductName, orderID: orderID}, nil + return &PaymentTypeResp{ + amount: amount, + outTradeNo: outTradeNo, + description: product.ProductName, + orderID: orderID, + payMerchantID: paymentMerchant, + }, nil } func (l *PaymentLogic) AgentVipOrderPayment(req *types.PaymentReq, session sqlx.Session) (resp *PaymentTypeResp, err error) { userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx) @@ -274,20 +294,32 @@ func (l *PaymentLogic) AgentVipOrderPayment(req *types.PaymentReq, session sqlx. if user.Inside == 1 { amount = 0.01 } + + paymentMerchant := "" + if req.PayMethod == "alipay" { + paymentMerchant = "one" + } + agentMembershipRechargeOrder := model.AgentMembershipRechargeOrder{ - OrderNo: req.Id, - UserId: userID, - AgentId: agentModel.Id, - Amount: amount, - PaymentMethod: req.PayMethod, - LevelName: agentVipCache.Type, - Status: "pending", + OrderNo: req.Id, + UserId: userID, + AgentId: agentModel.Id, + Amount: amount, + PaymentMethod: req.PayMethod, + PaymentMerchant: paymentMerchant, + 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 + return &PaymentTypeResp{ + amount: amount, + outTradeNo: req.Id, + description: fmt.Sprintf("%s代理会员充值", agentMembershipConfig.LevelName), + payMerchantID: paymentMerchant, + }, nil } func (l *PaymentLogic) agentParsing(agentIdentifier string) (*types.AgentIdentifier, error) { key, decodeErr := hex.DecodeString("8e3e7a2f60edb49221e953b9c029ed10") diff --git a/app/main/api/internal/logic/pay/wechatpaycallbacklogic.go b/app/main/api/internal/logic/pay/wechatpaycallbacklogic.go index 2f0649d..cfd8e5d 100644 --- a/app/main/api/internal/logic/pay/wechatpaycallbacklogic.go +++ b/app/main/api/internal/logic/pay/wechatpaycallbacklogic.go @@ -221,9 +221,10 @@ func (l *WechatPayCallbackLogic) handleRefund(order *model.AgentMembershipRechar return refundErr } } else { - // 代理会员订单以创建时间为准,仅 [2026-01-25 16:38:17, 2026-02-02 18:26) 区间内订单走 bak 商户号 + // 支付宝退款按订单记录的商户号 payment_merchant 走对应商户; + // 老订单若未写入商户号,则在 AliRefund 内按时间区间兜底。 orderPayTime := order.CreateTime - refund, refundErr := l.svcCtx.AlipayService.AliRefund(ctx, order.OrderNo, order.Amount, &orderPayTime, "") + refund, refundErr := l.svcCtx.AlipayService.AliRefund(ctx, order.PaymentMerchant, order.OrderNo, order.Amount, &orderPayTime, "") if refundErr != nil { return refundErr } diff --git a/app/main/api/internal/queue/paySuccessNotify.go b/app/main/api/internal/queue/paySuccessNotify.go index 966d7ea..8b832f1 100644 --- a/app/main/api/internal/queue/paySuccessNotify.go +++ b/app/main/api/internal/queue/paySuccessNotify.go @@ -322,12 +322,13 @@ func (l *PaySuccessNotifyUserHandler) handleError(ctx context.Context, err error logx.Infof("已发起微信退款申请, orderID: %d, amount: %f", order.Id, order.Amount) return asynq.SkipRetry } else { - // 支付宝退款为同步结果,仅 [2026-01-25 16:38:17, 2026-02-02 18:26) 区间内订单走 bak 商户号 + // 支付宝退款为同步结果,优先按订单记录的 payment_merchant 选择商户; + // 老订单若未写入商户号,则在 AliRefund 内按时间区间兜底。 orderPayTime := &order.CreateTime if order.PayTime.Valid { orderPayTime = &order.PayTime.Time } - refund, refundErr := l.svcCtx.AlipayService.AliRefund(ctx, order.OrderNo, order.Amount, orderPayTime, "") + refund, refundErr := l.svcCtx.AlipayService.AliRefund(ctx, order.PaymentMerchant, order.OrderNo, order.Amount, orderPayTime, "") if refundErr != nil { logx.Error(refundErr) return asynq.SkipRetry diff --git a/app/main/api/internal/service/alipayService.go b/app/main/api/internal/service/alipayService.go index e00b71b..e58d805 100644 --- a/app/main/api/internal/service/alipayService.go +++ b/app/main/api/internal/service/alipayService.go @@ -5,7 +5,7 @@ import ( "crypto/rand" "encoding/hex" "fmt" - "net/http" + "net/url" "strconv" "sync/atomic" "time" @@ -28,6 +28,28 @@ type AliPayService struct { AlipayClientBak *alipay.Client // 仅用于 [2026-01-25 16:38:17, 2026-02-02 18:26) 区间内订单的退款 } +// clientForMerchant 根据商户标识与订单时间选择对应的支付宝 client。 +// - merchant == "two" 且 Bak 存在:优先返回 Bak; +// - merchant == "one" 或空:默认返回主商户; +// - merchant 为空且 orderPayTime 落在备份时间区间:兼容老订单,走 Bak。 +func (a *AliPayService) clientForMerchant(merchant string, orderPayTime *time.Time) *alipay.Client { + // 显式指定 two,则优先走 Bak + if merchant == "two" && a.AlipayClientBak != nil { + return a.AlipayClientBak + } + // 显式指定 one 或其他未知标识,一律走主商户 + if merchant == "one" || merchant == "" { + // 对于老订单未写入 merchant 的情况,继续保留时间区间兜底逻辑 + if merchant == "" && orderPayTime != nil && a.AlipayClientBak != nil && + !orderPayTime.Before(AlipayBakRefundStart) && orderPayTime.Before(AlipayBakRefundEnd) { + return a.AlipayClientBak + } + return a.AlipayClient + } + // 兜底:未知标识时仍走主商户,避免因为配置问题导致整体不可用 + return a.AlipayClient +} + // NewAliPayService 是一个构造函数,用于初始化 AliPayService func NewAliPayService(c config.Config) *AliPayService { client, err := alipay.New(c.Alipay.AppID, c.Alipay.PrivateKey, c.Alipay.IsProduction) @@ -77,8 +99,8 @@ func NewAliPayService(c config.Config) *AliPayService { return svc } -func (a *AliPayService) CreateAlipayAppOrder(amount float64, subject string, outTradeNo string) (string, error) { - client := a.AlipayClient +func (a *AliPayService) CreateAlipayAppOrder(merchant string, amount float64, subject string, outTradeNo string) (string, error) { + client := a.clientForMerchant(merchant, nil) totalAmount := lzUtils.ToAlipayAmount(amount) // 构造移动支付请求 p := alipay.TradeAppPay{ @@ -101,8 +123,8 @@ func (a *AliPayService) CreateAlipayAppOrder(amount float64, subject string, out } // CreateAlipayH5Order 创建支付宝H5支付订单 -func (a *AliPayService) CreateAlipayH5Order(amount float64, subject string, outTradeNo string) (string, error) { - client := a.AlipayClient +func (a *AliPayService) CreateAlipayH5Order(merchant string, amount float64, subject string, outTradeNo string) (string, error) { + client := a.clientForMerchant(merchant, nil) totalAmount := lzUtils.ToAlipayAmount(amount) // 构造H5支付请求 p := alipay.TradeWapPay{ @@ -124,8 +146,9 @@ func (a *AliPayService) CreateAlipayH5Order(amount float64, subject string, outT return payUrl.String(), nil } -// CreateAlipayOrder 根据平台类型创建支付宝支付订单 -func (a *AliPayService) CreateAlipayOrder(ctx context.Context, amount float64, subject string, outTradeNo string) (string, error) { +// CreateAlipayOrder 根据平台类型和商户标识创建支付宝支付订单 +// merchant: 商户标识,目前约定 "one"=主商户, "two"=备商户 +func (a *AliPayService) CreateAlipayOrder(ctx context.Context, merchant string, amount float64, subject string, outTradeNo string) (string, error) { // 根据 ctx 中的 platform 判断平台 platform, platformOk := ctx.Value("platform").(string) if !platformOk { @@ -134,23 +157,21 @@ func (a *AliPayService) CreateAlipayOrder(ctx context.Context, amount float64, s switch platform { case model.PlatformApp: // 调用App支付的创建方法 - return a.CreateAlipayAppOrder(amount, subject, outTradeNo) + return a.CreateAlipayAppOrder(merchant, amount, subject, outTradeNo) case model.PlatformH5: // 调用H5支付的创建方法,并传入 returnUrl - return a.CreateAlipayH5Order(amount, subject, outTradeNo) + return a.CreateAlipayH5Order(merchant, amount, subject, outTradeNo) default: return "", fmt.Errorf("不支持的支付平台: %s", platform) } } -// AliRefund 发起支付宝退款。orderPayTime 为订单支付时间(或创建时间);仅当落在 [2026-01-25 16:38:17, 2026-02-02 18:26) 区间内时使用 bak 商户号,否则使用正式商户号;传 nil 则使用正式商户号。 +// AliRefund 发起支付宝退款。 +// merchant: 支付商户标识(one/two)。为空时按老逻辑仅在备份时间区间内使用 Bak。 +// orderPayTime 为订单支付时间(或创建时间);用于老订单按时间区间选择商户;传 nil 则忽略时间区间。 // outRequestNo 为商户退款请求号,同一笔退款需唯一;传空则使用 "refund-"+outTradeNo,重试时建议传入唯一号避免支付宝报重复。 -func (a *AliPayService) AliRefund(ctx context.Context, outTradeNo string, refundAmount float64, orderPayTime *time.Time, outRequestNo string) (*alipay.TradeRefundRsp, error) { - client := a.AlipayClient - if orderPayTime != nil && a.AlipayClientBak != nil && - !orderPayTime.Before(AlipayBakRefundStart) && orderPayTime.Before(AlipayBakRefundEnd) { - client = a.AlipayClientBak - } +func (a *AliPayService) AliRefund(ctx context.Context, merchant string, outTradeNo string, refundAmount float64, orderPayTime *time.Time, outRequestNo string) (*alipay.TradeRefundRsp, error) { + client := a.clientForMerchant(merchant, orderPayTime) if outRequestNo == "" { outRequestNo = fmt.Sprintf("refund-%s", outTradeNo) @@ -168,27 +189,26 @@ func (a *AliPayService) AliRefund(ctx context.Context, outTradeNo string, refund return refundResp, nil } -// HandleAliPaymentNotification 支付宝支付回调 -func (a *AliPayService) HandleAliPaymentNotification(r *http.Request) (*alipay.Notification, error) { - // 解析表单 - err := r.ParseForm() - if err != nil { - return nil, fmt.Errorf("解析请求表单失败:%v", err) - } +// HandleAliPaymentNotification 支付宝支付回调验签。 +// 由上层根据 out_trade_no 查出订单并传入对应商户标识 merchant。 +func (a *AliPayService) HandleAliPaymentNotification(merchant string, form url.Values) (*alipay.Notification, error) { + client := a.clientForMerchant(merchant, nil) // 解析并验证通知,DecodeNotification 会自动验证签名 - notification, err := a.AlipayClient.DecodeNotification(r.Form) + notification, err := client.DecodeNotification(form) if err != nil { return nil, fmt.Errorf("验证签名失败: %v", err) } return notification, nil } -func (a *AliPayService) QueryOrderStatus(ctx context.Context, outTradeNo string) (*alipay.TradeQueryRsp, error) { +// QueryOrderStatus 按商户标识查询支付宝订单状态 +func (a *AliPayService) QueryOrderStatus(ctx context.Context, merchant string, outTradeNo string) (*alipay.TradeQueryRsp, error) { + client := a.clientForMerchant(merchant, nil) queryRequest := alipay.TradeQuery{ OutTradeNo: outTradeNo, } // 发起查询请求 - resp, err := a.AlipayClient.TradeQuery(ctx, queryRequest) + resp, err := client.TradeQuery(ctx, queryRequest) if err != nil { return nil, fmt.Errorf("查询支付宝订单失败: %v", err) } diff --git a/app/main/model/agentMembershipRechargeOrderModel_gen.go b/app/main/model/agentMembershipRechargeOrderModel_gen.go index 1a91171..1370d88 100644 --- a/app/main/model/agentMembershipRechargeOrderModel_gen.go +++ b/app/main/model/agentMembershipRechargeOrderModel_gen.go @@ -10,8 +10,6 @@ import ( "time" - "tyc-server/common/globalkey" - "github.com/Masterminds/squirrel" "github.com/pkg/errors" "github.com/zeromicro/go-zero/core/stores/builder" @@ -19,6 +17,7 @@ import ( "github.com/zeromicro/go-zero/core/stores/sqlc" "github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/core/stringx" + "tyc-server/common/globalkey" ) var ( @@ -65,6 +64,7 @@ type ( LevelName string `db:"level_name"` // 会员级别,如 VIP,SVIP,normal Amount float64 `db:"amount"` // 充值金额 PaymentMethod string `db:"payment_method"` // 支付方式:支付宝,微信,苹果支付,其他 + PaymentMerchant string `db:"payment_merchant"` // 支付商户标识,例如 one/two OrderNo string `db:"order_no"` // 交易号 PlatformOrderId sql.NullString `db:"platform_order_id"` // 支付平台订单号 Status string `db:"status"` @@ -89,11 +89,11 @@ func (m *defaultAgentMembershipRechargeOrderModel) Insert(ctx context.Context, s tycAgentMembershipRechargeOrderOrderNoKey := fmt.Sprintf("%s%v", cacheTycAgentMembershipRechargeOrderOrderNoPrefix, data.OrderNo) tycAgentMembershipRechargeOrderPlatformOrderIdKey := fmt.Sprintf("%s%v", cacheTycAgentMembershipRechargeOrderPlatformOrderIdPrefix, 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.OrderNo, data.PlatformOrderId, data.Status, data.DeleteTime, data.DelState, data.Version) + return session.ExecCtx(ctx, query, data.UserId, data.AgentId, data.LevelName, data.Amount, data.PaymentMethod, data.PaymentMerchant, 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.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.PaymentMerchant, data.OrderNo, data.PlatformOrderId, data.Status, data.DeleteTime, data.DelState, data.Version) }, tycAgentMembershipRechargeOrderIdKey, tycAgentMembershipRechargeOrderOrderNoKey, tycAgentMembershipRechargeOrderPlatformOrderIdKey) } @@ -165,9 +165,9 @@ func (m *defaultAgentMembershipRechargeOrderModel) Update(ctx context.Context, s 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, 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 session.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.PaymentMerchant, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id) } - 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) + return conn.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.PaymentMerchant, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id) }, tycAgentMembershipRechargeOrderIdKey, tycAgentMembershipRechargeOrderOrderNoKey, tycAgentMembershipRechargeOrderPlatformOrderIdKey) } @@ -189,9 +189,9 @@ func (m *defaultAgentMembershipRechargeOrderModel) UpdateWithVersion(ctx context 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, 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 session.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.PaymentMerchant, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion) } - 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) + return conn.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.PaymentMerchant, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion) }, tycAgentMembershipRechargeOrderIdKey, tycAgentMembershipRechargeOrderOrderNoKey, tycAgentMembershipRechargeOrderPlatformOrderIdKey) if err != nil { return err diff --git a/app/main/model/orderModel_gen.go b/app/main/model/orderModel_gen.go index 0dd0c90..7737bdb 100644 --- a/app/main/model/orderModel_gen.go +++ b/app/main/model/orderModel_gen.go @@ -10,8 +10,6 @@ import ( "time" - "tyc-server/common/globalkey" - "github.com/Masterminds/squirrel" "github.com/pkg/errors" "github.com/zeromicro/go-zero/core/stores/builder" @@ -19,6 +17,7 @@ import ( "github.com/zeromicro/go-zero/core/stores/sqlc" "github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/core/stringx" + "tyc-server/common/globalkey" ) var ( @@ -63,6 +62,7 @@ type ( ProductId int64 `db:"product_id"` // 产品ID(软关联到产品表) PaymentPlatform string `db:"payment_platform"` // 支付平台(支付宝、微信、苹果内购、其他) PaymentScene string `db:"payment_scene"` // 支付场景(App、H5、微信小程序、公众号) + PaymentMerchant string `db:"payment_merchant"` // 支付商户标识,例如 one/two PlatformOrderId sql.NullString `db:"platform_order_id"` // 支付平台订单号 Amount float64 `db:"amount"` // 支付金额 Status string `db:"status"` // 支付状态 @@ -90,11 +90,11 @@ func (m *defaultOrderModel) Insert(ctx context.Context, session sqlx.Session, da tycOrderIdKey := fmt.Sprintf("%s%v", cacheTycOrderIdPrefix, data.Id) tycOrderOrderNoKey := fmt.Sprintf("%s%v", cacheTycOrderOrderNoPrefix, data.OrderNo) 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, orderRowsExpectAutoSet) + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, orderRowsExpectAutoSet) if session != nil { - return session.ExecCtx(ctx, query, data.OrderNo, data.UserId, data.ProductId, data.PaymentPlatform, data.PaymentScene, data.PlatformOrderId, data.Amount, data.Status, data.DelState, data.Version, data.PayTime, data.RefundTime, data.CloseTime, data.DeleteTime, data.SalesCost) + return session.ExecCtx(ctx, query, data.OrderNo, data.UserId, data.ProductId, data.PaymentPlatform, data.PaymentScene, data.PaymentMerchant, data.PlatformOrderId, data.Amount, data.Status, data.DelState, data.Version, data.PayTime, data.RefundTime, data.CloseTime, data.DeleteTime, data.SalesCost) } - return conn.ExecCtx(ctx, query, data.OrderNo, data.UserId, data.ProductId, data.PaymentPlatform, data.PaymentScene, data.PlatformOrderId, data.Amount, data.Status, data.DelState, data.Version, data.PayTime, data.RefundTime, data.CloseTime, data.DeleteTime, data.SalesCost) + return conn.ExecCtx(ctx, query, data.OrderNo, data.UserId, data.ProductId, data.PaymentPlatform, data.PaymentScene, data.PaymentMerchant, data.PlatformOrderId, data.Amount, data.Status, data.DelState, data.Version, data.PayTime, data.RefundTime, data.CloseTime, data.DeleteTime, data.SalesCost) }, tycOrderIdKey, tycOrderOrderNoKey) } @@ -145,9 +145,9 @@ func (m *defaultOrderModel) Update(ctx context.Context, session sqlx.Session, ne 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, orderRowsWithPlaceHolder) if session != nil { - return session.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id) + return session.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PaymentMerchant, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id) } - return conn.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id) + return conn.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PaymentMerchant, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id) }, tycOrderIdKey, tycOrderOrderNoKey) } @@ -168,9 +168,9 @@ func (m *defaultOrderModel) UpdateWithVersion(ctx context.Context, session sqlx. 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, orderRowsWithPlaceHolder) if session != nil { - return session.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id, oldVersion) + return session.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PaymentMerchant, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id, oldVersion) } - return conn.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id, oldVersion) + return conn.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PaymentMerchant, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id, oldVersion) }, tycOrderIdKey, tycOrderOrderNoKey) if err != nil { return err diff --git a/app/main/model/orderRefundModel_gen.go b/app/main/model/orderRefundModel_gen.go index d7b8772..f1411dc 100644 --- a/app/main/model/orderRefundModel_gen.go +++ b/app/main/model/orderRefundModel_gen.go @@ -10,8 +10,6 @@ import ( "time" - "tyc-server/common/globalkey" - "github.com/Masterminds/squirrel" "github.com/pkg/errors" "github.com/zeromicro/go-zero/core/stores/builder" @@ -19,6 +17,7 @@ import ( "github.com/zeromicro/go-zero/core/stores/sqlc" "github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/core/stringx" + "tyc-server/common/globalkey" ) var ( @@ -64,6 +63,7 @@ type ( OrderId int64 `db:"order_id"` // 关联的订单ID UserId int64 `db:"user_id"` // 用户ID ProductId int64 `db:"product_id"` // 产品ID + PaymentMerchant string `db:"payment_merchant"` // 退款对应的支付商户标识,例如 one/two PlatformRefundId sql.NullString `db:"platform_refund_id"` // 支付平台退款单号 RefundAmount float64 `db:"refund_amount"` // 退款金额 RefundReason sql.NullString `db:"refund_reason"` // 退款原因 @@ -91,11 +91,11 @@ func (m *defaultOrderRefundModel) Insert(ctx context.Context, session sqlx.Sessi tycOrderRefundPlatformRefundIdKey := fmt.Sprintf("%s%v", cacheTycOrderRefundPlatformRefundIdPrefix, data.PlatformRefundId) tycOrderRefundRefundNoKey := fmt.Sprintf("%s%v", cacheTycOrderRefundRefundNoPrefix, data.RefundNo) 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, orderRefundRowsExpectAutoSet) + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, orderRefundRowsExpectAutoSet) if session != nil { - return session.ExecCtx(ctx, query, data.RefundNo, data.OrderId, data.UserId, data.ProductId, data.PlatformRefundId, data.RefundAmount, data.RefundReason, data.Status, data.DelState, data.Version, data.RefundTime, data.CloseTime, data.DeleteTime) + return session.ExecCtx(ctx, query, data.RefundNo, data.OrderId, data.UserId, data.ProductId, data.PaymentMerchant, data.PlatformRefundId, data.RefundAmount, data.RefundReason, data.Status, data.DelState, data.Version, data.RefundTime, data.CloseTime, data.DeleteTime) } - return conn.ExecCtx(ctx, query, data.RefundNo, data.OrderId, data.UserId, data.ProductId, data.PlatformRefundId, data.RefundAmount, data.RefundReason, data.Status, data.DelState, data.Version, data.RefundTime, data.CloseTime, data.DeleteTime) + return conn.ExecCtx(ctx, query, data.RefundNo, data.OrderId, data.UserId, data.ProductId, data.PaymentMerchant, data.PlatformRefundId, data.RefundAmount, data.RefundReason, data.Status, data.DelState, data.Version, data.RefundTime, data.CloseTime, data.DeleteTime) }, tycOrderRefundIdKey, tycOrderRefundPlatformRefundIdKey, tycOrderRefundRefundNoKey) } @@ -167,9 +167,9 @@ func (m *defaultOrderRefundModel) Update(ctx context.Context, session sqlx.Sessi 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, orderRefundRowsWithPlaceHolder) if session != nil { - return session.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id) + return session.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PaymentMerchant, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id) } - return conn.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id) + return conn.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PaymentMerchant, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id) }, tycOrderRefundIdKey, tycOrderRefundPlatformRefundIdKey, tycOrderRefundRefundNoKey) } @@ -191,9 +191,9 @@ func (m *defaultOrderRefundModel) UpdateWithVersion(ctx context.Context, session 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, orderRefundRowsWithPlaceHolder) if session != nil { - return session.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id, oldVersion) + return session.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PaymentMerchant, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id, oldVersion) } - return conn.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id, oldVersion) + return conn.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PaymentMerchant, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id, oldVersion) }, tycOrderRefundIdKey, tycOrderRefundPlatformRefundIdKey, tycOrderRefundRefundNoKey) if err != nil { return err diff --git a/deploy/script/gen_models.ps1 b/deploy/script/gen_models.ps1 index c2c104c..60b8c5b 100644 --- a/deploy/script/gen_models.ps1 +++ b/deploy/script/gen_models.ps1 @@ -5,7 +5,7 @@ $DB_URL = "tyc:5vg67b3UNHu8@tcp(127.0.0.1:22001)/tyc" $OUTPUT_DIR = "./model" $TEMPLATE_DIR = "../template" -# 表名列表 +# 表名列表(按需开启) $tables = @( # "agent" # "agent_active_stat", @@ -16,7 +16,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,15 +29,15 @@ $tables = @( # "agent_withdrawal_tax_exemption" # "feature" # "global_notifications" - # "order" - # "order_refund" + "order" + "order_refund" # "product", # "product_feature" # "query", # "query_cleanup_log" # "query_cleanup_detail" # "query_cleanup_config" - "user" + # "user" # "user_auth" # "user_temp" # "example" @@ -55,7 +55,6 @@ $tables = @( # "admin_promotion_link_stats_history" # "admin_promotion_order" # "query_user_record" - ) # 为每个表生成模型 diff --git a/deploy/script/m.sql b/deploy/script/m.sql new file mode 100644 index 0000000..6cfb341 --- /dev/null +++ b/deploy/script/m.sql @@ -0,0 +1,90 @@ +-- ========================= +-- 1. 表结构变更:新增 payment_merchant +-- ========================= + +-- 1.1 order 表:增加支付商户标识 +ALTER TABLE `order` +ADD COLUMN `payment_merchant` varchar(64) NOT NULL DEFAULT '' COMMENT '支付商户标识,例如 one/two' AFTER `payment_scene`; + +-- 1.2 order_refund 表:增加支付商户标识 +ALTER TABLE `order_refund` +ADD COLUMN `payment_merchant` varchar(64) NOT NULL DEFAULT '' COMMENT '退款对应的支付商户标识,例如 one/two' AFTER `product_id`; + +-- 1.3 agent_membership_recharge_order 表:增加支付商户标识 +ALTER TABLE `agent_membership_recharge_order` +ADD COLUMN `payment_merchant` varchar(64) NOT NULL DEFAULT '' COMMENT '支付商户标识,例如 one/two' AFTER `payment_method`; + +-- ========================= +-- 2. 历史数据初始化:one / two +-- 约定: +-- - one:当前主支付宝商户 +-- - two:当前 bak 支付宝商户 +-- 时间区间: +-- [2026-01-25 16:38:17, 2026-02-02 18:26:00) +-- ========================= + +-- 2.1 order 表:按时间区间映射 one / two +-- 仅处理支付宝订单(payment_platform='alipay') +-- 区间内用 two,其余用 one +-- 时间优先用 pay_time,pay_time 为空则用 create_time + +-- 2.1.1 全部支付宝订单默认标记为 one +UPDATE `order` +SET + payment_merchant = 'one' +WHERE + payment_platform = 'alipay' + AND del_state = 0; + +-- 2.1.2 区间内的支付宝订单标记为 two +UPDATE `order` +SET + payment_merchant = 'two' +WHERE + payment_platform = 'alipay' + AND del_state = 0 + AND ( + ( + pay_time IS NOT NULL + AND pay_time >= '2026-01-25 16:38:17' + AND pay_time < '2026-02-02 18:26:00' + ) + OR ( + pay_time IS NULL + AND create_time >= '2026-01-25 16:38:17' + AND create_time < '2026-02-02 18:26:00' + ) + ); + +-- 2.2 agent_membership_recharge_order 表:按创建时间映射 one / two +-- 仅处理支付宝支付(payment_method='alipay') +-- 区间内创建的订单标记为 two,其余为 one + +-- 2.2.1 所有支付宝代理会员充值订单默认标记为 one +UPDATE `agent_membership_recharge_order` +SET + payment_merchant = 'one' +WHERE + payment_method = 'alipay' + AND del_state = 0; + +-- 2.2.2 区间内的支付宝代理会员订单标记为 two +UPDATE `agent_membership_recharge_order` +SET + payment_merchant = 'two' +WHERE + payment_method = 'alipay' + AND del_state = 0 + AND create_time >= '2026-01-25 16:38:17' + AND create_time < '2026-02-02 18:26:00'; + +-- 2.3 order_refund 表:跟随对应订单的 payment_merchant +-- 直接复制 order.payment_merchant,避免逻辑重复 + +UPDATE `order_refund` r +JOIN `order` o ON r.order_id = o.id +SET + r.payment_merchant = o.payment_merchant +WHERE + r.del_state = 0 + AND o.del_state = 0; \ No newline at end of file