优化
This commit is contained in:
@@ -6,6 +6,22 @@ const storeSource = readFileSync(new URL('./firstLegOrders.ts', import.meta.url)
|
||||
const apiSource = readFileSync(new URL('../api/firstLeg.ts', import.meta.url), 'utf8')
|
||||
const unifiedApiSource = readFileSync(new URL('../api/unifiedOrders.ts', import.meta.url), 'utf8')
|
||||
|
||||
test('maps the first-leg aggregate list fields without loading detail rows', () => {
|
||||
assert.match(apiSource, /interface MerchantFirstLegOrderRow/)
|
||||
assert.match(apiSource, /skuNos: string \| string\[\] \| null/)
|
||||
assert.match(apiSource, /cargoes\?: Array<\{ skuNo\?: string \| null \}>/)
|
||||
assert.match(apiSource, /apiRequest<PageResult<MerchantFirstLegOrderRow>>/)
|
||||
assert.match(storeSource, /function mapFirstLegOrderRow/)
|
||||
for (const field of ['inboundId', 'inboundCode', 'channelName', 'destinationWarehouseName', 'packageCount', 'expressCompany', 'trackingNo', 'totalGrossWeightKg', 'totalNetWeightKg', 'totalVolumeCbm', 'totalQuantity', 'remark', 'shipmentId', 'referenceId', 'createdAt']) {
|
||||
assert.match(storeSource, new RegExp(`row\\.${field}`))
|
||||
}
|
||||
assert.match(storeSource, /row\.skuNos/)
|
||||
assert.match(storeSource, /row\.cargoes/)
|
||||
assert.match(storeSource, /chargeableWeightKg: null/)
|
||||
assert.match(storeSource, /chargeableVolumeCbm: null/)
|
||||
assert.match(storeSource, /orders\.value = orderResult\.value\.records\.map\(mapFirstLegOrderRow\)/)
|
||||
})
|
||||
|
||||
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'/)
|
||||
@@ -16,6 +32,13 @@ test('declares the documented merchant warehouse and first-leg endpoints', () =>
|
||||
assert.match(apiSource, /url: '\/merchant\/v1\/first-leg\/pricing\/channels'/)
|
||||
assert.match(apiSource, /params: \{ originWarehouseId \}/)
|
||||
assert.match(apiSource, /url: '\/merchant\/v1\/first-leg\/pricing\/estimate'/)
|
||||
assert.match(apiSource, /`\/merchant\/v1\/first-leg\/inbounds\/\$\{encodeURIComponent\(String\(inboundId\)\)\}\/carton-label-pdf`/)
|
||||
assert.match(apiSource, /`\/merchant\/v1\/first-leg\/orders\/\$\{encodeURIComponent\(String\(orderId\)\)\}\/carton-label-pdf`/)
|
||||
assert.match(apiSource, /url: '\/merchant\/v1\/first-leg\/orders\/carton-label-pdf'/)
|
||||
assert.match(apiSource, /data: orderIds\.map\(String\)/)
|
||||
assert.doesNotMatch(apiSource, /`\/merchant\/v1\/inbounds\/\$\{encodeURIComponent\(String\(inboundId\)\)\}\/carton-label-pdf`/)
|
||||
assert.match(apiSource, /signature === '%PDF-'/)
|
||||
assert.match(apiSource, /throw new ApiError\('箱唛服务未返回有效的 PDF 文件', 'INVALID_PDF'\)/)
|
||||
})
|
||||
|
||||
test('maps transport and status fields instead of treating container mode as transport mode', () => {
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
type FirstLegOrderPartyPayload,
|
||||
type FirstLegOrderSaveRequest,
|
||||
type MerchantFirstLegOrder,
|
||||
type MerchantFirstLegOrderRow,
|
||||
type MerchantFirstLegOrderDetail,
|
||||
type MerchantBatchDraftResponse,
|
||||
type MerchantWarehouse,
|
||||
@@ -305,7 +306,10 @@ function mapOrder(order: MerchantFirstLegOrder, warehouses: PlatformReceivingWar
|
||||
receivingWarehouseSnapshot: orderWarehouseSnapshot(order, warehouse), expectedDepartureDate: order.expectedShipDate ?? '', etd: '', eta: '',
|
||||
shipperPartyId: shipper?.id ?? '', shipperPartySnapshot: shipper, shipper: shipper?.name ?? '',
|
||||
consigneePartyId: consignee?.id ?? '', consigneePartySnapshot: consignee, consignee: consignee?.name ?? '',
|
||||
expressCompanyName: order.expressCompany ?? '', trackingNumber: order.expressTrackingNo ?? '', priority: 'NORMAL', customerRemark: order.customerRemark ?? '', operatorName: '',
|
||||
expressCompanyName: order.expressCompany ?? '', trackingNumber: order.expressTrackingNo ?? '', skuNos: order.skuNos ?? [],
|
||||
totalNetWeightKg: order.totalNetWeightKg ?? null, totalQuantity: order.totalQuantity ?? null,
|
||||
chargeableVolumeCbm: null, inboundedAt: order.inboundedAt ?? '', businessDate: '',
|
||||
priority: 'NORMAL', customerRemark: order.customerRemark ?? '', operatorName: '',
|
||||
status: clientStatus(order.status), version: order.version ?? 0,
|
||||
items: (detail?.cargoes ?? []).map((item) => ({
|
||||
id: String(item.id), sku: item.skuNo ?? '', upc: item.upcNo ?? '', cargoNameCn: item.cargoName, cargoNameEn: item.cargoNameEn ?? '',
|
||||
@@ -323,7 +327,14 @@ function mapOrder(order: MerchantFirstLegOrder, warehouses: PlatformReceivingWar
|
||||
productHeightCm: item.productHeightCm ?? 0, shipmentId: item.shipmentId ?? order.shipmentId ?? '',
|
||||
referenceId: item.referenceId ?? order.referenceId ?? '',
|
||||
})),
|
||||
timeline: detail ? timeline(detail) : [], businessSummary: businessSummary(), createdAt: order.createdAt, updatedAt: order.updatedAt,
|
||||
timeline: detail ? timeline(detail) : [], businessSummary: {
|
||||
...businessSummary(),
|
||||
totalPackageCount: order.totalPackageCount ?? null,
|
||||
actualGrossWeightKg: order.totalGrossWeightKg ?? null,
|
||||
actualVolumeCbm: order.totalVolumeCbm ?? null,
|
||||
chargeableWeightKg: order.chargeableWeightKg ?? null,
|
||||
inboundCode: order.inboundCode ?? '',
|
||||
}, createdAt: order.createdAt, updatedAt: order.updatedAt,
|
||||
tradeTerm: order.tradeTerm ?? '', destinationCountryCode: order.destinationCountryCode,
|
||||
destinationWarehouseId: order.destinationWarehouseId ? String(order.destinationWarehouseId) : '',
|
||||
destinationWarehouseName: order.destinationWarehouseName, pickupMethod: order.pickupMethod, channelCode: order.channelCode,
|
||||
@@ -337,23 +348,55 @@ function mapOrder(order: MerchantFirstLegOrder, warehouses: PlatformReceivingWar
|
||||
function mapUnifiedOrderRow(summary: MerchantUnifiedOrderRow, warehouses: PlatformReceivingWarehouse[]): FirstLegOrder {
|
||||
const warehouse = warehouses.find((item) => item.id === String(summary.receivingWarehouseId))
|
||||
return {
|
||||
id: String(summary.orderId), orderNo: summary.orderNo, referenceNo: '', transportMode: null,
|
||||
id: String(summary.orderId), orderNo: summary.orderNo, referenceNo: summary.referenceId ?? '', transportMode: null,
|
||||
businessType: 'EXPORT', origin: '', destination: summary.destinationWarehouseName ?? '',
|
||||
receivingWarehouseId: summary.receivingWarehouseId == null ? '' : String(summary.receivingWarehouseId),
|
||||
receivingWarehouseName: summary.receivingWarehouseName ?? '', receivingWarehouseSnapshot: warehouseSnapshot(warehouse),
|
||||
expectedDepartureDate: summary.expectedShipDate ?? '', etd: '', eta: '', shipperPartyId: '', shipperPartySnapshot: null,
|
||||
shipper: '', consigneePartyId: '', consigneePartySnapshot: null, consignee: '', expressCompanyName: '',
|
||||
trackingNumber: summary.delivery?.trackingNo ?? '', priority: 'NORMAL', customerRemark: '', operatorName: '',
|
||||
shipper: '', consigneePartyId: '', consigneePartySnapshot: null, consignee: '', expressCompanyName: summary.expressCompany ?? '',
|
||||
trackingNumber: summary.delivery?.trackingNo ?? '', skuNos: summary.skuNos ?? [], totalNetWeightKg: summary.totalNetWeightKg ?? null,
|
||||
totalQuantity: summary.totalQuantity ?? null, chargeableVolumeCbm: null,
|
||||
inboundedAt: summary.inboundedAt ?? '', businessDate: '', priority: 'NORMAL', customerRemark: '', operatorName: '',
|
||||
status: summary.mainStatus, version: 0, items: [], timeline: [], businessSummary: businessSummary(summary),
|
||||
createdAt: summary.createdAt, updatedAt: summary.updatedAt, tradeTerm: '', destinationCountryCode: '',
|
||||
destinationWarehouseId: summary.destinationWarehouseId == null ? '' : String(summary.destinationWarehouseId),
|
||||
destinationWarehouseName: summary.destinationWarehouseName ?? '', pickupMethod: 'SELF_EXPRESS', channelCode: '',
|
||||
channelName: summary.channelName ?? '', pricingTaxMode: 'TAX_INCLUDED', carrierId: '', carrierName: '', taxMode: 'BUY_DECLARATION', customsInspection: false,
|
||||
destinationType: 'PRIVATE', amazonWarehouseCode: '', shipmentId: '',
|
||||
destinationType: 'PRIVATE', amazonWarehouseCode: '', shipmentId: summary.shipmentId ?? '',
|
||||
receivingTime: '', submittedAt: '', completedAt: '',
|
||||
}
|
||||
}
|
||||
|
||||
function mapFirstLegOrderRow(row: MerchantFirstLegOrderRow): FirstLegOrder {
|
||||
const skuNos = Array.isArray(row.skuNos)
|
||||
? row.skuNos
|
||||
: (row.skuNos ?? '').split('、').map((value) => value.trim()).filter(Boolean)
|
||||
const resolvedSkuNos = skuNos.length ? skuNos : (row.cargoes ?? [])
|
||||
.map((cargo) => cargo.skuNo?.trim())
|
||||
.filter((value): value is string => Boolean(value))
|
||||
const uniqueSkuNos = [...new Set(resolvedSkuNos)]
|
||||
return {
|
||||
id: String(row.orderId), orderNo: row.orderNo, referenceNo: row.referenceId ?? '', transportMode: null,
|
||||
businessType: 'EXPORT', origin: '', destination: row.destinationWarehouseName ?? '', receivingWarehouseId: '',
|
||||
receivingWarehouseName: '', receivingWarehouseSnapshot: null, expectedDepartureDate: '', etd: '', eta: '',
|
||||
shipperPartyId: '', shipperPartySnapshot: null, shipper: '', consigneePartyId: '', consigneePartySnapshot: null,
|
||||
consignee: row.receivingCompanyName ?? '', expressCompanyName: row.expressCompany ?? '', trackingNumber: row.trackingNo ?? '',
|
||||
skuNos: uniqueSkuNos, totalNetWeightKg: row.totalNetWeightKg, totalQuantity: row.totalQuantity,
|
||||
chargeableVolumeCbm: null, inboundedAt: row.inboundedAt ?? '', businessDate: '', priority: 'NORMAL', customerRemark: row.remark ?? '',
|
||||
operatorName: '', status: clientStatus(row.status), version: 0, items: [], timeline: [],
|
||||
businessSummary: {
|
||||
...businessSummary(), totalPackageCount: row.packageCount, actualGrossWeightKg: row.totalGrossWeightKg ?? row.weightKg,
|
||||
actualVolumeCbm: row.totalVolumeCbm, chargeableWeightKg: null,
|
||||
inboundId: row.inboundId == null ? '' : String(row.inboundId), inboundCode: row.inboundCode ?? '',
|
||||
},
|
||||
createdAt: row.createdAt, updatedAt: row.createdAt, tradeTerm: '', destinationCountryCode: '', destinationWarehouseId: '',
|
||||
destinationWarehouseName: row.destinationWarehouseName ?? '', pickupMethod: 'SELF_EXPRESS', channelCode: '',
|
||||
channelName: row.channelName ?? '', pricingTaxMode: 'TAX_INCLUDED', carrierId: '', carrierName: '', taxMode: 'BUY_DECLARATION',
|
||||
customsInspection: false, destinationType: row.destinationType ?? 'PRIVATE', amazonWarehouseCode: '',
|
||||
shipmentId: row.shipmentId ?? row.internationalOrderNo ?? '', receivingTime: '', submittedAt: '', completedAt: '',
|
||||
}
|
||||
}
|
||||
|
||||
function mapUnifiedOrderDetail(detail: MerchantUnifiedOrderDetail, warehouses: PlatformReceivingWarehouse[]): FirstLegOrder {
|
||||
if (!detail?.summary || !detail.order?.order) throw new Error('订单详情数据不完整,请刷新列表后重试')
|
||||
const mapped = mapOrder(detail.order.order, warehouses, detail.order)
|
||||
@@ -366,8 +409,7 @@ function mapUnifiedOrderDetail(detail: MerchantUnifiedOrderDetail, warehouses: P
|
||||
}
|
||||
|
||||
type OrderListReadResult =
|
||||
| { source: 'unified'; records: MerchantUnifiedOrderRow[]; drafts: MerchantFirstLegOrder[]; draftError: string }
|
||||
| { source: 'legacy'; records: MerchantFirstLegOrder[] }
|
||||
| { source: 'first-leg'; records: MerchantFirstLegOrderRow[] }
|
||||
|
||||
interface ClientOrderReadQuery extends MerchantUnifiedOrderQuery {
|
||||
draftOnly?: boolean
|
||||
@@ -384,41 +426,9 @@ function legacyQuery(query: ClientOrderReadQuery, status?: ApiFirstLegStatus) {
|
||||
}
|
||||
|
||||
async function getOrdersForClient(query: ClientOrderReadQuery = {}): Promise<OrderListReadResult> {
|
||||
if (query.draftOnly) {
|
||||
const drafts = await getMerchantFirstLegOrders(legacyQuery(query, 'DRAFT'))
|
||||
return { source: 'legacy', records: drafts.records }
|
||||
}
|
||||
const includeDrafts = query.includeDrafts ?? true
|
||||
const unifiedQuery: MerchantUnifiedOrderQuery = {
|
||||
keyword: query.keyword,
|
||||
orderNo: query.orderNo,
|
||||
mainStatus: query.mainStatus,
|
||||
receivingWarehouseId: query.receivingWarehouseId,
|
||||
destinationWarehouseId: query.destinationWarehouseId,
|
||||
createdFrom: query.createdFrom,
|
||||
createdTo: query.createdTo,
|
||||
page: query.page,
|
||||
size: query.size,
|
||||
}
|
||||
try {
|
||||
const response = await getMerchantUnifiedOrders(unifiedQuery)
|
||||
if (!includeDrafts) return { source: 'unified', records: response.records, drafts: [], draftError: '' }
|
||||
try {
|
||||
const drafts = await getMerchantFirstLegOrders(legacyQuery(query, 'DRAFT'))
|
||||
return { source: 'unified', records: response.records, drafts: drafts.records, draftError: '' }
|
||||
} catch (error) {
|
||||
return {
|
||||
source: 'unified',
|
||||
records: response.records,
|
||||
drafts: [],
|
||||
draftError: error instanceof Error ? error.message : '订单草稿加载失败',
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (!isUnifiedOrderQueryUnavailable(error)) throw error
|
||||
const response = await getMerchantFirstLegOrders(legacyQuery(query))
|
||||
return { source: 'legacy', records: response.records }
|
||||
}
|
||||
const status = query.draftOnly ? 'DRAFT' : undefined
|
||||
const response = await getMerchantFirstLegOrders(legacyQuery(query, status))
|
||||
return { source: 'first-leg', records: response.records }
|
||||
}
|
||||
|
||||
function mapWarehouse(item: MerchantWarehouse): ClientWarehouse {
|
||||
@@ -483,15 +493,7 @@ export const useFirstLegOrdersStore = defineStore('client-first-leg-orders', ()
|
||||
const [orderResult, warehouseResult] = await Promise.allSettled([getOrdersForClient(query), loadWarehouseType('DOMESTIC', true)])
|
||||
if (warehouseResult.status === 'rejected' && !warehouseLoadError.value) warehouseLoadError.value = warehouseResult.reason instanceof Error ? warehouseResult.reason.message : '公共仓库数据加载失败'
|
||||
if (orderResult.status === 'fulfilled') {
|
||||
if (orderResult.value.source === 'unified') {
|
||||
draftLoadError.value = orderResult.value.draftError
|
||||
orders.value = [
|
||||
...orderResult.value.drafts.map((item) => mapOrder(item, warehouses.value)),
|
||||
...orderResult.value.records.map((item) => mapUnifiedOrderRow(item, warehouses.value)),
|
||||
].sort((left, right) => Date.parse(right.createdAt) - Date.parse(left.createdAt))
|
||||
} else {
|
||||
orders.value = orderResult.value.records.map((item) => mapOrder(item, warehouses.value))
|
||||
}
|
||||
orders.value = orderResult.value.records.map(mapFirstLegOrderRow)
|
||||
} else {
|
||||
loadError.value = orderResult.reason instanceof Error ? orderResult.reason.message : '订单数据加载失败'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user