fix(pdd): 停止旧单刷匹配日志,并修复订单列表商品显示为 0
同步时已有工单/匹配结果未变不再写日志;列表按 Number(order_id) 挂 items,并补齐 PDD goods_name 回退与嵌套商品解析。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -99,3 +99,31 @@ test('mapPddOrderToSourceEvent prioritizes out_sku_sn as primary matching field'
|
||||
assert.equal((item.spec as Record<string, unknown>).goodsName, '和平精英苏尔南手枪皮肤')
|
||||
assert.equal((item.spec as Record<string, unknown>).spec, '暗潮1钻')
|
||||
})
|
||||
|
||||
test('mapPddOrderToSourceEvent reads nested order_goods when top-level goods fields missing', () => {
|
||||
const nestedOnly: PddRawOrderItem = {
|
||||
order_sn: '260915-111',
|
||||
order_status: 2,
|
||||
order_status_str: '已发货',
|
||||
order_amount: 9900,
|
||||
goods_id: '',
|
||||
goods_name: '',
|
||||
order_goods: [
|
||||
{
|
||||
goods_id: 555,
|
||||
goods_name: '套装-浪漫天命',
|
||||
spec: '默认',
|
||||
goods_number: 2,
|
||||
out_sku_sn: 'suit_romantic',
|
||||
},
|
||||
],
|
||||
} as PddRawOrderItem
|
||||
|
||||
const event = mapPddOrderToSourceEvent(nestedOnly, { shopId: 's1', shopName: '店1' })
|
||||
const item = event.items[0]!
|
||||
assert.equal(item.skuCode, 'suit_romantic')
|
||||
assert.equal(item.skuName, 'suit_romantic')
|
||||
assert.equal(item.quantity, 2)
|
||||
assert.equal((item.spec as Record<string, unknown>).goodsName, '套装-浪漫天命')
|
||||
assert.equal((item.spec as Record<string, unknown>).goodsId, '555')
|
||||
})
|
||||
|
||||
@@ -38,6 +38,13 @@ export interface MapPddOrderOptions {
|
||||
shopName: string
|
||||
}
|
||||
|
||||
type PddGoodsLine = {
|
||||
goodsId: string
|
||||
goodsName: string
|
||||
spec: string
|
||||
quantity: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract external SKU code (out_sku_sn) from raw PDD order payload.
|
||||
* 从拼多多原始报文中提取外部商家编码 out_sku_sn(作为派发工单及商品匹配的关键字段)。
|
||||
@@ -53,28 +60,71 @@ export function extractPddOutSkuSn(rawOrder: PddRawOrderItem): string {
|
||||
return direct.trim()
|
||||
}
|
||||
|
||||
for (const entry of listPddNestedGoodsEntries(rawOrder)) {
|
||||
const nestedSn =
|
||||
entry?.out_sku_sn ||
|
||||
entry?.outer_id ||
|
||||
entry?.out_goods_sn ||
|
||||
entry?.outSkuSn ||
|
||||
entry?.outerId
|
||||
if (typeof nestedSn === 'string' && nestedSn.trim()) {
|
||||
return nestedSn.trim()
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 从顶层或嵌套商品行提取 goods_id / goods_name / spec / quantity。
|
||||
* 部分 MMS 报文商品字段只在 order_goods / item_list 内。
|
||||
*/
|
||||
export function extractPddGoodsLine(rawOrder: PddRawOrderItem): PddGoodsLine {
|
||||
const top = {
|
||||
goodsId: String(rawOrder.goods_id || '').trim(),
|
||||
goodsName: String(rawOrder.goods_name || '').trim(),
|
||||
spec: String(rawOrder.spec || '').trim(),
|
||||
quantity: Math.max(1, Number(rawOrder.goods_number || 1) || 1),
|
||||
}
|
||||
if (top.goodsId || top.goodsName || top.spec) {
|
||||
return top
|
||||
}
|
||||
|
||||
for (const entry of listPddNestedGoodsEntries(rawOrder)) {
|
||||
const goodsId = String(entry?.goods_id || entry?.goodsId || entry?.sku_id || '').trim()
|
||||
const goodsName = String(entry?.goods_name || entry?.goodsName || entry?.name || '').trim()
|
||||
const spec = String(entry?.spec || entry?.sku_spec || entry?.skuSpec || '').trim()
|
||||
const quantity = Math.max(
|
||||
1,
|
||||
Number(entry?.goods_number || entry?.goods_count || entry?.quantity || 1) || 1,
|
||||
)
|
||||
if (goodsId || goodsName || spec) {
|
||||
return { goodsId, goodsName, spec, quantity }
|
||||
}
|
||||
}
|
||||
|
||||
return top
|
||||
}
|
||||
|
||||
function listPddNestedGoodsEntries(rawOrder: PddRawOrderItem): Array<Record<string, any>> {
|
||||
const nestedCandidates = [
|
||||
(rawOrder as any).order_items,
|
||||
(rawOrder as any).order_goods,
|
||||
(rawOrder as any).items,
|
||||
(rawOrder as any).order_item_list,
|
||||
(rawOrder as any).item_list,
|
||||
]
|
||||
const entries: Array<Record<string, any>> = []
|
||||
for (const list of nestedCandidates) {
|
||||
if (Array.isArray(list)) {
|
||||
for (const entry of list) {
|
||||
const nestedSn =
|
||||
entry?.out_sku_sn ||
|
||||
entry?.outer_id ||
|
||||
entry?.out_goods_sn ||
|
||||
entry?.outSkuSn ||
|
||||
entry?.outerId
|
||||
if (typeof nestedSn === 'string' && nestedSn.trim()) {
|
||||
return nestedSn.trim()
|
||||
}
|
||||
if (!Array.isArray(list)) {
|
||||
continue
|
||||
}
|
||||
for (const entry of list) {
|
||||
if (entry && typeof entry === 'object' && !Array.isArray(entry)) {
|
||||
entries.push(entry as Record<string, any>)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ''
|
||||
return entries
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,11 +164,12 @@ export function mapPddOrderToSourceEvent(
|
||||
const timestampSec = rawOrder.confirm_time || rawOrder.order_time || Math.floor(Date.now() / 1000)
|
||||
const paidAt = new Date(timestampSec * 1000).toISOString()
|
||||
|
||||
// Build items array / 构建订单商品明细
|
||||
const goodsIdStr = String(rawOrder.goods_id || '')
|
||||
const goodsName = String(rawOrder.goods_name || '').trim()
|
||||
const spec = String(rawOrder.spec || '').trim()
|
||||
const quantity = Math.max(1, Number(rawOrder.goods_number || 1))
|
||||
// Build items array / 构建订单商品明细(顶层缺失时回退嵌套商品行)
|
||||
const goodsLine = extractPddGoodsLine(rawOrder)
|
||||
const goodsIdStr = goodsLine.goodsId
|
||||
const goodsName = goodsLine.goodsName
|
||||
const spec = goodsLine.spec
|
||||
const quantity = goodsLine.quantity
|
||||
|
||||
// 提取商家外部编码 out_sku_sn(如 "安卓血宴3钻"),作为核心匹配字段
|
||||
const outSkuSn = extractPddOutSkuSn(rawOrder)
|
||||
|
||||
Reference in New Issue
Block a user