// @ts-check import { createHttpError } from '../../utils/http.js' import { normalizeProductName } from '../order/product-match-service.js' import { isPlainObject } from './admin-platform-config-context.js' import { resolveFulfillmentBindingMatchShopId } from './admin-platform-config-domain.js' export function assertAdminFulfillmentBindingsInput(bindings) { if (Array.isArray(bindings)) { return } throw createHttpError('履约配置格式不正确', { statusCode: 400, errorCode: 'admin_fulfillment_bindings_invalid_payload', }) } export function normalizeAdminFulfillmentBindingItem( rawBinding, options = {}, ) { const index = Number(options.index || 0) const kuaishouEticketSource = /** @type {Record} */ (options.kuaishouEticketSource || {}) const resolveKuaishouEticketShopConfig = /** @type {(shop: Record, source: Record) => Record | null} */ ( options.resolveKuaishouEticketShopConfig || (() => null) ) if (!isPlainObject(rawBinding)) { throw createHttpError(`第 ${index + 1} 条规则格式不正确`, { statusCode: 400, errorCode: 'admin_fulfillment_bindings_invalid_item', }) } const provider = String(rawBinding.provider || 'agiso').trim() || 'agiso' const platform = String(rawBinding.platform || '').trim() let shopId = String(rawBinding.shopId || '').trim() let shopName = String(rawBinding.shopName || '').trim() const khhaoShopId = String(rawBinding.khhaoShopId || '').trim() const skuCode = String(rawBinding.skuCode || '').trim() const skuName = String(rawBinding.skuName || '').trim() const profileKey = String(rawBinding.profileKey || '').trim() || 'manual_review' const match = isPlainObject(rawBinding.match) ? rawBinding.match : {} const externalItemId = String(match.externalItemId || '').trim() const externalSkuCode = String(match.externalSkuCode || '').trim() const externalSkuName = String(match.externalSkuName || '').trim() const config = isPlainObject(rawBinding.config) ? { ...rawBinding.config } : {} if (provider === 'khhao' && platform === 'kuaishou') { if (!khhaoShopId) { throw createHttpError(`第 ${index + 1} 条快手规则缺少 khhao 店铺 ID`, { statusCode: 400, errorCode: 'admin_fulfillment_bindings_missing_khhao_shop_id', }) } const matchedShop = resolveKuaishouEticketShopConfig( { shopId, shopName, }, kuaishouEticketSource, ) const matchedShopId = String(matchedShop?.shopId || '').trim() const matchedShopName = String(matchedShop?.kshopName || '').trim() if (!matchedShopId || !matchedShopName) { throw createHttpError( `第 ${index + 1} 条快手规则的店铺未匹配到已配置的快手官方店铺,请先到“平台配置”补齐 Cookie 后再选择`, { statusCode: 400, errorCode: 'admin_fulfillment_bindings_kuaishou_shop_not_configured', }, ) } shopId = matchedShopId shopName = matchedShopName config.kuaishouShop = { ...(isPlainObject(config.kuaishouShop) ? config.kuaishouShop : {}), shopId, shopName, khhaoShopId, } } if (!skuCode) { throw createHttpError(`第 ${index + 1} 条规则缺少内部履约 SKU`, { statusCode: 400, errorCode: 'admin_fulfillment_bindings_missing_sku_code', }) } if (!externalItemId && !externalSkuCode && !externalSkuName) { throw createHttpError(`第 ${index + 1} 条规则至少需要一种外部匹配条件`, { statusCode: 400, errorCode: 'admin_fulfillment_bindings_missing_match_condition', }) } return { provider, platform, shopId, shopName, khhaoShopId, skuCode, skuName, profileKey, enabled: rawBinding.enabled !== false, priority: rawBinding.priority, config, match: { externalSkuCode, externalItemId, externalSkuName, config: isPlainObject(match.config) ? match.config : {}, }, } } export function buildAdminFulfillmentBindingUniqueKey(binding) { return [ String(binding?.provider || '').trim(), String(binding?.platform || '').trim(), resolveFulfillmentBindingMatchShopId({ provider: binding?.provider, platform: binding?.platform, shopId: binding?.shopId, khhaoShopId: binding?.khhaoShopId, }), String(binding?.match?.externalItemId || '').trim(), String(binding?.match?.externalSkuCode || '').trim(), normalizeProductName(String(binding?.match?.externalSkuName || '').trim()), String(binding?.skuCode || '').trim(), ].join('::') }