fix(consignment): 手动匹配寄卖后刷新工单列表并展示寄卖价格

This commit is contained in:
2026-11-07 15:57:39 +08:00
parent 8920afa0e5
commit 0e9087c8bb
11 changed files with 712 additions and 75 deletions
@@ -1,3 +1,4 @@
import { query } from '../../db/client.js'
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
import {
createWorkOrderEvent,
@@ -18,12 +19,59 @@ import {
import { resolveSharingQuantity } from './admin-worker-catalog-service.js'
import { getRequiredWorkOrder } from './worker-session-context-service.js'
/**
* 拼单份额的寄卖价格:优先取匹配时固化的 allocation.unit_price_fen,
* 老数据缺失时回退库存当前售价。普通打手份额返回 null。
*/
async function loadConsignmentShareSalePrices(
shares: Array<{ id: number; consignment_inventory_id?: number | null }>,
): Promise<Map<number, number>> {
const shareIds = shares
.filter((share) => Number(share.consignment_inventory_id || 0) > 0)
.map((share) => Number(share.id))
const priceByShareId = new Map<number, number>()
if (shareIds.length === 0) return priceByShareId
const result = await query<{
share_id: number | string
unit_price_fen: number | string | null
inventory_sale_price_fen: number | string | null
}>(
`
SELECT
wos.id AS share_id,
cia.unit_price_fen,
ci.sale_price_fen AS inventory_sale_price_fen
FROM work_order_shares wos
LEFT JOIN LATERAL (
SELECT unit_price_fen
FROM consignment_inventory_allocations
WHERE work_order_share_id = wos.id
ORDER BY id DESC
LIMIT 1
) cia ON TRUE
LEFT JOIN consignment_inventories ci ON ci.id = wos.consignment_inventory_id
WHERE wos.id = ANY($1::bigint[])
`,
[shareIds],
)
for (const row of result.rows) {
const price = Number(row.unit_price_fen ?? row.inventory_sale_price_fen ?? 0)
if (price > 0) priceByShareId.set(Number(row.share_id), Math.round(price))
}
return priceByShareId
}
export async function getAdminWorkOrderSharing(workOrderId: number | string) {
const workOrder = await getRequiredWorkOrder(workOrderId)
const shares = await listWorkOrderShares(workOrder.id)
const priceByShareId = await loadConsignmentShareSalePrices(shares)
return {
order: mapWorkOrderAdmin(workOrder, shares),
shares: shares.map(mapWorkOrderShare),
shares: shares.map((share) => ({
...mapWorkOrderShare(share),
consignmentSalePriceFen: priceByShareId.get(Number(share.id)) ?? null,
})),
}
}
@@ -0,0 +1,76 @@
import assert from 'node:assert/strict'
import test from 'node:test'
import type { ConsignmentInventoryRow } from '../../repositories/worker-platform/consignment-repo.js'
import type { WorkOrderRow } from '../../repositories/worker-platform/types.js'
import { resolveConsignmentSalePriceDisplay } from './work-order-display-mappers.js'
function order(overrides: Record<string, unknown> = {}): WorkOrderRow {
return {
id: 1,
sharing_enabled: false,
material_json: {},
...overrides,
} as WorkOrderRow
}
test('寄卖价格:整单优先使用匹配时快照', () => {
const result = resolveConsignmentSalePriceDisplay(
order({
material_json: {
consignment: { salePriceFen: 27500, quantity: 1 },
},
}),
null,
)
assert.deepEqual(result, { unitPriceFen: 27500, quantity: 1, totalFen: 27500 })
})
test('寄卖价格:整单数量 > 1 时总价 = 单价 × 数量', () => {
const result = resolveConsignmentSalePriceDisplay(
order({
material_json: {
consignment: { salePriceFen: 27500, quantity: 2 },
},
}),
null,
)
assert.deepEqual(result, { unitPriceFen: 27500, quantity: 2, totalFen: 55000 })
})
test('寄卖价格:老手动寄售没有快照时回退库存当前售价', () => {
const result = resolveConsignmentSalePriceDisplay(
order({
material_json: {
consignment: { inventoryId: 739, costPriceFen: 0 },
},
}),
{ sale_price_fen: 30000 } as ConsignmentInventoryRow,
)
assert.deepEqual(result, { unitPriceFen: 30000, quantity: 1, totalFen: 30000 })
})
test('寄卖价格:拼单主列不汇总,返回 null', () => {
const result = resolveConsignmentSalePriceDisplay(
order({
sharing_enabled: true,
material_json: {
consignment: { salePriceFen: 27500, quantity: 1 },
},
}),
null,
)
assert.equal(result, null)
})
test('寄卖价格:没有任何价格时返回 null', () => {
const result = resolveConsignmentSalePriceDisplay(
order({
material_json: {
consignment: { inventoryId: 739 },
},
}),
null,
)
assert.equal(result, null)
})
@@ -244,6 +244,26 @@ function resolveWorkOrderCancelSource(cancelEventType: string | null | undefined
return eventType || '未知来源'
}
/**
* 工单列表「寄卖价格」:整单匹配优先用 material 中的匹配时快照,
* 老「手动匹配寄售」没有快照时回退库存当前售价;拼单由拼单明细逐份额展示。
*/
export function resolveConsignmentSalePriceDisplay(
workOrder: WorkOrderRow,
consignmentInventory?: ConsignmentInventoryRow | null,
): { unitPriceFen: number; quantity: number; totalFen: number } | null {
if (workOrder.sharing_enabled === true) return null
const material = safeParseJson(workOrder.material_json)
const consignment = safeParseJson(material.consignment)
const unitPriceFen = Math.max(
0,
Math.round(Number(consignment?.salePriceFen || consignmentInventory?.sale_price_fen || 0)),
)
if (unitPriceFen <= 0) return null
const quantity = Math.max(1, Math.round(Number(consignment?.quantity || 1)))
return { unitPriceFen, quantity, totalFen: unitPriceFen * quantity }
}
export function mapWorkOrderAdmin(
workOrder: WorkOrderRow,
shares?: WorkOrderShareRow[],
@@ -253,6 +273,7 @@ export function mapWorkOrderAdmin(
const pendingShareCount = Math.max(0, Number(workOrder.pending_share_count || 0))
const sharingTotalQuantity = Math.max(1, Number(workOrder.sharing_total_quantity || 1))
const acceptedShareQuantity = Math.max(0, Number(workOrder.accepted_share_quantity || 0))
const consignmentSalePrice = resolveConsignmentSalePriceDisplay(workOrder, consignmentInventory)
const hasActiveShares = activeShareQuantity > 0
const sharingFilled =
workOrder.sharing_enabled === true && activeShareQuantity >= sharingTotalQuantity
@@ -390,6 +411,10 @@ export function mapWorkOrderAdmin(
},
capabilities,
rewardAmount: Number(workOrder.reward_amount || 0),
/** 整单寄卖匹配价格(分);拼单为 null,价格在拼单明细展示 */
consignmentSalePriceFen: consignmentSalePrice?.unitPriceFen ?? null,
consignmentSaleQuantity: consignmentSalePrice?.quantity ?? null,
consignmentSaleTotalFen: consignmentSalePrice?.totalFen ?? null,
requiredDepositAmount: Number(workOrder.required_deposit_amount || 0),
/** 来源订单实付金额(分):取消部分时用于预填退款金额。 */
sourceOrderAmount: Number(workOrder.source_order_amount_fen || 0),