fix(consignment): 手动匹配寄卖后刷新工单列表并展示寄卖价格
This commit is contained in:
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user