refactor(order): 结账单状态常量化并锁定仲裁结单统计口径

仲裁结案会把结账单置为终态 settled,但该状态一直是裸字符串;同时 adminfinance 按日结算聚合只按
accepted 过滤,容易被误读成"仲裁单掉出统计"。本次只做卫生与口径固化,不改任何行为:
- order 新增 CheckoutStatus{Submitted,Countered,Accepted,Disputed,Settled},包内沿用非导出别名
- dispute 的仲裁结案与争议取消分支改用常量;distribution 不能反向依赖 order,本地声明同名常量
- adminfinance 聚合里的 oc.status = 'accepted' 改为常量绑定,并注释说明仲裁单不计入是有意口径
- 新增 distribution 结账单退款重算用例(该分支原先无覆盖):accepted/settled 按结账单实际租金,
  submitted 不被采用;dashboard 用例补一张 settled 结账单,钉住"不计入已结算订单数"
This commit is contained in:
yml2213
2026-09-16 12:49:21 +08:00
parent 0eff43ad52
commit d3d571357a
8 changed files with 154 additions and 6 deletions
@@ -5,6 +5,7 @@ import (
"errors"
"sync"
ordermodule "hfb_sys/backend/internal/modules/order"
"hfb_sys/backend/internal/timeutil"
)
@@ -442,7 +443,9 @@ func (r *Repository) dailySettlements(ctx context.Context, query DashboardQuery)
ELSE 0
END), 0) AS financial_exception_count,
COUNT(ro.id) AS settled_order_count`, settlementDiffThresholdCent, refundBizTypes(), []string{"refunding", "failed"}).
Joins("JOIN order_checkouts AS oc ON oc.order_id = ro.id AND oc.status = 'accepted'").
// 统计口径:只算"正常结账确认"的订单。仲裁结案的结账单终态是 settled
// (由 dispute 模块写入),不纳入本指标,此处保持既有口径不变。
Joins("JOIN order_checkouts AS oc ON oc.order_id = ro.id AND oc.status = ?", ordermodule.CheckoutStatusAccepted).
Joins("LEFT JOIN (?) AS w ON w.order_id = ro.id", ownerWalletIncomeForSettledOrdersSubquery(db, query)).
Where("ro.settled_at >= ? AND ro.settled_at <= ?", query.StartDate, query.EndDate).
Group("DATE_FORMAT(ro.settled_at, '%Y-%m-%d')").
@@ -192,9 +192,11 @@ func TestSummaryReturnsNormalOrderCountAndScopedExceptionCount(t *testing.T) {
loc := timeutil.ShanghaiLocation()
settledAt := time.Date(2026, 8, 2, 10, 0, 0, 0, loc)
// ORD-S3 的结账单终态是 settled(仲裁结案),不纳入"正常结账确认"口径。
for _, row := range [][]any{
{1, "ORD-S1", 1, 1, 1, 1, settledAt, "owner_wallet", 0, "none", "none", "settled", "completed", settledAt, 300},
{2, "ORD-S2", 2, 2, 2, 2, settledAt, "owner_wallet", 0, "none", "none", "settled", "completed", settledAt, 200},
{3, "ORD-S3", 3, 3, 3, 3, settledAt, "owner_wallet", 0, "none", "none", "settled", "completed", settledAt, 0},
} {
if err := db.Exec(`INSERT INTO rental_orders
(id, order_no, listing_id, account_id, owner_id, renter_id,
@@ -204,7 +206,11 @@ func TestSummaryReturnsNormalOrderCountAndScopedExceptionCount(t *testing.T) {
t.Fatalf("写入订单失败: %v", err)
}
}
for _, row := range [][]any{{1, 1, 1, "accepted", 300, 700}, {2, 2, 1, "accepted", 200, 600}} {
for _, row := range [][]any{
{1, 1, 1, "accepted", 300, 700},
{2, 2, 1, "accepted", 200, 600},
{3, 3, 1, "settled", 0, 0},
} {
if err := db.Exec(`INSERT INTO order_checkouts
(id, order_id, initiated_by, status, platform_fee_cent, owner_income_amount_cent)
VALUES (?, ?, ?, ?, ?, ?)`, row...).Error; err != nil {
@@ -236,6 +242,7 @@ func TestSummaryReturnsNormalOrderCountAndScopedExceptionCount(t *testing.T) {
t.Fatalf("读取每日结算汇总失败: %v", err)
}
summary := summaryWithPickup(summaryFromDailyRows(nil, settlements, nil), pickup)
// ORD-S3 的结账单终态为 settled(仲裁结案),按既有口径不计入"已结算订单数"。
if summary.SettledOrderCount != 2 || summary.NormalOrderProfitAmountCent != 500 {
t.Fatalf("普通订单数量或利润错误: %+v", summary)
}