This commit is contained in:
2026-08-13 09:48:51 +08:00
parent 3366c58a5e
commit d765bd4340
10 changed files with 799 additions and 27 deletions
@@ -9,6 +9,7 @@ const unifiedApiSource = readFileSync(new URL('../api/unifiedOrders.ts', import.
test('declares the documented merchant warehouse and first-leg endpoints', () => {
assert.match(apiSource, /url: '\/merchant\/v1\/warehouses'/)
assert.match(apiSource, /url: '\/merchant\/v1\/orders\/first-leg'/)
assert.match(apiSource, /url: '\/merchant\/v1\/orders\/first-leg\/batch'/)
assert.match(apiSource, /`\/merchant\/v1\/orders\/first-leg\/\$\{id\}`/)
assert.match(apiSource, /`\/merchant\/v1\/orders\/first-leg\/\$\{id\}\/submit`/)
assert.match(apiSource, /`\/merchant\/v1\/warehouses\/\$\{id\}`/)
@@ -125,6 +126,9 @@ test('does not expose the out-of-scope cancellation write', () => {
test('sends an idempotency key for create and submit writes', () => {
assert.match(apiSource, /'Idempotency-Key': createIdempotencyKey\('first-leg-create'\)/)
assert.match(apiSource, /'Idempotency-Key': createIdempotencyKey\(`first-leg-submit-\$\{id\}`\)/)
assert.match(apiSource, /createMerchantFirstLegOrderBatch\(items: MerchantBatchDraftItem\[\], idempotencyKey: string\)/)
assert.match(apiSource, /headers: \{ 'Idempotency-Key': idempotencyKey \}/)
assert.match(storeSource, /createMerchantFirstLegOrderBatch\(items, idempotencyKey\)/)
})
test('does not expose the contradictory backend rejected state in the client model', () => {
+35 -12
View File
@@ -1,6 +1,7 @@
import { computed, ref } from 'vue'
import { defineStore } from 'pinia'
import {
createMerchantFirstLegOrderBatch,
createMerchantFirstLegOrder,
getMerchantFirstLegOrder,
getMerchantFirstLegOrders,
@@ -13,6 +14,7 @@ import {
type FirstLegOrderSaveRequest,
type MerchantFirstLegOrder,
type MerchantFirstLegOrderDetail,
type MerchantBatchDraftResponse,
type MerchantWarehouse,
} from '@/modules/first-leg/api/firstLeg'
import {
@@ -152,6 +154,21 @@ function savePayload(draft: FirstLegOrderDraft, warehouse: ClientWarehouse, cust
}
}
function prepareDraftForSave(draft: FirstLegOrderDraft, warehouses: ClientWarehouse[]) {
const warehouse = warehouses.find((item) => item.id === draft.receivingWarehouseId)
if (!warehouse || warehouse.warehouseType !== 'DOMESTIC') throw new Error('所选国内收货仓当前不可用')
if (draft.destinationType !== 'PRIVATE') {
const destinationWarehouse = warehouses.find((item) => item.id === draft.destinationWarehouseId && item.warehouseType === draft.destinationType)
if (!destinationWarehouse) throw new Error('所选目的仓当前不可用,请重新选择')
draft.destinationWarehouseName = destinationWarehouse.name
draft.destinationCountryCode = destinationWarehouse.countryCode
draft.amazonWarehouseCode = draft.destinationType === 'FBA' ? destinationWarehouse.code : ''
} else {
draft.destinationWarehouseId = ''
}
return warehouse
}
function warehouseSnapshot(warehouse?: PlatformReceivingWarehouse): PlatformReceivingWarehouseSnapshot | null {
return warehouse ? { id: warehouse.id, code: warehouse.code, name: warehouse.name, province: warehouse.province, city: warehouse.city, address: warehouse.address } : null
}
@@ -524,17 +541,7 @@ export const useFirstLegOrdersStore = defineStore('client-first-leg-orders', ()
}
async function saveDraft(draft: FirstLegOrderDraft, customerName: string, id?: string) {
const warehouse = warehouses.value.find((item) => item.id === draft.receivingWarehouseId)
if (!warehouse || warehouse.warehouseType !== 'DOMESTIC') throw new Error('所选国内收货仓当前不可用')
if (draft.destinationType !== 'PRIVATE') {
const destinationWarehouse = warehouses.value.find((item) => item.id === draft.destinationWarehouseId && item.warehouseType === draft.destinationType)
if (!destinationWarehouse) throw new Error('所选目的仓当前不可用,请重新选择')
draft.destinationWarehouseName = destinationWarehouse.name
draft.destinationCountryCode = destinationWarehouse.countryCode
draft.amazonWarehouseCode = draft.destinationType === 'FBA' ? destinationWarehouse.code : ''
} else {
draft.destinationWarehouseId = ''
}
const warehouse = prepareDraftForSave(draft, warehouses.value)
if (id) {
const order = getById(id)
if (!order || !canClientEditFirstLegOrder(order.status)) throw new Error('当前订单状态不允许编辑')
@@ -545,6 +552,18 @@ export const useFirstLegOrdersStore = defineStore('client-first-leg-orders', ()
return loadLegacyDetail(String(createdId))
}
async function saveDraftBatch(
drafts: Array<{ clientRowId: string; draft: FirstLegOrderDraft }>,
customerName: string,
idempotencyKey: string,
): Promise<MerchantBatchDraftResponse> {
const items = drafts.map(({ clientRowId, draft }) => {
const warehouse = prepareDraftForSave(draft, warehouses.value)
return { clientRowId, draft: savePayload(draft, warehouse, customerName) }
})
return createMerchantFirstLegOrderBatch(items, idempotencyKey)
}
async function submit(draft: FirstLegOrderDraft, customerName: string, id?: string, companyAuditStatus?: MerchantTenantStatus) {
if (companyAuditStatus && companyAuditStatus !== 'ACTIVE') throw new Error('企业资料尚未审核通过,请先完善企业资料并等待平台审核')
const order = await saveDraft(draft, customerName, id)
@@ -552,5 +571,9 @@ export const useFirstLegOrdersStore = defineStore('client-first-leg-orders', ()
return loadUnifiedDetail(order.id)
}
return { orders, warehouses, loading, loadedFromApi, loadError, warehouseLoadError, draftLoadError, activeCount, pendingCount, getById, load, loadDetail, loadWarehouseDetail, loadWarehouseType, saveDraft, submit }
async function loadDraftDetail(id: string) {
return loadLegacyDetail(id)
}
return { orders, warehouses, loading, loadedFromApi, loadError, warehouseLoadError, draftLoadError, activeCount, pendingCount, getById, load, loadDetail, loadDraftDetail, loadWarehouseDetail, loadWarehouseType, saveDraft, saveDraftBatch, submit }
})