package pay import ( "context" "database/sql" "encoding/hex" "encoding/json" "fmt" "os" "qnc-server/app/main/api/internal/svc" "qnc-server/app/main/api/internal/types" "qnc-server/app/main/model" "qnc-server/common/ctxdata" "qnc-server/common/globalkey" "qnc-server/common/xerr" "qnc-server/pkg/lzkit/crypto" "qnc-server/pkg/lzkit/lzUtils" "strconv" "strings" "time" "github.com/Masterminds/squirrel" "github.com/google/uuid" "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" ) type PaymentLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } type PaymentTypeResp struct { amount float64 outTradeNo string description string orderID string // 订单ID,用于开发环境测试支付模式 } func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLogic { return &PaymentLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, err error) { var paymentTypeResp *PaymentTypeResp var prepayData interface{} var orderID string // 检查是否为开发环境的测试支付模式 env := os.Getenv("ENV") isDevTestPayment := env == "development" && (req.PayMethod == "test" || req.PayMethod == "test_empty") isEmptyReportMode := env == "development" && req.PayMethod == "test_empty" 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 } case "agent_upgrade": paymentTypeResp, err = l.AgentUpgradeOrderPayment(req, session) if err != nil { return err } } // 开发环境测试支付模式:跳过实际支付流程 // 注意:订单状态更新在事务外进行,避免在事务中查询不到订单的问题 if isDevTestPayment { // 获取订单ID(从 QueryOrderPayment 返回的 orderID) if paymentTypeResp.orderID == "" { return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "开发测试模式,订单ID无效") } orderID = paymentTypeResp.orderID // 在事务中只记录订单ID,不更新订单状态 // 订单状态的更新和后续流程在事务提交后处理 logx.Infof("开发环境测试支付模式:订单 %s (ID: %s) 将在事务提交后更新状态", paymentTypeResp.outTradeNo, orderID) // 返回测试支付标识 prepayData = "test_payment_success" return nil } // 正常支付流程 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 } // 开发环境测试支付模式:事务提交后处理订单状态更新和后续流程 if isDevTestPayment && paymentTypeResp != nil && paymentTypeResp.orderID != "" { // 使用 goroutine 异步处理,确保事务已完全提交 go func() { // 短暂延迟,确保事务已完全提交到数据库 time.Sleep(200 * time.Millisecond) finalOrderID := paymentTypeResp.orderID // 查找订单并更新状态为已支付 order, findOrderErr := l.svcCtx.OrderModel.FindOne(context.Background(), finalOrderID) if findOrderErr != nil { logx.Errorf("开发测试模式,查找订单失败,订单ID: %s, 错误: %v", finalOrderID, findOrderErr) return } // 更新订单状态为已支付 order.Status = "paid" now := time.Now() order.PayTime = sql.NullTime{Time: now, Valid: true} // 空报告模式:在 PaymentPlatform 字段中标记,用于后续生成空报告 if isEmptyReportMode { order.PaymentPlatform = "test_empty" logx.Infof("开发环境空报告模式:订单 %s (ID: %s) 已标记为空报告模式", paymentTypeResp.outTradeNo, finalOrderID) } // 更新订单状态(在事务外执行) updateErr := l.svcCtx.OrderModel.UpdateWithVersion(context.Background(), nil, order) if updateErr != nil { logx.Errorf("开发测试模式,更新订单状态失败,订单ID: %s, 错误: %+v", finalOrderID, updateErr) return } logx.Infof("开发环境测试支付模式:订单 %s (ID: %s) 已自动标记为已支付", paymentTypeResp.outTradeNo, finalOrderID) // 再次短暂延迟,确保订单状态更新已提交 time.Sleep(100 * time.Millisecond) // 根据订单类型处理后续流程 if strings.HasPrefix(paymentTypeResp.outTradeNo, "U_") { // 升级订单:直接执行升级操作 upgradeRecords, findUpgradeErr := l.svcCtx.AgentUpgradeModel.FindAll(context.Background(), l.svcCtx.AgentUpgradeModel.SelectBuilder(). Where("order_no = ?", paymentTypeResp.outTradeNo). Limit(1), "") if findUpgradeErr != nil || len(upgradeRecords) == 0 { logx.Errorf("开发测试模式,查找升级记录失败,订单号: %s, 错误: %+v", paymentTypeResp.outTradeNo, findUpgradeErr) return } upgradeRecord := upgradeRecords[0] // 执行升级操作 err := l.svcCtx.AgentWalletModel.Trans(context.Background(), func(transCtx context.Context, session sqlx.Session) error { if err := l.svcCtx.AgentService.ProcessUpgrade(transCtx, upgradeRecord.AgentId, upgradeRecord.ToLevel, upgradeRecord.UpgradeType, upgradeRecord.UpgradeFee, upgradeRecord.RebateAmount, paymentTypeResp.outTradeNo, ""); err != nil { return errors.Wrapf(err, "执行升级操作失败") } // 更新升级记录状态为已完成 upgradeRecord.Status = 2 // 已完成(status: 1=待处理,2=已完成,3=已失败) upgradeRecord.Remark = lzUtils.StringToNullString("测试支付成功,升级完成") if updateErr := l.svcCtx.AgentUpgradeModel.UpdateWithVersion(transCtx, session, upgradeRecord); updateErr != nil { return errors.Wrapf(updateErr, "更新升级记录状态失败") } return nil }) if err != nil { logx.Errorf("开发测试模式,处理升级订单失败,订单号: %s, 错误: %+v", paymentTypeResp.outTradeNo, err) } else { logx.Infof("开发测试模式,代理升级成功,订单号: %s, 代理ID: %s", paymentTypeResp.outTradeNo, upgradeRecord.AgentId) } } else { // 查询订单:发送支付成功通知任务,触发后续流程(生成报告和代理处理) if sendErr := l.svcCtx.AsynqService.SendQueryTask(finalOrderID); sendErr != nil { logx.Errorf("开发测试模式,发送支付成功通知任务失败,订单ID: %s, 错误: %+v", finalOrderID, sendErr) } else { logx.Infof("开发测试模式,已发送支付成功通知任务,订单ID: %s", finalOrderID) } } }() } 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) } outTradeNo := req.Id redisKey := fmt.Sprintf(types.QueryCacheKey, userID, outTradeNo) cache, cacheErr := l.svcCtx.Redis.GetCtx(l.ctx, redisKey) if cacheErr != nil { 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) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 解析缓存内容失败, %v", err) } product, err := l.svcCtx.ProductModel.FindOneByProductEn(l.ctx, data.Product) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 查找产品错误: %v", err) } var amount float64 user, err := l.svcCtx.UserModel.FindOne(l.ctx, userID) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取用户信息失败: %v", err) } var agentLinkModel *model.AgentLink if data.AgentIdentifier != "" { var findAgentLinkErr error agentLinkModel, findAgentLinkErr = l.svcCtx.AgentLinkModel.FindOneByLinkIdentifier(l.ctx, data.AgentIdentifier) if findAgentLinkErr != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取代理链接失败: %+v", findAgentLinkErr) } amount = agentLinkModel.SetPrice // 检查被查询人身份证在72小时内的已支付订单次数 // 如果是代理渠道订单,需要检查该身份证在72小时内已支付的订单是否超过2次 logx.Infof("生成订单, 检测到代理渠道订单,开始检查订单限制, AgentIdentifier: %s", data.AgentIdentifier) checkErr := l.checkIdCardPaidOrdersIn72Hours(data.Params) if checkErr != nil { logx.Errorf("生成订单, 订单限制检查失败: %v", checkErr) return nil, checkErr } logx.Infof("生成订单, 订单限制检查通过,允许创建订单") } else { amount = product.SellPrice } if user.Inside == 1 { amount = 0.01 } order := model.Order{ Id: uuid.NewString(), OrderNo: outTradeNo, UserId: userID, ProductId: product.Id, PaymentPlatform: req.PayMethod, PaymentScene: "app", Amount: amount, Status: "pending", } _, insertOrderErr := l.svcCtx.OrderModel.Insert(l.ctx, session, &order) if insertOrderErr != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存订单失败: %+v", insertOrderErr) } orderID := order.Id // 更新 query_user_record 表的 order_id(通过 query_no 匹配) queryUserRecords, findRecordErr := l.svcCtx.QueryUserRecordModel.FindAll(l.ctx, l.svcCtx.QueryUserRecordModel.SelectBuilder(). Where("query_no = ?", outTradeNo). Where("del_state = ?", 0). Limit(1), "") if findRecordErr == nil && len(queryUserRecords) > 0 { record := queryUserRecords[0] record.OrderId = lzUtils.StringToNullString(orderID) record.Version = record.Version + 1 if updateRecordErr := l.svcCtx.QueryUserRecordModel.UpdateWithVersion(l.ctx, session, record); updateRecordErr != nil { logx.Errorf("更新查询用户记录 order_id 失败: %+v", updateRecordErr) // 更新失败不影响主流程,只记录日志 } else { logx.Infof("更新查询用户记录成功,query_no: %s, order_id: %s", outTradeNo, orderID) } } // 如果是代理推广订单,创建完整的代理订单记录 if data.AgentIdentifier != "" && agentLinkModel != nil { // 获取代理信息 agent, err := l.svcCtx.AgentModel.FindOne(l.ctx, agentLinkModel.AgentId) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 查询代理信息失败: %+v", err) } // 获取产品配置(必须存在) productConfig, err := l.svcCtx.AgentProductConfigModel.FindOneByProductId(l.ctx, product.Id) if err != nil { if errors.Is(err, model.ErrNotFound) { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单失败,产品配置不存在, productId: %s,请先在后台配置产品价格参数", product.Id) } return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 查询产品配置失败: %+v", err) } // 获取等级加成(需要从系统配置读取) levelBonus, err := l.getLevelBonus(agent.Level) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取等级加成配置失败: %+v", err) } // 使用产品配置的底价计算实际底价 basePrice := productConfig.BasePrice actualBasePrice := basePrice + float64(levelBonus) // 计算提价成本(使用产品配置) priceThreshold := 0.0 priceFeeRate := 0.0 if productConfig.PriceThreshold.Valid { priceThreshold = productConfig.PriceThreshold.Float64 } if productConfig.PriceFeeRate.Valid { priceFeeRate = productConfig.PriceFeeRate.Float64 } priceCost := 0.0 if agentLinkModel.SetPrice > priceThreshold { priceCost = (agentLinkModel.SetPrice - priceThreshold) * priceFeeRate } // 计算代理收益 agentProfit := agentLinkModel.SetPrice - actualBasePrice - priceCost // 创建代理订单记录 agentOrder := model.AgentOrder{ Id: uuid.NewString(), AgentId: agentLinkModel.AgentId, OrderId: orderID, ProductId: product.Id, OrderAmount: amount, SetPrice: agentLinkModel.SetPrice, ActualBasePrice: actualBasePrice, PriceCost: priceCost, AgentProfit: agentProfit, ProcessStatus: 0, // 待处理 } _, agentOrderInsert := l.svcCtx.AgentOrderModel.Insert(l.ctx, session, &agentOrder) if agentOrderInsert != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存代理订单失败: %+v", agentOrderInsert) } } return &PaymentTypeResp{amount: amount, outTradeNo: outTradeNo, description: product.ProductName, orderID: orderID}, nil } // AgentVipOrderPayment 代理会员充值订单(已废弃,新系统使用升级功能替代) func (l *PaymentLogic) AgentVipOrderPayment(req *types.PaymentReq, session sqlx.Session) (resp *PaymentTypeResp, err error) { // 新代理系统已废弃会员充值功能,请使用升级功能 return nil, errors.Wrapf(xerr.NewErrMsg("该功能已废弃,请使用代理升级功能"), "") } // AgentUpgradeOrderPayment 代理升级订单支付 func (l *PaymentLogic) AgentUpgradeOrderPayment(req *types.PaymentReq, session sqlx.Session) (resp *PaymentTypeResp, err error) { userID, err := ctxdata.GetUidFromCtx(l.ctx) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err) } // 1. 解析升级记录ID upgradeId := req.Id // 2. 查找升级记录 upgradeRecord, err := l.svcCtx.AgentUpgradeModel.FindOne(l.ctx, upgradeId) if err != nil { if errors.Is(err, model.ErrNotFound) { return nil, errors.Wrapf(xerr.NewErrMsg("升级记录不存在"), "") } return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询升级记录失败, %v", err) } // 3. 验证升级记录状态(必须是待支付状态) if upgradeRecord.Status != 1 { return nil, errors.Wrapf(xerr.NewErrMsg("升级记录状态不正确,无法支付"), "") } // 4. 验证代理ID是否匹配 agent, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err) } if agent.Id != upgradeRecord.AgentId { return nil, errors.Wrapf(xerr.NewErrMsg("无权支付此升级订单"), "") } // 5. 生成订单号(升级订单前缀 U_,限制长度不超过32) base := l.svcCtx.AlipayService.GenerateOutTradeNo() outTradeNo := "U_" + base if len(outTradeNo) > 32 { outTradeNo = outTradeNo[:32] } // 6. 获取用户信息(用于内部用户判断) user, err := l.svcCtx.UserModel.FindOne(l.ctx, userID) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取用户信息失败: %v", err) } // 7. 计算支付金额 amount := upgradeRecord.UpgradeFee if user.Inside == 1 { amount = 0.01 // 内部用户测试金额 } // 8. 创建订单记录 order := model.Order{ Id: uuid.NewString(), OrderNo: outTradeNo, UserId: userID, ProductId: "", // 升级订单没有产品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) } _ = orderInsertResult orderID := order.Id // 9. 更新升级记录的订单号 upgradeRecord.OrderNo = lzUtils.StringToNullString(outTradeNo) if updateErr := l.svcCtx.AgentUpgradeModel.UpdateWithVersion(l.ctx, session, upgradeRecord); updateErr != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新升级记录订单号失败: %+v", updateErr) } // 10. 生成描述信息 levelNames := map[int64]string{ 1: "普通代理", 2: "黄金代理", 3: "钻石代理", } fromLevelName := levelNames[upgradeRecord.FromLevel] toLevelName := levelNames[upgradeRecord.ToLevel] description := fmt.Sprintf("代理升级:%s → %s", fromLevelName, toLevelName) return &PaymentTypeResp{ amount: amount, outTradeNo: outTradeNo, description: description, orderID: orderID, }, nil } // getLevelBonus 获取等级加成(从配置表读取) func (l *PaymentLogic) getLevelBonus(level int64) (int64, error) { var configKey string switch level { case 1: // 普通 configKey = "level_1_bonus" case 2: // 黄金 configKey = "level_2_bonus" case 3: // 钻石 configKey = "level_3_bonus" default: return 0, nil } bonus, err := l.getConfigFloat(configKey) if err != nil { // 配置不存在时返回默认值 l.Errorf("获取等级加成配置失败, level: %d, key: %s, err: %v,使用默认值", level, configKey, err) switch level { case 1: return 6, nil case 2: return 3, nil case 3: return 0, nil } return 0, nil } return int64(bonus), nil } // getConfigFloat 获取配置值(浮点数) func (l *PaymentLogic) getConfigFloat(configKey string) (float64, error) { config, err := l.svcCtx.AgentConfigModel.FindOneByConfigKey(l.ctx, configKey) if err != nil { return 0, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取配置失败, key: %s, %v", configKey, err) } value, err := strconv.ParseFloat(config.ConfigValue, 64) if err != nil { return 0, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "解析配置值失败, key: %s, value: %s, %v", configKey, config.ConfigValue, err) } return value, nil } // checkIdCardPaidOrdersIn72Hours 检查被查询人身份证在72小时内的已支付订单次数 // 如果72小时内已支付订单大于2次,则返回错误 // encryptedParams: 加密的参数字符串(data.Params),需要解密后获取身份证号 func (l *PaymentLogic) checkIdCardPaidOrdersIn72Hours(encryptedParams string) error { logx.Infof("检查订单限制, 开始检查代理渠道订单限制, encryptedParams长度: %d", len(encryptedParams)) // 1. 解密参数获取身份证号 secretKey := l.svcCtx.Config.Encrypt.SecretKey key, decodeErr := hex.DecodeString(secretKey) if decodeErr != nil { return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "检查订单限制, 解析加密密钥失败 err: %v", decodeErr) } // 解密 data.Params(加密的 JSON 字符串) decryptData, aesDecryptErr := crypto.AesDecrypt(encryptedParams, key) if aesDecryptErr != nil { return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "检查订单限制, 解密参数失败 err: %v", aesDecryptErr) } // 解析解密后的 JSON 获取参数 var params map[string]interface{} if unmarshalErr := json.Unmarshal(decryptData, ¶ms); unmarshalErr != nil { return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "检查订单限制, 解析参数失败 err: %v, decryptData: %s", unmarshalErr, string(decryptData)) } idCard, ok := params["id_card"].(string) if !ok || idCard == "" { // 如果没有身份证号,跳过检查(可能是其他类型的查询) logx.Infof("检查订单限制, 未找到身份证号,跳过检查") return nil } logx.Infof("检查订单限制, 被查询人身份证号: %s", idCard) // 2. 加密身份证号用于查询 logx.Infof("检查订单限制, 开始加密身份证号: %s", idCard) encryptedIdCard, encryptErr := crypto.EncryptIDCard(idCard, key) if encryptErr != nil { logx.Errorf("检查订单限制, 加密身份证号失败: %v", encryptErr) return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "检查订单限制, 加密身份证号失败 err: %v", encryptErr) } logx.Infof("检查订单限制, 身份证号加密成功, encryptedIdCard长度: %d", len(encryptedIdCard)) // 3. 查询该身份证对应的所有查询记录(agent_identifier IS NOT NULL) // 统计该身份证的记录数,然后通过order_id关联订单表查询已支付的订单 encryptedIdCardPreview := encryptedIdCard if len(encryptedIdCard) > 20 { encryptedIdCardPreview = encryptedIdCard[:20] + "..." } logx.Infof("检查订单限制, 开始查询数据库") logx.Infof("检查订单限制, 查询条件: id_card=%s, del_state=0, agent_identifier IS NOT NULL, agent_identifier != ''", encryptedIdCardPreview) logx.Infof("检查订单限制, 注意:不要求order_id必须存在,先查询所有记录") queryUserRecords, findRecordErr := l.svcCtx.QueryUserRecordModel.FindAll(l.ctx, l.svcCtx.QueryUserRecordModel.SelectBuilder(). Where("id_card = ?", encryptedIdCard). Where("del_state = ?", globalkey.DelStateNo). Where("agent_identifier IS NOT NULL"). Where("agent_identifier != ''"), "") if findRecordErr != nil { if errors.Is(findRecordErr, model.ErrNotFound) { logx.Infof("检查订单限制, 查询结果: 未找到记录 (ErrNotFound)") } else { logx.Errorf("检查订单限制, 查询数据库失败: %v", findRecordErr) return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "检查订单限制, 查询用户记录失败 err: %v", findRecordErr) } } else { logx.Infof("检查订单限制, 查询数据库成功") } logx.Infof("检查订单限制, 查询到 %d 条该身份证的查询记录(agent_identifier IS NOT NULL)", len(queryUserRecords)) // 统计记录详情 if len(queryUserRecords) > 0 { logx.Infof("检查订单限制, ========== 记录详情 ==========") for i, record := range queryUserRecords { orderId := "" hasOrderId := false if record.OrderId.Valid && record.OrderId.String != "" { orderId = record.OrderId.String hasOrderId = true } agentId := "" if record.AgentIdentifier.Valid { agentId = record.AgentIdentifier.String } logx.Infof("检查订单限制, 记录[%d/%d]: order_id=%s (有order_id: %v), agent_identifier=%s, query_no=%s, create_time=%s, product=%s", i+1, len(queryUserRecords), orderId, hasOrderId, agentId, record.QueryNo, record.CreateTime.Format("2006-01-02 15:04:05"), record.Product) } logx.Infof("检查订单限制, ========== 记录详情结束 ==========") } if len(queryUserRecords) == 0 { // 没有历史订单记录,可以继续 logx.Infof("检查订单限制, 身份证 %s 无历史订单记录,允许支付", idCard) return nil } // 4. 提取所有订单ID(去重),只提取有order_id的记录 logx.Infof("检查订单限制, 开始提取订单ID,总记录数: %d", len(queryUserRecords)) orderIdSet := make(map[string]bool) orderIds := make([]string, 0) recordsWithOrderId := 0 for i, record := range queryUserRecords { if record.OrderId.Valid && record.OrderId.String != "" { recordsWithOrderId++ orderId := record.OrderId.String if !orderIdSet[orderId] { orderIdSet[orderId] = true orderIds = append(orderIds, orderId) logx.Infof("检查订单限制, 记录[%d]有order_id: %s", i+1, orderId) } else { logx.Infof("检查订单限制, 记录[%d]order_id重复: %s (已存在)", i+1, orderId) } } else { logx.Infof("检查订单限制, 记录[%d]无order_id,跳过", i+1) } } logx.Infof("检查订单限制, 有order_id的记录数: %d, 提取到 %d 个唯一订单ID: %v", recordsWithOrderId, len(orderIds), orderIds) if len(orderIds) == 0 { logx.Infof("检查订单限制, 身份证 %s 无有效订单ID,允许支付", idCard) return nil } // 5. 查询72小时内已支付的订单数量(只统计已支付状态的订单) // 计算72小时前的时间 seventyTwoHoursAgo := time.Now().Add(-72 * time.Hour) logx.Infof("检查订单限制, 查询时间范围: %s 至今", seventyTwoHoursAgo.Format("2006-01-02 15:04:05")) logx.Infof("检查订单限制, 查询条件: status='paid', pay_time IS NOT NULL, pay_time >= %s", seventyTwoHoursAgo.Format("2006-01-02 15:04:05")) // 只统计已支付状态的订单(status='paid') paidOrderCount, countErr := l.svcCtx.OrderModel.FindCount(l.ctx, l.svcCtx.OrderModel.SelectBuilder(). Where(squirrel.Eq{"id": orderIds}). Where("status = ?", model.OrderStatusPaid). // 只查询已支付状态的订单 Where("pay_time IS NOT NULL"). // 必须有支付时间 Where("pay_time >= ?", seventyTwoHoursAgo). // 72小时内 Where("del_state = ?", globalkey.DelStateNo), "id") if countErr != nil { return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "检查订单限制, 查询已支付订单数量失败 err: %v", countErr) } logx.Infof("检查订单限制, 身份证 %s 在72小时内已支付的订单数量: %d (限制: 已支付订单数量>2次则拒绝)", idCard, paidOrderCount) // 6. 如果72小时内已支付订单数量大于2次,则拒绝支付 if paidOrderCount > 2 { return errors.Wrapf(xerr.NewErrMsg("该身份证在72小时内已支付订单超过2次,无法进行代理渠道的报告查询支付"), "") } return nil }