fix(order): 修正仲裁后号主实际收入
This commit is contained in:
@@ -199,7 +199,7 @@ func (r *Repository) ListAdmin(ctx context.Context, query AdminOrderQuery) (*Adm
|
||||
}
|
||||
}
|
||||
if len(incomeOrderIDs) > 0 {
|
||||
ownerIncome, err = r.latestOwnerIncomeByOrder(ctx, incomeOrderIDs)
|
||||
ownerIncome, err = r.ownerActualIncomeByOrder(ctx, incomeOrderIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -255,48 +255,42 @@ func (r *Repository) adminOrderCountQuery(ctx context.Context, query AdminOrderQ
|
||||
return r.adminOrderJoinQuery(ctx)
|
||||
}
|
||||
|
||||
// latestOwnerIncomeByOrder 批量读取每单「最新一次结账」的号主实际到手金额(分)。
|
||||
// ownerActualIncomeByOrder 批量读取每单号主最终实际结算金额(分)。
|
||||
//
|
||||
// 后台订单列表专用:一次查询覆盖整页,不会退化为逐行查询的 N+1。
|
||||
// 只取结账表两列,不加载 content / evidence_urls 等大字段。
|
||||
// 结账行只能代表协商结果,不能代表仲裁后的最终落账:
|
||||
// - 平台代管订单:最终金额写入 rental_orders.offline_settlement_amount_cent;
|
||||
// - 普通钱包订单:最终金额以 wallet_ledger 中号主的实际入账合计为准。
|
||||
//
|
||||
// 语义:多轮还价是原地更新同一行,但订单可能经历多次结账流程,
|
||||
// 因此按 order_id 取 MAX(id) 作为最终结账行。
|
||||
//
|
||||
// 执行计划(MySQL 8.4 实测,EXPLAIN FORMAT=TREE):
|
||||
//
|
||||
// -> Nested loop inner join
|
||||
// -> Materialize
|
||||
// -> Group aggregate: max(order_checkouts.id)
|
||||
// -> Covering index scan on order_checkouts using idx_order_checkouts_order_id
|
||||
// -> Single-row index lookup on oc using PRIMARY (id=latest.latest_id)
|
||||
//
|
||||
// 用 STRAIGHT_JOIN 固定连接顺序:先物化「每单最新结账 id」小集合(走
|
||||
// idx_order_checkouts_order_id 覆盖索引),再按主键逐行取金额。避免优化器
|
||||
// 在数据量增长后改选全表扫描;开销只与当前页订单数相关,与结账表总量无关。
|
||||
func (r *Repository) latestOwnerIncomeByOrder(ctx context.Context, orderIDs []uint64) (map[uint64]int64, error) {
|
||||
// 仲裁可能不更新历史结账行,甚至 dispute.checkout_id 为空,因此不能继续取
|
||||
// order_checkouts 的 owner_income_amount_cent,否则列表会显示仲裁前金额。
|
||||
func (r *Repository) ownerActualIncomeByOrder(ctx context.Context, orderIDs []uint64) (map[uint64]int64, error) {
|
||||
result := make(map[uint64]int64, len(orderIDs))
|
||||
if len(orderIDs) == 0 {
|
||||
return result, nil
|
||||
}
|
||||
latest := r.db.WithContext(ctx).
|
||||
Table("order_checkouts").
|
||||
Select("order_id, MAX(id) AS latest_id").
|
||||
Where("order_id IN ?", orderIDs).
|
||||
Group("order_id")
|
||||
var rows []struct {
|
||||
OrderID uint64
|
||||
ID uint64
|
||||
OwnerIncomeAmountCent int64
|
||||
}
|
||||
if err := r.db.WithContext(ctx).
|
||||
Table("(?) AS latest", latest).
|
||||
Select("oc.order_id, oc.owner_income_amount_cent").
|
||||
Joins("STRAIGHT_JOIN order_checkouts AS oc ON oc.id = latest.latest_id").
|
||||
Table("rental_orders AS o").
|
||||
Select(`o.id,
|
||||
CASE WHEN o.settlement_mode = 'platform_managed'
|
||||
THEN COALESCE(o.offline_settlement_amount_cent, 0)
|
||||
ELSE COALESCE(SUM(wl.amount_cent), 0)
|
||||
END AS owner_income_amount_cent`).
|
||||
Joins(`LEFT JOIN wallet_ledger AS wl
|
||||
ON wl.order_id = o.id
|
||||
AND wl.user_id = o.owner_id
|
||||
AND wl.direction = 'in'
|
||||
AND wl.biz_type IN ?`, []string{walletBizOwnerIncome, walletBizDepositCompensation, "arbitration_owner_income"}).
|
||||
Where("o.id IN ?", orderIDs).
|
||||
Group("o.id, o.settlement_mode, o.offline_settlement_amount_cent").
|
||||
Scan(&rows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, row := range rows {
|
||||
result[row.OrderID] = row.OwnerIncomeAmountCent
|
||||
result[row.ID] = row.OwnerIncomeAmountCent
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user