diff --git a/src/modules/overseas-warehouse/AGENTS.md b/src/modules/overseas-warehouse/AGENTS.md index a2803843..b16b216e 100644 --- a/src/modules/overseas-warehouse/AGENTS.md +++ b/src/modules/overseas-warehouse/AGENTS.md @@ -38,7 +38,7 @@ ## 验证 -- 一件代发出库候选选择:`pages/OutboundsView.vue` 按 `inventoryPositionId + skuCode` 保留跨页选择,只提供本页全选;查询/重置回到第一页,切换海外仓清空选择。提交仍校验同客户、同海外仓,数量取所选行的 `availablePackages`(箱数),不能按 SKU 件数替代。候选交互回归见 `pages/OutboundsView.selection.test.ts`;状态展示与取消门禁见 `pages/OutboundsView.test.ts`、`pages/OutboundDetailView.test.ts`。 +- 一件代发出库候选选择:`pages/OutboundsView.vue` 按 `inventoryPositionId + skuCode` 保留跨页选择,只提供本页全选;查询/重置回到第一页,切换海外仓清空选择。提交仍校验同客户、同海外仓,数量取所选行的 `availablePackages`(箱数),不能按 SKU 件数替代;候选同时展示当前可出箱数对应的毛重、材积重和体积,创建出库单时服务端按本次出库箱数占实际入库箱数的比例冻结三项测量快照。候选交互回归见 `pages/OutboundsView.selection.test.ts`;状态展示与取消门禁见 `pages/OutboundsView.test.ts`、`pages/OutboundDetailView.test.ts`。 - 转运审核定向测试:从应用根运行 `pnpm test src/modules/overseas-warehouse/api/warehouseTransfers.test.ts src/modules/overseas-warehouse/pages/prototypeContract.test.ts`,分别核对客户作用域/API 与审核入口权限、状态。 - 排车列表编辑、托盘移除、BOL PDF 和转派送从 `pages/DispatchesView.vue` → `api/dispatches.ts` 进入;智能预排的候选、草稿柜与托盘锁从 `components/SmartDispatchDialog.vue` 进入。回归为 `pages/DispatchesView.test.ts`、`pages/prototypeContract.test.ts`,不要把列表操作与预排草稿当作同一入口。 - 从应用根按目标页面选择相邻测试:`pnpm test src/modules/overseas-warehouse/<目标测试路径>`;API 或类型变化同时运行 `pnpm typecheck`。应用完整门禁继续遵循上层指引。 diff --git a/src/modules/overseas-warehouse/api/outbounds.test.ts b/src/modules/overseas-warehouse/api/outbounds.test.ts index 5255dc4f..5e8b265c 100644 --- a/src/modules/overseas-warehouse/api/outbounds.test.ts +++ b/src/modules/overseas-warehouse/api/outbounds.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { overseasHttp } from '@/shared/api/overseasHttp' -import { cancelOutbound, createOneClickDropshipOutbound, getOutbound, listOutbounds } from './outbounds' +import { cancelOutbound, createOneClickDropshipOutbound, getOutbound, listOneClickOutboundCandidates, listOutbounds } from './outbounds' vi.mock('@/shared/api/overseasHttp', () => ({ overseasHttp: { get: vi.fn(), post: vi.fn() } })) @@ -28,4 +28,16 @@ describe('outbound overseas API', () => { await createOneClickDropshipOutbound('customer-1', payload) expect(overseasHttp.post).toHaveBeenCalledWith('/platform/v1/last-leg/outbound-orders/one-click-dropship', payload, { params: { customerId: 'customer-1' } }) }) + + it('normalizes one-click candidate measurements returned as decimal strings', async () => { + vi.mocked(overseasHttp.get).mockResolvedValue({ code: '200', data: [{ + inventoryPositionId: '99', availablePackages: 4, + grossWeightKg: '40.000', volumeWeightKg: '80.000', volumeCbm: '4.0000', + }] }) + const [candidate] = await listOneClickOutboundCandidates(undefined, { warehouseId: 'warehouse-1' }) + expect(candidate).toMatchObject({ + inventoryPositionId: '99', availablePackages: 4, + grossWeightKg: 40, volumeWeightKg: 80, volumeCbm: 4, + }) + }) }) diff --git a/src/modules/overseas-warehouse/api/outbounds.ts b/src/modules/overseas-warehouse/api/outbounds.ts index b193b8d1..d1126fdc 100644 --- a/src/modules/overseas-warehouse/api/outbounds.ts +++ b/src/modules/overseas-warehouse/api/outbounds.ts @@ -22,7 +22,7 @@ export interface OutboundPalletRow { export interface OutboundDetail { outbound: OutboundRow; pallets?: OutboundPalletRow[]; deliveries?: DeliveryOrderRow[] } export interface OutboundQuery { page: number; size: number; documentNo?: string; lxCode?: string; warehouseId?: string; status?: string; outboundType?: string } export interface ReturnOutboundCandidate { returnNo?: string | null; overseasWarehouseId?: string | null; cartonMark?: string | null; fbaCartonMark?: string | null; destinationWarehouseCode?: string | null; destinationWarehouseName?: string | null; totalQuantity?: number | null; status?: string | null } -export interface OneClickOutboundCandidate { inventoryPositionId: string; orderNo?: string | null; customerId?: string | null; customerName?: string | null; overseasWarehouseId?: string | null; overseasWarehouseName?: string | null; palletNo?: string | null; inboundCode?: string | null; skuCode?: string | null; productName?: string | null; availablePackages: number } +export interface OneClickOutboundCandidate { inventoryPositionId: string; orderNo?: string | null; customerId?: string | null; customerName?: string | null; overseasWarehouseId?: string | null; overseasWarehouseName?: string | null; palletNo?: string | null; inboundCode?: string | null; skuCode?: string | null; productName?: string | null; availablePackages: number; grossWeightKg: number; volumeWeightKg: number; volumeCbm: number } export interface WarehouseTransferOutboundCandidate { customerId: string; customerName?: string | null; transferNo: string; overseasWarehouseId: string; transferStatus: string; needRelabel: boolean; relabelNo?: string | null; destinationType?: 'FBA' | 'PRIVATE' | null; destinationWarehouseCode?: string | null; privateDestinationAddress?: string | null; privateDestinationPostalCode?: string | null; packageCount: number; grossWeightKg?: number | null; volumeCbm?: number | null } export interface WarehouseTransferDestinationPayload { transfers: Array<{ customerId: string; transferNo: string }>; destinationType: 'FBA' | 'PRIVATE'; destinationWarehouseId?: string; destinationWarehouseCode?: string; destinationWarehouseName?: string; privateDestinationAddress?: string; privateDestinationPostalCode?: string; privateDestinationContactName?: string; privateDestinationContactPhone?: string; idempotencyKey: string } export async function listOutbounds(query: OutboundQuery) { @@ -39,7 +39,14 @@ export async function createOneClickDropshipOutbound(customerId: string, payload } export async function listOneClickOutboundCandidates(customerId?: string, query: { warehouseId?: string } = {}) { const response = await overseasHttp.get, ApiEnvelope>('/platform/v1/last-leg/outbound-orders/one-click-dropship/candidates', { params: { customerId, ...query } }) - return unwrapApiResponse(response).map((item) => ({ ...item, inventoryPositionId: String(item.inventoryPositionId), availablePackages: Number(item.availablePackages || 0) })) + return unwrapApiResponse(response).map((item) => ({ + ...item, + inventoryPositionId: String(item.inventoryPositionId), + availablePackages: Number(item.availablePackages || 0), + grossWeightKg: Number(item.grossWeightKg || 0), + volumeWeightKg: Number(item.volumeWeightKg || 0), + volumeCbm: Number(item.volumeCbm || 0), + })) } export async function listReturnOutboundCandidates(customerId: string, warehouseId: string) { const response = await overseasHttp.get, ApiEnvelope>('/platform/v1/last-leg/outbound-orders/return/candidates', { params: { customerId, warehouseId } }) diff --git a/src/modules/overseas-warehouse/pages/OutboundsView.selection.test.ts b/src/modules/overseas-warehouse/pages/OutboundsView.selection.test.ts index 52967e4f..d88d1c74 100644 --- a/src/modules/overseas-warehouse/pages/OutboundsView.selection.test.ts +++ b/src/modules/overseas-warehouse/pages/OutboundsView.selection.test.ts @@ -19,6 +19,7 @@ const fixtures = Array.from({ length: 7 }, (_, index) => ({ inventoryPositionId: `position-${index}`, orderNo: `ORDER-${index}`, customerId: 'customer-a', customerName: '客户甲', overseasWarehouseId: 'warehouse-a', palletNo: `PALLET-${index}`, inboundCode: `IN-${index}`, skuCode: index < 6 ? 'MATCH' : 'OTHER', productName: '测试品名', availablePackages: index + 1, + grossWeightKg: (index + 1) * 10, volumeWeightKg: (index + 1) * 20, volumeCbm: index + 1, })) let wrapper: VueWrapper async function clickButton(text: string) { @@ -60,6 +61,9 @@ describe('outbound candidate search and selection', () => { it('selects and deselects the current page while preserving other pages, then submits all selected quantities', async () => { await openCreate() + expect(wrapper.text()).toContain('可出毛重(kg)') + expect(wrapper.text()).toContain('可出材积重(kg)') + expect(wrapper.text()).toContain('可出体积(m³)') pageCheckbox().vm.$emit('change', true) await flushPromises() expect(wrapper.text()).toContain('已选择 5 条') diff --git a/src/modules/overseas-warehouse/pages/OutboundsView.vue b/src/modules/overseas-warehouse/pages/OutboundsView.vue index 2becf233..4eada84f 100644 --- a/src/modules/overseas-warehouse/pages/OutboundsView.vue +++ b/src/modules/overseas-warehouse/pages/OutboundsView.vue @@ -247,6 +247,9 @@ onMounted(load) + + +
暂无可直接出库的已完成入库订单