diff --git a/src/modules/first-leg/store/firstLegOrders.test.mjs b/src/modules/first-leg/store/firstLegOrders.test.mjs index ae720a8..1956517 100644 --- a/src/modules/first-leg/store/firstLegOrders.test.mjs +++ b/src/modules/first-leg/store/firstLegOrders.test.mjs @@ -71,6 +71,9 @@ test('declares the final C02 row and detail contract in the API adapter', () => assert.match(unifiedApiSource, /mainStatus: ApiUnifiedOrderMainStatus/) assert.match(unifiedApiSource, /nextAction: string \| null/) assert.match(unifiedApiSource, /customerRemark: string \| null/) + for (const field of ['pickupMethod', 'requestedPickupAt', 'containerMode', 'destinationType', 'destinationCode', 'skuNos', 'totalQuantity', 'totalNetWeightKg', 'chargeableVolumeCbm', 'inboundCompletedAt', 'shipmentId', 'referenceId']) { + assert.match(unifiedApiSource, new RegExp(`${field}:`)) + } assert.match(unifiedApiSource, /loadingVersion: number/) assert.match(unifiedApiSource, /pickingVersion: number/) assert.match(unifiedApiSource, /summary: MerchantUnifiedOrderRow/) @@ -99,9 +102,16 @@ test('routes supported filters to C02 without sending DRAFT as a main status', ( assert.match(storeSource, /getMerchantUnifiedOrders\(unifiedQuery\)/) }) -test('maps C02 rows by orderId and leaves absent transport details unknown', () => { +test('maps C02 authoritative status, transport, cargo and pickup snapshots', () => { assert.match(storeSource, /id: String\(summary\.orderId\)/) - assert.match(storeSource, /transportMode: null/) + assert.match(storeSource, /transportMode: unifiedTransport\(summary\.containerMode\)/) + assert.match(storeSource, /status: summary\.mainStatus/) + assert.match(storeSource, /requestedPickupAt: summary\.requestedPickupAt \?\? ''/) + assert.match(storeSource, /chargeableVolumeCbm: summary\.chargeableVolumeCbm \?\? null/) + assert.match(storeSource, /inboundedAt: summary\.inboundCompletedAt \?\? ''/) + assert.match(storeSource, /pickupMethod: summary\.pickupMethod \?\? 'SELF_EXPRESS'/) + assert.match(storeSource, /destinationType: summary\.destinationType \?\? 'PRIVATE'/) + assert.match(storeSource, /mapped\.requestedPickupAt = summary\.requestedPickupAt/) assert.match(storeSource, /summary\?\.loading\?\.loadingVersion/) assert.match(storeSource, /summary\?\.loading\?\.pickingVersion/) assert.match(storeSource, /summary\?\.inboundId == null \? '' : String\(summary\.inboundId\)/) diff --git a/src/modules/first-leg/store/firstLegOrders.ts b/src/modules/first-leg/store/firstLegOrders.ts index 0262a74..42c8c56 100644 --- a/src/modules/first-leg/store/firstLegOrders.ts +++ b/src/modules/first-leg/store/firstLegOrders.ts @@ -61,6 +61,12 @@ function clientTransport(order: MerchantFirstLegOrder): FirstLegOrder['transport return 'ROAD' } +function unifiedTransport(containerMode: MerchantUnifiedOrderRow['containerMode']): FirstLegOrder['transportMode'] { + if (containerMode === 'FULL_CONTAINER') return 'FCL' + if (containerMode === 'LCL') return 'LCL' + return null +} + function apiTransport(draft: FirstLegOrderDraft): FirstLegOrderSaveRequest['transportMode'] { if (draft.transportMode === 'AIR') return 'AIR' if (draft.transportMode === 'ROAD') return 'TRUCK' @@ -342,29 +348,29 @@ function mapOrder(order: MerchantFirstLegOrder, warehouses: PlatformReceivingWar channelName: order.channelName, carrierId: order.carrierId == null ? '' : String(order.carrierId), carrierName: order.carrierName ?? '', pricingTaxMode: order.pricingTaxMode ?? 'TAX_INCLUDED', taxMode: order.taxMode, customsInspection: order.customsInspection, destinationType: order.destinationType, amazonWarehouseCode: order.amazonWarehouseCode ?? '', shipmentId: order.shipmentId ?? '', - receivingTime: order.receivingTime ?? '', submittedAt: order.submittedAt ?? '', completedAt: order.completedAt ?? '', + requestedPickupAt: '', receivingTime: order.receivingTime ?? '', submittedAt: order.submittedAt ?? '', completedAt: order.completedAt ?? '', } } 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: summary.referenceId ?? '', transportMode: null, + id: String(summary.orderId), orderNo: summary.orderNo, referenceNo: summary.referenceId ?? '', transportMode: unifiedTransport(summary.containerMode), 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: summary.expressCompany ?? '', - trackingNumber: summary.delivery?.trackingNo ?? '', skuNos: summary.skuNos ?? [], totalNetWeightKg: summary.totalNetWeightKg ?? null, - totalQuantity: summary.totalQuantity ?? null, chargeableVolumeCbm: null, - inboundedAt: summary.inboundedAt ?? '', businessDate: summary.businessDate ?? '', priority: 'NORMAL', customerRemark: summary.customerRemark ?? '', operatorName: '', + trackingNumber: summary.expressTrackingNo ?? summary.delivery?.trackingNo ?? '', skuNos: summary.skuNos ?? [], totalNetWeightKg: summary.totalNetWeightKg ?? null, + totalQuantity: summary.totalQuantity ?? null, chargeableVolumeCbm: summary.chargeableVolumeCbm ?? null, + inboundedAt: summary.inboundCompletedAt ?? '', businessDate: '', priority: 'NORMAL', customerRemark: summary.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: '', + destinationWarehouseName: summary.destinationWarehouseName ?? '', pickupMethod: summary.pickupMethod ?? 'SELF_EXPRESS', channelCode: '', channelName: summary.channelName ?? '', pricingTaxMode: 'TAX_INCLUDED', carrierId: '', carrierName: '', taxMode: 'BUY_DECLARATION', customsInspection: false, - destinationType: 'PRIVATE', amazonWarehouseCode: '', shipmentId: summary.shipmentId ?? '', - receivingTime: '', submittedAt: '', completedAt: '', + destinationType: summary.destinationType ?? 'PRIVATE', amazonWarehouseCode: summary.destinationCode ?? '', shipmentId: summary.shipmentId ?? '', + requestedPickupAt: summary.requestedPickupAt ?? '', receivingTime: '', submittedAt: '', completedAt: '', } } @@ -394,7 +400,7 @@ function mapFirstLegOrderRow(row: MerchantFirstLegOrderRow): FirstLegOrder { 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: '', + shipmentId: row.shipmentId ?? row.internationalOrderNo ?? '', requestedPickupAt: '', receivingTime: '', submittedAt: '', completedAt: '', } } @@ -405,7 +411,21 @@ function mapUnifiedOrderDetail(detail: MerchantUnifiedOrderDetail, warehouses: P mapped.status = detail.summary.mainStatus mapped.businessSummary = businessSummary(detail.summary) mapped.timeline = unifiedTimeline(detail) - mapped.trackingNumber = detail.summary.delivery?.trackingNo ?? mapped.trackingNumber + const summary = mapUnifiedOrderRow(detail.summary, warehouses) + mapped.referenceNo = summary.referenceNo + mapped.transportMode = summary.transportMode + mapped.expressCompanyName = summary.expressCompanyName + mapped.trackingNumber = summary.trackingNumber + mapped.skuNos = summary.skuNos + mapped.totalNetWeightKg = summary.totalNetWeightKg + mapped.totalQuantity = summary.totalQuantity + mapped.chargeableVolumeCbm = summary.chargeableVolumeCbm + mapped.inboundedAt = summary.inboundedAt + mapped.pickupMethod = summary.pickupMethod + mapped.requestedPickupAt = summary.requestedPickupAt + mapped.destinationType = summary.destinationType + mapped.amazonWarehouseCode = summary.amazonWarehouseCode + mapped.shipmentId = summary.shipmentId return mapped } diff --git a/src/modules/first-leg/views/FirstLegOrdersView.test.mjs b/src/modules/first-leg/views/FirstLegOrdersView.test.mjs index 665f440..acf2552 100644 --- a/src/modules/first-leg/views/FirstLegOrdersView.test.mjs +++ b/src/modules/first-leg/views/FirstLegOrdersView.test.mjs @@ -137,10 +137,12 @@ test('downloads selected carton labels with one array request', () => { test('exports every visible order field with normalized dates', () => { assert.match(source, /function formatExportDateTime\(value: string \| null \| undefined\)/) assert.match(source, /return `\$\{date\.getFullYear\(\)\}-\$\{pad\(date\.getMonth\(\) \+ 1\)\}-\$\{pad\(date\.getDate\(\)\)\} \$\{pad\(date\.getHours\(\)\)\}:\$\{pad\(date\.getMinutes\(\)\)\}:\$\{pad\(date\.getSeconds\(\)\)\}`/) - for (const label of ['订单号', '入仓码', '渠道', '目的仓', '当前订单状态', '箱数', '快递公司', '快递单号', 'SKUS', '总毛重', '总净重', '总体积', '总数量', '计费单价', '计费体积', '计费重量', '备注', '货件编号', '跟踪编号', '国内仓入库时间', '创建时间']) { + for (const label of ['订单号', '入仓码', '渠道', '运输方式', '交货方式', '预约提货时间', '目的仓', '目的仓类型', '当前订单状态', '箱数', '快递公司', '快递单号', 'SKUS', '总毛重', '总净重', '总体积', '总数量', '计费单价', '计费体积', '计费重量', '备注', '货件编号', '跟踪编号', '国内仓入库时间', '创建时间']) { assert.match(source, new RegExp(`'${label}'`)) } assert.match(source, /formatExportDateTime\(order\.inboundedAt\)/) + assert.match(source, /order\.pickupMethod === 'PICKUP' \? formatExportDateTime\(order\.requestedPickupAt\) : '-'/) + assert.match(source, /formatListMetric\(order\.chargeableVolumeCbm, 'm³'\)/) assert.doesNotMatch(source, /formatExportDateTime\(order\.businessDate\)/) assert.match(source, /formatExportDateTime\(order\.createdAt\)/) }) @@ -156,7 +158,7 @@ test('matches the prototype with selectable dense order-list columns', () => { assert.match(source, />恢复默认<\/el-button>/) assert.match(source, /const visibleOrderColumns = computed/) assert.match(source, /:columns="visibleOrderColumns"/) - for (const label of ['入仓码', '渠道', '目的仓', '当前订单状态', '箱数', '快递公司', '快递单号', 'SKUS', '总毛重', '总净重', '总体积', '总数量', '计费单价', '计费体积', '计费重量', '备注', '货件编号', '跟踪编号', '国内仓入库时间']) { + for (const label of ['入仓码', '渠道', '运输方式', '交货方式', '预约提货时间', '目的仓', '目的仓类型', '当前订单状态', '箱数', '快递公司', '快递单号', 'SKUS', '总毛重', '总净重', '总体积', '总数量', '计费单价', '计费体积', '计费重量', '备注', '货件编号', '跟踪编号', '国内仓入库时间']) { assert.match(source, new RegExp(`label: '${label}'`)) } assert.match(source, /order\.businessSummary\.totalPackageCount/) @@ -164,7 +166,8 @@ test('matches the prototype with selectable dense order-list columns', () => { assert.match(source, /order\.items\.reduce/) assert.match(source, /