f
This commit is contained in:
@@ -99,6 +99,24 @@ func (l *AlipayCallbackLogic) handleQueryOrderPayment(w http.ResponseWriter, not
|
||||
return nil
|
||||
}
|
||||
|
||||
// 更新 query_user_record 表的 platform_order_id
|
||||
queryUserRecords, findRecordErr := l.svcCtx.QueryUserRecordModel.FindAll(l.ctx,
|
||||
l.svcCtx.QueryUserRecordModel.SelectBuilder().
|
||||
Where("query_no = ?", notification.OutTradeNo).
|
||||
Where("del_state = ?", 0).
|
||||
Limit(1), "")
|
||||
if findRecordErr == nil && len(queryUserRecords) > 0 {
|
||||
record := queryUserRecords[0]
|
||||
record.PlatformOrderId = lzUtils.StringToNullString(notification.TradeNo)
|
||||
record.Version = record.Version + 1
|
||||
if updateRecordErr := l.svcCtx.QueryUserRecordModel.UpdateWithVersion(l.ctx, nil, record); updateRecordErr != nil {
|
||||
logx.Errorf("支付宝支付回调,更新查询用户记录失败: %+v", updateRecordErr)
|
||||
// 更新失败不影响主流程,只记录日志
|
||||
} else {
|
||||
logx.Infof("支付宝支付回调,更新查询用户记录成功,query_no: %s, platform_order_id: %s", notification.OutTradeNo, notification.TradeNo)
|
||||
}
|
||||
}
|
||||
|
||||
if order.Status == "paid" {
|
||||
if asyncErr := l.svcCtx.AsynqService.SendQueryTask(order.Id); asyncErr != nil {
|
||||
logx.Errorf("异步任务调度失败: %v", asyncErr)
|
||||
|
||||
@@ -3,19 +3,23 @@ package pay
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"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"
|
||||
@@ -241,6 +245,16 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
|
||||
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
|
||||
}
|
||||
@@ -264,6 +278,24 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
|
||||
}
|
||||
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 {
|
||||
// 获取代理信息
|
||||
@@ -473,3 +505,158 @@ func (l *PaymentLogic) getConfigFloat(configKey string) (float64, error) {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -97,6 +97,24 @@ func (l *WechatPayCallbackLogic) handleQueryOrderPayment(w http.ResponseWriter,
|
||||
return nil
|
||||
}
|
||||
|
||||
// 更新 query_user_record 表的 platform_order_id
|
||||
queryUserRecords, findRecordErr := l.svcCtx.QueryUserRecordModel.FindAll(l.ctx,
|
||||
l.svcCtx.QueryUserRecordModel.SelectBuilder().
|
||||
Where("query_no = ?", *notification.OutTradeNo).
|
||||
Where("del_state = ?", 0).
|
||||
Limit(1), "")
|
||||
if findRecordErr == nil && len(queryUserRecords) > 0 {
|
||||
record := queryUserRecords[0]
|
||||
record.PlatformOrderId = lzUtils.StringToNullString(*notification.TransactionId)
|
||||
record.Version = record.Version + 1
|
||||
if updateRecordErr := l.svcCtx.QueryUserRecordModel.UpdateWithVersion(l.ctx, nil, record); updateRecordErr != nil {
|
||||
logx.Errorf("微信支付回调,更新查询用户记录失败: %+v", updateRecordErr)
|
||||
// 更新失败不影响主流程,只记录日志
|
||||
} else {
|
||||
logx.Infof("微信支付回调,更新查询用户记录成功,query_no: %s, platform_order_id: %s", *notification.OutTradeNo, *notification.TransactionId)
|
||||
}
|
||||
}
|
||||
|
||||
if order.Status == "paid" {
|
||||
if asyncErr := l.svcCtx.AsynqService.SendQueryTask(order.Id); asyncErr != nil {
|
||||
logx.Errorf("异步任务调度失败: %v", asyncErr)
|
||||
|
||||
Reference in New Issue
Block a user