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 pickupPaid struct { AmountCent int64 Count int64 } if err := db.Table("admin_pickups"). Select(`COALESCE(SUM(settle_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(&pickupPaid).Error; err != nil { return nil, err } var pickupAdjustmentPaid struct { AmountCent int64 Count int64 } if err := db.Table("admin_pickup_financial_adjustments"). Select(`COALESCE(SUM(settle_delta_cent), 0) AS amount_cent, COUNT(id) AS count`). Where("settlement_mode = ?", "platform_managed"). Where("status = ?", "settled"). Where("settle_delta_cent > 0"). Where("settled_at >= ? AND settled_at <= ?", query.StartDate, query.EndDate). Scan(&pickupAdjustmentPaid).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 pickupPending struct { AmountCent int64 Count int64 } if err := db.Table("admin_pickups"). Select(`COALESCE(SUM(settle_amount_cent), 0) AS amount_cent, COUNT(id) AS count`). Where("settlement_mode = ?", "platform_managed"). Where("offline_settlement_status = ?", "pending"). Where("settle_amount_cent > 0"). Scan(&pickupPending).Error; err != nil { return nil, err } var pickupAdjustmentPending struct { AmountCent int64 Count int64 } if err := db.Table("admin_pickup_financial_adjustments"). Select(`COALESCE(SUM(settle_delta_cent), 0) AS amount_cent, COUNT(id) AS count`). Where("settlement_mode = ?", "platform_managed"). Where("status = ?", "pending"). Where("settle_delta_cent > 0"). Scan(&pickupAdjustmentPending).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 } var manualPaid struct { AmountCent int64 Count int64 } if err := db.Table("manual_disbursements"). Select(`COALESCE(SUM(amount_cent), 0) AS amount_cent, COUNT(id) AS count`). Where("status = ?", "paid"). Where("paid_at >= ? AND paid_at <= ?", query.StartDate, query.EndDate). Scan(&manualPaid).Error; err != nil { return nil, err } return &DisbursementSummaryDTO{ PaidAmountCent: offlinePaid.AmountCent + pickupPaid.AmountCent + pickupAdjustmentPaid.AmountCent + withdrawalPaid.ActualAmountCent + manualPaid.AmountCent, PaidCount: offlinePaid.Count + pickupPaid.Count + pickupAdjustmentPaid.Count + withdrawalPaid.Count + manualPaid.Count, PendingPaymentAmountCent: offlinePending.AmountCent + pickupPending.AmountCent + pickupAdjustmentPending.AmountCent + withdrawalPending.ActualAmountCent, PendingPaymentCount: offlinePending.Count + pickupPending.Count + pickupAdjustmentPending.Count + withdrawalPending.Count, OfflineSettlementPaidAmountCent: offlinePaid.AmountCent + pickupPaid.AmountCent + pickupAdjustmentPaid.AmountCent, OfflineSettlementPaidCount: offlinePaid.Count + pickupPaid.Count + pickupAdjustmentPaid.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, ManualPaidAmountCent: manualPaid.AmountCent, ManualPaidCount: manualPaid.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 } pickupOfflineRows := make([]dailyDisbursementSourceRow, 0) if err := db.Table("admin_pickups"). Select(`DATE(offline_settled_at) AS date, COALESCE(SUM(settle_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(&pickupOfflineRows).Error; err != nil { return nil, err } pickupAdjustmentRows := make([]dailyDisbursementSourceRow, 0) if err := db.Table("admin_pickup_financial_adjustments"). Select(`DATE(settled_at) AS date, COALESCE(SUM(settle_delta_cent), 0) AS amount_cent, COUNT(id) AS count`). Where("settlement_mode = ?", "platform_managed"). Where("status = ?", "settled"). Where("settle_delta_cent > 0"). Where("settled_at >= ? AND settled_at <= ?", query.StartDate, query.EndDate). Group("DATE(settled_at)"). Scan(&pickupAdjustmentRows).Error; err != nil { return nil, err } offlineRows = append(offlineRows, pickupOfflineRows...) offlineRows = append(offlineRows, pickupAdjustmentRows...) 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 } manualRows := make([]dailyDisbursementSourceRow, 0) if err := db.Table("manual_disbursements"). Select(`DATE(paid_at) AS date, COALESCE(SUM(amount_cent), 0) AS amount_cent, COUNT(id) AS count`). Where("status = ?", "paid"). Where("paid_at >= ? AND paid_at <= ?", query.StartDate, query.EndDate). Group("DATE(paid_at)"). Scan(&manualRows).Error; err != nil { return nil, err } rowsByDate := make(map[string]dailyDisbursementRow, len(offlineRows)+len(withdrawalRows)+len(manualRows)) 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 } for _, row := range manualRows { date := dailyDateKey(row.Date) item := rowsByDate[date] item.Date = date item.ManualPaidAmountCent = row.AmountCent item.ManualPaidCount = 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 ManualPaidAmountCent int64 ManualPaidCount int64 }