feat(orders): 订单读取与筛选只认渠道/状态三列

- 展示与筛选全部改读 fulfillment_channel/status,不再回退旧列
- 支持 third_party_voucher 与 archived,legacy_platform 映射为归档
- 前端类型、筛选项与标签同步
This commit is contained in:
yml2213
2026-10-31 19:52:13 +08:00
parent 65b7f4f9dc
commit 4272515956
10 changed files with 122 additions and 31 deletions
@@ -292,10 +292,16 @@ function buildOrderForFulfillmentTest(): OrderListRow {
}
}
const CHANNEL_VALUES = new Set(['work_order', 'affiliate_dash', 'third_party_voucher', 'manual'])
function buildOrderItemForFulfillmentTest(
id: number,
fulfillmentMode: string | null,
patch: Partial<OrderItemRow> = {},
): OrderItemRow {
const channel = fulfillmentMode && CHANNEL_VALUES.has(fulfillmentMode) ? fulfillmentMode : null
const status =
fulfillmentMode === 'legacy_platform' ? 'archived' : channel ? 'assigned' : 'pending'
return {
id,
order_id: 501,
@@ -303,7 +309,9 @@ function buildOrderItemForFulfillmentTest(
sku_name: `商品-${id}`,
quantity: 1,
spec_json: { itemTitle: `商品-${id}`, skuNick: `规格-${id}` },
fulfillment_mode: fulfillmentMode,
fulfillment_channel: channel,
fulfillment_status: status,
...patch,
}
}
@@ -321,7 +329,7 @@ test('人工单即使有已核销快照也仍然判为 manual,核销码单独
assert.equal(mapped.canClaimH5, false)
})
test('自动发货与历史平台按 fulfillment_mode 区分,不再按 provider 猜', () => {
test('自动发货与历史归档按渠道/状态区分,不再按 provider 猜', () => {
const affiliate = resolveOrderFulfillmentSummary({
items: [buildOrderItemForFulfillmentTest(1, 'affiliate_dash')],
})
@@ -331,7 +339,7 @@ test('自动发货与历史平台按 fulfillment_mode 区分,不再按 provide
assert.equal(affiliate.fulfillmentMode, 'affiliate_dash')
assert.equal(affiliate.canClaimH5, true)
assert.equal(legacy.fulfillmentMode, 'legacy_platform')
assert.equal(legacy.fulfillmentMode, 'archived')
assert.equal(legacy.canClaimH5, false)
})
@@ -358,3 +366,35 @@ test('核销码状态汇总:无、单一、混合', () => {
{ hasVoucher: true, voucherState: 'mixed' },
)
})
test('v2 读取口径:归档状态优先于旧 fulfillment_mode', () => {
const summary = resolveOrderFulfillmentSummary({
items: [buildOrderItemForFulfillmentTest(1, 'work_order', { fulfillment_status: 'archived' })],
})
assert.equal(summary.fulfillmentMode, 'archived')
})
test('v2 读取口径:渠道列优先于旧 fulfillment_mode', () => {
const summary = resolveOrderFulfillmentSummary({
items: [
buildOrderItemForFulfillmentTest(1, 'manual', {
fulfillment_status: 'assigned',
fulfillment_channel: 'third_party_voucher',
}),
],
})
assert.equal(summary.fulfillmentMode, 'third_party_voucher')
})
test('v2 读取口径:状态 pending 且无渠道时判为待分类', () => {
const summary = resolveOrderFulfillmentSummary({
items: [
buildOrderItemForFulfillmentTest(1, 'manual', {
fulfillment_status: 'pending',
fulfillment_channel: null,
}),
],
})
assert.equal(summary.fulfillmentMode, 'pending')
assert.equal(summary.pendingItemCount, 1)
})
@@ -56,7 +56,7 @@ export function mapAdminOrderListItem(
skuNick: itSkuNick,
matchSku: itMatchSku,
quantity: Math.max(1, Number(orderItem.quantity || 1)),
fulfillmentMode: normalizeOrderItemFulfillmentMode(orderItem.fulfillment_mode),
fulfillmentMode: resolveOrderItemFulfillmentMode(orderItem),
}
})
resolvedItemTitle = itemsList[0]?.itemTitle || ''
@@ -141,9 +141,11 @@ export function mapAdminOrderListItem(
const ORDER_ITEM_FULFILLMENT_MODES = new Set<AdminOrderItemFulfillmentMode>([
'work_order',
'affiliate_dash',
'third_party_voucher',
'legacy_platform',
'manual',
'pending',
'archived',
])
export function normalizeOrderItemFulfillmentMode(value: unknown): AdminOrderItemFulfillmentMode {
@@ -153,6 +155,23 @@ export function normalizeOrderItemFulfillmentMode(value: unknown): AdminOrderIte
return ORDER_ITEM_FULFILLMENT_MODES.has(mode) ? mode : 'pending'
}
/**
* v2 读取口径:只认渠道/状态三列,不再回退旧 fulfillment_mode。
*
* archived → archived
* channel → 该渠道
* 其余 → pending
*/
export function resolveOrderItemFulfillmentMode(
item: Pick<OrderItemRow, 'fulfillment_status' | 'fulfillment_channel'> | null | undefined,
): AdminOrderItemFulfillmentMode {
if (!item) return 'pending'
if (String(item.fulfillment_status || '').trim() === 'archived') return 'archived'
const channel = String(item.fulfillment_channel || '').trim()
if (channel) return normalizeOrderItemFulfillmentMode(channel)
return 'pending'
}
export function resolveVoucherSummary(vouchers: KuaishouIndustryVoucherRow[] = []): {
hasVoucher: boolean
voucherState: AdminVoucherState
@@ -182,7 +201,7 @@ export function resolveVoucherSummary(vouchers: KuaishouIndustryVoucherRow[] = [
}
/**
* 订单级履约摘要:只读 order_items.fulfillment_mode,不再按 provider 或核销码推断。
* 订单级履约摘要:只读 order_items.fulfillment_channel / fulfillment_status。
* 多商品订单出现不同模式时显示 mixed;尚未判定的订单项单独计数。
*/
export function resolveOrderFulfillmentSummary({
@@ -205,9 +224,7 @@ export function resolveOrderFulfillmentSummary({
canClaimH5: boolean
} {
const normalizedItems = Array.isArray(items) ? items : []
const itemModes = normalizedItems.map((item) =>
normalizeOrderItemFulfillmentMode(item.fulfillment_mode),
)
const itemModes = normalizedItems.map((item) => resolveOrderItemFulfillmentMode(item))
const knownModes = Array.from(
new Set(
itemModes.filter((mode): mode is Exclude<typeof mode, 'pending'> => mode !== 'pending'),
@@ -232,7 +249,7 @@ export function resolveOrderFulfillmentSummary({
task.executor_key === 'kuaishou_ct_assisted' || task.executor_key === 'kuaishou_feifei',
)
) {
fulfillmentMode = 'legacy_platform'
fulfillmentMode = 'archived'
} else {
fulfillmentMode = 'pending'
}
@@ -67,6 +67,7 @@ import {
mapAdminOrderListItem,
normalizeOrderItemFulfillmentMode,
resolveOrderFulfillmentSummary,
resolveOrderItemFulfillmentMode,
summarizeOrderItems,
} from './admin-order-read-helpers.js'
import {
@@ -149,10 +150,12 @@ export async function getAdminOrders(
const ADMIN_ORDER_FULFILLMENT_MODES = new Set([
'work_order',
'affiliate_dash',
'legacy_platform',
'third_party_voucher',
'manual',
'legacy_platform',
'mixed',
'pending',
'archived',
])
function normalizeOrderFulfillmentModeFilter(value: unknown): string {
@@ -278,7 +281,7 @@ export async function getAdminOrderDetail(
revenueFen,
refundedFen,
refundableFen: Math.max(0, revenueFen - refundedFen),
fulfillmentMode: normalizeOrderItemFulfillmentMode(item.fulfillment_mode),
fulfillmentMode: resolveOrderItemFulfillmentMode(item),
deliveryMode: resolveOrderItemDeliveryMode(tasks, item.id),
spec:
item.spec_json && typeof item.spec_json === 'object'