收口审计治理与套餐任务进展
Constraint: 在线热修前必须保存当前迭代分支全部有效代码进展 Confidence: medium Scope-risk: broad Directive: 后续修改需保持审计事件与业务事务边界一致 Tested: git diff --cached --check Not-tested: 未运行全量测试,提交用于切换分支前保存既有工作
This commit is contained in:
187
internal/infrastructure/audit/recharge.go
Normal file
187
internal/infrastructure/audit/recharge.go
Normal file
@@ -0,0 +1,187 @@
|
||||
package audit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
agentrecharge "github.com/break/junhong_cmp_fiber/internal/application/agentrecharge"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
)
|
||||
|
||||
// WriteAgentRecharge 将代理充值申请、终态和实际入账写入统一 Audit Event。
|
||||
func (w *Writer) WriteAgentRecharge(ctx context.Context, tx *gorm.DB, change agentrecharge.RechargeAudit) error {
|
||||
if change.Record == nil || change.Record.ID == 0 || change.Record.RechargeNo == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "代理充值审计资源不完整")
|
||||
}
|
||||
resources, err := agentRechargeResources(ctx, tx, change)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return w.Append(ctx, tx, AppendInput{
|
||||
ActionCode: change.ActionCode, Summary: change.Summary,
|
||||
ScopeType: constants.AuditScopePlatform, Result: constants.AuditResultSuccess,
|
||||
CorrelationID: change.Record.RechargeNo, Resources: resources,
|
||||
})
|
||||
}
|
||||
|
||||
func agentRechargeResources(ctx context.Context, tx *gorm.DB, change agentrecharge.RechargeAudit) ([]ResourceInput, error) {
|
||||
record := change.Record
|
||||
id := strconv.FormatUint(uint64(record.ID), 10)
|
||||
primary := ResourceInput{
|
||||
Type: constants.AuditResourceAgentRecharge, ID: &id, Key: record.RechargeNo, DisplayName: record.RechargeNo,
|
||||
Relation: constants.AuditResourceRelationPrimary, Role: constants.AuditResourceRoleRechargeTarget,
|
||||
IdentitySnapshot: map[string]any{
|
||||
"id": record.ID, "recharge_no": record.RechargeNo, "user_id": record.UserID,
|
||||
"shop_id": record.ShopID, "agent_wallet_id": record.AgentWalletID, "amount": record.Amount,
|
||||
"payment_method": record.PaymentMethod, "payment_channel": record.PaymentChannel,
|
||||
"payment_transaction_id": record.PaymentTransactionID, "approval_instance_id": record.ApprovalInstanceID,
|
||||
"status": record.Status,
|
||||
},
|
||||
BeforeData: change.BeforeData, AfterData: change.AfterData,
|
||||
SubjectVisibility: constants.AuditSubjectResult, SubjectSummary: change.Summary,
|
||||
}
|
||||
resources := []ResourceInput{primary}
|
||||
|
||||
var account model.Account
|
||||
if record.UserID > 0 {
|
||||
if err := tx.WithContext(ctx).Unscoped().First(&account, record.UserID).Error; err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询代理充值提交人审计快照失败")
|
||||
}
|
||||
if account.ID > 0 {
|
||||
accountID := strconv.FormatUint(uint64(account.ID), 10)
|
||||
resources = append(resources, ResourceInput{
|
||||
Type: constants.AuditResourceAccount, ID: &accountID, Key: accountID, DisplayName: account.Username,
|
||||
Relation: constants.AuditResourceRelationReference, Role: constants.AuditResourceRoleRechargeSubmitter,
|
||||
IdentitySnapshot: accountIdentity(&account),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var shop model.Shop
|
||||
if err := tx.WithContext(ctx).Unscoped().First(&shop, record.ShopID).Error; err != nil {
|
||||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询代理充值店铺审计快照失败")
|
||||
}
|
||||
resources = append(resources, ShopResource(&shop, constants.AuditResourceRelationReference, constants.AuditResourceRoleRechargeShop))
|
||||
|
||||
if change.Payment != nil {
|
||||
resources = append(resources, PaymentResource(change.Payment, constants.AuditResourceRelationReference, constants.AuditResourceRolePaymentTarget, nil, nil))
|
||||
}
|
||||
if change.Approval != nil {
|
||||
approvalID := strconv.FormatUint(uint64(change.Approval.ID), 10)
|
||||
resources = append(resources, ResourceInput{
|
||||
Type: constants.AuditResourceApprovalInstance, ID: &approvalID, Key: approvalID, DisplayName: "审批实例 " + approvalID,
|
||||
Relation: constants.AuditResourceRelationReference, Role: constants.AuditResourceRoleRechargeApproval,
|
||||
IdentitySnapshot: map[string]any{
|
||||
"id": change.Approval.ID, "business_type": change.Approval.BusinessType,
|
||||
"business_id": change.Approval.BusinessID, "submitter_account_id": change.Approval.SubmitterAccountID,
|
||||
"provider": change.Approval.Provider, "external_ref": change.Approval.ExternalRef,
|
||||
"correlation_id": change.Approval.CorrelationID, "status": change.Approval.Status,
|
||||
},
|
||||
})
|
||||
}
|
||||
if change.Wallet != nil {
|
||||
walletID := strconv.FormatUint(uint64(change.Wallet.ID), 10)
|
||||
relation := constants.AuditResourceRelationReference
|
||||
if change.Transaction != nil {
|
||||
relation = constants.AuditResourceRelationAffected
|
||||
}
|
||||
wallet := ResourceInput{
|
||||
Type: constants.AuditResourceAgentWallet, ID: &walletID, Key: walletID, DisplayName: "代理主钱包 " + walletID,
|
||||
Relation: relation, Role: constants.AuditResourceRoleRechargeWallet,
|
||||
IdentitySnapshot: map[string]any{
|
||||
"id": change.Wallet.ID, "shop_id": change.Wallet.ShopID, "wallet_type": change.Wallet.WalletType,
|
||||
"currency": change.Wallet.Currency, "status": change.Wallet.Status,
|
||||
},
|
||||
SubjectVisibility: constants.AuditSubjectResult, SubjectSummary: change.Summary,
|
||||
}
|
||||
if change.Transaction != nil {
|
||||
wallet.BeforeData = map[string]any{"balance": change.Transaction.BalanceBefore}
|
||||
wallet.AfterData = map[string]any{"balance": change.Transaction.BalanceAfter}
|
||||
}
|
||||
resources = append(resources, wallet)
|
||||
}
|
||||
if change.Transaction != nil {
|
||||
transactionID := strconv.FormatUint(uint64(change.Transaction.ID), 10)
|
||||
resources = append(resources, ResourceInput{
|
||||
Type: constants.AuditResourceAgentWalletTransaction, ID: &transactionID, Key: transactionID, DisplayName: "代理钱包流水 " + transactionID,
|
||||
Relation: constants.AuditResourceRelationAffected, Role: constants.AuditResourceRoleRechargeWalletTransaction,
|
||||
IdentitySnapshot: map[string]any{
|
||||
"id": change.Transaction.ID, "agent_wallet_id": change.Transaction.AgentWalletID,
|
||||
"shop_id": change.Transaction.ShopID, "transaction_type": change.Transaction.TransactionType,
|
||||
"transaction_subtype": change.Transaction.TransactionSubtype,
|
||||
"reference_type": change.Transaction.ReferenceType, "reference_id": change.Transaction.ReferenceID,
|
||||
"status": change.Transaction.Status,
|
||||
},
|
||||
AfterData: map[string]any{
|
||||
"amount": change.Transaction.Amount, "balance_before": change.Transaction.BalanceBefore,
|
||||
"balance_after": change.Transaction.BalanceAfter,
|
||||
},
|
||||
})
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
// AssetRechargeReferences 构造个人资产充值关联的提交人、钱包和资产资源。
|
||||
func AssetRechargeReferences(ctx context.Context, tx *gorm.DB, recharge *model.RechargeOrder) ([]ResourceInput, error) {
|
||||
if recharge == nil || recharge.ID == 0 {
|
||||
return nil, errors.New(errors.CodeInvalidParam, "资产充值审计资源不完整")
|
||||
}
|
||||
resources := make([]ResourceInput, 0, 3)
|
||||
var customer model.PersonalCustomer
|
||||
if err := tx.WithContext(ctx).Unscoped().First(&customer, recharge.UserID).Error; err != nil {
|
||||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询资产充值提交人审计快照失败")
|
||||
}
|
||||
customerID := strconv.FormatUint(uint64(customer.ID), 10)
|
||||
resources = append(resources, ResourceInput{
|
||||
Type: constants.AuditResourcePersonalCustomer, ID: &customerID, Key: customerID, DisplayName: customer.Nickname,
|
||||
Relation: constants.AuditResourceRelationReference, Role: constants.AuditResourceRoleRechargeSubmitter,
|
||||
IdentitySnapshot: map[string]any{
|
||||
"id": customer.ID, "nickname": customer.Nickname, "wx_open_id": customer.WxOpenID,
|
||||
"wx_union_id": customer.WxUnionID, "status": customer.Status,
|
||||
},
|
||||
})
|
||||
var wallet model.AssetWallet
|
||||
if err := tx.WithContext(ctx).First(&wallet, recharge.AssetWalletID).Error; err != nil {
|
||||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询资产充值钱包审计快照失败")
|
||||
}
|
||||
walletID := strconv.FormatUint(uint64(wallet.ID), 10)
|
||||
resources = append(resources, ResourceInput{
|
||||
Type: constants.AuditResourceAssetWallet, ID: &walletID, Key: walletID, DisplayName: "资产钱包 " + walletID,
|
||||
Relation: constants.AuditResourceRelationReference, Role: constants.AuditResourceRoleRechargeWallet,
|
||||
IdentitySnapshot: map[string]any{
|
||||
"id": wallet.ID, "resource_type": wallet.ResourceType, "resource_id": wallet.ResourceID,
|
||||
"currency": wallet.Currency, "shop_id_tag": wallet.ShopIDTag, "enterprise_id_tag": wallet.EnterpriseIDTag,
|
||||
},
|
||||
})
|
||||
switch recharge.ResourceType {
|
||||
case constants.AssetWalletResourceTypeIotCard:
|
||||
var card model.IotCard
|
||||
if err := tx.WithContext(ctx).Unscoped().First(&card, recharge.ResourceID).Error; err != nil {
|
||||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询资产充值卡审计快照失败")
|
||||
}
|
||||
cardID := strconv.FormatUint(uint64(card.ID), 10)
|
||||
resources = append(resources, ResourceInput{
|
||||
Type: constants.AuditResourceIotCard, ID: &cardID, Key: IotCardResourceKey(&card), DisplayName: card.ICCID,
|
||||
Relation: constants.AuditResourceRelationReference, Role: constants.AuditResourceRoleOrderAsset,
|
||||
IdentitySnapshot: IotCardIdentitySnapshot(&card), SubjectVisibility: constants.AuditSubjectResult,
|
||||
SubjectSummary: "资产充值状态已更新",
|
||||
})
|
||||
case constants.AssetWalletResourceTypeDevice:
|
||||
var device model.Device
|
||||
if err := tx.WithContext(ctx).Unscoped().First(&device, recharge.ResourceID).Error; err != nil {
|
||||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询资产充值设备审计快照失败")
|
||||
}
|
||||
deviceID := strconv.FormatUint(uint64(device.ID), 10)
|
||||
resources = append(resources, ResourceInput{
|
||||
Type: constants.AuditResourceDevice, ID: &deviceID, Key: DeviceResourceKey(&device), DisplayName: device.VirtualNo,
|
||||
Relation: constants.AuditResourceRelationReference, Role: constants.AuditResourceRoleOrderAsset,
|
||||
IdentitySnapshot: DeviceIdentitySnapshot(&device), SubjectVisibility: constants.AuditSubjectResult,
|
||||
SubjectSummary: "资产充值状态已更新",
|
||||
})
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
Reference in New Issue
Block a user