后端迁移订单详情服务

This commit is contained in:
yml
2026-05-21 14:56:14 +08:00
parent 6d6e64beda
commit b9d84679a1
2 changed files with 129 additions and 15 deletions
@@ -1,5 +1,3 @@
// @ts-nocheck
import crypto from 'node:crypto'
import { runtimeConfig } from '../../../../config/runtime.js'
@@ -11,11 +9,113 @@ import { parseJsonObject } from '../../../../utils/json.js'
const DEFAULT_DETAIL_TIMEOUT_MS = 5000
export async function enrichAgisoXianyuTradeOrder(parsed, { requestId = '' } = {}) {
type JsonObject = Record<string, unknown>
type AgisoParsedTrade = {
provider?: string
platform?: string
shopId?: string
shopName?: string
platformOrderId?: string
totalAmount?: number
paidAt?: string | null
buyerId?: string
buyerName?: string
receiverContact?: string
rawPayload?: JsonObject
items?: AgisoOrderItem[]
[key: string]: unknown
}
type AgisoOrderItem = {
skuCode: string
skuName: string
externalItemId: string
externalSkuCode: string
externalSkuName: string
quantity: number
spec: JsonObject
snapshot: {
externalItemId: string
externalSkuCode: string
externalSkuName: string
}
}
type AgisoDetailQueryInput = {
shopId?: string
platformOrderId?: string
requestId?: string
}
type FetchResponseLike = {
status: number
text: () => Promise<string>
}
type FetchWithTimeout = (
url: string,
options: RequestInit,
timeoutMs: number,
) => Promise<FetchResponseLike>
type AgisoDetailDeps = {
fetchWithTimeout?: FetchWithTimeout
queryAgisoXianyuOrderDetail?: (
input: Required<AgisoDetailQueryInput>,
) => Promise<AgisoDetailResult>
}
type AgisoTradeDetailConfig = {
endpoint: string
apiVersion: string
accessToken: string
appSecret: string
timeoutMs: number
}
type AgisoShopConfig = {
accessToken?: string
appSecret?: string
tradeDetailEndpoint?: string
tradeDetailApiVersion?: string
tradeDetailTimeoutMs?: string | number
}
type DeliveryState = {
shipped: boolean
shipTime: number
orderStatus: number
}
type AgisoDetailResult = {
success: boolean
reason: string
errorMessage: string
responseStatus: number
payload: JsonObject
detailPayload: JsonObject
totalAmountFen: number
shipped: boolean
shipTime: number
orderStatus: number
}
type ExternalSkuDescriptor = {
raw: string
externalSkuCode: string
externalSkuName: string
}
export async function enrichAgisoXianyuTradeOrder(parsed: AgisoParsedTrade, { requestId = '' } = {}) {
return enrichAgisoXianyuTradeOrderWithDeps(parsed, { requestId })
}
export async function enrichAgisoXianyuTradeOrderWithDeps(parsed, { requestId = '' } = {}, deps = {}) {
export async function enrichAgisoXianyuTradeOrderWithDeps(
parsed: AgisoParsedTrade,
{ requestId = '' } = {},
deps: AgisoDetailDeps = {},
) {
const queryOrderDetail = deps.queryAgisoXianyuOrderDetail || queryAgisoXianyuOrderDetail
if (!shouldHydrateAgisoXianyuTradeOrder(parsed)) {
@@ -69,8 +169,8 @@ export async function queryAgisoXianyuOrderDetail({ shopId = '', platformOrderId
export async function queryAgisoXianyuOrderDetailWithDeps(
{ shopId = '', platformOrderId = '', requestId = '' } = {},
deps = {},
) {
deps: AgisoDetailDeps = {},
): Promise<AgisoDetailResult> {
const requestWithTimeout = deps.fetchWithTimeout || fetchWithTimeout
const normalizedShopId = String(shopId || '').trim()
const normalizedPlatformOrderId = String(platformOrderId || '').trim()
@@ -114,7 +214,7 @@ export async function queryAgisoXianyuOrderDetailWithDeps(
body: new URLSearchParams(requestBody).toString(),
}, config.timeoutMs)
const rawText = await response.text()
const payload = parseJsonObject(rawText, { preserveLargeIntegers: true })
const payload = parseJsonObject(rawText, { preserveLargeIntegers: true }) as JsonObject
const detailPayload = extractAgisoDetailPayload(payload)
const delivery = resolveAgisoXianyuOrderDeliveryState(detailPayload)
const totalAmountFen = resolveTotalAmountFen(detailPayload)
@@ -216,16 +316,16 @@ export async function queryAgisoXianyuOrderDetailWithDeps(
}
}
function shouldHydrateAgisoXianyuTradeOrder(parsed) {
function shouldHydrateAgisoXianyuTradeOrder(parsed: AgisoParsedTrade | null | undefined): boolean {
return parsed?.provider === 'agiso'
&& parsed?.platform === 'xianyu'
&& String(parsed?.platformOrderId || '').trim()
&& Number(parsed?.totalAmount || 0) <= 0
}
function resolveAgisoXianyuTradeDetailConfig(shopId) {
const baseConfig = runtimeConfig.platforms?.agiso?.tradeDetail || {}
const shopConfig = getAgisoShopConfig(shopId) || {}
function resolveAgisoXianyuTradeDetailConfig(shopId: string): AgisoTradeDetailConfig {
const baseConfig = runtimeConfig.platforms.agiso.tradeDetail
const shopConfig = (getAgisoShopConfig(shopId) || {}) as AgisoShopConfig
return {
endpoint: String(shopConfig.tradeDetailEndpoint || baseConfig.endpoint || '').trim(),
@@ -236,7 +336,10 @@ function resolveAgisoXianyuTradeDetailConfig(shopId) {
}
}
function buildRequestHeaders({ accessToken, apiVersion }) {
function buildRequestHeaders({
accessToken,
apiVersion,
}: { accessToken: string; apiVersion: string }): Record<string, string> {
return {
Authorization: `Bearer ${accessToken}`,
ApiVersion: apiVersion,
@@ -244,9 +347,12 @@ function buildRequestHeaders({ accessToken, apiVersion }) {
}
}
function buildRequestBody({ platformOrderId, appSecret }) {
function buildRequestBody({
platformOrderId,
appSecret,
}: { platformOrderId: string; appSecret: string }): Record<string, string> {
const timestamp = String(Math.floor(Date.now() / 1000))
const payload = {
const payload: Record<string, string> = {
tid: String(platformOrderId || '').trim(),
timestamp,
}
@@ -255,7 +361,7 @@ function buildRequestBody({ platformOrderId, appSecret }) {
return payload
}
function generateSign(params, appSecret) {
function generateSign(params: Record<string, string>, appSecret: string): string {
const sortedEntries = Object.entries(params).sort(([left], [right]) => left.localeCompare(right))
let raw = appSecret
@@ -349,6 +349,14 @@
- `npm run typecheck`
- `npm run build`
- `npm test` 共 136 个用例通过
57. Agiso 订单详情服务迁移到 `.ts`
- `src/services/platforms/agiso/xianyu/order-detail-service.ts`
58. 订单详情补查入参、依赖注入、HTTP 响应、详情查询结果、发货状态、店铺配置、外部 SKU 解析结果已显式类型化
59. Docker 内验证通过:
- `src/services/platforms/agiso/xianyu/order-detail-service.test.js` 共 5 个用例通过
- `npm run typecheck`
- `npm run build`
- `npm test` 共 136 个用例通过
## 下一步建议