重构充值订单模块:用 tb_recharge_order + tb_payment 替换 tb_asset_recharge_record
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m32s

- 新增 RechargeOrder 和 Payment 模型及对应 Store
- 新增 ClientRechargeOrderHandler 提供充值订单列表/详情接口
- 修改 client_wallet.go 使用新表读写充值数据
- 修改 callback/payment.go 将 CRCH 订单路由到 rechargeOrderService
- 修改 client_order/service.go 的强充流程使用新表
- 修改 auto_purchase.go 从 tb_recharge_order 读取 linked_package_ids
- 修改 order/service.go 的 WalletPay 使用 tb_payment 记录
- 修改 wechat_config_store.go 从 tb_recharge_order 统计待支付充值数
- 移除 AssetRechargeStore 和 AssetRechargeRecord 的注册引用
- 修复文档生成器缺失 ClientRechargeOrder handler
- 状态枚举改为 0-based: Pending=0, Paid=1, Closed=2, Refunded=3
This commit is contained in:
2026-04-15 11:00:32 +08:00
parent d26010b29d
commit b972a776d9
33 changed files with 1589 additions and 1017 deletions

View File

@@ -51,7 +51,8 @@ type Service struct {
assetService *asset.Service
purchaseValidationService *purchase_validation.Service
orderStore *postgres.OrderStore
rechargeRecordStore *postgres.AssetRechargeStore
rechargeOrderStore *postgres.RechargeOrderStore
paymentStore *postgres.PaymentStore
walletStore *postgres.AssetWalletStore
personalDeviceStore *postgres.PersonalCustomerDeviceStore
openIDStore *postgres.PersonalCustomerOpenIDStore
@@ -73,7 +74,8 @@ func New(
assetService *asset.Service,
purchaseValidationService *purchase_validation.Service,
orderStore *postgres.OrderStore,
rechargeRecordStore *postgres.AssetRechargeStore,
rechargeOrderStore *postgres.RechargeOrderStore,
paymentStore *postgres.PaymentStore,
walletStore *postgres.AssetWalletStore,
personalDeviceStore *postgres.PersonalCustomerDeviceStore,
openIDStore *postgres.PersonalCustomerOpenIDStore,
@@ -93,7 +95,8 @@ func New(
assetService: assetService,
purchaseValidationService: purchaseValidationService,
orderStore: orderStore,
rechargeRecordStore: rechargeRecordStore,
rechargeOrderStore: rechargeOrderStore,
paymentStore: paymentStore,
walletStore: walletStore,
personalDeviceStore: personalDeviceStore,
openIDStore: openIDStore,
@@ -172,6 +175,27 @@ func (s *Service) CreateOrder(ctx context.Context, customerID uint, req *dto.Cli
if lockAcquired {
_ = s.redis.Del(skipCtx, lockKey).Err()
}
existingValue, err := s.redis.Get(skipCtx, redisKey).Result()
if err == nil && strings.HasPrefix(existingValue, "CRCH") {
existingOrder, queryErr := s.rechargeOrderStore.GetByRechargeOrderNo(skipCtx, existingValue)
if queryErr == nil && existingOrder.Status == model.RechargeOrderStatusPending {
return &dto.ClientCreateOrderResponse{
OrderType: "recharge",
Recharge: &dto.ClientRechargeInfo{
RechargeID: existingOrder.ID,
RechargeNo: existingOrder.RechargeOrderNo,
Amount: existingOrder.Amount,
Status: rechargeStatusToClientStatus(int(existingOrder.Status)),
StatusName: clientRechargeStatusName(rechargeStatusToClientStatus(int(existingOrder.Status))),
AutoPurchaseStatus: existingOrder.AutoPurchaseStatus,
},
Idempotent: true,
}, nil
}
if queryErr == nil {
_ = s.redis.Del(skipCtx, redisKey).Err()
}
}
return nil, errors.New(errors.CodeTooManyRequests, "订单正在创建中,请勿重复提交")
}
@@ -360,17 +384,26 @@ func (s *Service) createForceRechargeOrder(
return nil, errors.Wrap(errors.CodeInternalError, err, "序列化关联套餐失败")
}
carrierID := resourceID
recharge := &model.AssetRechargeRecord{
rechargeOrderNo := generateClientRechargeNo()
var iotCardID *uint
var deviceID *uint
if validationResult.Card != nil {
iotCardID = &validationResult.Card.ID
}
if validationResult.Device != nil {
deviceID = &validationResult.Device.ID
}
rechargeOrder := &model.RechargeOrder{
RechargeOrderNo: rechargeOrderNo,
UserID: customerID,
AssetWalletID: wallet.ID,
ResourceType: resourceType,
ResourceID: resourceID,
RechargeNo: generateClientRechargeNo(),
IotCardID: iotCardID,
DeviceID: deviceID,
Amount: forceRecharge.ForceRechargeAmount,
PaymentMethod: model.PaymentMethodWechat,
PaymentConfigID: &activeConfig.ID,
Status: 1,
Status: model.RechargeOrderStatusPending,
ShopIDTag: wallet.ShopIDTag,
EnterpriseIDTag: wallet.EnterpriseIDTag,
OperatorType: "personal_customer",
@@ -378,33 +411,47 @@ func (s *Service) createForceRechargeOrder(
LinkedPackageIDs: datatypes.JSON(linkedPackageIDs),
LinkedOrderType: resolveOrderType(validationResult),
LinkedCarrierType: assetInfo.AssetType,
LinkedCarrierID: &carrierID,
AutoPurchaseStatus: constants.AutoPurchaseStatusPending,
LinkedCarrierID: &resourceID,
AutoPurchaseStatus: model.AutoPurchaseStatusPending,
}
if err := s.rechargeRecordStore.Create(ctx, recharge); err != nil {
return nil, errors.Wrap(errors.CodeDatabaseError, err, "创建充值记录失败")
if err := s.rechargeOrderStore.Create(ctx, rechargeOrder); err != nil {
return nil, errors.Wrap(errors.CodeDatabaseError, err, "创建充值订单失败")
}
paymentResult, err := paymentProvider.CreateJSAPIPayment(ctx, recharge.RechargeNo, "余额充值", openID, int(recharge.Amount))
paymentNo := generateClientRechargeNo()
payment := &model.Payment{
PaymentNo: paymentNo,
OrderID: rechargeOrder.ID,
OrderType: model.PaymentOrderTypeRecharge,
PaymentMethod: model.PaymentByWechat,
Amount: forceRecharge.ForceRechargeAmount,
Status: model.PaymentRecordStatusPending,
PaymentConfigID: &activeConfig.ID,
}
if err := s.paymentStore.Create(ctx, payment); err != nil {
return nil, errors.Wrap(errors.CodeDatabaseError, err, "创建支付记录失败")
}
paymentResult, err := paymentProvider.CreateJSAPIPayment(ctx, rechargeOrderNo, "余额充值", openID, int(rechargeOrder.Amount))
if err != nil {
return nil, err
}
// 微信支付创建成功后才标记幂等 key确保支付失败时 defer 能正确清除 key
s.markClientPurchaseCreated(ctx, redisKey, recharge.RechargeNo)
s.markClientPurchaseCreated(ctx, redisKey, rechargeOrderNo)
*created = true
clientStatus := rechargeStatusToClientStatus(recharge.Status)
clientStatus := rechargeStatusToClientStatus(int(rechargeOrder.Status))
return &dto.ClientCreateOrderResponse{
OrderType: "recharge",
Recharge: &dto.ClientRechargeInfo{
RechargeID: recharge.ID,
RechargeNo: recharge.RechargeNo,
Amount: recharge.Amount,
RechargeID: rechargeOrder.ID,
RechargeNo: rechargeOrderNo,
Amount: rechargeOrder.Amount,
Status: clientStatus,
StatusName: clientRechargeStatusName(clientStatus),
AutoPurchaseStatus: recharge.AutoPurchaseStatus,
AutoPurchaseStatus: rechargeOrder.AutoPurchaseStatus,
},
PayConfig: buildClientPayConfigFromResult(paymentResult),
LinkedPackageInfo: buildLinkedPackageInfo(validationResult, forceRecharge),