package commission_calculation import ( "context" "strconv" "gorm.io/gorm" "github.com/break/junhong_cmp_fiber/internal/infrastructure/audit" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" ) func (s *Service) appendCommissionCalculationAudit(ctx context.Context, tx *gorm.DB, order *model.Order, status, result int) error { if s.auditWriter == nil { return errors.New(errors.CodeInvalidStatus, "佣金统一审计接缝未配置") } primary := audit.OrderResource(order, constants.AuditResourceRelationPrimary, constants.AuditResourceRoleCommissionOrder) primary.BeforeData = map[string]any{"commission_status": order.CommissionStatus, "commission_result": order.CommissionResult} primary.AfterData = map[string]any{"commission_status": status, "commission_result": result} primary.SubjectVisibility = constants.AuditSubjectInternalOnly resources := []audit.ResourceInput{primary} var records []model.CommissionRecord if err := tx.WithContext(ctx).Where("order_id = ?", order.ID).Order("id ASC").Find(&records).Error; err != nil { return errors.Wrap(errors.CodeDatabaseError, err, "查询订单佣金审计快照失败") } shopIDs := make([]uint, 0, len(records)) seenShops := make(map[uint]struct{}, len(records)) for i := range records { resource := audit.CommissionRecordResource(&records[i], nil, map[string]any{ "amount": records[i].Amount, "status": records[i].Status, "balance_after": records[i].BalanceAfter, }) resource.Relation = constants.AuditResourceRelationAffected resource.Role = constants.AuditResourceRoleCommissionRecord resource.SubjectVisibility = constants.AuditSubjectInternalOnly resources = append(resources, resource) if _, ok := seenShops[records[i].ShopID]; !ok { seenShops[records[i].ShopID] = struct{}{} shopIDs = append(shopIDs, records[i].ShopID) } } if len(shopIDs) > 0 { var shops []model.Shop if err := tx.WithContext(ctx).Where("id IN ?", shopIDs).Order("id ASC").Find(&shops).Error; err != nil { return errors.Wrap(errors.CodeDatabaseError, err, "查询佣金归属店铺审计快照失败") } for i := range shops { resource := audit.ShopResource(&shops[i], constants.AuditResourceRelationReference, constants.AuditResourceRoleCommissionShop) resource.SubjectVisibility = constants.AuditSubjectInternalOnly resources = append(resources, resource) } } seriesResource, err := commissionSeriesResource(ctx, tx, order) if err != nil { return err } if seriesResource != nil { resources = append(resources, *seriesResource) } return s.auditWriter.Append(ctx, tx, audit.AppendInput{ EventID: "commission:order:" + strconv.FormatUint(uint64(order.ID), 10) + ":calculated", ActionCode: constants.AuditActionCommissionCalculated, Summary: "完成订单佣金计算", ScopeType: constants.AuditScopePlatform, Result: constants.AuditResultSuccess, CorrelationID: order.OrderNo, Resources: resources, Metadata: map[string]any{"commission_status": status, "commission_result": result, "record_count": len(records)}, }) } func (s *Service) appendCommissionCreditAudit(ctx context.Context, tx *gorm.DB, record *model.CommissionRecord, wallet *model.AgentWallet, transaction *model.AgentWalletTransaction, balanceBefore int64) error { if s.auditWriter == nil { return errors.New(errors.CodeInvalidStatus, "佣金统一审计接缝未配置") } var saved model.CommissionRecord if err := tx.WithContext(ctx).First(&saved, record.ID).Error; err != nil { return errors.Wrap(errors.CodeDatabaseError, err, "查询佣金入账审计快照失败") } var order model.Order if err := tx.WithContext(ctx).First(&order, saved.OrderID).Error; err != nil { return errors.Wrap(errors.CodeDatabaseError, err, "查询佣金关联订单审计快照失败") } var shop model.Shop if err := tx.WithContext(ctx).First(&shop, saved.ShopID).Error; err != nil { return errors.Wrap(errors.CodeDatabaseError, err, "查询佣金归属店铺审计快照失败") } primary := audit.CommissionRecordResource(&saved, map[string]any{"amount": record.Amount, "status": record.Status, "balance_after": record.BalanceAfter}, map[string]any{"amount": saved.Amount, "status": saved.Status, "balance_after": saved.BalanceAfter, "released_at": saved.ReleasedAt}) primary.Relation = constants.AuditResourceRelationPrimary primary.Role = constants.AuditResourceRoleCommissionRecord primary.SubjectVisibility = constants.AuditSubjectInternalOnly walletResource := audit.AgentWalletResource(wallet, constants.AuditResourceRelationAffected, constants.AuditResourceRoleCommissionWallet, map[string]any{"balance": balanceBefore, "frozen_balance": wallet.FrozenBalance}, map[string]any{"balance": balanceBefore + saved.Amount, "frozen_balance": wallet.FrozenBalance}) walletResource.SubjectVisibility = constants.AuditSubjectInternalOnly transactionResource := audit.AgentWalletTransactionResource(transaction, constants.AuditResourceRelationAffected, constants.AuditResourceRoleCommissionTransaction) transactionResource.SubjectVisibility = constants.AuditSubjectInternalOnly orderResource := audit.OrderResource(&order, constants.AuditResourceRelationReference, constants.AuditResourceRoleCommissionOrder) orderResource.SubjectVisibility = constants.AuditSubjectInternalOnly shopResource := audit.ShopResource(&shop, constants.AuditResourceRelationReference, constants.AuditResourceRoleCommissionShop) shopResource.SubjectVisibility = constants.AuditSubjectInternalOnly resources := []audit.ResourceInput{primary, walletResource, transactionResource, orderResource, shopResource} seriesResource, err := commissionSeriesResource(ctx, tx, &order) if err != nil { return err } if seriesResource != nil { resources = append(resources, *seriesResource) } return s.auditWriter.Append(ctx, tx, audit.AppendInput{ EventID: "commission:record:" + strconv.FormatUint(uint64(saved.ID), 10) + ":credited", ActionCode: constants.AuditActionCommissionCredited, Summary: "佣金已入账", ScopeType: constants.AuditScopePlatform, Result: constants.AuditResultSuccess, CorrelationID: order.OrderNo, Resources: resources, Metadata: map[string]any{"amount": saved.Amount, "balance_before": transaction.BalanceBefore, "balance_after": transaction.BalanceAfter}, }) } func commissionSeriesResource(ctx context.Context, tx *gorm.DB, order *model.Order) (*audit.ResourceInput, error) { if order.SeriesID == nil { return nil, nil } var series model.PackageSeries if err := tx.WithContext(ctx).First(&series, *order.SeriesID).Error; err != nil { return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询佣金关联套餐系列审计快照失败") } resource := audit.PackageSeriesResource(&series, constants.AuditResourceRelationReference, constants.AuditResourceRoleCommissionSeries, nil, nil) resource.SubjectVisibility = constants.AuditSubjectInternalOnly return &resource, nil } func (s *Service) recordCommissionCalculationFailure(ctx context.Context, order *model.Order, businessErr error) { if businessErr == nil || order == nil || order.OrderNo == "" || s.auditWriter == nil || s.db == nil { return } primary := audit.OrderResource(order, constants.AuditResourceRelationPrimary, constants.AuditResourceRoleCommissionOrder) primary.BeforeData = map[string]any{"commission_status": order.CommissionStatus, "commission_result": order.CommissionResult} primary.SubjectVisibility = constants.AuditSubjectInternalOnly s.auditWriter.RecordFailure(ctx, s.db, audit.AppendInput{ ActionCode: constants.AuditActionCommissionCalculated, Summary: "订单佣金计算失败", ScopeType: constants.AuditScopePlatform, CorrelationID: order.OrderNo, Resources: []audit.ResourceInput{primary}, }, businessErr) }