From c391122c67fb4b49c7259f4b22b54251b3252c06 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Tue, 11 Aug 2026 10:15:29 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B1=A5=E7=BA=A6=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=88=9B=E5=BB=BA=E7=AD=9B=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/services/order/order-service.test.ts | 37 ++++++++++++++++++- .../src/services/order/order-service.ts | 25 ++++++++----- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/apps/backend/src/services/order/order-service.test.ts b/apps/backend/src/services/order/order-service.test.ts index c1ba1b3c..bd091c6b 100644 --- a/apps/backend/src/services/order/order-service.test.ts +++ b/apps/backend/src/services/order/order-service.test.ts @@ -1,7 +1,42 @@ import test from 'node:test' import assert from 'node:assert/strict' -import { mergeSourceOrderState } from './order-service.js' +import { + isOrderItemConfiguredForFulfillment, + mergeSourceOrderState, +} from './order-service.js' +import type { OrderItemRow } from '../../types/repository/rows.js' + +function buildOrderItem(snapshot: OrderItemRow['item_snapshot_json']): OrderItemRow { + return { + id: 1, + order_id: 1, + sku_code: 'TEST-SKU', + sku_name: '测试商品', + quantity: 1, + spec_json: '{}', + item_snapshot_json: snapshot, + } +} + +test('isOrderItemConfiguredForFulfillment accepts PostgreSQL JSONB object results', () => { + assert.equal( + isOrderItemConfiguredForFulfillment(buildOrderItem({ isConfigured: true })), + true, + ) +}) + +test('isOrderItemConfiguredForFulfillment accepts serialized snapshots', () => { + assert.equal( + isOrderItemConfiguredForFulfillment(buildOrderItem('{"isConfigured":true}')), + true, + ) +}) + +test('isOrderItemConfiguredForFulfillment rejects unconfigured or malformed snapshots', () => { + assert.equal(isOrderItemConfiguredForFulfillment(buildOrderItem({})), false) + assert.equal(isOrderItemConfiguredForFulfillment(buildOrderItem('{invalid')), false) +}) test('mergeSourceOrderState keeps paid state when a late created source event arrives', () => { const merged = mergeSourceOrderState( diff --git a/apps/backend/src/services/order/order-service.ts b/apps/backend/src/services/order/order-service.ts index 1d03e159..32c1b421 100644 --- a/apps/backend/src/services/order/order-service.ts +++ b/apps/backend/src/services/order/order-service.ts @@ -283,17 +283,24 @@ export function mergeSourceOrderState( } } -function isOrderItemConfiguredForFulfillment(item: OrderItemRow): boolean { +export function isOrderItemConfiguredForFulfillment(item: OrderItemRow): boolean { + const rawSnapshot = item.item_snapshot_json + const snapshot = + rawSnapshot && typeof rawSnapshot === 'object' && !Array.isArray(rawSnapshot) + ? rawSnapshot + : parseOrderItemSnapshot(rawSnapshot) + + return Boolean(snapshot && snapshot.isConfigured === true) +} + +function parseOrderItemSnapshot(value: unknown): Record | null { try { - const snapshot = JSON.parse(String(item.item_snapshot_json || '{}')) - return Boolean( - snapshot && - typeof snapshot === 'object' && - !Array.isArray(snapshot) && - snapshot.isConfigured === true, - ) + const parsed = JSON.parse(String(value || '{}')) + return parsed && typeof parsed === 'object' && !Array.isArray(parsed) + ? parsed as Record + : null } catch { - return false + return null } }