移除了 khhao 平台相关
This commit is contained in:
@@ -50,7 +50,6 @@ export function mapAdminFulfillmentBindingConfigItem(item) {
|
||||
platform: String(item?.platform || '').trim(),
|
||||
shopId: String(item?.shopId || '').trim(),
|
||||
shopName: String(item?.shopName || '').trim(),
|
||||
khhaoShopId: String(item?.khhaoShopId || '').trim(),
|
||||
skuCode: String(item?.skuCode || '').trim(),
|
||||
skuName: String(item?.skuName || '').trim(),
|
||||
profileKey: String(item?.profileKey || '').trim(),
|
||||
@@ -66,19 +65,6 @@ export function mapAdminFulfillmentBindingConfigItem(item) {
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveFulfillmentBindingMatchShopId({
|
||||
provider = '',
|
||||
platform = '',
|
||||
shopId = '',
|
||||
khhaoShopId = '',
|
||||
} = {}) {
|
||||
if (String(provider || '').trim() === 'khhao' && String(platform || '').trim() === 'kuaishou') {
|
||||
return String(khhaoShopId || shopId || '').trim()
|
||||
}
|
||||
|
||||
return String(shopId || '').trim()
|
||||
}
|
||||
|
||||
export function matchesObservedProduct(binding, observed) {
|
||||
const provider = String(binding?.provider || '').trim()
|
||||
const platform = String(binding?.platform || '').trim()
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
mapAdminFulfillmentBindingConfigItem,
|
||||
mapAdminObservedProductItem,
|
||||
matchesObservedProduct,
|
||||
resolveFulfillmentBindingMatchShopId,
|
||||
} from './domain.js'
|
||||
|
||||
test('mapAdminAgisoMessagingDefaults normalizes escaped newlines', () => {
|
||||
@@ -78,7 +77,6 @@ test('mapAdminFulfillmentBindingConfigItem normalizes binding shape', () => {
|
||||
platform: 'xianyu',
|
||||
shopId: 'shop-1',
|
||||
shopName: '',
|
||||
khhaoShopId: '',
|
||||
skuCode: 'sku-1',
|
||||
skuName: '',
|
||||
profileKey: '',
|
||||
@@ -95,28 +93,6 @@ test('mapAdminFulfillmentBindingConfigItem normalizes binding shape', () => {
|
||||
)
|
||||
})
|
||||
|
||||
test('resolveFulfillmentBindingMatchShopId prefers khhaoShopId for khhao kuaishou bindings', () => {
|
||||
assert.equal(
|
||||
resolveFulfillmentBindingMatchShopId({
|
||||
provider: 'khhao',
|
||||
platform: 'kuaishou',
|
||||
shopId: 'shop-a',
|
||||
khhaoShopId: 'khhao-1',
|
||||
}),
|
||||
'khhao-1',
|
||||
)
|
||||
|
||||
assert.equal(
|
||||
resolveFulfillmentBindingMatchShopId({
|
||||
provider: 'agiso',
|
||||
platform: 'xianyu',
|
||||
shopId: 'shop-a',
|
||||
khhaoShopId: 'khhao-1',
|
||||
}),
|
||||
'shop-a',
|
||||
)
|
||||
})
|
||||
|
||||
test('matchesObservedProduct honors provider platform shop and external fields', () => {
|
||||
const binding = {
|
||||
provider: 'agiso',
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
saveOrderFulfillmentBindingConfigs,
|
||||
} from '../../order/fulfillment-binding-config-service.js'
|
||||
import { enrichAgisoXianyuTradeOrder } from '../../platforms/agiso/xianyu/order-detail-service.js'
|
||||
import { getKuaishouEticketSourceConfig, resolveKuaishouEticketShopConfig } from '../../platforms/kuaishou-eticket/source-config-service.js'
|
||||
import { syncConfiguredFulfillmentBindings } from '../../bootstrap/fulfillment-bootstrap-service.js'
|
||||
import { getFulfillmentProfileByKey } from '../../../repositories/fulfillment-profile-repo.js'
|
||||
import { createHttpError } from '../../../utils/http.js'
|
||||
@@ -78,8 +77,6 @@ export async function updateAdminFulfillmentBindingConfigs(
|
||||
) {
|
||||
const bindingsInput = Array.isArray(payload.bindings) ? payload.bindings : []
|
||||
const normalizedBindings = await validateAdminFulfillmentBindingConfigs(bindingsInput, {
|
||||
kuaishouEticketSource: getKuaishouEticketSourceConfig(),
|
||||
resolveKuaishouEticketShopConfig,
|
||||
getFulfillmentProfileByKey,
|
||||
})
|
||||
assertLegacyBindingConfigsOnly(normalizedBindings)
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
// @ts-check
|
||||
|
||||
import { queryKhhaoOrderList } from '../../platforms/khhao/order-query-service.js'
|
||||
import { syncKhhaoOrders } from '../../platforms/khhao/order-sync-service.js'
|
||||
import { getKhhaoSourceConfig, getKhhaoSourcesFilePath, saveKhhaoSourceConfig } from '../../platforms/khhao/source-config-service.js'
|
||||
import { ensureKhhaoSyncBaseline, getKhhaoSyncState, getKhhaoSyncStateFilePath } from '../../platforms/khhao/sync-state-service.js'
|
||||
import { loginKhhaoSession } from '../../platforms/khhao/session-service.js'
|
||||
import {
|
||||
buildAdminKhhaoLoginPayload,
|
||||
buildAdminKhhaoLoginResult,
|
||||
buildAdminKhhaoOrderQueryResult,
|
||||
buildAdminKhhaoSyncPayload,
|
||||
resolveAdminKhhaoCredentialPayload,
|
||||
} from './khhao.js'
|
||||
import { normalizeAdminKhhaoSourceConfigPayload } from './writes.js'
|
||||
import {
|
||||
mapAdminKhhaoSourceConfig,
|
||||
mapAdminKhhaoSyncState,
|
||||
} from './mappers.js'
|
||||
|
||||
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKhhaoSourceConfigInput} AdminKhhaoSourceConfigInput */
|
||||
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKhhaoOrderQueryInput} AdminKhhaoOrderQueryInput */
|
||||
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKhhaoTestLoginInput} AdminKhhaoTestLoginInput */
|
||||
|
||||
export function getAdminKhhaoSourceConfig() {
|
||||
const config = getKhhaoSourceConfig()
|
||||
const syncState = getKhhaoSyncState()
|
||||
|
||||
return {
|
||||
filePath: getKhhaoSourcesFilePath(),
|
||||
stateFilePath: getKhhaoSyncStateFilePath(),
|
||||
source: mapAdminKhhaoSourceConfig(config),
|
||||
syncState: mapAdminKhhaoSyncState(syncState),
|
||||
}
|
||||
}
|
||||
|
||||
/** @param {AdminKhhaoSourceConfigInput} [payload] */
|
||||
export function updateAdminKhhaoSourceConfig(payload = /** @type {AdminKhhaoSourceConfigInput} */ ({})) {
|
||||
const saved = saveKhhaoSourceConfig(normalizeAdminKhhaoSourceConfigPayload(payload))
|
||||
const syncState = saved.autoSync?.enabled ? ensureKhhaoSyncBaseline() : getKhhaoSyncState()
|
||||
|
||||
return {
|
||||
filePath: getKhhaoSourcesFilePath(),
|
||||
stateFilePath: getKhhaoSyncStateFilePath(),
|
||||
source: mapAdminKhhaoSourceConfig(saved),
|
||||
syncState: mapAdminKhhaoSyncState(syncState),
|
||||
}
|
||||
}
|
||||
|
||||
/** @param {AdminKhhaoTestLoginInput} [payload] */
|
||||
export async function testAdminKhhaoLogin(payload = /** @type {AdminKhhaoTestLoginInput} */ ({})) {
|
||||
const session = await loginKhhaoSession(buildAdminKhhaoLoginPayload(payload))
|
||||
return buildAdminKhhaoLoginResult(session)
|
||||
}
|
||||
|
||||
/** @param {AdminKhhaoOrderQueryInput} [payload] */
|
||||
export async function queryAdminKhhaoOrders(payload = /** @type {AdminKhhaoOrderQueryInput} */ ({})) {
|
||||
const credential = resolveAdminKhhaoCredentialPayload(payload)
|
||||
const session = await loginKhhaoSession(buildAdminKhhaoLoginPayload(payload, {
|
||||
requestIdScope: 'query-orders',
|
||||
}))
|
||||
|
||||
const result = await queryKhhaoOrderList({
|
||||
baseUrl: credential.baseUrl,
|
||||
page: payload.page,
|
||||
limit: payload.limit,
|
||||
session,
|
||||
})
|
||||
|
||||
return buildAdminKhhaoOrderQueryResult(session, result)
|
||||
}
|
||||
|
||||
/** @param {AdminKhhaoOrderQueryInput} [payload] */
|
||||
export async function syncAdminKhhaoOrders(payload = /** @type {AdminKhhaoOrderQueryInput} */ ({})) {
|
||||
return syncKhhaoOrders(buildAdminKhhaoSyncPayload(payload))
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
// @ts-check
|
||||
|
||||
import { getKhhaoSourceConfig } from '../../platforms/khhao/source-config-service.js'
|
||||
import { mapKhhaoOrderPreviewList } from '../../platforms/khhao/order-mapper-service.js'
|
||||
import { maskSecret } from './mappers.js'
|
||||
|
||||
export function resolveAdminKhhaoCredentialPayload(
|
||||
payload = {},
|
||||
options = {},
|
||||
) {
|
||||
const savedSource = /** @type {Record<string, unknown>} */ (
|
||||
options.savedSource || getKhhaoSourceConfig()
|
||||
)
|
||||
|
||||
return {
|
||||
baseUrl: String(payload.baseUrl || savedSource.baseUrl || '').trim(),
|
||||
username: String(payload.username || savedSource.username || '').trim(),
|
||||
password: String(payload.password || savedSource.password || '').trim(),
|
||||
maxCaptchaAttempts: payload.maxCaptchaAttempts || savedSource.maxCaptchaAttempts,
|
||||
}
|
||||
}
|
||||
|
||||
export function buildAdminKhhaoLoginPayload(
|
||||
payload = {},
|
||||
options = {},
|
||||
) {
|
||||
const credential = resolveAdminKhhaoCredentialPayload(payload, options)
|
||||
const requestIdScope = String(options.requestIdScope || 'test-login').trim() || 'test-login'
|
||||
|
||||
return {
|
||||
...credential,
|
||||
includeImageBase64: payload.includeImageBase64,
|
||||
requestId: `admin-khhao-${requestIdScope}:${credential.username || 'anonymous'}`,
|
||||
}
|
||||
}
|
||||
|
||||
export function buildAdminKhhaoSyncPayload(
|
||||
payload = {},
|
||||
options = {},
|
||||
) {
|
||||
return {
|
||||
...payload,
|
||||
...resolveAdminKhhaoCredentialPayload(payload, options),
|
||||
}
|
||||
}
|
||||
|
||||
export function buildAdminKhhaoLoginResult(session = {}) {
|
||||
const cookieKeys = Object.keys(session.cookieMap || {})
|
||||
|
||||
return {
|
||||
baseUrl: String(session.baseUrl || '').trim(),
|
||||
username: String(session.username || '').trim(),
|
||||
loggedInAt: String(session.loggedInAt || '').trim(),
|
||||
attempt: Number(session.attempt || 0),
|
||||
responseMessage: String(session.responseMessage || '').trim(),
|
||||
captcha: {
|
||||
recognizedText: String(session.captchaText || '').trim(),
|
||||
imageBase64: String(session.captchaImageBase64 || '').trim(),
|
||||
},
|
||||
session: {
|
||||
cookieKeys,
|
||||
cookieCount: cookieKeys.length,
|
||||
cookieHeaderMasked: maskSecret(session.cookieHeader),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function buildAdminKhhaoOrderQueryResult(
|
||||
session = {},
|
||||
result = {},
|
||||
) {
|
||||
const items = Array.isArray(result.items) ? result.items : []
|
||||
|
||||
return {
|
||||
baseUrl: String(session.baseUrl || '').trim(),
|
||||
page: Number(result.page || 1),
|
||||
limit: Number(result.limit || 0),
|
||||
total: Number(result.total || 0),
|
||||
itemCount: items.length,
|
||||
items: mapKhhaoOrderPreviewList(items),
|
||||
rawItems: items,
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
|
||||
import {
|
||||
buildAdminKhhaoLoginPayload,
|
||||
buildAdminKhhaoLoginResult,
|
||||
buildAdminKhhaoOrderQueryResult,
|
||||
buildAdminKhhaoSyncPayload,
|
||||
resolveAdminKhhaoCredentialPayload,
|
||||
} from './khhao.js'
|
||||
|
||||
test('resolveAdminKhhaoCredentialPayload merges payload and saved source defaults', () => {
|
||||
assert.deepEqual(
|
||||
resolveAdminKhhaoCredentialPayload(
|
||||
{
|
||||
baseUrl: ' https://override.example.com ',
|
||||
maxCaptchaAttempts: 5,
|
||||
},
|
||||
{
|
||||
savedSource: {
|
||||
baseUrl: 'https://saved.example.com',
|
||||
username: 'saved-user',
|
||||
password: 'saved-pass',
|
||||
maxCaptchaAttempts: 3,
|
||||
},
|
||||
},
|
||||
),
|
||||
{
|
||||
baseUrl: 'https://override.example.com',
|
||||
username: 'saved-user',
|
||||
password: 'saved-pass',
|
||||
maxCaptchaAttempts: 5,
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
test('buildAdminKhhaoLoginPayload appends request id and includeImageBase64', () => {
|
||||
assert.deepEqual(
|
||||
buildAdminKhhaoLoginPayload(
|
||||
{
|
||||
username: ' user ',
|
||||
includeImageBase64: true,
|
||||
},
|
||||
{
|
||||
requestIdScope: 'query-orders',
|
||||
savedSource: {
|
||||
baseUrl: 'https://saved.example.com',
|
||||
password: 'saved-pass',
|
||||
maxCaptchaAttempts: 3,
|
||||
},
|
||||
},
|
||||
),
|
||||
{
|
||||
baseUrl: 'https://saved.example.com',
|
||||
username: 'user',
|
||||
password: 'saved-pass',
|
||||
maxCaptchaAttempts: 3,
|
||||
includeImageBase64: true,
|
||||
requestId: 'admin-khhao-query-orders:user',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
test('buildAdminKhhaoSyncPayload merges normalized credential fields into payload', () => {
|
||||
assert.deepEqual(
|
||||
buildAdminKhhaoSyncPayload(
|
||||
{
|
||||
page: 2,
|
||||
limit: 20,
|
||||
username: ' user ',
|
||||
},
|
||||
{
|
||||
savedSource: {
|
||||
baseUrl: 'https://saved.example.com',
|
||||
password: 'saved-pass',
|
||||
maxCaptchaAttempts: 4,
|
||||
},
|
||||
},
|
||||
),
|
||||
{
|
||||
page: 2,
|
||||
limit: 20,
|
||||
username: 'user',
|
||||
baseUrl: 'https://saved.example.com',
|
||||
password: 'saved-pass',
|
||||
maxCaptchaAttempts: 4,
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
test('buildAdminKhhaoLoginResult assembles login response payload', () => {
|
||||
assert.deepEqual(
|
||||
buildAdminKhhaoLoginResult({
|
||||
baseUrl: ' https://admin.khhao.com ',
|
||||
username: ' test-user ',
|
||||
loggedInAt: ' 2026-05-04T12:00:00.000Z ',
|
||||
attempt: 2,
|
||||
responseMessage: ' success ',
|
||||
captchaText: ' abcd ',
|
||||
captchaImageBase64: ' image-data ',
|
||||
cookieMap: {
|
||||
PHPSESSID: 'a',
|
||||
foo: 'b',
|
||||
},
|
||||
cookieHeader: 'abcdef1234567890',
|
||||
}),
|
||||
{
|
||||
baseUrl: 'https://admin.khhao.com',
|
||||
username: 'test-user',
|
||||
loggedInAt: '2026-05-04T12:00:00.000Z',
|
||||
attempt: 2,
|
||||
responseMessage: 'success',
|
||||
captcha: {
|
||||
recognizedText: 'abcd',
|
||||
imageBase64: 'image-data',
|
||||
},
|
||||
session: {
|
||||
cookieKeys: ['PHPSESSID', 'foo'],
|
||||
cookieCount: 2,
|
||||
cookieHeaderMasked: 'abcdef****567890',
|
||||
},
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
test('buildAdminKhhaoOrderQueryResult maps preview list and preserves raw items', () => {
|
||||
const rawItems = [
|
||||
{
|
||||
ordersn: ' A1 ',
|
||||
pingtai: '3',
|
||||
pingtaiName: '快手',
|
||||
shopid: '1001',
|
||||
shopName: '店铺A',
|
||||
goodid: 'g1',
|
||||
goodName: '商品A',
|
||||
sku: 'sku-1',
|
||||
num: '2',
|
||||
fee: '12.34',
|
||||
status: '2',
|
||||
statusName: '<span>已支付</span>',
|
||||
addtime: '2026-05-04 10:00:00',
|
||||
},
|
||||
]
|
||||
|
||||
const result = buildAdminKhhaoOrderQueryResult(
|
||||
{
|
||||
baseUrl: ' https://admin.khhao.com ',
|
||||
},
|
||||
{
|
||||
page: 2,
|
||||
limit: 20,
|
||||
total: 50,
|
||||
items: rawItems,
|
||||
},
|
||||
)
|
||||
|
||||
assert.equal(result.baseUrl, 'https://admin.khhao.com')
|
||||
assert.equal(result.page, 2)
|
||||
assert.equal(result.limit, 20)
|
||||
assert.equal(result.total, 50)
|
||||
assert.equal(result.itemCount, 1)
|
||||
assert.equal(result.rawItems, rawItems)
|
||||
assert.equal(result.items[0].platformOrderId, 'A1')
|
||||
assert.equal(result.items[0].platform, 'kuaishou')
|
||||
assert.equal(result.items[0].itemTitle, '商品A')
|
||||
})
|
||||
@@ -26,47 +26,6 @@ export function maskPhone(value) {
|
||||
return `${normalized.slice(0, 3)}****${normalized.slice(-4)}`
|
||||
}
|
||||
|
||||
export function mapAdminKhhaoSourceConfig(config = {}) {
|
||||
return {
|
||||
enabled: config.enabled !== false,
|
||||
baseUrl: String(config.baseUrl || '').trim(),
|
||||
username: String(config.username || '').trim(),
|
||||
password: String(config.password || '').trim(),
|
||||
maxCaptchaAttempts: Number(config.maxCaptchaAttempts || 3) || 3,
|
||||
autoSync: {
|
||||
enabled: config.autoSync?.enabled === true,
|
||||
intervalMinutes: Number(config.autoSync?.intervalMinutes || 3) || 3,
|
||||
pages: Number(config.autoSync?.pages || 2) || 2,
|
||||
pageSize: Number(config.autoSync?.pageSize || 20) || 20,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function mapAdminKhhaoSyncState(syncState = {}) {
|
||||
return {
|
||||
syncFromCreatedAt: String(syncState.syncFromCreatedAt || '').trim(),
|
||||
lastRunStartedAt: String(syncState.lastRunStartedAt || '').trim(),
|
||||
lastRunFinishedAt: String(syncState.lastRunFinishedAt || '').trim(),
|
||||
lastRunStatus: String(syncState.lastRunStatus || '').trim(),
|
||||
lastErrorMessage: String(syncState.lastErrorMessage || '').trim(),
|
||||
fetchedCount: Number(syncState.fetchedCount || 0),
|
||||
syncedCount: Number(syncState.syncedCount || 0),
|
||||
ignoredCount: Number(syncState.ignoredCount || 0),
|
||||
watchMode: String(syncState.watchMode || 'normal').trim() || 'normal',
|
||||
watchOrders: Array.isArray(syncState.watchOrders)
|
||||
? syncState.watchOrders.map((item) => ({
|
||||
platformOrderId: String(item?.platformOrderId || '').trim(),
|
||||
shopId: String(item?.shopId || '').trim(),
|
||||
shopName: String(item?.shopName || '').trim(),
|
||||
itemTitle: String(item?.itemTitle || '').trim(),
|
||||
payStatus: String(item?.payStatus || '').trim(),
|
||||
detectedAt: String(item?.detectedAt || '').trim(),
|
||||
lastSeenAt: String(item?.lastSeenAt || '').trim(),
|
||||
}))
|
||||
: [],
|
||||
}
|
||||
}
|
||||
|
||||
export function mapAdminKuaishouEticketShopItem(item = {}) {
|
||||
return {
|
||||
shopId: String(item.shopId || '').trim(),
|
||||
@@ -118,10 +77,9 @@ export function mapAdminKuaishouCloudFulfillmentItem(item = {}) {
|
||||
id: String(item.id || '').trim(),
|
||||
enabled: item.enabled !== false,
|
||||
priority: Number(item.priority || 100) || 100,
|
||||
provider: String(item.provider || 'khhao').trim() || 'khhao',
|
||||
provider: String(item.provider || '91kaquan').trim() || '91kaquan',
|
||||
platform: String(item.platform || 'kuaishou').trim() || 'kuaishou',
|
||||
shopId: String(item.shopId || '').trim(),
|
||||
khhaoShopId: String(item.khhaoShopId || '').trim(),
|
||||
internalSkuCode: String(item.internalSkuCode || '').trim(),
|
||||
internalSkuName: String(item.internalSkuName || '').trim(),
|
||||
externalSkuCode: String(item.externalSkuCode || '').trim(),
|
||||
|
||||
@@ -3,8 +3,6 @@ import assert from 'node:assert/strict'
|
||||
|
||||
import {
|
||||
mapAdminCloudtentaclesSession,
|
||||
mapAdminKhhaoSourceConfig,
|
||||
mapAdminKhhaoSyncState,
|
||||
mapAdminKuaishouCloudFulfillmentSource,
|
||||
mapAdminKuaishouEticketSourceConfig,
|
||||
maskPhone,
|
||||
@@ -23,79 +21,6 @@ test('maskPhone hides middle digits for mobile numbers', () => {
|
||||
assert.equal(maskPhone(''), '')
|
||||
})
|
||||
|
||||
test('mapAdminKhhaoSourceConfig normalizes defaults and nested auto sync values', () => {
|
||||
assert.deepEqual(
|
||||
mapAdminKhhaoSourceConfig({
|
||||
enabled: true,
|
||||
baseUrl: ' https://admin.khhao.com ',
|
||||
username: ' user ',
|
||||
password: ' pass ',
|
||||
maxCaptchaAttempts: '0',
|
||||
autoSync: {
|
||||
enabled: true,
|
||||
intervalMinutes: '',
|
||||
pages: '0',
|
||||
pageSize: '50',
|
||||
},
|
||||
}),
|
||||
{
|
||||
enabled: true,
|
||||
baseUrl: 'https://admin.khhao.com',
|
||||
username: 'user',
|
||||
password: 'pass',
|
||||
maxCaptchaAttempts: 3,
|
||||
autoSync: {
|
||||
enabled: true,
|
||||
intervalMinutes: 3,
|
||||
pages: 2,
|
||||
pageSize: 50,
|
||||
},
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
test('mapAdminKhhaoSyncState normalizes watch orders and fallback values', () => {
|
||||
assert.deepEqual(
|
||||
mapAdminKhhaoSyncState({
|
||||
watchMode: '',
|
||||
fetchedCount: '8',
|
||||
watchOrders: [
|
||||
{
|
||||
platformOrderId: ' A1 ',
|
||||
shopId: ' S1 ',
|
||||
shopName: ' 店铺 ',
|
||||
itemTitle: ' 商品 ',
|
||||
payStatus: ' unpaid ',
|
||||
detectedAt: ' t1 ',
|
||||
lastSeenAt: ' t2 ',
|
||||
},
|
||||
],
|
||||
}),
|
||||
{
|
||||
syncFromCreatedAt: '',
|
||||
lastRunStartedAt: '',
|
||||
lastRunFinishedAt: '',
|
||||
lastRunStatus: '',
|
||||
lastErrorMessage: '',
|
||||
fetchedCount: 8,
|
||||
syncedCount: 0,
|
||||
ignoredCount: 0,
|
||||
watchMode: 'normal',
|
||||
watchOrders: [
|
||||
{
|
||||
platformOrderId: 'A1',
|
||||
shopId: 'S1',
|
||||
shopName: '店铺',
|
||||
itemTitle: '商品',
|
||||
payStatus: 'unpaid',
|
||||
detectedAt: 't1',
|
||||
lastSeenAt: 't2',
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
test('mapAdminKuaishouEticketSourceConfig maps shops and masks cookies', () => {
|
||||
assert.deepEqual(
|
||||
mapAdminKuaishouEticketSourceConfig(
|
||||
@@ -169,10 +94,9 @@ test('mapAdminKuaishouCloudFulfillmentSource normalizes items and defaults', ()
|
||||
id: 'item-1',
|
||||
enabled: true,
|
||||
priority: 100,
|
||||
provider: 'khhao',
|
||||
provider: '91kaquan',
|
||||
platform: 'kuaishou',
|
||||
shopId: '',
|
||||
khhaoShopId: '',
|
||||
internalSkuCode: '',
|
||||
internalSkuName: '',
|
||||
externalSkuCode: '',
|
||||
|
||||
@@ -3,14 +3,6 @@ export {
|
||||
updateAdminAgisoShopConfigs,
|
||||
} from './agiso-service.js'
|
||||
|
||||
export {
|
||||
getAdminKhhaoSourceConfig,
|
||||
updateAdminKhhaoSourceConfig,
|
||||
testAdminKhhaoLogin,
|
||||
queryAdminKhhaoOrders,
|
||||
syncAdminKhhaoOrders,
|
||||
} from './khhao-service.js'
|
||||
|
||||
export {
|
||||
getAdminNinetyoneOrders,
|
||||
retryAdminNinetyoneOrder,
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import { createHttpError } from '../../../utils/http.js'
|
||||
import { normalizeProductName } from '../../order/product-match-service.js'
|
||||
import { isPlainObject } from './context.js'
|
||||
import { resolveFulfillmentBindingMatchShopId } from './domain.js'
|
||||
|
||||
export function assertAdminFulfillmentBindingsInput(bindings) {
|
||||
if (Array.isArray(bindings)) {
|
||||
@@ -21,10 +20,6 @@ export function normalizeAdminFulfillmentBindingItem(
|
||||
options = {},
|
||||
) {
|
||||
const index = Number(options.index || 0)
|
||||
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)
|
||||
)
|
||||
if (!isPlainObject(rawBinding)) {
|
||||
throw createHttpError(`第 ${index + 1} 条规则格式不正确`, {
|
||||
statusCode: 400,
|
||||
@@ -34,9 +29,8 @@ export function normalizeAdminFulfillmentBindingItem(
|
||||
|
||||
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 shopId = String(rawBinding.shopId || '').trim()
|
||||
const shopName = String(rawBinding.shopName || '').trim()
|
||||
const skuCode = String(rawBinding.skuCode || '').trim()
|
||||
const skuName = String(rawBinding.skuName || '').trim()
|
||||
const profileKey = String(rawBinding.profileKey || '').trim() || 'manual_review'
|
||||
@@ -46,44 +40,6 @@ export function normalizeAdminFulfillmentBindingItem(
|
||||
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,
|
||||
@@ -103,7 +59,6 @@ export function normalizeAdminFulfillmentBindingItem(
|
||||
platform,
|
||||
shopId,
|
||||
shopName,
|
||||
khhaoShopId,
|
||||
skuCode,
|
||||
skuName,
|
||||
profileKey,
|
||||
@@ -123,12 +78,7 @@ 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?.shopId || '').trim(),
|
||||
String(binding?.match?.externalItemId || '').trim(),
|
||||
String(binding?.match?.externalSkuCode || '').trim(),
|
||||
normalizeProductName(String(binding?.match?.externalSkuName || '').trim()),
|
||||
@@ -142,10 +92,6 @@ export async function validateAdminFulfillmentBindingConfigs(
|
||||
) {
|
||||
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)
|
||||
)
|
||||
@@ -153,11 +99,7 @@ export async function validateAdminFulfillmentBindingConfigs(
|
||||
const normalizedBindings = []
|
||||
|
||||
for (const [index, rawBinding] of bindings.entries()) {
|
||||
const normalized = normalizeAdminFulfillmentBindingItem(rawBinding, {
|
||||
index,
|
||||
kuaishouEticketSource,
|
||||
resolveKuaishouEticketShopConfig,
|
||||
})
|
||||
const normalized = normalizeAdminFulfillmentBindingItem(rawBinding, { index })
|
||||
|
||||
const profile = await getFulfillmentProfileByKey(normalized.profileKey)
|
||||
if (!profile) {
|
||||
|
||||
@@ -13,14 +13,13 @@ test('assertAdminFulfillmentBindingsInput rejects non-array payloads', () => {
|
||||
assert.throws(() => assertAdminFulfillmentBindingsInput({}), /履约配置格式不正确/)
|
||||
})
|
||||
|
||||
test('normalizeAdminFulfillmentBindingItem normalizes kuaishou binding shop mapping', () => {
|
||||
test('normalizeAdminFulfillmentBindingItem normalizes generic binding fields', () => {
|
||||
const result = normalizeAdminFulfillmentBindingItem(
|
||||
{
|
||||
provider: 'khhao',
|
||||
platform: 'kuaishou',
|
||||
shopId: 'legacy-shop',
|
||||
shopName: '旧店铺',
|
||||
khhaoShopId: 'khhao-1',
|
||||
provider: ' agiso ',
|
||||
platform: ' xianyu ',
|
||||
shopId: ' shop-1 ',
|
||||
shopName: ' 店铺 ',
|
||||
skuCode: 'sku-1',
|
||||
match: {
|
||||
externalSkuCode: 'ext-1',
|
||||
@@ -31,24 +30,14 @@ test('normalizeAdminFulfillmentBindingItem normalizes kuaishou binding shop mapp
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
index: 0,
|
||||
kuaishouEticketSource: { source: true },
|
||||
resolveKuaishouEticketShopConfig() {
|
||||
return {
|
||||
shopId: 'ks-100',
|
||||
kshopName: '快手店铺A',
|
||||
}
|
||||
},
|
||||
},
|
||||
{ index: 0 },
|
||||
)
|
||||
|
||||
assert.deepEqual(result, {
|
||||
provider: 'khhao',
|
||||
platform: 'kuaishou',
|
||||
shopId: 'ks-100',
|
||||
shopName: '快手店铺A',
|
||||
khhaoShopId: 'khhao-1',
|
||||
provider: 'agiso',
|
||||
platform: 'xianyu',
|
||||
shopId: 'shop-1',
|
||||
shopName: '店铺',
|
||||
skuCode: 'sku-1',
|
||||
skuName: '',
|
||||
profileKey: 'manual_review',
|
||||
@@ -57,9 +46,6 @@ test('normalizeAdminFulfillmentBindingItem normalizes kuaishou binding shop mapp
|
||||
config: {
|
||||
kuaishouShop: {
|
||||
note: 'keep',
|
||||
shopId: 'ks-100',
|
||||
shopName: '快手店铺A',
|
||||
khhaoShopId: 'khhao-1',
|
||||
},
|
||||
},
|
||||
match: {
|
||||
@@ -104,10 +90,9 @@ test('normalizeAdminFulfillmentBindingItem rejects missing sku and match conditi
|
||||
test('buildAdminFulfillmentBindingUniqueKey uses normalized external sku name and shop id rules', () => {
|
||||
assert.equal(
|
||||
buildAdminFulfillmentBindingUniqueKey({
|
||||
provider: 'khhao',
|
||||
provider: '91kaquan',
|
||||
platform: 'kuaishou',
|
||||
shopId: 'shop-a',
|
||||
khhaoShopId: 'khhao-a',
|
||||
skuCode: 'sku-1',
|
||||
match: {
|
||||
externalItemId: '',
|
||||
@@ -115,7 +100,7 @@ test('buildAdminFulfillmentBindingUniqueKey uses normalized external sku name an
|
||||
externalSkuName: ' 礼包 A ',
|
||||
},
|
||||
}),
|
||||
'khhao::kuaishou::khhao-a::::::礼包 a::sku-1',
|
||||
'91kaquan::kuaishou::shop-a::::::礼包 a::sku-1',
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -88,22 +88,6 @@ export function buildAdminAgisoMessagingSavePayload(
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeAdminKhhaoSourceConfigPayload(payload = {}) {
|
||||
return {
|
||||
enabled: payload.enabled !== false,
|
||||
baseUrl: String(payload.baseUrl || '').trim() || 'https://admin.khhao.com',
|
||||
username: String(payload.username || '').trim(),
|
||||
password: String(payload.password || '').trim(),
|
||||
maxCaptchaAttempts: Number(payload.maxCaptchaAttempts || 3) || 3,
|
||||
autoSync: {
|
||||
enabled: payload.autoSync?.enabled === true,
|
||||
intervalMinutes: Number(payload.autoSync?.intervalMinutes || 3) || 3,
|
||||
pages: Number(payload.autoSync?.pages || 2) || 2,
|
||||
pageSize: Number(payload.autoSync?.pageSize || 20) || 20,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeAdminCloudtentaclesSourceConfigPayload(payload = {}) {
|
||||
return {
|
||||
enabled: payload.enabled !== false,
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
buildAdminAgisoMessagingSavePayload,
|
||||
buildAdminAgisoShopConfigUpdate,
|
||||
normalizeAdminCloudtentaclesSourceConfigPayload,
|
||||
normalizeAdminKhhaoSourceConfigPayload,
|
||||
} from './writes.js'
|
||||
|
||||
test('buildAdminAgisoShopConfigUpdate merges item fields and drops explicit empty templates', () => {
|
||||
@@ -102,37 +101,6 @@ test('buildAdminAgisoMessagingSavePayload updates defaults and keeps only shops
|
||||
)
|
||||
})
|
||||
|
||||
test('normalizeAdminKhhaoSourceConfigPayload applies defaults and numeric fallbacks', () => {
|
||||
assert.deepEqual(
|
||||
normalizeAdminKhhaoSourceConfigPayload({
|
||||
enabled: true,
|
||||
baseUrl: ' https://admin.khhao.com ',
|
||||
username: ' user ',
|
||||
password: ' pass ',
|
||||
maxCaptchaAttempts: 0,
|
||||
autoSync: {
|
||||
enabled: true,
|
||||
intervalMinutes: '',
|
||||
pages: '0',
|
||||
pageSize: '50',
|
||||
},
|
||||
}),
|
||||
{
|
||||
enabled: true,
|
||||
baseUrl: 'https://admin.khhao.com',
|
||||
username: 'user',
|
||||
password: 'pass',
|
||||
maxCaptchaAttempts: 3,
|
||||
autoSync: {
|
||||
enabled: true,
|
||||
intervalMinutes: 3,
|
||||
pages: 2,
|
||||
pageSize: 50,
|
||||
},
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
test('normalizeAdminCloudtentaclesSourceConfigPayload applies defaults', () => {
|
||||
assert.deepEqual(
|
||||
normalizeAdminCloudtentaclesSourceConfigPayload({
|
||||
|
||||
Reference in New Issue
Block a user