import { getFulfillmentProfileByKey, listFulfillmentProfileRequirements, replaceFulfillmentProfileRequirements, upsertFulfillmentProfile, upsertSkuFulfillmentBinding, } from '../../repositories/fulfillment-profile-repo.js' import { upsertProductMatchRule } from '../../repositories/product-match-rule-repo.js' import { normalizeProductName } from '../order/product-match-service.js' import { query } from '../../db/client.js' import { getOrderFulfillmentBindingConfigs } from '../order/fulfillment-binding-config-service.js' import { getKuaishouCloudFulfillmentConfig, mapKuaishouCloudFulfillmentItemsToBindings, } from '../order/kuaishou-cloud-fulfillment-config-service.js' import { nowIso } from '../../utils/time.js' const CORE_PROFILES = [ { profileKey: 'manual_review', name: '人工发货', executorKey: 'manual_dispatch', requiresClaim: false, autoDispatch: false, inventoryStrategy: 'static_pool', requirements: [], }, { profileKey: 'tencent_claim_redeem', name: '腾讯领取兑换', executorKey: 'tencent_claim_redeem', requiresClaim: true, autoDispatch: false, inventoryStrategy: 'static_pool', requirements: [ { roleKey: 'primary_code', credentialType: 'tencent_code', quantityPerUnit: 1, isRequired: true, }, ], }, { profileKey: 'tencent_claim_assisted', name: '腾讯领取兑换(半自动+人工)', executorKey: 'tencent_claim_assisted', requiresClaim: true, autoDispatch: false, inventoryStrategy: 'static_pool', requirements: [ { roleKey: 'primary_code', credentialType: 'tencent_code', quantityPerUnit: 1, isRequired: true, }, ], }, { profileKey: 'kuaishou_ct_assisted', name: '快手 cloud 履约', executorKey: 'kuaishou_ct_assisted', requiresClaim: false, autoDispatch: false, inventoryStrategy: 'external_platform', requirements: [], }, ] export async function ensureFulfillmentCatalogBootstrapped() { const profileMap = await ensureCoreProfiles() await syncConfiguredFulfillmentBindings(profileMap) } async function ensureCoreProfiles() { const timestamp = nowIso() const profileMap = {} for (const profile of CORE_PROFILES) { const saved = await upsertFulfillmentProfile({ profileKey: profile.profileKey, name: profile.name, executorKey: profile.executorKey, requiresClaim: profile.requiresClaim, autoDispatch: profile.autoDispatch, inventoryStrategy: profile.inventoryStrategy, configJson: '{}', createdAt: timestamp, updatedAt: timestamp, }) if (!saved) { continue } profileMap[profile.profileKey] = saved const currentRequirements = await listFulfillmentProfileRequirements(saved.id) if (currentRequirements.length !== profile.requirements.length) { await replaceFulfillmentProfileRequirements(saved.id, profile.requirements, timestamp) } } return profileMap } export async function syncConfiguredFulfillmentBindings(profileMap = {}) { const timestamp = nowIso() const bindingsToApply = [ ...getOrderFulfillmentBindingConfigs(), ...mapKuaishouCloudFulfillmentItemsToBindings(getKuaishouCloudFulfillmentConfig()), ] await query('DELETE FROM product_match_rules') await query('DELETE FROM sku_fulfillment_bindings') for (const binding of bindingsToApply) { const profile = profileMap[binding.profileKey] || await getFulfillmentProfileByKey(binding.profileKey) if (!profile) { continue } await upsertSkuFulfillmentBinding({ skuCode: binding.skuCode, provider: binding.provider, platform: binding.platform, shopId: binding.shopId, profileId: profile.id, enabled: binding.enabled, priority: binding.priority, configJson: JSON.stringify(binding.config || {}), createdAt: timestamp, updatedAt: timestamp, }) const match = binding.match || {} const externalSkuName = String(match.externalSkuName || '').trim() const externalItemId = String(match.externalItemId || '').trim() const externalSkuCode = String(match.externalSkuCode || '').trim() if (!externalSkuName && !externalItemId && !externalSkuCode) { continue } await upsertProductMatchRule({ provider: binding.provider, platform: binding.platform, shopId: binding.shopId, externalItemId, externalSkuCode, externalSkuName, externalSkuNameNormalized: normalizeProductName(externalSkuName), resolvedSkuCode: binding.skuCode, enabled: binding.enabled, priority: binding.priority, configJson: JSON.stringify(match.config || {}), createdAt: timestamp, updatedAt: timestamp, }) } }