package adminfinance import "context" // disbursementSummary 使用实际确认打款时间统计区间出款,同时返回不受日期限制的当前待办。 func (r *Repository) disbursementSummary(ctx context.Context, query DashboardQuery) (*DisbursementSummaryDTO, error) { db := r.db.WithContext(ctx) var offlinePaid struct { AmountCent int64 Count int64 } if err := db.Table("rental_orders"). Select(`COALESCE(SUM(offline_settlement_amount_cent), 0) AS amount_cent, COUNT(id) AS count`). Where("settlement_mode = ?", "platform_managed"). Where("offline_settlement_status = ?", "settled"). Where("offline_settled_at >= ? AND offline_settled_at <= ?", query.StartDate, query.EndDate). Scan(&offlinePaid).Error; err != nil { return nil, err } var offlinePending struct { AmountCent int64 Count int64 } if err := db.Table("rental_orders"). Select(`COALESCE(SUM(offline_settlement_amount_cent), 0) AS amount_cent, COUNT(id) AS count`). Where("settlement_mode = ?", "platform_managed"). Where("offline_settlement_status = ?", "pending"). Where("offline_settlement_amount_cent > 0"). Scan(&offlinePending).Error; err != nil { return nil, err } var withdrawalPaid struct { AmountCent int64 FeeAmountCent int64 ActualAmountCent int64 Count int64 } if err := db.Table("withdrawal_requests"). Select(`COALESCE(SUM(amount_cent), 0) AS amount_cent, COALESCE(SUM(fee_cent), 0) AS fee_amount_cent, COALESCE(SUM(actual_amount_cent), 0) AS actual_amount_cent, COUNT(id) AS count`). Where("status = ?", "completed"). Where("paid_at >= ? AND paid_at <= ?", query.StartDate, query.EndDate). Scan(&withdrawalPaid).Error; err != nil { return nil, err } var withdrawalPending struct { ActualAmountCent int64 Count int64 } if err := db.Table("withdrawal_requests"). Select(`COALESCE(SUM(actual_amount_cent), 0) AS actual_amount_cent, COUNT(id) AS count`). Where("status = ?", "processing"). Scan(&withdrawalPending).Error; err != nil { return nil, err } var withdrawalReview struct { ActualAmountCent int64 Count int64 } if err := db.Table("withdrawal_requests"). Select(`COALESCE(SUM(actual_amount_cent), 0) AS actual_amount_cent, COUNT(id) AS count`). Where("status = ?", "pending"). Scan(&withdrawalReview).Error; err != nil { return nil, err } return &DisbursementSummaryDTO{ PaidAmountCent: offlinePaid.AmountCent + withdrawalPaid.ActualAmountCent, PaidCount: offlinePaid.Count + withdrawalPaid.Count, PendingPaymentAmountCent: offlinePending.AmountCent + withdrawalPending.ActualAmountCent, PendingPaymentCount: offlinePending.Count + withdrawalPending.Count, OfflineSettlementPaidAmountCent: offlinePaid.AmountCent, OfflineSettlementPaidCount: offlinePaid.Count, OfflineSettlementPendingAmountCent: offlinePending.AmountCent, OfflineSettlementPendingCount: offlinePending.Count, WithdrawalAmountCent: withdrawalPaid.AmountCent, WithdrawalFeeAmountCent: withdrawalPaid.FeeAmountCent, WithdrawalPaidAmountCent: withdrawalPaid.ActualAmountCent, WithdrawalPaidCount: withdrawalPaid.Count, WithdrawalPendingAmountCent: withdrawalPending.ActualAmountCent, WithdrawalPendingCount: withdrawalPending.Count, WithdrawalReviewAmountCent: withdrawalReview.ActualAmountCent, WithdrawalReviewCount: withdrawalReview.Count, }, nil } func (r *Repository) dailyDisbursements(ctx context.Context, query DashboardQuery) ([]dailyDisbursementRow, error) { db := r.db.WithContext(ctx) offlineRows := make([]dailyDisbursementSourceRow, 0) if err := db.Table("rental_orders"). Select(`DATE(offline_settled_at) AS date, COALESCE(SUM(offline_settlement_amount_cent), 0) AS amount_cent, COUNT(id) AS count`). Where("settlement_mode = ?", "platform_managed"). Where("offline_settlement_status = ?", "settled"). Where("offline_settled_at >= ? AND offline_settled_at <= ?", query.StartDate, query.EndDate). Group("DATE(offline_settled_at)"). Scan(&offlineRows).Error; err != nil { return nil, err } withdrawalRows := make([]dailyDisbursementSourceRow, 0) if err := db.Table("withdrawal_requests"). Select(`DATE(paid_at) AS date, COALESCE(SUM(actual_amount_cent), 0) AS amount_cent, COUNT(id) AS count`). Where("status = ?", "completed"). Where("paid_at >= ? AND paid_at <= ?", query.StartDate, query.EndDate). Group("DATE(paid_at)"). Scan(&withdrawalRows).Error; err != nil { return nil, err } rowsByDate := make(map[string]dailyDisbursementRow, len(offlineRows)+len(withdrawalRows)) for _, row := range offlineRows { date := dailyDateKey(row.Date) item := rowsByDate[date] item.Date = date item.OfflineSettlementPaidAmountCent = row.AmountCent item.OfflineSettlementPaidCount = row.Count rowsByDate[date] = item } for _, row := range withdrawalRows { date := dailyDateKey(row.Date) item := rowsByDate[date] item.Date = date item.WithdrawalPaidAmountCent = row.AmountCent item.WithdrawalPaidCount = row.Count rowsByDate[date] = item } rows := make([]dailyDisbursementRow, 0, len(rowsByDate)) for day := dayStart(query.StartDate); !day.After(query.EndDate); day = day.AddDate(0, 0, 1) { if row, ok := rowsByDate[day.Format("2006-01-02")]; ok { rows = append(rows, row) } } return rows, nil } type dailyDisbursementSourceRow struct { Date string AmountCent int64 Count int64 } type dailyDisbursementRow struct { Date string OfflineSettlementPaidAmountCent int64 OfflineSettlementPaidCount int64 WithdrawalPaidAmountCent int64 WithdrawalPaidCount int64 }