后端迁移平台配置读写辅助

This commit is contained in:
yml
2026-05-21 16:06:45 +08:00
parent 38b0bf8ba5
commit 381ac44472
4 changed files with 42 additions and 29 deletions
@@ -1,11 +1,11 @@
// @ts-check
import { createHttpError } from '../../../utils/http.js' import { createHttpError } from '../../../utils/http.js'
import { formatFenToAmount } from '../../../utils/money.js' import { formatFenToAmount } from '../../../utils/money.js'
import { isPlainObject, pickFirstNonEmpty } from './context.js' import { isPlainObject, pickFirstNonEmpty } from './context.js'
import { mapAdminObservedProductItem } from './domain.js' import { mapAdminObservedProductItem } from './domain.js'
export function normalizeFulfillmentLookupPayload(payload = {}) { type JsonObject = Record<string, any>
export function normalizeFulfillmentLookupPayload(payload: JsonObject = {}) {
const provider = String(payload.provider || 'agiso').trim() || 'agiso' const provider = String(payload.provider || 'agiso').trim() || 'agiso'
const platform = String(payload.platform || 'xianyu').trim() || 'xianyu' const platform = String(payload.platform || 'xianyu').trim() || 'xianyu'
const shopId = String(payload.shopId || '').trim() const shopId = String(payload.shopId || '').trim()
@@ -35,7 +35,7 @@ export function normalizeFulfillmentLookupPayload(payload = {}) {
return { provider, platform, shopId, platformOrderId } return { provider, platform, shopId, platformOrderId }
} }
export function resolveFulfillmentLookupDetail(detailResult, platformOrderId) { export function resolveFulfillmentLookupDetail(detailResult: JsonObject, platformOrderId: unknown) {
const detail = isPlainObject(detailResult?.parsed) ? detailResult.parsed : {} const detail = isPlainObject(detailResult?.parsed) ? detailResult.parsed : {}
const items = Array.isArray(detail.items) ? detail.items : [] const items = Array.isArray(detail.items) ? detail.items : []
@@ -66,10 +66,19 @@ export function buildFulfillmentLookupResult({
platform = '', platform = '',
shopId = '', shopId = '',
platformOrderId = '', platformOrderId = '',
detail = /** @type {Record<string, unknown>} */ ({}), detail = {},
detailResult = /** @type {Record<string, unknown>} */ ({}), detailResult = {},
bindings = [], bindings = [],
fallbackShopName = '', fallbackShopName = '',
}: {
provider?: string
platform?: string
shopId?: string
platformOrderId?: string
detail?: JsonObject
detailResult?: JsonObject
bindings?: JsonObject[]
fallbackShopName?: string
} = {}) { } = {}) {
const resolvedShopName = pickFirstNonEmpty([detail.shopName, fallbackShopName]) const resolvedShopName = pickFirstNonEmpty([detail.shopName, fallbackShopName])
const items = Array.isArray(detail.items) ? detail.items : [] const items = Array.isArray(detail.items) ? detail.items : []
@@ -1,8 +1,8 @@
// @ts-check
import { query } from '../../../db/client.js' import { query } from '../../../db/client.js'
import { mapAdminObservedProductItem } from './domain.js' import { mapAdminObservedProductItem } from './domain.js'
type JsonObject = Record<string, any>
export const ADMIN_OBSERVED_PRODUCTS_QUERY = ` export const ADMIN_OBSERVED_PRODUCTS_QUERY = `
SELECT SELECT
o.provider, o.provider,
@@ -31,7 +31,7 @@ export const ADMIN_OBSERVED_PRODUCTS_QUERY = `
LIMIT 200 LIMIT 200
` `
export function mapAdminObservedProductRow(row = {}) { export function mapAdminObservedProductRow(row: JsonObject = {}) {
return { return {
provider: String(row.provider || '').trim(), provider: String(row.provider || '').trim(),
platform: String(row.platform || '').trim(), platform: String(row.platform || '').trim(),
@@ -45,10 +45,8 @@ export function mapAdminObservedProductRow(row = {}) {
} }
} }
export async function listAdminObservedProducts(bindings = [], options = {}) { export async function listAdminObservedProducts(bindings: JsonObject[] = [], options: JsonObject = {}) {
const queryImpl = /** @type {(sql: string) => Promise<{ rows: Array<Record<string, unknown>> }>} */ ( const queryImpl = (options.query || query) as (sql: string) => Promise<{ rows: JsonObject[] }>
options.query || query
)
const rowsResult = await queryImpl(ADMIN_OBSERVED_PRODUCTS_QUERY) const rowsResult = await queryImpl(ADMIN_OBSERVED_PRODUCTS_QUERY)
return rowsResult.rows.map((row) => mapAdminObservedProductItem(mapAdminObservedProductRow(row), bindings)) return rowsResult.rows.map((row) => mapAdminObservedProductItem(mapAdminObservedProductRow(row), bindings))
} }
@@ -1,14 +1,14 @@
// @ts-check
import { applyOptionalStringField } from "./domain.js"; import { applyOptionalStringField } from "./domain.js";
export function buildAdminAgisoShopConfigUpdate(item, current = {}) { type JsonObject = Record<string, any>
export function buildAdminAgisoShopConfigUpdate(item: JsonObject, current: JsonObject = {}) {
const shopId = String(item?.shopId || "").trim(); const shopId = String(item?.shopId || "").trim();
if (!shopId) { if (!shopId) {
return null; return null;
} }
const next = /** @type {Record<string, unknown>} */ ({ ...current }); const next: JsonObject = { ...current };
const shopName = String(item?.shopName || "").trim(); const shopName = String(item?.shopName || "").trim();
const accessToken = String(item?.accessToken || "").trim(); const accessToken = String(item?.accessToken || "").trim();
const messageTemplate = String(item?.messageTemplate || "").trim(); const messageTemplate = String(item?.messageTemplate || "").trim();
@@ -58,20 +58,16 @@ export function buildAdminAgisoShopConfigUpdate(item, current = {}) {
} }
export function buildAdminAgisoMessagingSavePayload( export function buildAdminAgisoMessagingSavePayload(
payload = {}, payload: JsonObject = {},
options = {} options: JsonObject = {}
) { ) {
const rawItems = Array.isArray(payload.shops) ? payload.shops : []; const rawItems = Array.isArray(payload.shops) ? payload.shops : [];
const currentDefaults = /** @type {Record<string, unknown>} */ ( const currentDefaults: JsonObject = options.currentDefaults || {};
options.currentDefaults || {} const currentMap: Record<string, JsonObject> = options.currentMap || {};
); const nextDefaults: JsonObject = {
const currentMap = /** @type {Record<string, Record<string, unknown>>} */ (
options.currentMap || {}
);
const nextDefaults = /** @type {Record<string, unknown>} */ ({
...currentDefaults, ...currentDefaults,
}); };
const nextMap = /** @type {Record<string, Record<string, unknown>>} */ ({}); const nextMap: Record<string, JsonObject> = {};
applyOptionalStringField(nextDefaults, "messageTemplate", payload.defaults); applyOptionalStringField(nextDefaults, "messageTemplate", payload.defaults);
applyOptionalStringField( applyOptionalStringField(
@@ -103,7 +99,7 @@ export function buildAdminAgisoMessagingSavePayload(
}; };
} }
export function normalizeAdminCloudtentaclesSourceConfigPayload(payload = {}) { export function normalizeAdminCloudtentaclesSourceConfigPayload(payload: JsonObject = {}) {
const sourceKey = const sourceKey =
String(payload.sourceKey || payload.key || "").trim() || "default"; String(payload.sourceKey || payload.key || "").trim() || "default";
return { return {
+10
View File
@@ -589,6 +589,16 @@
- `npm run typecheck` - `npm run typecheck`
- `npm run build` - `npm run build`
- `npm test` 共 139 个用例通过 - `npm test` 共 139 个用例通过
138. 后台平台配置观察 / 查询 / 写入辅助模块迁移到 `.ts`
- `src/services/admin/platform-config/observed-products.ts`
- `src/services/admin/platform-config/fulfillment.ts`
- `src/services/admin/platform-config/writes.ts`
139. 后台观察商品列表、履约手动查询结果组装、Agiso 店铺消息配置写入与 Cloudtentacles 来源配置归一化已进入 TS 编译链路;查询依赖、payload 与配置 map 补齐动态对象类型
140. Docker 内验证通过:
- `src/services/admin/platform-config/observed-products.test.js``fulfillment.test.js``writes.test.js` 共 8 个用例通过
- `npm run typecheck`
- `npm run build`
- `npm test` 共 139 个用例通过
## 下一步建议 ## 下一步建议