feat(procurement): add sample fulfillment operation workspace

This commit is contained in:
2026-10-10 02:19:39 +08:00
parent 2f23e30e20
commit 302cc50a4b
30 changed files with 2107 additions and 301 deletions
@@ -4,9 +4,9 @@ const overseas = vi.hoisted(() => ({ get: vi.fn(), patch: vi.fn(), post: vi.fn()
vi.mock('@/shared/api/http', async (importOriginal) => ({ ...(await importOriginal<typeof import('@/shared/api/http')>()), http: overseas }))
import {
createLocalLooseboardOrder, createUsTruckOrder, getLocalLooseboardOrder, getOverseasPurchase, getUsTruckOrder,
createLocalLooseboardOrder, createUsTruckOrder, getLocalLooseboardOrder, getOverseasPurchase, getOverseasPurchaseEditor, getUsTruckOrder,
listLocalLooseboardOrders, listOverseasPurchaseCustomerOptions, listOverseasPurchases,
listOverseasPurchaseWarehouseOptions, listUsTruckOrders, reviewOverseasPurchase, updateLocalLooseboardOrder, updateOverseasPurchase,
listOverseasPurchaseWarehouseOptions, listUsTruckOrders, updateLocalLooseboardOrder, updateOverseasPurchase,
updateUsTruckOrder,
} from './platformOverseasBusiness'
import type { UpdateLocalTransportOrderRequest } from '../types'
@@ -15,7 +15,7 @@ const envelope = <T>(data: T) => ({ code: '200', message: 'success', data })
const purchaseSummary = {
id: '9007199254740993', orderNo: 'OP-1', customerId: '10001', customerName: '客户一', purchaseCategory: '服装', productName: '外套',
productSpecification: null, purchaseQuantity: 10, budgetUnitPrice: 12.34, currency: 'USD', purchaseWarehouseId: '9007199254740995',
purchaseWarehouseName: '采购仓', inboundQuantity: 5, outboundQuantity: 0, inventoryQuantity: 5, status: 'PENDING_OUTBOUND', version: 4,
purchaseWarehouseName: '采购仓', status: 'WAIT_PACKING', version: 4,
createdAt: '2026-08-01T00:00:00', updatedAt: '2026-08-02T00:00:00',
}
const truckSummary = {
@@ -48,23 +48,24 @@ describe('platform overseas business API adapter', () => {
})
it('loads and patches procurement detail with three-state null payloads', async () => {
const detail = { summary: purchaseSummary, productUrl: null, histories: [{ operationType: 'UPDATE', fromStatus: 'APPROVED', toStatus: 'APPROVED', operatorId: '7', changeDetail: '{}', remark: null, createdAt: '2026-08-02T00:00:00' }] }
overseas.get.mockResolvedValue(envelope(detail))
expect((await getOverseasPurchase('OP/1', '10001')).histories[0]?.operationType).toBe('UPDATE')
const detail = { summary: purchaseSummary, productUrl: null, histories: [{ operationType: 'UPDATE', fromStatus: 'WAIT_PURCHASE', toStatus: 'WAIT_PURCHASE', operatorId: '7', changeDetail: '{}', remark: null, createdAt: '2026-08-02T00:00:00' }] }
overseas.get.mockResolvedValue(envelope({ customerView: { order: purchaseSummary }, reviewHistory: detail.histories, physical: { dispositions: [], receipts: [], cartons: [] }, fees: [], feeCorrections: [], controls: { notes: [], remaining: [], closures: [], closureItems: [] }, files: [], transport: { overseasCargo: [], domesticCargo: [], overseasLabels: null, domesticLabels: null, shipments: [] } }))
expect((await getOverseasPurchase('OP/1', '10001')).reviewHistory[0]?.operationType).toBe('UPDATE')
overseas.patch.mockResolvedValue(envelope(detail))
const payload = { version: 4, productUrl: null, estimatedArrivalAt: null }
const payload = { version: 4, remark: null }
await updateOverseasPurchase('OP-1', '10001', payload)
expect(overseas.patch).toHaveBeenCalledWith('/platform/v1/last-leg/overseas-procurements/OP-1', payload, { params: { customerId: '10001' } })
})
it('submits procurement review with version and idempotency data', async () => {
const detail = { summary: { ...purchaseSummary, status: 'APPROVED', version: 5 }, histories: [] }
overseas.post.mockResolvedValue(envelope(detail))
const payload = { version: 4, decision: 'APPROVE' as const, idempotencyKey: 'review-key', remark: '资料齐全' }
const result = await reviewOverseasPurchase('OP/1', '10001', payload)
expect(overseas.post).toHaveBeenCalledWith('/platform/v1/last-leg/overseas-procurements/OP%2F1/review', payload, { params: { customerId: '10001' } })
expect(result.status).toBe('APPROVED')
expect(result.version).toBe(5)
it('reads the aggregate editor context and strips obsolete mutation fields', async () => {
const detail = { customerView: { order: { orderNo: 'OP/1', customerId: '10001', productName: '外套', purchaseQuantity: 10, version: 4 } }, internalRemark: '内部' }
overseas.get.mockResolvedValue(envelope(detail))
expect(await getOverseasPurchaseEditor('OP/1', '10001')).toEqual(detail)
expect(overseas.get).toHaveBeenCalledWith('/platform/v1/last-leg/overseas-procurements/OP%2F1', { params: { customerId: '10001' } })
overseas.patch.mockResolvedValue(envelope({ summary: purchaseSummary }))
const obsolete = { version: 4, remark: '内部', inboundQuantity: 200, purchaseWarehouseId: 'other', productName: 'changed' }
await updateOverseasPurchase('OP/1', '10001', obsolete)
expect(overseas.patch).toHaveBeenCalledWith('/platform/v1/last-leg/overseas-procurements/OP%2F1', { version: 4, remark: '内部' }, { params: { customerId: '10001' } })
})
it('supports platform truck list/detail/create/update without status endpoints', async () => {