277 lines
11 KiB
Go
277 lines
11 KiB
Go
package adminfinance
|
|
|
|
import "context"
|
|
|
|
type dailyOperatingExpenseRow struct {
|
|
Date string
|
|
AmountCent int64
|
|
Count int64
|
|
}
|
|
|
|
func (r *Repository) dailyOperatingExpenses(ctx context.Context, query DashboardQuery) ([]dailyOperatingExpenseRow, error) {
|
|
rows := make([]dailyOperatingExpenseRow, 0)
|
|
err := r.db.WithContext(ctx).Table("operating_expenses").
|
|
Select(`DATE(occurred_at) AS date, COALESCE(SUM(amount_cent), 0) AS amount_cent, COUNT(id) AS count`).
|
|
Where("status = ?", "paid").
|
|
Where("occurred_at >= ? AND occurred_at <= ?", query.StartDate, query.EndDate).
|
|
Group("DATE(occurred_at)").
|
|
Scan(&rows).Error
|
|
return rows, err
|
|
}
|
|
|
|
// 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 withdrawal struct {
|
|
PaidAmountCent int64
|
|
PaidFeeAmountCent int64
|
|
PaidActualAmountCent int64
|
|
PaidCount int64
|
|
PendingAmountCent int64
|
|
PendingCount int64
|
|
ReviewAmountCent int64
|
|
ReviewCount int64
|
|
}
|
|
if err := db.Table("withdrawal_requests").Select(`
|
|
COALESCE(SUM(CASE WHEN status = 'completed' AND paid_at >= ? AND paid_at <= ? THEN amount_cent ELSE 0 END), 0) AS paid_amount_cent,
|
|
COALESCE(SUM(CASE WHEN status = 'completed' AND paid_at >= ? AND paid_at <= ? THEN fee_cent ELSE 0 END), 0) AS paid_fee_amount_cent,
|
|
COALESCE(SUM(CASE WHEN status = 'completed' AND paid_at >= ? AND paid_at <= ? THEN actual_amount_cent ELSE 0 END), 0) AS paid_actual_amount_cent,
|
|
COALESCE(SUM(CASE WHEN status = 'completed' AND paid_at >= ? AND paid_at <= ? THEN 1 ELSE 0 END), 0) AS paid_count,
|
|
COALESCE(SUM(CASE WHEN status = 'processing' THEN actual_amount_cent ELSE 0 END), 0) AS pending_amount_cent,
|
|
COALESCE(SUM(CASE WHEN status = 'processing' THEN 1 ELSE 0 END), 0) AS pending_count,
|
|
COALESCE(SUM(CASE WHEN status = 'pending' THEN actual_amount_cent ELSE 0 END), 0) AS review_amount_cent,
|
|
COALESCE(SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END), 0) AS review_count`,
|
|
query.StartDate, query.EndDate, query.StartDate, query.EndDate,
|
|
query.StartDate, query.EndDate, query.StartDate, query.EndDate).
|
|
Scan(&withdrawal).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 + withdrawal.PaidActualAmountCent + manualPaid.AmountCent,
|
|
PaidCount: offlinePaid.Count + pickupPaid.Count + pickupAdjustmentPaid.Count + withdrawal.PaidCount + manualPaid.Count,
|
|
PendingPaymentAmountCent: offlinePending.AmountCent + pickupPending.AmountCent + pickupAdjustmentPending.AmountCent + withdrawal.PendingAmountCent,
|
|
PendingPaymentCount: offlinePending.Count + pickupPending.Count + pickupAdjustmentPending.Count + withdrawal.PendingCount,
|
|
OfflineSettlementPaidAmountCent: offlinePaid.AmountCent + pickupPaid.AmountCent + pickupAdjustmentPaid.AmountCent,
|
|
OfflineSettlementPaidCount: offlinePaid.Count + pickupPaid.Count + pickupAdjustmentPaid.Count,
|
|
OfflineSettlementPendingAmountCent: offlinePending.AmountCent,
|
|
OfflineSettlementPendingCount: offlinePending.Count,
|
|
WithdrawalAmountCent: withdrawal.PaidAmountCent,
|
|
WithdrawalFeeAmountCent: withdrawal.PaidFeeAmountCent,
|
|
WithdrawalPaidAmountCent: withdrawal.PaidActualAmountCent,
|
|
WithdrawalPaidCount: withdrawal.PaidCount,
|
|
WithdrawalPendingAmountCent: withdrawal.PendingAmountCent,
|
|
WithdrawalPendingCount: withdrawal.PendingCount,
|
|
WithdrawalReviewAmountCent: withdrawal.ReviewAmountCent,
|
|
WithdrawalReviewCount: withdrawal.ReviewCount,
|
|
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
|
|
}
|