统一财务统计与线下提号出款口径

This commit is contained in:
yml2213
2026-09-03 20:44:55 +08:00
parent e418a4dfb1
commit 86a9b25d57
12 changed files with 202 additions and 49 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ import (
)
// AdminPickup 管理员线下提号记录。
// 独立于 rental_orders,不进入正常订单状态机与财务统计口径。
// 独立于 rental_orders 和正常订单状态机;完成后进入线下提号财务统计。
// 站内上传完成时入卖家钱包;平台代管完成后进入线下结算。
type AdminPickup struct {
ID uint64 `gorm:"primaryKey" json:"id"`
@@ -125,11 +125,33 @@ func (r *Repository) pickupSummary(ctx context.Context, query DashboardQuery) (*
if err := db.Table("admin_pickups").Where("status = ?", "picking_up").Count(&inProgress).Error; err != nil {
return nil, err
}
var pending 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 = ? AND offline_settlement_status = ? AND settle_amount_cent > 0", "platform_managed", "pending").
Scan(&pending).Error; err != nil {
return nil, err
}
var pendingAdjustments 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 = ? AND status = ? AND settle_delta_cent > 0", "platform_managed", "pending").
Scan(&pendingAdjustments).Error; err != nil {
return nil, err
}
return &PickupSummaryDTO{
SettledAmountCent: row.SettledAmountCent + adjustments.SettledAmountCent,
ProfitAmountCent: row.ProfitAmountCent + adjustments.ProfitAmountCent,
CompletedCount: row.CompletedCount,
InProgressCount: inProgress,
PendingAmountCent: pending.AmountCent + pendingAdjustments.AmountCent,
PendingCount: pending.Count + pendingAdjustments.Count,
}, nil
}
@@ -250,7 +272,7 @@ func (r *Repository) summary(ctx context.Context, query DashboardQuery, pickup *
OwnerWalletIncomeAmountCent: settlement.OwnerWalletIncomeAmountCent,
OwnerEffectiveSettlementAmountCent: settlement.OwnerEffectiveSettlementAmountCent,
OfflineSettlementAmountCent: settlement.OfflineSettlementAmountCent,
OfflineSettlementPendingAmountCent: settlement.OfflineSettlementPendingAmountCent,
OfflineSettlementPendingAmountCent: settlement.OfflineSettlementPendingAmountCent + pickup.PendingAmountCent,
SettlementDiffAmountCent: settlement.OwnerShouldIncomeAmountCent - settlement.OwnerEffectiveSettlementAmountCent,
EstimatedIncomeAmountCent: estimated.EstimatedIncomeAmountCent,
SuccessfulPayCount: payment.SuccessfulPayCount,
@@ -260,7 +282,7 @@ func (r *Repository) summary(ctx context.Context, query DashboardQuery, pickup *
PendingRefundCount: payment.PendingRefundCount,
SettledOrderCount: settlement.SettledOrderCount,
PendingSettleOrderCount: estimated.PendingSettleOrderCount,
OfflineSettlementPendingCount: settlement.OfflineSettlementPendingCount,
OfflineSettlementPendingCount: settlement.OfflineSettlementPendingCount + pickup.PendingCount,
FinancialExceptionCount: settlement.FinancialExceptionCount,
}, nil
}
@@ -499,7 +521,7 @@ func (r *Repository) dailyPickupCancelled(ctx context.Context, query DashboardQu
return rows, err
}
// dailyPaidOrders 按实际付款日统计普通租赁订单,并将创建的线下提号视为已付款成交。
// dailyPaidOrders 按实际付款日统计普通租赁订单,并将已完成的线下提号按完成日计入成交。
func (r *Repository) dailyPaidOrders(ctx context.Context, query DashboardQuery) ([]dailyPaidOrderRow, error) {
items := make([]dailyPaidOrderRow, 0)
err := r.db.WithContext(ctx).Table(`(
@@ -508,10 +530,10 @@ func (r *Repository) dailyPaidOrders(ctx context.Context, query DashboardQuery)
WHERE biz_type = 'order_pay' AND status = 'paid' AND paid_at >= ? AND paid_at <= ?
GROUP BY DATE(paid_at)
UNION ALL
SELECT DATE(created_at) AS date, COUNT(id) AS paid_order_count
SELECT DATE(completed_at) AS date, COUNT(id) AS paid_order_count
FROM admin_pickups
WHERE created_at >= ? AND created_at <= ?
GROUP BY DATE(created_at)
WHERE status = 'completed' AND completed_at >= ? AND completed_at <= ?
GROUP BY DATE(completed_at)
) AS daily_paid_orders`, query.StartDate, query.EndDate, query.StartDate, query.EndDate).
Select("date, SUM(paid_order_count) AS paid_order_count").
Group("date").
@@ -27,7 +27,9 @@ func TestDailyPaidOrdersUsePaidAtAndIncludeCreatedPickups(t *testing.T) {
}
if err := db.Exec(`CREATE TABLE admin_pickups (
id INTEGER PRIMARY KEY,
created_at DATETIME NOT NULL
status TEXT NOT NULL,
created_at DATETIME NOT NULL,
completed_at DATETIME NULL
)`).Error; err != nil {
t.Fatalf("创建提号表失败: %v", err)
}
@@ -49,12 +51,12 @@ func TestDailyPaidOrdersUsePaidAtAndIncludeCreatedPickups(t *testing.T) {
}
}
for _, row := range [][]any{
{1, day(2)},
{2, day(2)},
{3, day(3)},
{4, day(1)},
{1, "completed", day(2), day(2)},
{2, "picking_up", day(2), nil},
{3, "completed", day(3), day(3)},
{4, "cancelled", day(1), nil},
} {
if err := db.Exec(`INSERT INTO admin_pickups (id, created_at) VALUES (?, ?)`, row...).Error; err != nil {
if err := db.Exec(`INSERT INTO admin_pickups (id, status, created_at, completed_at) VALUES (?, ?, ?, ?)`, row...).Error; err != nil {
t.Fatalf("写入提号记录失败: %v", err)
}
}
@@ -75,8 +77,8 @@ func TestDailyPaidOrdersUsePaidAtAndIncludeCreatedPickups(t *testing.T) {
for _, row := range result {
counts[row.Date] = row.PaidOrderCount
}
if counts["2026-08-02"] != 3 || counts["2026-08-03"] != 2 {
t.Fatalf("每日已付款订单 = %#v, want 8月2日为3、8月3日为2", counts)
if counts["2026-08-02"] != 2 || counts["2026-08-03"] != 2 {
t.Fatalf("每日已付款订单 = %#v, want 8月2日为2、8月3日为2", counts)
}
}
@@ -194,7 +196,9 @@ func TestPickupSummaryKeepsOriginalAndAdjustmentOnTheirOwnDates(t *testing.T) {
status TEXT NOT NULL,
settle_amount_cent INTEGER NOT NULL,
profit_amount_cent INTEGER NOT NULL,
completed_at DATETIME NULL
completed_at DATETIME NULL,
settlement_mode TEXT NOT NULL DEFAULT 'owner_wallet',
offline_settlement_status TEXT NOT NULL DEFAULT 'none'
)`).Error; err != nil {
t.Fatalf("创建提号表失败: %v", err)
}
@@ -203,7 +207,9 @@ func TestPickupSummaryKeepsOriginalAndAdjustmentOnTheirOwnDates(t *testing.T) {
pickup_id INTEGER NOT NULL,
settle_delta_cent INTEGER NOT NULL,
profit_delta_cent INTEGER NOT NULL,
created_at DATETIME NOT NULL
created_at DATETIME NOT NULL,
settlement_mode TEXT NOT NULL DEFAULT 'owner_wallet',
status TEXT NOT NULL DEFAULT 'settled'
)`).Error; err != nil {
t.Fatalf("创建提号调整表失败: %v", err)
}
@@ -267,11 +273,13 @@ func TestSummaryReturnsNormalOrderCountAndScopedExceptionCount(t *testing.T) {
)`,
`CREATE TABLE admin_pickups (
id INTEGER PRIMARY KEY, status TEXT NOT NULL, settle_amount_cent INTEGER NOT NULL,
profit_amount_cent INTEGER NOT NULL, completed_at DATETIME NULL
profit_amount_cent INTEGER NOT NULL, completed_at DATETIME NULL,
settlement_mode TEXT NOT NULL DEFAULT 'owner_wallet', offline_settlement_status TEXT NOT NULL DEFAULT 'none'
)`,
`CREATE TABLE admin_pickup_financial_adjustments (
id INTEGER PRIMARY KEY, pickup_id INTEGER NOT NULL, settle_delta_cent INTEGER NOT NULL,
profit_delta_cent INTEGER NOT NULL, created_at DATETIME NOT NULL
profit_delta_cent INTEGER NOT NULL, created_at DATETIME NOT NULL,
settlement_mode TEXT NOT NULL DEFAULT 'owner_wallet', status TEXT NOT NULL DEFAULT 'settled'
)`,
} {
if err := db.Exec(statement).Error; err != nil {
@@ -143,8 +143,8 @@ func (r *Repository) disbursementSummary(ctx context.Context, query DashboardQue
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,
OfflineSettlementPendingAmountCent: offlinePending.AmountCent + pickupPending.AmountCent + pickupAdjustmentPending.AmountCent,
OfflineSettlementPendingCount: offlinePending.Count + pickupPending.Count + pickupAdjustmentPending.Count,
WithdrawalAmountCent: withdrawal.PaidAmountCent,
WithdrawalFeeAmountCent: withdrawal.PaidFeeAmountCent,
WithdrawalPaidAmountCent: withdrawal.PaidActualAmountCent,
@@ -95,6 +95,83 @@ func (r *Repository) disbursementListBaseQuery(ctx context.Context) *gorm.DB {
Where("ro.offline_settlement_status IN ?", []string{"pending", "settled"}).
Where("ro.offline_settlement_amount_cent > 0")
pickupManaged := db.Table("admin_pickups AS ap").
Select(`'pickup' AS source_type,
ap.id AS source_id,
ap.pickup_no AS business_no,
0 AS order_id,
0 AS withdrawal_id,
ap.owner_id AS user_id,
'外部卖家' AS payee_name,
'' AS payee_phone,
'' AS uploader_name,
ap.source_channel,
'' AS account_type,
'' AS account_name,
'' AS account_no,
'' AS bank_name,
ap.settle_amount_cent AS amount_cent,
0 AS fee_cent,
ap.settle_amount_cent AS actual_amount_cent,
CASE WHEN ap.offline_settlement_status = 'settled' THEN 'paid' ELSE 'payment_pending' END AS status,
ap.offline_settlement_status AS raw_status,
ap.completed_at AS business_created_at,
ap.offline_settled_at AS paid_at,
ap.offline_settled_by AS operator_id,
COALESCE(NULLIF(operator.nickname, ''), operator.username, '') AS operator_name,
ap.offline_settlement_remark AS remark,
'' AS category,
'' AS custom_category_name,
'' AS voucher_url,
NULL AS voided_at,
NULL AS voided_by,
'' AS voided_by_name,
'' AS void_reason,
ap.account_snapshot AS source_payload`).
Joins("LEFT JOIN admin_users AS operator ON operator.id = ap.offline_settled_by").
Where("ap.settlement_mode = ?", "platform_managed").
Where("ap.offline_settlement_status IN ?", []string{"pending", "settled"}).
Where("ap.settle_amount_cent > 0")
pickupAdjustments := db.Table("admin_pickup_financial_adjustments AS fa").
Select(`'pickup_adjustment' AS source_type,
fa.id AS source_id,
CAST(fa.id AS CHAR) AS business_no,
0 AS order_id,
0 AS withdrawal_id,
ap.owner_id AS user_id,
'外部卖家' AS payee_name,
'' AS payee_phone,
'' AS uploader_name,
ap.source_channel,
'' AS account_type,
'' AS account_name,
'' AS account_no,
'' AS bank_name,
fa.settle_delta_cent AS amount_cent,
0 AS fee_cent,
fa.settle_delta_cent AS actual_amount_cent,
CASE WHEN fa.status = 'settled' THEN 'paid' ELSE 'payment_pending' END AS status,
fa.status AS raw_status,
fa.created_at AS business_created_at,
fa.settled_at AS paid_at,
fa.settled_by AS operator_id,
COALESCE(NULLIF(operator.nickname, ''), operator.username, '') AS operator_name,
fa.reason AS remark,
'' AS category,
'' AS custom_category_name,
'' AS voucher_url,
NULL AS voided_at,
NULL AS voided_by,
'' AS voided_by_name,
'' AS void_reason,
ap.account_snapshot AS source_payload`).
Joins("JOIN admin_pickups AS ap ON ap.id = fa.pickup_id").
Joins("LEFT JOIN admin_users AS operator ON operator.id = fa.settled_by").
Where("fa.settlement_mode = ?", "platform_managed").
Where("fa.status IN ?", []string{"pending", "settled"}).
Where("fa.settle_delta_cent > 0")
withdrawal := db.Table("withdrawal_requests AS wr").
Select(`'withdrawal' AS source_type,
wr.id AS source_id,
@@ -172,7 +249,7 @@ func (r *Repository) disbursementListBaseQuery(ctx context.Context) *gorm.DB {
Joins("LEFT JOIN admin_users AS creator ON creator.id = md.created_by").
Joins("LEFT JOIN admin_users AS voider ON voider.id = md.voided_by")
union := db.Raw("? UNION ALL ? UNION ALL ?", platformManaged, withdrawal, manualOffline)
union := db.Raw("? UNION ALL ? UNION ALL ? UNION ALL ? UNION ALL ?", platformManaged, pickupManaged, pickupAdjustments, withdrawal, manualOffline)
return db.Table("(?) AS d", union)
}
@@ -42,6 +42,17 @@ func TestDisbursementListCombinesPlatformSettlementsAndWithdrawals(t *testing.T)
status TEXT, created_by INTEGER, voided_by INTEGER, voided_at DATETIME,
void_reason TEXT, created_at DATETIME
)`,
`CREATE TABLE admin_pickups (
id INTEGER PRIMARY KEY, pickup_no TEXT, owner_id INTEGER, source_channel TEXT,
settlement_mode TEXT, settle_amount_cent INTEGER, offline_settlement_status TEXT,
offline_settlement_remark TEXT, offline_settled_by INTEGER, offline_settled_at DATETIME,
completed_at DATETIME, account_snapshot BLOB
)`,
`CREATE TABLE admin_pickup_financial_adjustments (
id INTEGER PRIMARY KEY, pickup_id INTEGER, settle_delta_cent INTEGER,
settlement_mode TEXT, status TEXT, reason TEXT, settled_by INTEGER,
settled_at DATETIME, created_at DATETIME
)`,
}
for _, statement := range statements {
if err := db.Exec(statement).Error; err != nil {
@@ -75,6 +86,17 @@ func TestDisbursementListCombinesPlatformSettlementsAndWithdrawals(t *testing.T)
at(2), at(3), at(4)).Error; err != nil {
t.Fatal(err)
}
if err := db.Exec(`INSERT INTO admin_pickups
(id, pickup_no, owner_id, source_channel, settlement_mode, settle_amount_cent, offline_settlement_status,
offline_settlement_remark, offline_settled_by, offline_settled_at, completed_at, account_snapshot)
VALUES (30, 'P202607010001', 1, '线下录入', 'platform_managed', 4000, 'settled', '提号结算', 7, ?, ?, '{}')`, at(4), at(3)).Error; err != nil {
t.Fatal(err)
}
if err := db.Exec(`INSERT INTO admin_pickup_financial_adjustments
(id, pickup_id, settle_delta_cent, settlement_mode, status, reason, settled_by, settled_at, created_at)
VALUES (31, 30, 500, 'platform_managed', 'settled', '补差价', 7, ?, ?)`, at(5), at(5)).Error; err != nil {
t.Fatal(err)
}
if err := db.Exec(`INSERT INTO withdrawal_requests
(id, withdraw_no, user_id, account_type, account_name, account_no, bank_name,
amount_cent, fee_cent, actual_amount_cent, status, created_at, paid_at,
@@ -108,11 +130,11 @@ func TestDisbursementListCombinesPlatformSettlementsAndWithdrawals(t *testing.T)
if err != nil {
t.Fatalf("Disbursements() error = %v", err)
}
if result.Total != 7 || len(result.Items) != 7 {
t.Fatalf("记录数 = %d/%d, want 7/7", result.Total, len(result.Items))
if result.Total != 9 || len(result.Items) != 9 {
t.Fatalf("记录数 = %d/%d, want 9/9", result.Total, len(result.Items))
}
if result.Summary.PaidAmountCent != 24400 || result.Summary.PaidCount != 3 {
t.Fatalf("已出款 = %d/%d, want 24400/3", result.Summary.PaidAmountCent, result.Summary.PaidCount)
if result.Summary.PaidAmountCent != 28900 || result.Summary.PaidCount != 5 {
t.Fatalf("已出款 = %d/%d, want 28900/5", result.Summary.PaidAmountCent, result.Summary.PaidCount)
}
if result.Summary.PaymentPendingAmountCent != 11000 || result.Summary.PaymentPendingCount != 2 {
t.Fatalf("待打款 = %d/%d, want 11000/2", result.Summary.PaymentPendingAmountCent, result.Summary.PaymentPendingCount)
@@ -134,6 +156,16 @@ func TestDisbursementListCombinesPlatformSettlementsAndWithdrawals(t *testing.T)
if platformItem.PayeeName != "外部卖家" || platformItem.PayeePhone != "13800000000" || platformItem.UploaderName != "上传客服甲" {
t.Fatalf("平台收款人/上传人 = %s/%s/%s", platformItem.PayeeName, platformItem.PayeePhone, platformItem.UploaderName)
}
var pickupItem *DisbursementItemDTO
for index := range result.Items {
if result.Items[index].BusinessNo == "P202607010001" {
pickupItem = &result.Items[index]
break
}
}
if pickupItem == nil || pickupItem.SourceType != "pickup" || pickupItem.ActualAmountCent != 4000 {
t.Fatalf("线下提号出款信息不正确: %+v", pickupItem)
}
var manualItem *DisbursementItemDTO
for index := range result.Items {
@@ -150,6 +150,9 @@ func TestDisbursementStatisticsUseActualPaymentTimeAndAmount(t *testing.T) {
if summary.PendingPaymentAmountCent != 15600 || summary.PendingPaymentCount != 4 {
t.Fatalf("待出款 = %d/%d, want 15600/4", summary.PendingPaymentAmountCent, summary.PendingPaymentCount)
}
if summary.OfflineSettlementPendingAmountCent != 10800 || summary.OfflineSettlementPendingCount != 3 {
t.Fatalf("线下结算待出款 = %d/%d, want 10800/3", summary.OfflineSettlementPendingAmountCent, summary.OfflineSettlementPendingCount)
}
if summary.WithdrawalReviewAmountCent != 2000 || summary.WithdrawalReviewCount != 1 {
t.Fatalf("待审核提现 = %d/%d, want 2000/1", summary.WithdrawalReviewAmountCent, summary.WithdrawalReviewCount)
}
+20 -18
View File
@@ -61,6 +61,8 @@ type PickupSummaryDTO struct {
ProfitAmountCent int64 `json:"profit_amount_cent"` // 区间内已完成提号的线下利润合计
CompletedCount int64 `json:"completed_count"` // 区间内已完成提号笔数
InProgressCount int64 `json:"in_progress_count"` // 当前提号中笔数(不按时间)
PendingAmountCent int64 `json:"pending_amount_cent"` // 当前平台代管提号待结算金额(含正向调整)
PendingCount int64 `json:"pending_count"` // 当前平台代管提号待结算笔数(含正向调整)
}
// MohongSummaryDTO 撞车商城的交易流水,单独展示,不计入平台利润。
@@ -239,11 +241,11 @@ type FinanceSummaryDTO struct {
ChannelNetAmountCent int64 `json:"channel_net_amount_cent"`
// PlatformIncomeAmountCent 为正常订单最终结账利润与已完成线下提号利润之和。
// 保留原 JSON 字段名,避免影响已接入的管理端客户端。
PlatformIncomeAmountCent int64 `json:"platform_income_amount_cent"`
NormalOrderProfitAmountCent int64 `json:"normal_order_profit_amount_cent"`
PickupProfitAmountCent int64 `json:"pickup_profit_amount_cent"`
PlatformIncomeAmountCent int64 `json:"platform_income_amount_cent"`
NormalOrderProfitAmountCent int64 `json:"normal_order_profit_amount_cent"`
PickupProfitAmountCent int64 `json:"pickup_profit_amount_cent"`
// PickupCompletedCount 线下提号利润对应的已完成提号笔数。
PickupCompletedCount int64 `json:"pickup_completed_count"`
PickupCompletedCount int64 `json:"pickup_completed_count"`
OwnerShouldIncomeAmountCent int64 `json:"owner_should_income_amount_cent"`
OwnerWalletIncomeAmountCent int64 `json:"owner_wallet_income_amount_cent"`
OwnerEffectiveSettlementAmountCent int64 `json:"owner_effective_settlement_amount_cent"`
@@ -286,20 +288,20 @@ type FinanceDailyDTO struct {
// NormalFullRefundCount 正常(租赁)订单已退全款笔数(不含撞车商城退款)。
NormalFullRefundCount int64 `json:"normal_full_refund_count"`
// PickupCancelledCount 线下提号取消笔数(按取消日归集)。
PickupCancelledCount int64 `json:"pickup_cancelled_count"`
SalesCount int64 `json:"sales_count"`
PaidOrderCount int64 `json:"paid_order_count"`
OfflineSettlementPendingCount int64 `json:"offline_settlement_pending_count"`
OfflineSettlementPaidAmountCent int64 `json:"offline_settlement_paid_amount_cent"`
OfflineSettlementPaidCount int64 `json:"offline_settlement_paid_count"`
WithdrawalPaidAmountCent int64 `json:"withdrawal_paid_amount_cent"`
WithdrawalPaidCount int64 `json:"withdrawal_paid_count"`
ManualPaidAmountCent int64 `json:"manual_paid_amount_cent"`
ManualPaidCount int64 `json:"manual_paid_count"`
OperatingExpenseAmountCent int64 `json:"operating_expense_amount_cent"`
OperatingExpenseCount int64 `json:"operating_expense_count"`
DisbursementPaidAmountCent int64 `json:"disbursement_paid_amount_cent"`
DisbursementPaidCount int64 `json:"disbursement_paid_count"`
PickupCancelledCount int64 `json:"pickup_cancelled_count"`
SalesCount int64 `json:"sales_count"`
PaidOrderCount int64 `json:"paid_order_count"`
OfflineSettlementPendingCount int64 `json:"offline_settlement_pending_count"`
OfflineSettlementPaidAmountCent int64 `json:"offline_settlement_paid_amount_cent"`
OfflineSettlementPaidCount int64 `json:"offline_settlement_paid_count"`
WithdrawalPaidAmountCent int64 `json:"withdrawal_paid_amount_cent"`
WithdrawalPaidCount int64 `json:"withdrawal_paid_count"`
ManualPaidAmountCent int64 `json:"manual_paid_amount_cent"`
ManualPaidCount int64 `json:"manual_paid_count"`
OperatingExpenseAmountCent int64 `json:"operating_expense_amount_cent"`
OperatingExpenseCount int64 `json:"operating_expense_count"`
DisbursementPaidAmountCent int64 `json:"disbursement_paid_amount_cent"`
DisbursementPaidCount int64 `json:"disbursement_paid_count"`
}
type PaginatedResult struct {
@@ -225,7 +225,7 @@ func parseDisbursementQuery(c *gin.Context) (DisbursementQuery, bool) {
StartDate: start,
EndDate: end,
}
if query.SourceType != "" && query.SourceType != "platform_managed" && query.SourceType != "withdrawal" && query.SourceType != "manual_offline" {
if query.SourceType != "" && query.SourceType != "platform_managed" && query.SourceType != "pickup" && query.SourceType != "pickup_adjustment" && query.SourceType != "withdrawal" && query.SourceType != "manual_offline" {
response.BadRequest(c, "出款类型不正确")
return query, false
}
@@ -25,7 +25,7 @@ func orderPaymentSubquery(db *gorm.DB) *gorm.DB {
func ownerWalletIncomeSubquery(db *gorm.DB) *gorm.DB {
return db.Table("wallet_ledger").
Select("order_id, COALESCE(SUM(amount_cent), 0) AS owner_wallet_income_amount_cent").
Where("direction = ? AND biz_type IN ? AND order_id IS NOT NULL", "in", []string{"owner_income", "deposit_compensation"}).
Where("direction = ? AND biz_type IN ? AND order_id IS NOT NULL", "in", []string{"owner_income", "deposit_compensation", "arbitration_owner_income"}).
Group("order_id")
}
@@ -39,7 +39,7 @@ func ownerWalletIncomeForSettledOrdersSubquery(db *gorm.DB, query DashboardQuery
Joins(`LEFT JOIN wallet_ledger AS wallet
ON wallet.order_id = scoped_order.id
AND wallet.direction = ?
AND wallet.biz_type IN ?`, "in", []string{"owner_income", "deposit_compensation"}).
AND wallet.biz_type IN ?`, "in", []string{"owner_income", "deposit_compensation", "arbitration_owner_income"}).
Where("scoped_order.settled_at >= ? AND scoped_order.settled_at <= ?", query.StartDate, query.EndDate).
Group("scoped_order.id")
}
@@ -126,7 +126,7 @@ export interface FinanceDisbursementListSummary {
}
export interface FinanceDisbursementItem {
source_type: 'platform_managed' | 'withdrawal' | 'manual_offline'
source_type: 'platform_managed' | 'pickup' | 'pickup_adjustment' | 'withdrawal' | 'manual_offline'
source_id: number
business_no: string
order_id?: number
@@ -274,6 +274,8 @@ function money(cents: number | undefined | null) {
function sourceLabel(sourceType: string) {
const labels: Record<string, string> = {
platform_managed: '平台代管',
pickup: '线下提号',
pickup_adjustment: '提号调整',
withdrawal: '用户提现',
manual_offline: '线下出款',
}
@@ -283,6 +285,8 @@ function sourceLabel(sourceType: string) {
function sourceType(sourceType: string) {
const types: Record<string, 'primary' | 'success' | 'warning' | 'info' | 'danger'> = {
platform_managed: 'primary',
pickup: 'success',
pickup_adjustment: 'warning',
withdrawal: 'success',
manual_offline: 'warning',
}
@@ -312,7 +316,10 @@ function itemStatusLabel(row: FinanceDisbursementItem) {
}
return map[row.raw_status] || row.status
}
if (row.source_type === 'platform_managed') {
if (row.source_type === 'platform_managed' || row.source_type === 'pickup') {
return row.raw_status === 'settled' ? '已打款' : '待打款'
}
if (row.source_type === 'pickup_adjustment') {
return row.raw_status === 'settled' ? '已打款' : '待打款'
}
return row.status === 'paid' ? '已记账' : '已作废'
@@ -472,6 +479,8 @@ function accountTypeLabel(type: string) {
class="full-control"
>
<el-option label="平台代管" value="platform_managed" />
<el-option label="线下提号" value="pickup" />
<el-option label="提号调整" value="pickup_adjustment" />
<el-option label="用户提现" value="withdrawal" />
<el-option label="其他线下出款" value="manual_offline" />
</el-select>