fix(pdd): 长 SKU 精确名优先于短模板 contains,消除父子模板冲突
out_sku_sn「安卓血宴5钻带2璀璨」会被短名「安卓血宴5钻」contains 同分命中;精确相等提分,contains 按名称长度区分优先级。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -317,20 +317,30 @@ function scoreWorkProductRule(order: OrderRow, item: OrderItemRow, rule: WorkPro
|
||||
const ruleSkuCode = normalizeMatchId(rule.sku_code)
|
||||
const ruleProductName = normalizeMatchText(rule.product_name)
|
||||
const skuCodeMatched = Boolean(ruleSkuCode && skuCodes.includes(ruleSkuCode))
|
||||
const productNameMatched = ruleProductName
|
||||
? rule.match_type === 'exact'
|
||||
? skuNames.includes(ruleProductName) || skuCodes.includes(ruleProductName)
|
||||
: skuNames.some((value) => value.includes(ruleProductName)) ||
|
||||
skuCodes.some((value) => value.includes(ruleProductName))
|
||||
: false
|
||||
const exactProductName = Boolean(
|
||||
ruleProductName && (skuNames.includes(ruleProductName) || skuCodes.includes(ruleProductName)),
|
||||
)
|
||||
const containsProductName = Boolean(
|
||||
ruleProductName &&
|
||||
!exactProductName &&
|
||||
rule.match_type !== 'exact' &&
|
||||
(skuNames.some((value) => value.includes(ruleProductName)) ||
|
||||
skuCodes.some((value) => value.includes(ruleProductName))),
|
||||
)
|
||||
|
||||
// sku_code 与 product_name 任一命中即可(不再要求两者同时成立,避免误填的 sku_code 挡住 out_sku_sn)
|
||||
if (!skuCodeMatched && !productNameMatched) return null
|
||||
if (skuCodeMatched && productNameMatched) {
|
||||
return { rule, score: rule.match_type === 'exact' ? 300 : 220 }
|
||||
// sku_code 与 product_name 任一命中即可
|
||||
if (!skuCodeMatched && !exactProductName && !containsProductName) return null
|
||||
|
||||
// 同分冲突常见场景:短名「安卓血宴5钻」contains 命中长编码「安卓血宴5钻带2璀璨」
|
||||
// 精确相等优先;contains 则更长的模板名更具体、分更高
|
||||
let score = 100
|
||||
if (exactProductName) {
|
||||
score = 250
|
||||
} else if (containsProductName) {
|
||||
score = 100 + Math.min(80, ruleProductName.length)
|
||||
}
|
||||
if (skuCodeMatched) return { rule, score: 120 }
|
||||
return { rule, score: rule.match_type === 'exact' ? 150 : 100 }
|
||||
if (skuCodeMatched) score += exactProductName || containsProductName ? 40 : 120
|
||||
return { rule, score }
|
||||
}
|
||||
|
||||
/** 拼多多常复用原快手模板;来源/平台残留 91kaquan、kuaishou 时不拦截 out_sku_sn 模板名匹配。 */
|
||||
|
||||
@@ -713,6 +713,36 @@ test('拼多多订单在 sku_code 误填时仍可按 product_name/out_sku_sn 命
|
||||
assert.equal(decision.rule?.id, rule.id)
|
||||
})
|
||||
|
||||
test('长 out_sku_sn 在短模板名 contains 时可优先命中精确相等的长模板,避免冲突', () => {
|
||||
const longRule = buildProductRule({
|
||||
id: 101,
|
||||
rule_key: 'rule-79bf8b3006ea',
|
||||
product_name: '安卓血宴5钻带2璀璨',
|
||||
match_type: 'contains',
|
||||
})
|
||||
const shortRule = buildProductRule({
|
||||
id: 102,
|
||||
rule_key: 'rule-f93c368547e1',
|
||||
product_name: '安卓血宴5钻',
|
||||
match_type: 'contains',
|
||||
})
|
||||
const order = { ...buildOrderRow(), provider: 'pdd', platform: 'pdd' }
|
||||
const item = {
|
||||
...buildOrderItemRow(),
|
||||
sku_code: '安卓血宴5钻带2璀璨',
|
||||
sku_name: '安卓血宴5钻带2璀璨',
|
||||
item_snapshot_json: {
|
||||
out_sku_sn: '安卓血宴5钻带2璀璨',
|
||||
spec: '安卓区(qv互通),苏尔南-血宴5钻带2璀璨',
|
||||
},
|
||||
}
|
||||
|
||||
const decision = resolveMatchingProductRuleDecision(order, item, [longRule, shortRule], [])
|
||||
assert.equal(decision.reason, 'matched')
|
||||
assert.equal(decision.rule?.rule_key, 'rule-79bf8b3006ea')
|
||||
assert.ok((decision.score || 0) > 100)
|
||||
})
|
||||
|
||||
test('拼多多订单缺少 out_sku_sn 且 spec 不含规则名时不命中', () => {
|
||||
const rule = buildProductRule({
|
||||
provider: 'pdd',
|
||||
|
||||
Reference in New Issue
Block a user