This commit is contained in:
2026-08-07 18:15:59 +08:00
parent 8575df0793
commit dd7aa0e4cf
7 changed files with 92 additions and 8 deletions
@@ -2,12 +2,14 @@ import assert from 'node:assert/strict'
import test from 'node:test'
import { createFirstLegPartySnapshot } from '../data/firstLegParties.ts'
import {
applyCargoBoxSize,
canClientCancelFirstLegOrder,
canClientEditFirstLegOrder,
createEmptyCargoItem,
getFirstLegStatusLabel,
getFirstLegTransportModeLabel,
summarizeFirstLegCargo,
updateCargoBoxVolume,
validateFirstLegOrderDraft,
} from './firstLegOrder.ts'
@@ -52,10 +54,24 @@ function validDraft() {
destinationType: 'FBA',
amazonWarehouseCode: 'ONT8',
shipmentId: 'FBA-001',
items: [{ ...createEmptyCargoItem('cargo-1'), sku: 'SKU-001', upc: '012345678905', cargoNameCn: '家居用品', pieces: 100, grossWeightKg: 1200, volumeCbm: 3.5, containerType: '40HQ', containerCount: 1 }],
items: [{ ...createEmptyCargoItem('cargo-1'), sku: 'SKU-001', upc: '012345678905', cargoNameCn: '家居用品', pieces: 100, grossWeightKg: 1200, volumeCbm: 3.5, boxSizeType: 'SMALL', lengthCm: 34, widthCm: 24, heightCm: 24, containerType: '40HQ', containerCount: 1 }],
}
}
test('applies the four fixed box sizes and recalculates total CBM from package count', () => {
const item = createEmptyCargoItem('cargo-box')
item.packageCount = 2
applyCargoBoxSize(item, 'SMALL')
assert.deepEqual([item.lengthCm, item.widthCm, item.heightCm, item.volumeCbm], [34, 24, 24, 0.039])
item.packageCount = 3
updateCargoBoxVolume(item)
assert.equal(item.volumeCbm, 0.059)
applyCargoBoxSize(item, '')
assert.deepEqual([item.lengthCm, item.widthCm, item.heightCm, item.volumeCbm], [0, 0, 0, 0])
})
test('uses the confirmed status and transport labels', () => {
assert.equal(getFirstLegStatusLabel('WAIT_MEASURE'), '待测量数据')
assert.equal(getFirstLegStatusLabel('INBOUNDED'), '已入库')
+45 -1
View File
@@ -4,7 +4,46 @@ import {
type FirstLegOrderStatus,
type FirstLegTransportMode,
} from '@chongchong/shared'
import type { FirstLegCargoItem, FirstLegOrderDraft } from '../types/firstLegOrder.ts'
import type { CargoBoxSizeType, FirstLegCargoItem, FirstLegOrderDraft } from '../types/firstLegOrder.ts'
export const CARGO_BOX_SIZES = [
{ code: 'SMALL', label: '小箱', inner: '30 × 20 × 20', lengthCm: 34, widthCm: 24, heightCm: 24 },
{ code: 'MEDIUM', label: '中箱', inner: '40 × 30 × 30', lengthCm: 44, widthCm: 34, heightCm: 34 },
{ code: 'LARGE', label: '大箱', inner: '50 × 40 × 40', lengthCm: 54, widthCm: 44, heightCm: 44 },
{ code: 'EXTRA_LARGE', label: '特大箱', inner: '60 × 50 × 50', lengthCm: 64, widthCm: 54, heightCm: 54 },
] as const satisfies ReadonlyArray<{
code: Exclude<CargoBoxSizeType, ''>
label: string
inner: string
lengthCm: number
widthCm: number
heightCm: number
}>
export function inferCargoBoxSizeType(lengthCm?: number, widthCm?: number, heightCm?: number): CargoBoxSizeType {
return CARGO_BOX_SIZES.find((box) => box.lengthCm === lengthCm && box.widthCm === widthCm && box.heightCm === heightCm)?.code ?? ''
}
export function applyCargoBoxSize(item: FirstLegCargoItem, type: CargoBoxSizeType) {
item.boxSizeType = type
const box = CARGO_BOX_SIZES.find((option) => option.code === type)
if (!box) {
item.lengthCm = 0
item.widthCm = 0
item.heightCm = 0
item.volumeCbm = 0
return
}
item.lengthCm = box.lengthCm
item.widthCm = box.widthCm
item.heightCm = box.heightCm
updateCargoBoxVolume(item)
}
export function updateCargoBoxVolume(item: FirstLegCargoItem) {
if (!item.boxSizeType || item.packageCount <= 0) return
item.volumeCbm = Number(((item.lengthCm * item.widthCm * item.heightCm * item.packageCount) / 1_000_000).toFixed(3))
}
const statusLabels = new Map<FirstLegOrderStatus, string>(
FIRST_LEG_ORDER_STATUSES.map((item) => [item.code, item.label]),
@@ -57,6 +96,10 @@ export function createEmptyCargoItem(id = `cargo-${Date.now()}`): FirstLegCargoI
packageCount: 1,
grossWeightKg: 0,
volumeCbm: 0,
boxSizeType: '',
lengthCm: 0,
widthCm: 0,
heightCm: 0,
containerType: '',
containerCount: 0,
remark: '',
@@ -104,6 +147,7 @@ export function validateFirstLegOrderDraft(draft: FirstLegOrderDraft) {
const line = `第 ${index + 1} 条货物`
if (!item.cargoNameCn.trim()) errors.push(`${line}缺少中文品名`)
if (!item.packageType.trim()) errors.push(`${line}缺少包装类型`)
if (!item.boxSizeType) errors.push(`${line}请选择箱规`)
if (draft.destinationType === 'FBA' && !item.sku.trim()) errors.push(`${line}缺少客户 SKU`)
if (draft.destinationType === 'FBA' && !item.upc.trim()) errors.push(`${line}缺少 UPC`)
if (!Number.isInteger(item.pieces) || item.pieces <= 0) errors.push(`${line}件数必须为正整数`)