Webhook 增加订单号查询

This commit is contained in:
yml2213
2026-04-13 17:32:42 +08:00
parent 96d1644b1c
commit 7008c85e58
6 changed files with 126 additions and 55 deletions
@@ -75,6 +75,7 @@ export async function listWebhookEvents({
pageSize = 20,
provider = '',
platform = '',
platformOrderId = '',
processed = '',
relatedOrderId = '',
dateFrom = '',
@@ -94,6 +95,11 @@ export async function listWebhookEvents({
filters.push(`platform = $${params.length}`)
}
if (platformOrderId) {
params.push(`%${platformOrderId}%`)
filters.push(`(event_key ILIKE $${params.length} OR body_json::text ILIKE $${params.length})`)
}
if (processed === '0' || processed === '1') {
params.push(processed === '1')
filters.push(`processed = $${params.length}`)
@@ -41,6 +41,7 @@ import { nowIso } from '../../utils/time.js'
import { reserveInventoryForTask } from '../order/inventory-service.js'
import { replayAgisoTradeWebhookEvent } from '../order/webhook-service.js'
import { syncConfiguredFulfillmentBindings } from '../bootstrap/fulfillment-bootstrap-service.js'
import { extractAgisoTradePayload, resolveAgisoTradePlatformOrderId } from '../order/agiso-trade-parsing.js'
import { normalizeProductName } from '../order/product-match-service.js'
import { normalizeDateQuery, normalizePage, normalizePageSize, safeParseJson } from './admin-query-utils.js'
import { normalizeAdminRole } from './admin-auth-service.js'
@@ -493,6 +494,7 @@ export async function getAdminWebhookEvents(query = {}) {
pageSize,
provider: String(query.provider || '').trim(),
platform: String(query.platform || '').trim(),
platformOrderId: String(query.platformOrderId || '').trim(),
processed: String(query.processed || '').trim(),
relatedOrderId: String(query.relatedOrderId || '').trim(),
dateFrom: normalizeDateQuery(query.dateFrom),
@@ -1404,7 +1406,6 @@ async function mapAdminWebhookEvent(item, { includeRaw = false } = {}) {
const body = normalizeRecord(safeParseJson(item.body_json))
const payload = extractWebhookPayload(body)
const itemSources = extractWebhookItemSources(payload)
const firstItem = itemSources[0] || {}
const rawAmount = pickFirstNonEmpty([
payload.total_fee,
payload.totalFee,
@@ -1473,18 +1474,7 @@ async function mapAdminWebhookEvent(item, { includeRaw = false } = {}) {
processError: item.process_error,
relatedOrderId: item.related_order_id,
createdAt: item.created_at,
platformOrderId: pickFirstNonEmpty([
payload.biz_order_id,
payload.bizOrderId,
payload.Tid,
payload.tid,
payload.Oid,
payload.oid,
payload.order_id,
payload.orderId,
firstItem.Oid,
firstItem.oid,
]),
platformOrderId: resolveAgisoTradePlatformOrderId(payload),
buyerId: pickFirstNonEmpty([
payload.buyer_id,
payload.buyerId,
@@ -2238,14 +2228,7 @@ function isPlainObject(value) {
}
function extractWebhookPayload(body) {
const normalizedBody = normalizeRecord(body)
const rawJson = String(normalizedBody.json || normalizedBody.JSON || '').trim()
if (rawJson) {
return normalizeRecord(safeParseJson(rawJson))
}
return normalizedBody
return extractAgisoTradePayload(body)
}
function extractWebhookItemSources(payload) {
@@ -0,0 +1,71 @@
import { parseJsonObject } from '../../utils/json.js'
export function extractAgisoTradePayload(body) {
const normalizedBody = normalizeRecord(body)
const rawJson = String(normalizedBody.json || normalizedBody.JSON || '').trim()
if (rawJson) {
return normalizeRecord(parseJsonObject(rawJson, { preserveLargeIntegers: true }))
}
return normalizedBody
}
export function resolveAgisoTradePlatformOrderId(payload) {
const normalizedPayload = normalizeRecord(payload)
const firstItem = extractAgisoTradeOrderItemSources(normalizedPayload)[0] || {}
return pickFirstNonEmpty([
normalizedPayload.biz_order_id,
normalizedPayload.Tid,
normalizedPayload.tid,
normalizedPayload.Oid,
normalizedPayload.oid,
normalizedPayload.order_id,
normalizedPayload.orderId,
firstItem.Oid,
firstItem.oid,
])
}
export function extractAgisoTradeOrderItemSources(payload) {
const normalizedPayload = normalizeRecord(payload)
const candidates = [
normalizedPayload.items,
normalizedPayload.Items,
normalizedPayload.orders,
normalizedPayload.Orders,
normalizedPayload.order_list,
normalizedPayload.OrderList,
]
for (const current of candidates) {
if (Array.isArray(current) && current.length > 0) {
return current.map((item) => normalizeRecord(item)).filter((item) => Object.keys(item).length > 0)
}
}
if (Object.keys(normalizedPayload).length > 0) {
return [normalizedPayload]
}
return []
}
function normalizeRecord(value) {
return value && typeof value === 'object' && !Array.isArray(value) ? value : {}
}
function pickFirstNonEmpty(values) {
for (const value of values) {
if (typeof value === 'string' && value.trim()) {
return value.trim()
}
if (typeof value === 'number' && Number.isFinite(value)) {
return String(value)
}
}
return ''
}
@@ -0,0 +1,31 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { extractAgisoTradePayload, resolveAgisoTradePlatformOrderId } from './agiso-trade-parsing.js'
test('extractAgisoTradePayload preserves large integer order ids from raw json', () => {
const payload = extractAgisoTradePayload({
json: '{"biz_order_id":4502259793206016214,"item_id":978102431355,"order_status":4}',
})
assert.equal(payload.biz_order_id, '4502259793206016214')
assert.equal(typeof payload.biz_order_id, 'string')
})
test('resolveAgisoTradePlatformOrderId keeps exact webhook order id', () => {
const payload = extractAgisoTradePayload({
json: '{"biz_order_id":4502259793206016214,"item_id":978102431355,"order_status":4}',
})
assert.equal(resolveAgisoTradePlatformOrderId(payload), '4502259793206016214')
})
test('resolveAgisoTradePlatformOrderId falls back to tid when biz_order_id is absent', () => {
assert.equal(
resolveAgisoTradePlatformOrderId({
tid: '4502251008019011224',
orders: [{ oid: '4502251008019011888' }],
}),
'4502251008019011224',
)
})
@@ -3,6 +3,10 @@ import crypto from 'node:crypto'
import { runtimeConfig } from '../../config/runtime.js'
import { createWebhookEvent, updateWebhookEvent } from '../../repositories/webhook-event-repo.js'
import { enrichAgisoXianyuTradeOrder } from '../platforms/agiso/xianyu/order-detail-service.js'
import {
extractAgisoTradePayload,
resolveAgisoTradePlatformOrderId,
} from './agiso-trade-parsing.js'
import { upsertOrderFromWebhook } from './order-service.js'
import { hasConfiguredOrderItems } from './product-match-service.js'
import { createHttpError } from '../../utils/http.js'
@@ -305,7 +309,7 @@ function parseAgisoTradeRequest(requestLike) {
const query = normalizeRecord(requestLike.query)
const body = normalizeRecord(requestLike.body)
const rawJson = String(body.json || '').trim()
const payload = rawJson ? parsePayloadJson(rawJson) : body
const payload = rawJson ? parsePayloadJson(rawJson) : extractAgisoTradePayload(body)
const timestamp = String(query.timestamp || '').trim()
const sign = String(query.sign || '').trim().toLowerCase()
const provider = 'agiso'
@@ -323,19 +327,7 @@ function parseAgisoTradeRequest(requestLike) {
const shop = resolveShop(payload)
const eventType = resolveEventType(query.aopic, payload)
const signatureValid = verifyAgisoSignature({ rawJson, timestamp, sign })
const itemSources = extractOrderItemSources(payload)
const firstItem = itemSources[0] || {}
const platformOrderId = pickFirstNonEmpty([
payload.biz_order_id,
payload.Tid,
payload.tid,
payload.Oid,
payload.oid,
payload.order_id,
payload.orderId,
firstItem.Oid,
firstItem.oid,
])
const platformOrderId = resolveAgisoTradePlatformOrderId(payload)
return {
provider,
@@ -663,25 +655,6 @@ function normalizeOrderItems(payload) {
})
}
function extractOrderItemSources(payload) {
const candidates = [
payload.items,
payload.Items,
payload.orders,
payload.Orders,
payload.order_list,
payload.OrderList,
]
for (const current of candidates) {
if (Array.isArray(current) && current.length > 0) {
return current
}
}
return [payload]
}
function resolveBusinessPlatform(rawPlatform) {
const normalized = normalizePlatformKey(rawPlatform)
@@ -910,6 +883,10 @@ function isPlainObject(value) {
}
function safeParseJson(rawValue) {
if (rawValue && typeof rawValue === 'object' && !Array.isArray(rawValue)) {
return rawValue
}
const normalized = String(rawValue || '').trim()
if (!normalized) {