解耦接单与履约订单处理

This commit is contained in:
yml2213
2026-08-10 18:23:41 +08:00
parent a7de443cb9
commit 5885720c36
2 changed files with 51 additions and 35 deletions
@@ -118,29 +118,8 @@ export async function upsertOrderFromSource(
}),
),
)
const configuredItems = (resolvedItems as FulfillmentOrderItem[]).filter(
(item) => item.isConfigured,
)
if (configuredItems.length === 0) {
logIntegration('[order-service]', `${sourceLabel} 订单已忽略:未命中任何已配置履约商品`, {
provider: event.provider,
platform: event.platform,
shopId: event.shopId,
shopName: event.shopName,
platformOrderId: event.platformOrderId,
existingOrderId: existing?.id || null,
rawItemCount: event.items.length,
})
return {
ignored: true,
ignoreReason: 'unconfigured_items',
order: null,
orderItems: [],
tasks: [],
}
}
const resolvedFulfillmentItems = resolvedItems as FulfillmentOrderItem[]
const configuredItems = resolvedFulfillmentItems.filter((item) => item.isConfigured)
const basePayload = {
provider: event.provider,
@@ -182,7 +161,7 @@ export async function upsertOrderFromSource(
const orderItems = await replaceOrderItems(
order.id,
configuredItems.map((item) => ({
resolvedFulfillmentItems.map((item) => ({
skuCode: item.skuCode,
skuName: item.skuName,
quantity: item.quantity,
@@ -193,7 +172,11 @@ export async function upsertOrderFromSource(
})),
)
const readiness = await resolveOrderFulfillmentReadiness(order)
const configuredOrderItems = orderItems.filter(isOrderItemConfiguredForFulfillment)
const readiness =
configuredOrderItems.length > 0
? await resolveOrderFulfillmentReadiness(order)
: { allowed: true as const, voucherCount: 0, reason: '', blockReason: '' }
if (!readiness.allowed) {
logIntegration(
'[order-service]',
@@ -209,6 +192,10 @@ export async function upsertOrderFromSource(
{ level: 'warn' },
)
await syncWorkerOrdersForSourceOrder(order, orderItems, {
source: `${sourceLabel}_order_upsert`,
autoOnly: true,
})
return {
ignoreReason: readiness.blockReason || 'fulfillment_not_ready',
order,
@@ -217,7 +204,10 @@ export async function upsertOrderFromSource(
}
}
const tasks = await syncDeliveryTasksForOrder(order, orderItems)
const tasks =
configuredOrderItems.length > 0
? await syncDeliveryTasksForOrder(order, configuredOrderItems)
: []
await syncOrderFulfillmentAttachments(order, tasks, {
source: `${sourceLabel}_order_upsert`,
now,
@@ -293,6 +283,20 @@ export function mergeSourceOrderState(
}
}
function isOrderItemConfiguredForFulfillment(item: OrderItemRow): boolean {
try {
const snapshot = JSON.parse(String(item.item_snapshot_json || '{}'))
return Boolean(
snapshot &&
typeof snapshot === 'object' &&
!Array.isArray(snapshot) &&
snapshot.isConfigured === true,
)
} catch {
return false
}
}
function chooseHigherPriorityStatus(
existingValue: string,
incomingValue: string,
@@ -594,12 +594,21 @@ export function resolveMatchingProductRule(
if (!matchesOptionalText(rule.platform, order.platform)) return false
if (!matchesOptionalText(rule.shop_id, order.shop_id)) return false
const skuCode = String(item.sku_code || '')
.trim()
.toLowerCase()
const skuName = String(item.sku_name || '')
.trim()
.toLowerCase()
const snapshot = safeParseJson(item.item_snapshot_json)
const skuCodes = [item.sku_code, snapshot.externalSkuCode, snapshot.externalItemId]
.map((value) =>
String(value || '')
.trim()
.toLowerCase(),
)
.filter(Boolean)
const skuNames = [item.sku_name, snapshot.externalSkuName, snapshot.externalSkuNameNormalized]
.map((value) =>
String(value || '')
.trim()
.toLowerCase(),
)
.filter(Boolean)
const ruleSkuCode = String(rule.sku_code || '')
.trim()
.toLowerCase()
@@ -607,16 +616,19 @@ export function resolveMatchingProductRule(
.trim()
.toLowerCase()
if (ruleSkuCode && ruleSkuCode !== skuCode) {
if (ruleSkuCode && !skuCodes.includes(ruleSkuCode)) {
return false
}
if (!ruleProductName) {
return Boolean(ruleSkuCode)
}
if (rule.match_type === 'exact') {
return ruleProductName === skuName || ruleProductName === skuCode
return skuNames.includes(ruleProductName) || skuCodes.includes(ruleProductName)
}
return skuName.includes(ruleProductName) || skuCode.includes(ruleProductName)
return (
skuNames.some((value) => value.includes(ruleProductName)) ||
skuCodes.some((value) => value.includes(ruleProductName))
)
}) || null
)
}