下沉后台履约规则校验编排逻辑

This commit is contained in:
yml
2026-05-04 15:31:07 +08:00
parent d629bc96c8
commit d11879f682
3 changed files with 123 additions and 43 deletions
@@ -74,7 +74,6 @@ import {
saveKuaishouCloudFulfillmentConfig,
} from '../../order/kuaishou-cloud-fulfillment-config-service.js'
import { getFulfillmentProfileByKey } from '../../../repositories/fulfillment-profile-repo.js'
import { createHttpError } from '../../../utils/http.js'
import { syncConfiguredFulfillmentBindings } from '../../bootstrap/fulfillment-bootstrap-service.js'
import { resolveDisplayShopName } from '../admin-read-shared-helpers.js'
import {
@@ -94,9 +93,7 @@ import {
} from './cloudtentacles.js'
import { listAdminObservedProducts } from './observed-products.js'
import {
assertAdminFulfillmentBindingsInput,
buildAdminFulfillmentBindingUniqueKey,
normalizeAdminFulfillmentBindingItem,
validateAdminFulfillmentBindingConfigs,
} from './validation.js'
import {
applyOptionalStringField,
@@ -740,7 +737,11 @@ export async function updateAdminFulfillmentBindingConfigs(
payload = /** @type {AdminFulfillmentBindingConfigSaveInput} */ ({}),
) {
const bindingsInput = Array.isArray(payload.bindings) ? payload.bindings : []
const normalizedBindings = await validateAdminFulfillmentBindingConfigs(bindingsInput)
const normalizedBindings = await validateAdminFulfillmentBindingConfigs(bindingsInput, {
kuaishouEticketSource: getKuaishouEticketSourceConfig(),
resolveKuaishouEticketShopConfig,
getFulfillmentProfileByKey,
})
const saved = saveOrderFulfillmentBindingConfigs(normalizedBindings)
await syncConfiguredFulfillmentBindings()
@@ -749,41 +750,3 @@ export async function updateAdminFulfillmentBindingConfigs(
bindings: saved.map(mapAdminFulfillmentBindingConfigItem),
}
}
async function validateAdminFulfillmentBindingConfigs(bindings = []) {
assertAdminFulfillmentBindingsInput(bindings)
const seenKeys = new Set()
const kuaishouEticketSource = getKuaishouEticketSourceConfig()
const normalizedBindings = []
for (const [index, rawBinding] of bindings.entries()) {
const normalized = normalizeAdminFulfillmentBindingItem(rawBinding, {
index,
kuaishouEticketSource,
resolveKuaishouEticketShopConfig,
})
const profile = await getFulfillmentProfileByKey(normalized.profileKey)
if (!profile) {
throw createHttpError(`${index + 1} 条规则使用了不存在的履约方式: ${normalized.profileKey}`, {
statusCode: 400,
errorCode: 'admin_fulfillment_bindings_invalid_profile_key',
})
}
const uniqueKey = buildAdminFulfillmentBindingUniqueKey(normalized)
if (seenKeys.has(uniqueKey)) {
throw createHttpError(`${index + 1} 条规则与其它规则重复,请调整匹配条件或内部履约 SKU`, {
statusCode: 409,
errorCode: 'admin_fulfillment_bindings_duplicate_rule',
})
}
seenKeys.add(uniqueKey)
normalizedBindings.push(normalized)
}
return normalizedBindings
}
@@ -135,3 +135,49 @@ export function buildAdminFulfillmentBindingUniqueKey(binding) {
String(binding?.skuCode || '').trim(),
].join('::')
}
export async function validateAdminFulfillmentBindingConfigs(
bindings,
options = {},
) {
assertAdminFulfillmentBindingsInput(bindings)
const kuaishouEticketSource = /** @type {Record<string, unknown>} */ (options.kuaishouEticketSource || {})
const resolveKuaishouEticketShopConfig = /** @type {(shop: Record<string, unknown>, source: Record<string, unknown>) => Record<string, unknown> | null} */ (
options.resolveKuaishouEticketShopConfig || (() => null)
)
const getFulfillmentProfileByKey = /** @type {(profileKey: string) => Promise<unknown>} */ (
options.getFulfillmentProfileByKey || (async () => null)
)
const seenKeys = new Set()
const normalizedBindings = []
for (const [index, rawBinding] of bindings.entries()) {
const normalized = normalizeAdminFulfillmentBindingItem(rawBinding, {
index,
kuaishouEticketSource,
resolveKuaishouEticketShopConfig,
})
const profile = await getFulfillmentProfileByKey(normalized.profileKey)
if (!profile) {
throw createHttpError(`${index + 1} 条规则使用了不存在的履约方式: ${normalized.profileKey}`, {
statusCode: 400,
errorCode: 'admin_fulfillment_bindings_invalid_profile_key',
})
}
const uniqueKey = buildAdminFulfillmentBindingUniqueKey(normalized)
if (seenKeys.has(uniqueKey)) {
throw createHttpError(`${index + 1} 条规则与其它规则重复,请调整匹配条件或内部履约 SKU`, {
statusCode: 409,
errorCode: 'admin_fulfillment_bindings_duplicate_rule',
})
}
seenKeys.add(uniqueKey)
normalizedBindings.push(normalized)
}
return normalizedBindings
}
@@ -5,6 +5,7 @@ import {
assertAdminFulfillmentBindingsInput,
buildAdminFulfillmentBindingUniqueKey,
normalizeAdminFulfillmentBindingItem,
validateAdminFulfillmentBindingConfigs,
} from './validation.js'
test('assertAdminFulfillmentBindingsInput rejects non-array payloads', () => {
@@ -117,3 +118,73 @@ test('buildAdminFulfillmentBindingUniqueKey uses normalized external sku name an
'khhao::kuaishou::khhao-a::::::礼包 a::sku-1',
)
})
test('validateAdminFulfillmentBindingConfigs rejects missing fulfillment profile', async () => {
await assert.rejects(
() =>
validateAdminFulfillmentBindingConfigs(
[
{
provider: 'agiso',
platform: 'xianyu',
shopId: 'shop-1',
skuCode: 'sku-1',
profileKey: 'missing-profile',
match: {
externalSkuCode: 'ext-1',
},
},
],
{
kuaishouEticketSource: {},
resolveKuaishouEticketShopConfig() {
return null
},
async getFulfillmentProfileByKey() {
return null
},
},
),
/第 1 条规则使用了不存在的履约方式: missing-profile/,
)
})
test('validateAdminFulfillmentBindingConfigs rejects duplicate rules after normalization', async () => {
await assert.rejects(
() =>
validateAdminFulfillmentBindingConfigs(
[
{
provider: 'agiso',
platform: 'xianyu',
shopId: 'shop-1',
skuCode: 'sku-1',
profileKey: 'manual_review',
match: {
externalSkuCode: ' ext-1 ',
},
},
{
provider: 'agiso',
platform: 'xianyu',
shopId: ' shop-1 ',
skuCode: 'sku-1',
profileKey: 'manual_review',
match: {
externalSkuCode: 'ext-1',
},
},
],
{
kuaishouEticketSource: {},
resolveKuaishouEticketShopConfig() {
return null
},
async getFulfillmentProfileByKey() {
return { key: 'manual_review' }
},
},
),
/第 2 条规则与其它规则重复/,
)
})