package wallet import ( "context" "github.com/bytedance/sonic" "gorm.io/gorm" walletapp "github.com/break/junhong_cmp_fiber/internal/application/wallet" "github.com/break/junhong_cmp_fiber/internal/infrastructure/messaging/outbox" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" ) // DebitEventConsumer 校验已投递的代理主钱包扣款事件具有对应权威资金流水。 // 后续余额预警等消费者在此稳定接缝上扩展,不需要回读或改写订单扣款事务。 type DebitEventConsumer struct { db *gorm.DB } // NewDebitEventConsumer 创建代理主钱包扣款事件消费者。 func NewDebitEventConsumer(db *gorm.DB) *DebitEventConsumer { return &DebitEventConsumer{db: db} } // Consume 校验事件载荷及不可变流水,保证未知或损坏事件不会被静默确认。 func (c *DebitEventConsumer) Consume(ctx context.Context, envelope outbox.DeliveryEnvelope) error { if c == nil || c.db == nil { return errors.New(errors.CodeInternalError, "代理主钱包扣款事件消费者未配置") } if envelope.EventType != constants.OutboxEventTypeAgentMainWalletDebited || envelope.PayloadVersion != constants.AgentMainWalletDebitedPayloadVersionV1 { return errors.New(errors.CodeInvalidParam, "代理主钱包扣款事件类型或版本不受支持") } var event walletapp.DebitedEvent if err := sonic.Unmarshal(envelope.Payload, &event); err != nil { return errors.Wrap(errors.CodeInvalidParam, err, "代理主钱包扣款事件载荷无法解析") } if event.EventID != envelope.EventID || event.WalletID == 0 || event.ReferenceID == 0 || event.ReferenceType != constants.ReferenceTypeOrder || event.TransactionType != constants.AgentTransactionTypeDeduct || event.Amount <= 0 { return errors.New(errors.CodeInvalidParam, "代理主钱包扣款事件载荷不完整") } var transaction model.AgentWalletTransaction err := c.db.WithContext(ctx).Unscoped(). Where("agent_wallet_id = ? AND reference_type = ? AND reference_id = ? AND transaction_type = ? AND status = ?", event.WalletID, event.ReferenceType, event.ReferenceID, constants.AgentTransactionTypeDeduct, constants.TransactionStatusSuccess). First(&transaction).Error if err != nil { if err == gorm.ErrRecordNotFound { return errors.New(errors.CodeInternalError, "代理主钱包扣款事件缺少权威资金流水") } return errors.Wrap(errors.CodeDatabaseError, err, "查询代理主钱包扣款流水失败") } if transaction.Amount != -event.Amount || transaction.BalanceBefore != event.BalanceBefore || transaction.BalanceAfter != event.BalanceAfter { return errors.New(errors.CodeInternalError, "代理主钱包扣款事件与权威资金流水不一致") } return nil }