后端迁移商品匹配服务
This commit is contained in:
+66
-49
@@ -1,37 +1,65 @@
|
||||
import { resolveFulfillmentBinding } from '../../repositories/fulfillment-profile-repo.js'
|
||||
import { resolveProductMatchRule } from '../../repositories/product-match-rule-repo.js'
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* itemId?: string
|
||||
* externalItemId?: string
|
||||
* skuCode?: string
|
||||
* skuName?: string
|
||||
* externalSkuCode?: string
|
||||
* externalSkuName?: string
|
||||
* quantity?: number
|
||||
* spec?: Record<string, unknown>
|
||||
* snapshot?: Record<string, unknown>
|
||||
* [key: string]: unknown
|
||||
* }} FulfillmentItem
|
||||
*/
|
||||
export type FulfillmentItem = {
|
||||
itemId?: string
|
||||
externalItemId?: string
|
||||
skuCode?: string
|
||||
skuName?: string
|
||||
externalSkuCode?: string
|
||||
externalSkuName?: string
|
||||
quantity?: number
|
||||
spec?: Record<string, unknown>
|
||||
snapshot?: Record<string, unknown>
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
type ResolveOrderItemForFulfillmentInput = {
|
||||
provider?: string
|
||||
platform?: string
|
||||
shopId?: string
|
||||
shopIdAliases?: string[]
|
||||
item?: FulfillmentItem
|
||||
}
|
||||
|
||||
type HasConfiguredOrderItemsInput = Omit<ResolveOrderItemForFulfillmentInput, 'item'> & {
|
||||
items?: FulfillmentItem[]
|
||||
}
|
||||
|
||||
type FulfillmentItemCandidate = {
|
||||
externalItemId: string
|
||||
externalSkuCode: string
|
||||
externalSkuName: string
|
||||
externalSkuNameNormalized: string
|
||||
matchedRule: Awaited<ReturnType<typeof resolveProductMatchRule>>
|
||||
resolvedSkuCode: string
|
||||
binding: Awaited<ReturnType<typeof resolveFulfillmentBinding>>
|
||||
isConfigured: boolean
|
||||
}
|
||||
|
||||
export type ResolvedFulfillmentItem = FulfillmentItem & {
|
||||
itemId: string
|
||||
externalItemId: string
|
||||
externalSkuCode: string
|
||||
externalSkuName: string
|
||||
skuCode: string
|
||||
skuName: string
|
||||
snapshot: Record<string, unknown>
|
||||
isConfigured: boolean
|
||||
}
|
||||
|
||||
type ShopIdCandidatesInput = {
|
||||
shopId?: string
|
||||
shopIdAliases?: string[]
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* provider?: string
|
||||
* platform?: string
|
||||
* shopId?: string
|
||||
* shopIdAliases?: string[]
|
||||
* item?: FulfillmentItem
|
||||
* }} params
|
||||
*/
|
||||
export async function resolveOrderItemForFulfillment({
|
||||
provider = '',
|
||||
platform = '',
|
||||
shopId = '',
|
||||
shopIdAliases = [],
|
||||
item = /** @type {FulfillmentItem} */ ({}),
|
||||
}) {
|
||||
item = {},
|
||||
}: ResolveOrderItemForFulfillmentInput): Promise<ResolvedFulfillmentItem> {
|
||||
const candidate = await resolveConfiguredItemCandidate({
|
||||
provider,
|
||||
platform,
|
||||
@@ -87,22 +115,13 @@ export async function resolveOrderItemForFulfillment({
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* provider?: string
|
||||
* platform?: string
|
||||
* shopId?: string
|
||||
* shopIdAliases?: string[]
|
||||
* items?: FulfillmentItem[]
|
||||
* }} params
|
||||
*/
|
||||
export async function hasConfiguredOrderItems({
|
||||
provider = '',
|
||||
platform = '',
|
||||
shopId = '',
|
||||
shopIdAliases = [],
|
||||
items = [],
|
||||
}) {
|
||||
}: HasConfiguredOrderItemsInput): Promise<boolean> {
|
||||
const candidates = await Promise.all(
|
||||
(Array.isArray(items) ? items : []).map((item) => resolveConfiguredItemCandidate({
|
||||
provider,
|
||||
@@ -116,7 +135,7 @@ export async function hasConfiguredOrderItems({
|
||||
return candidates.some((item) => item.isConfigured)
|
||||
}
|
||||
|
||||
export function normalizeProductName(value) {
|
||||
export function normalizeProductName(value: unknown): string {
|
||||
return String(value || '')
|
||||
.toLowerCase()
|
||||
.replace(/[【】\[\]()()]/g, ' ')
|
||||
@@ -126,7 +145,7 @@ export function normalizeProductName(value) {
|
||||
.trim()
|
||||
}
|
||||
|
||||
function pickFirstNonEmpty(values) {
|
||||
function pickFirstNonEmpty(values: unknown[]): string {
|
||||
for (const value of values) {
|
||||
const normalized = String(value || '').trim()
|
||||
if (normalized) {
|
||||
@@ -142,8 +161,8 @@ async function resolveConfiguredItemCandidate({
|
||||
platform = '',
|
||||
shopId = '',
|
||||
shopIdAliases = [],
|
||||
item = /** @type {FulfillmentItem} */ ({}),
|
||||
}) {
|
||||
item = {},
|
||||
}: ResolveOrderItemForFulfillmentInput): Promise<FulfillmentItemCandidate> {
|
||||
const externalItemId = pickFirstNonEmpty([
|
||||
item.externalItemId,
|
||||
item.itemId,
|
||||
@@ -213,7 +232,10 @@ async function resolveConfiguredItemCandidate({
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveShopIdCandidates({ shopId = '', shopIdAliases = [] } = {}) {
|
||||
export function resolveShopIdCandidates({
|
||||
shopId = '',
|
||||
shopIdAliases = [],
|
||||
}: ShopIdCandidatesInput = {}): string[] {
|
||||
const candidates = [...new Set([
|
||||
String(shopId || '').trim(),
|
||||
...(Array.isArray(shopIdAliases) ? shopIdAliases : []).map((item) => String(item || '').trim()),
|
||||
@@ -222,7 +244,7 @@ export function resolveShopIdCandidates({ shopId = '', shopIdAliases = [] } = {}
|
||||
return candidates.length > 0 ? candidates : ['']
|
||||
}
|
||||
|
||||
function readConfigValue(rawValue, key) {
|
||||
function readConfigValue(rawValue: unknown, key: string): string {
|
||||
if (!rawValue) {
|
||||
return ''
|
||||
}
|
||||
@@ -232,11 +254,10 @@ function readConfigValue(rawValue, key) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const config = /** @type {Record<string, unknown>} */ (parsed)
|
||||
return String(config[key] || '').trim()
|
||||
return String(parsed[key] || '').trim()
|
||||
}
|
||||
|
||||
function safeParseJson(rawValue) {
|
||||
function safeParseJson(rawValue: unknown): unknown {
|
||||
try {
|
||||
return JSON.parse(String(rawValue || '{}'))
|
||||
} catch {
|
||||
@@ -244,10 +265,6 @@ function safeParseJson(rawValue) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {unknown} value
|
||||
* @returns {value is Record<string, unknown>}
|
||||
*/
|
||||
function isPlainObject(value) {
|
||||
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
||||
return Object.prototype.toString.call(value) === '[object Object]'
|
||||
}
|
||||
Reference in New Issue
Block a user