From 9b4a3039fa1f9f564560250d833c09db283194a1 Mon Sep 17 00:00:00 2001 From: yml Date: Mon, 4 May 2026 15:14:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=BD=E7=A6=BB=E5=90=8E=E5=8F=B0=E5=B1=A5?= =?UTF-8?q?=E7=BA=A6=E8=A7=82=E5=AF=9F=E5=95=86=E5=93=81=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...admin-platform-config-observed-products.js | 54 +++++++++++ ...-platform-config-observed-products.test.js | 97 +++++++++++++++++++ .../admin/admin-platform-config-service.js | 43 +------- 3 files changed, 153 insertions(+), 41 deletions(-) create mode 100644 apps/backend/src/services/admin/admin-platform-config-observed-products.js create mode 100644 apps/backend/src/services/admin/admin-platform-config-observed-products.test.js diff --git a/apps/backend/src/services/admin/admin-platform-config-observed-products.js b/apps/backend/src/services/admin/admin-platform-config-observed-products.js new file mode 100644 index 00000000..adef2858 --- /dev/null +++ b/apps/backend/src/services/admin/admin-platform-config-observed-products.js @@ -0,0 +1,54 @@ +// @ts-check + +import { query } from '../../db/client.js' +import { mapAdminObservedProductItem } from './admin-platform-config-domain.js' + +export const ADMIN_OBSERVED_PRODUCTS_QUERY = ` + SELECT + o.provider, + o.platform, + o.shop_id, + MAX(CASE WHEN trim(o.shop_name) != '' THEN o.shop_name ELSE '' END) AS shop_name, + COALESCE(NULLIF(oi.item_snapshot_json ->> 'externalItemId', ''), '') AS external_item_id, + COALESCE(NULLIF(oi.item_snapshot_json ->> 'externalSkuCode', ''), '') AS external_sku_code, + COALESCE(NULLIF(oi.item_snapshot_json ->> 'externalSkuName', ''), '') AS external_sku_name, + MAX(oi.created_at) AS latest_seen_at, + COUNT(*)::int AS order_item_count + FROM order_items oi + JOIN orders o ON o.id = oi.order_id + WHERE + COALESCE(NULLIF(oi.item_snapshot_json ->> 'externalItemId', ''), '') != '' + OR COALESCE(NULLIF(oi.item_snapshot_json ->> 'externalSkuCode', ''), '') != '' + OR COALESCE(NULLIF(oi.item_snapshot_json ->> 'externalSkuName', ''), '') != '' + GROUP BY + o.provider, + o.platform, + o.shop_id, + external_item_id, + external_sku_code, + external_sku_name + ORDER BY latest_seen_at DESC, o.platform ASC, o.shop_id ASC, external_sku_code ASC + LIMIT 200 +` + +export function mapAdminObservedProductRow(row = {}) { + return { + provider: String(row.provider || '').trim(), + platform: String(row.platform || '').trim(), + shopId: String(row.shop_id || '').trim(), + shopName: String(row.shop_name || '').trim(), + externalItemId: String(row.external_item_id || '').trim(), + externalSkuCode: String(row.external_sku_code || '').trim(), + externalSkuName: String(row.external_sku_name || '').trim(), + latestSeenAt: row.latest_seen_at || null, + orderItemCount: Number(row.order_item_count || 0), + } +} + +export async function listAdminObservedProducts(bindings = [], options = {}) { + const queryImpl = /** @type {(sql: string) => Promise<{ rows: Array> }>} */ ( + options.query || query + ) + const rowsResult = await queryImpl(ADMIN_OBSERVED_PRODUCTS_QUERY) + return rowsResult.rows.map((row) => mapAdminObservedProductItem(mapAdminObservedProductRow(row), bindings)) +} diff --git a/apps/backend/src/services/admin/admin-platform-config-observed-products.test.js b/apps/backend/src/services/admin/admin-platform-config-observed-products.test.js new file mode 100644 index 00000000..516bc0b6 --- /dev/null +++ b/apps/backend/src/services/admin/admin-platform-config-observed-products.test.js @@ -0,0 +1,97 @@ +import test from 'node:test' +import assert from 'node:assert/strict' + +import { + ADMIN_OBSERVED_PRODUCTS_QUERY, + listAdminObservedProducts, + mapAdminObservedProductRow, +} from './admin-platform-config-observed-products.js' + +test('mapAdminObservedProductRow normalizes query row fields', () => { + assert.deepEqual( + mapAdminObservedProductRow({ + provider: ' agiso ', + platform: ' xianyu ', + shop_id: ' shop-1 ', + shop_name: ' 店铺A ', + external_item_id: ' item-1 ', + external_sku_code: ' sku-1 ', + external_sku_name: ' 商品A ', + latest_seen_at: '2026-05-04T12:00:00.000Z', + order_item_count: '3', + }), + { + provider: 'agiso', + platform: 'xianyu', + shopId: 'shop-1', + shopName: '店铺A', + externalItemId: 'item-1', + externalSkuCode: 'sku-1', + externalSkuName: '商品A', + latestSeenAt: '2026-05-04T12:00:00.000Z', + orderItemCount: 3, + }, + ) +}) + +test('listAdminObservedProducts queries rows and maps matched binding summary', async () => { + /** @type {string[]} */ + const sqlCalls = [] + const result = await listAdminObservedProducts( + [ + { + provider: 'agiso', + platform: 'xianyu', + shopId: 'shop-1', + skuCode: 'inner-1', + skuName: '内部商品A', + profileKey: 'manual_review', + match: { + externalSkuCode: 'sku-1', + }, + }, + ], + { + async query(sql) { + sqlCalls.push(sql) + return { + rows: [ + { + provider: 'agiso', + platform: 'xianyu', + shop_id: 'shop-1', + shop_name: '店铺A', + external_item_id: '', + external_sku_code: 'sku-1', + external_sku_name: '商品A', + latest_seen_at: '2026-05-04T12:00:00.000Z', + order_item_count: 2, + }, + ], + } + }, + }, + ) + + assert.equal(sqlCalls.length, 1) + assert.equal(sqlCalls[0], ADMIN_OBSERVED_PRODUCTS_QUERY) + assert.deepEqual(result, [ + { + provider: 'agiso', + platform: 'xianyu', + shopId: 'shop-1', + shopName: '店铺A', + externalItemId: '', + externalSkuCode: 'sku-1', + externalSkuName: '商品A', + latestSeenAt: '2026-05-04T12:00:00.000Z', + orderItemCount: 2, + configured: true, + matchedBinding: { + skuCode: 'inner-1', + skuName: '内部商品A', + profileKey: 'manual_review', + }, + }, + ]) +}) diff --git a/apps/backend/src/services/admin/admin-platform-config-service.js b/apps/backend/src/services/admin/admin-platform-config-service.js index 5102f4e1..95b5ee2b 100644 --- a/apps/backend/src/services/admin/admin-platform-config-service.js +++ b/apps/backend/src/services/admin/admin-platform-config-service.js @@ -89,6 +89,7 @@ import { normalizeFulfillmentLookupPayload, resolveFulfillmentLookupDetail, } from './admin-platform-config-fulfillment.js' +import { listAdminObservedProducts } from './admin-platform-config-observed-products.js' import { assertAdminFulfillmentBindingsInput, buildAdminFulfillmentBindingUniqueKey, @@ -99,7 +100,6 @@ import { mapAdminAgisoMessagingDefaults, mapAdminAgisoShopConfigItem, mapAdminFulfillmentBindingConfigItem, - mapAdminObservedProductItem, } from './admin-platform-config-domain.js' import { mapAdminCloudtentaclesSession, @@ -721,50 +721,11 @@ export async function runAdminCloudtentaclesFullFlow(payload = /** @type {AdminC export async function getAdminFulfillmentBindingConfigs() { const bindings = getOrderFulfillmentBindingConfigs() - const rowsResult = await query( - ` - SELECT - o.provider, - o.platform, - o.shop_id, - MAX(CASE WHEN trim(o.shop_name) != '' THEN o.shop_name ELSE '' END) AS shop_name, - COALESCE(NULLIF(oi.item_snapshot_json ->> 'externalItemId', ''), '') AS external_item_id, - COALESCE(NULLIF(oi.item_snapshot_json ->> 'externalSkuCode', ''), '') AS external_sku_code, - COALESCE(NULLIF(oi.item_snapshot_json ->> 'externalSkuName', ''), '') AS external_sku_name, - MAX(oi.created_at) AS latest_seen_at, - COUNT(*)::int AS order_item_count - FROM order_items oi - JOIN orders o ON o.id = oi.order_id - WHERE - COALESCE(NULLIF(oi.item_snapshot_json ->> 'externalItemId', ''), '') != '' - OR COALESCE(NULLIF(oi.item_snapshot_json ->> 'externalSkuCode', ''), '') != '' - OR COALESCE(NULLIF(oi.item_snapshot_json ->> 'externalSkuName', ''), '') != '' - GROUP BY - o.provider, - o.platform, - o.shop_id, - external_item_id, - external_sku_code, - external_sku_name - ORDER BY latest_seen_at DESC, o.platform ASC, o.shop_id ASC, external_sku_code ASC - LIMIT 200 - `, - ) return { filePath: getOrderFulfillmentBindingsFilePath(), bindings: bindings.map(mapAdminFulfillmentBindingConfigItem), - observedProducts: rowsResult.rows.map((row) => mapAdminObservedProductItem({ - provider: String(row.provider || '').trim(), - platform: String(row.platform || '').trim(), - shopId: String(row.shop_id || '').trim(), - shopName: String(row.shop_name || '').trim(), - externalItemId: String(row.external_item_id || '').trim(), - externalSkuCode: String(row.external_sku_code || '').trim(), - externalSkuName: String(row.external_sku_name || '').trim(), - latestSeenAt: row.latest_seen_at || null, - orderItemCount: Number(row.order_item_count || 0), - }, bindings)), + observedProducts: await listAdminObservedProducts(bindings), } }