package exporter import ( "context" "strconv" "time" "gorm.io/gorm" "github.com/break/junhong_cmp_fiber/pkg/constants" ) // AgentWalletTransactionDataSource 代理主钱包流水导出数据源。 type AgentWalletTransactionDataSource struct { db *gorm.DB } // NewAgentWalletTransactionDataSource 创建代理主钱包流水导出数据源。 func NewAgentWalletTransactionDataSource(db *gorm.DB) *AgentWalletTransactionDataSource { return &AgentWalletTransactionDataSource{db: db} } // Scene 返回导出场景编码。 func (s *AgentWalletTransactionDataSource) Scene() string { return constants.ExportTaskSceneAgentWalletTransaction } // Count 统计代理主钱包流水导出行数。 func (s *AgentWalletTransactionDataSource) Count(ctx context.Context, params ExportParams) (int, error) { var total int64 query := s.applyFilters(s.baseQuery(ctx), params) if err := query.Count(&total).Error; err != nil { return 0, err } return int(total), nil } // Headers 返回代理主钱包流水导出表头。 func (s *AgentWalletTransactionDataSource) Headers(context.Context, ExportParams) ([]string, error) { return []string{ "店铺名称", "交易类型", "交易金额(元)", "状态", "资产类型", "资产标识", "交易时间", "交易前金额(元)", "交易后金额(元)", "购买套餐名称", "操作人", "交易ID", "关联业务订单号", "交易渠道/支付方式", }, nil } // Fetch 按 offset/limit 查询代理主钱包流水导出数据。 func (s *AgentWalletTransactionDataSource) Fetch(ctx context.Context, params ExportParams, offset, limit int) ([][]string, error) { if limit <= 0 { return [][]string{}, nil } var items []agentWalletTransactionExportRow query := s.applyFilters(s.baseQuery(ctx), params). Select(` t.id, t.transaction_type, t.amount, t.status, t.asset_type, t.asset_identifier, t.created_at, t.balance_before, t.balance_after, COALESCE(sh.shop_name, '') AS shop_name, COALESCE(items.package_names, t.metadata ->> 'package_name', '') AS package_name, COALESCE(ac.username, '') AS operator_name, COALESCE( CASE t.reference_type WHEN ? THEN o.order_no WHEN ? THEN ar.recharge_no WHEN ? THEN rr.refund_no WHEN ? THEN wr.withdrawal_no WHEN ? THEN ex.exchange_no END, '' ) AS business_order_no, COALESCE(t.metadata ->> 'payment_method', '') AS payment_method `, constants.ReferenceTypeOrder, constants.ReferenceTypeTopup, constants.ReferenceTypeRefund, constants.ReferenceTypeWithdrawal, constants.ReferenceTypeExchange). Joins("LEFT JOIN tb_shop AS sh ON sh.id = t.shop_id"). Joins("LEFT JOIN tb_account AS ac ON ac.id = COALESCE(NULLIF(t.creator, 0), t.user_id)"). Joins("LEFT JOIN tb_order AS o ON t.reference_type = ? AND o.id = t.reference_id AND o.deleted_at IS NULL", constants.ReferenceTypeOrder). Joins("LEFT JOIN tb_agent_recharge_record AS ar ON t.reference_type = ? AND ar.id = t.reference_id AND ar.deleted_at IS NULL", constants.ReferenceTypeTopup). Joins("LEFT JOIN tb_refund_request AS rr ON t.reference_type = ? AND rr.id = t.reference_id AND rr.deleted_at IS NULL", constants.ReferenceTypeRefund). Joins("LEFT JOIN tb_commission_withdrawal_request AS wr ON t.reference_type = ? AND wr.id = t.reference_id AND wr.deleted_at IS NULL", constants.ReferenceTypeWithdrawal). Joins("LEFT JOIN tb_exchange_order AS ex ON t.reference_type = ? AND ex.id = t.reference_id AND ex.deleted_at IS NULL", constants.ReferenceTypeExchange). Joins(`LEFT JOIN LATERAL ( SELECT string_agg(oi.package_name, ',' ORDER BY oi.id) AS package_names FROM tb_order_item AS oi WHERE t.reference_type = ? AND oi.order_id = t.reference_id AND oi.deleted_at IS NULL ) AS items ON TRUE`, constants.ReferenceTypeOrder). Order("t.id ASC"). Limit(limit). Offset(offset) if err := query.Scan(&items).Error; err != nil { return nil, err } rows := make([][]string, 0, len(items)) for _, item := range items { paymentMethod := item.PaymentMethod if paymentMethod == "" && item.TransactionType == constants.AgentTransactionTypeDeduct { paymentMethod = constants.PaymentMethodWallet } rows = append(rows, []string{ item.ShopName, constants.GetAgentTransactionTypeName(item.TransactionType), formatMoneyYuan(item.Amount), constants.GetTransactionStatusName(item.Status), constants.GetWalletAssetTypeName(item.AssetType), item.AssetIdentifier, item.CreatedAt.Format(exportTimeLayout), formatMoneyYuan(item.BalanceBefore), formatMoneyYuan(item.BalanceAfter), item.PackageName, item.OperatorName, strconv.FormatUint(uint64(item.ID), 10), item.BusinessOrderNo, constants.GetBusinessPaymentMethodName(paymentMethod), }) } return rows, nil } func (s *AgentWalletTransactionDataSource) baseQuery(ctx context.Context) *gorm.DB { return s.db.WithContext(ctx). Table("tb_agent_wallet_transaction AS t"). Joins("INNER JOIN tb_agent_wallet AS w ON w.id = t.agent_wallet_id AND w.wallet_type = ? AND w.deleted_at IS NULL", constants.AgentWalletTypeMain). Where("t.deleted_at IS NULL") } func (s *AgentWalletTransactionDataSource) applyFilters(query *gorm.DB, params ExportParams) *gorm.DB { query = applyExportShopScope(query, params, "t.shop_id") if shopID, ok := filterUint(params.Filters, "shop_id"); ok { query = query.Where("t.shop_id = ?", shopID) } if transactionType, ok := filterString(params.Filters, "transaction_type"); ok { query = query.Where("t.transaction_type = ?", transactionType) } if start, ok := filterTime(params.Filters, "start_date"); ok { query = query.Where("t.created_at >= ?", start) } if end, ok := filterEndDate(params.Filters, "end_date"); ok { query = query.Where("t.created_at <= ?", end) } if assetIdentifier, ok := filterString(params.Filters, "asset_identifier"); ok { query = query.Where("t.asset_identifier = ?", assetIdentifier) } return query } type agentWalletTransactionExportRow struct { ID uint `gorm:"column:id"` ShopName string `gorm:"column:shop_name"` TransactionType string `gorm:"column:transaction_type"` Amount int64 `gorm:"column:amount"` Status int `gorm:"column:status"` AssetType string `gorm:"column:asset_type"` AssetIdentifier string `gorm:"column:asset_identifier"` CreatedAt time.Time `gorm:"column:created_at"` BalanceBefore int64 `gorm:"column:balance_before"` BalanceAfter int64 `gorm:"column:balance_after"` PackageName string `gorm:"column:package_name"` OperatorName string `gorm:"column:operator_name"` BusinessOrderNo string `gorm:"column:business_order_no"` PaymentMethod string `gorm:"column:payment_method"` }