package recharge import ( "context" "fmt" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/store/postgres" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" "github.com/break/junhong_cmp_fiber/pkg/payment" "go.uber.org/zap" "gorm.io/gorm" ) // ForceRechargeRequirement 强充要求信息 type ForceRechargeRequirement struct { NeedForceRecharge bool `json:"need_force_recharge"` // 是否需要强充 ForceRechargeAmount int64 `json:"force_recharge_amount"` // 强充金额(分) TriggerType string `json:"trigger_type"` // 触发类型: single_recharge/accumulated_recharge MinAmount int64 `json:"min_amount"` // 最小充值金额 MaxAmount int64 `json:"max_amount"` // 最大充值金额 CurrentAccumulated int64 `json:"current_accumulated"` // 当前累计充值 Threshold int64 `json:"threshold"` // 佣金触发阈值 Message string `json:"message"` // 提示信息 } // WechatConfigServiceInterface 支付配置服务接口 type WechatConfigServiceInterface interface { GetActiveConfig(ctx context.Context) (*model.WechatConfig, error) } // Service 充值服务 // 负责资产钱包(IoT卡/设备)的充值订单创建、预检、支付回调处理等业务逻辑 type Service struct { db *gorm.DB assetWalletStore *postgres.AssetWalletStore assetWalletTransactionStore *postgres.AssetWalletTransactionStore iotCardStore *postgres.IotCardStore deviceStore *postgres.DeviceStore shopSeriesAllocationStore *postgres.ShopSeriesAllocationStore packageSeriesStore *postgres.PackageSeriesStore commissionRecordStore *postgres.CommissionRecordStore wechatConfigService WechatConfigServiceInterface paymentLoader payment.PaymentConfigLoader logger *zap.Logger } // New 创建充值服务实例 func New( db *gorm.DB, assetWalletStore *postgres.AssetWalletStore, assetWalletTransactionStore *postgres.AssetWalletTransactionStore, iotCardStore *postgres.IotCardStore, deviceStore *postgres.DeviceStore, shopSeriesAllocationStore *postgres.ShopSeriesAllocationStore, packageSeriesStore *postgres.PackageSeriesStore, commissionRecordStore *postgres.CommissionRecordStore, wechatConfigService WechatConfigServiceInterface, paymentLoader payment.PaymentConfigLoader, logger *zap.Logger, ) *Service { return &Service{ db: db, assetWalletStore: assetWalletStore, assetWalletTransactionStore: assetWalletTransactionStore, iotCardStore: iotCardStore, deviceStore: deviceStore, shopSeriesAllocationStore: shopSeriesAllocationStore, packageSeriesStore: packageSeriesStore, commissionRecordStore: commissionRecordStore, wechatConfigService: wechatConfigService, paymentLoader: paymentLoader, logger: logger, } } // GetRechargeCheck 充值预检 // 返回强充要求、金额限制等信息 func (s *Service) GetRechargeCheck(ctx context.Context, resourceType string, resourceID uint) (*ForceRechargeRequirement, error) { // 验证资源类型 if resourceType != "iot_card" && resourceType != "device" { return nil, errors.New(errors.CodeInvalidParam, "无效的资源类型") } // 验证资源是否存在 if resourceType == "iot_card" { if _, err := s.iotCardStore.GetByID(ctx, resourceID); err != nil { if err == gorm.ErrRecordNotFound { return nil, errors.New(errors.CodeIotCardNotFound, "IoT卡不存在") } return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询IoT卡失败") } } else { if _, err := s.deviceStore.GetByID(ctx, resourceID); err != nil { if err == gorm.ErrRecordNotFound { return nil, errors.New(errors.CodeNotFound, "设备不存在") } return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询设备失败") } } return s.checkForceRechargeRequirement(ctx, resourceType, resourceID) } // checkForceRechargeRequirement 检查强充要求 // 根据资源类型和ID检查是否需要强制充值指定金额 func (s *Service) checkForceRechargeRequirement(ctx context.Context, resourceType string, resourceID uint) (*ForceRechargeRequirement, error) { result := &ForceRechargeRequirement{ NeedForceRecharge: false, MinAmount: constants.AssetRechargeMinAmount, MaxAmount: constants.AssetRechargeMaxAmount, Message: "无强充要求,可自由充值", } var seriesID *uint var shopID *uint var accumulatedRecharge int64 var firstCommissionPaid bool if resourceType == "iot_card" { card, err := s.iotCardStore.GetByID(ctx, resourceID) if err != nil { if err == gorm.ErrRecordNotFound { return nil, errors.New(errors.CodeIotCardNotFound, "IoT卡不存在") } return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询IoT卡失败") } seriesID = card.SeriesID shopID = card.ShopID if seriesID != nil { accumulatedRecharge = card.GetAccumulatedRechargeBySeries(*seriesID) firstCommissionPaid = card.IsFirstRechargeTriggeredBySeries(*seriesID) } } else if resourceType == "device" { device, err := s.deviceStore.GetByID(ctx, resourceID) if err != nil { if err == gorm.ErrRecordNotFound { return nil, errors.New(errors.CodeNotFound, "设备不存在") } return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询设备失败") } seriesID = device.SeriesID shopID = device.ShopID if seriesID != nil { accumulatedRecharge = device.GetAccumulatedRechargeBySeries(*seriesID) firstCommissionPaid = device.IsFirstRechargeTriggeredBySeries(*seriesID) } } result.CurrentAccumulated = accumulatedRecharge if seriesID == nil || shopID == nil { return result, nil } series, err := s.packageSeriesStore.GetByID(ctx, *seriesID) if err != nil { if err == gorm.ErrRecordNotFound { return result, nil } return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询套餐系列失败") } config, err := series.GetOneTimeCommissionConfig() if err != nil || config == nil || !config.Enable { return result, nil } result.Threshold = config.Threshold result.TriggerType = config.TriggerType if firstCommissionPaid { result.Message = "一次性佣金已发放,无强充要求" return result, nil } if config.TriggerType == model.OneTimeCommissionTriggerFirstRecharge { result.NeedForceRecharge = true result.ForceRechargeAmount = config.Threshold result.Message = fmt.Sprintf("首次充值必须充值%d分", config.Threshold) } else if config.EnableForceRecharge { result.NeedForceRecharge = true if config.ForceAmount > 0 { result.ForceRechargeAmount = config.ForceAmount } else { result.ForceRechargeAmount = config.Threshold } result.Message = fmt.Sprintf("每次充值必须充值%d分", result.ForceRechargeAmount) } else { result.Message = "累计充值模式,可自由充值" } return result, nil }