优化
This commit is contained in:
@@ -5,7 +5,7 @@ import { runInNewContext } from 'node:vm'
|
||||
|
||||
const source = readFileSync(new URL('../src/pages/return-counting/return-counting.vue', import.meta.url), 'utf8')
|
||||
const script = source.match(/<script>([\s\S]*?)<\/script>/)[1].replace(/^import .+$/gm, '').replace('export default', 'page =')
|
||||
const scope = { PortalHeader: {}, ScanTargetInput: {} }
|
||||
const scope = { PortalHeader: {}, ScanTargetInput: {}, CartonCountFields: {} }
|
||||
runInNewContext(script, scope)
|
||||
|
||||
function state(a = '2', b = '2', c = '2') {
|
||||
|
||||
@@ -54,12 +54,12 @@ test('warehouse transfer removes completed work from the pending list', async ()
|
||||
assert.match(page, /this\.selected = null; this\.pendingKey = '';[\s\S]*await this\.loadCandidates\(\)/)
|
||||
})
|
||||
|
||||
test('warehouse transfer shows forecast and actual variance without blocking short or over receipt', async () => {
|
||||
test('warehouse transfer shows forecast and actual variance and requires counted box reconciliation', async () => {
|
||||
const page = await readFile(new URL('../src/pages/warehouse-transfer/warehouse-transfer.vue', import.meta.url), 'utf8')
|
||||
for (const label of ['客户预报', '当前实收', '短收差异', '超收差异']) assert.match(page, new RegExp(label))
|
||||
assert.match(page, /cartonDifference/)
|
||||
assert.doesNotMatch(page, /全部托盘箱数必须等于订单计划箱数/)
|
||||
assert.doesNotMatch(page, /本托 SKU 箱数|itemCounts|transferItemId/)
|
||||
assert.doesNotMatch(page, /本托 SKU 箱数|itemCounts/)
|
||||
})
|
||||
|
||||
test('warehouse transfer retries reuse the pending idempotency key', async () => {
|
||||
@@ -71,13 +71,13 @@ test('warehouse transfer retries reuse the pending idempotency key', async () =>
|
||||
|
||||
test('warehouse transfer measurement inputs retain explicit placeholders', async () => {
|
||||
const page = await readFile(new URL('../src/pages/warehouse-transfer/warehouse-transfer.vue', import.meta.url), 'utf8')
|
||||
for (const placeholder of ['长度', '宽度', '高度', '毛重']) assert.match(page, new RegExp(`placeholder="${placeholder}"`))
|
||||
assert.doesNotMatch(page, /v-model.number="pallet\.(lengthCm|widthCm|heightCm|grossWeightKg)"/)
|
||||
})
|
||||
|
||||
test('warehouse transfer measurements are grouped and summarized per pallet', async () => {
|
||||
const page = await readFile(new URL('../src/pages/warehouse-transfer/warehouse-transfer.vue', import.meta.url), 'utf8')
|
||||
assert.match(page, /v-for="\(pallet, index\) in pallets"/)
|
||||
for (const label of ['本托实测', '当前托重量', '当前托箱数', '自动体积']) assert.match(page, new RegExp(label))
|
||||
for (const label of ['本托箱子汇总', '实收箱数', '箱子重量 kg', '箱子体积 m³']) assert.match(page, new RegExp(label))
|
||||
assert.match(page, /palletVolume\(pallet\)/)
|
||||
assert.match(page, /rawPalletVolume\(pallet\)/)
|
||||
})
|
||||
@@ -138,7 +138,7 @@ test('warehouse transfer pallet cards prepare generated and server-bound states'
|
||||
assert.match(page, /扫描或手输新托盘标签号/)
|
||||
assert.match(page, /已绑定实物托盘/)
|
||||
assert.match(page, /!pallet\.generated.*removePallet/)
|
||||
assert.match(page, /:disabled="pallet\.generated"/)
|
||||
assert.match(page, /请先生成托盘号,再填写签收箱子/)
|
||||
assert.match(page, /collapsed: false/)
|
||||
assert.match(page, /pallet\.collapsed = !pallet\.collapsed/)
|
||||
assert.match(page, /v-show="!pallet\.collapsed"/)
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { runInNewContext } from 'node:vm'
|
||||
const source = readFileSync(new URL('../src/pages/warehouse-transfer/warehouse-transfer.vue',import.meta.url),'utf8')
|
||||
const script = source.match(/<script>([\s\S]*?)<\/script>/)[1].replace(/^import .+$/gm,'').replace('export default','page =')
|
||||
function setup() {
|
||||
const storage = new Map()
|
||||
const scope = { CartonCountFields:{},PortalHeader:{},ScanTargetInput:{},session:{apiBase:'LOCAL',currentUser:{id:'OP',warehouseId:'WH'}},uni:{getStorageSync:key=>storage.get(key),setStorageSync:(key,value)=>storage.set(key,JSON.parse(JSON.stringify(value))),removeStorageSync:key=>storage.delete(key)} }
|
||||
runInNewContext(script,scope)
|
||||
const value = scope.page.data()
|
||||
for(const [key,method] of Object.entries(scope.page.methods)) value[key]=method.bind(value)
|
||||
for(const [key,get] of Object.entries(scope.page.computed)) Object.defineProperty(value,key,{get:()=>get.call(value)})
|
||||
value.selected={transferNo:'WT1',packageCount:1,status:'WAIT_PDA_RECEIVING',items:[{id:'I1',skuCode:'A'}],cartons:[{cartonMark:'BOX1',transferItemId:'I1',status:'EXPECTED'}]}
|
||||
value.pallets=[{key:'P1',draftId:'P1',palletNo:'PALLET1',generated:true,bound:false}];value.restoreCartons();Object.assign(value.cartonBoxes[0],{length:10,width:20,height:30,weight:2});value.cartonBoxes[0].items[0].quantity=4
|
||||
return {scope,value,storage}
|
||||
}
|
||||
test('transfer counts require valid pieces and measurements and record variance reason',()=>{
|
||||
const {value}=setup();assert.equal(value.cartonCountReady,true)
|
||||
value.cartonBoxes[0].items[0].quantity=0;assert.equal(value.cartonCountReady,false)
|
||||
value.cartonBoxes[0].items[0].quantity=1.5;assert.equal(value.cartonCountReady,false)
|
||||
value.cartonBoxes[0].items[0].quantity=4;value.cartonBoxes[0].height=0;assert.equal(value.cartonCountReady,false)
|
||||
value.cartonBoxes[0].height=30;value.addExtraCarton();Object.assign(value.cartonBoxes[1],{length:10,width:20,height:30,weight:2});value.cartonBoxes[1].items[0].quantity=5
|
||||
assert.equal(value.cartonCountReady,false);value.countDiscrepancyReason='多一箱';assert.equal(value.cartonCountReady,true)
|
||||
assert.equal(value.cartonQuantity,9);assert.equal(value.cartonVolume,'0.012000')
|
||||
})
|
||||
test('network retry preserves request key and changed content uses a new request',async()=>{
|
||||
const {value,scope}=setup();const requests=[]
|
||||
scope.countWarehouseTransferCartons=async(no,request)=>{requests.push(request);throw new Error('offline')}
|
||||
await value.confirmCartons();await value.confirmCartons()
|
||||
assert.equal(requests.length,2);assert.equal(requests[0].idempotencyKey,requests[1].idempotencyKey)
|
||||
value.cartonBoxes[0].items[0].quantity=8;await value.confirmCartons();assert.notEqual(requests[1].idempotencyKey,requests[2].idempotencyKey)
|
||||
assert.equal(value.countingCartons,false);assert.equal(value.error.message,'offline')
|
||||
})
|
||||
test('draft restores additional cartons and discrepancy reason and scanning rejects foreign box',()=>{
|
||||
const {value}=setup();value.addExtraCarton();value.countDiscrepancyReason='超收';value.saveCartonDraft();value.restoreCartons()
|
||||
assert.equal(value.cartonBoxes.length,2);assert.equal(value.countDiscrepancyReason,'超收')
|
||||
value.locateCarton('FOREIGN');assert.match(value.error.message,/不属于/)
|
||||
value.locateCarton('BOX1');assert.equal(value.selectedCartonMark,'BOX1');assert.equal(value.cartonScrollTarget,'transfer-box-0')
|
||||
value.selected={...value.selected,transferNo:'WT2'};value.restoreCartons();assert.equal(value.cartonBoxes.length,1)
|
||||
})
|
||||
test('received count gates pallet completion and saving cannot switch active order',()=>{
|
||||
const {value}=setup();assert.match(value.validationMessage,/先完成全部箱子/)
|
||||
value.selected.cartons[0].countedAt='2026-10-15';value.cartonBoxes[0].transferPalletId='FOREIGN';assert.match(value.validationMessage,/已清点实收箱数/)
|
||||
value.countingCartons=true;value.backToCandidates();assert.equal(value.selected.transferNo,'WT1')
|
||||
})
|
||||
|
||||
test('batch applies only selected received boxes of one SKU and preserves independent drafts',()=>{
|
||||
const {value}=setup()
|
||||
value.addExtraCarton();value.addExtraCarton();value.addExtraCarton()
|
||||
value.cartonBoxes[2].items[0].skuCode='B'
|
||||
value.cartonBoxes[3].received=false
|
||||
value.selectBatchCartons(true)
|
||||
assert.equal(value.batchTargetBoxes.length,2)
|
||||
value.toggleBatchCarton(0)
|
||||
Object.assign(value.batchBox,{length:32,width:24,height:18,weight:3.2})
|
||||
value.batchBox.items[0].quantity=6
|
||||
assert.equal(value.batchTotalQuantity,6)
|
||||
value.applyBatchCartons()
|
||||
assert.equal(value.cartonBoxes[0].items[0].quantity,4)
|
||||
assert.equal(value.cartonBoxes[1].items[0].quantity,6)
|
||||
assert.equal(value.cartonBoxes[2].items[0].quantity,'')
|
||||
assert.equal(value.cartonBoxes[3].items[0].quantity,'')
|
||||
value.batchBox.items[0].quantity=8
|
||||
assert.equal(value.cartonBoxes[1].items[0].quantity,6)
|
||||
value.restoreCartons()
|
||||
assert.equal(value.cartonBoxes[1].items[0].quantity,6)
|
||||
assert.equal(value.batchTargetBoxes.length,0)
|
||||
value.changeBatchSku(1)
|
||||
assert.equal(value.batchSku,'B')
|
||||
assert.equal(value.batchBox.items[0].quantity,'')
|
||||
})
|
||||
|
||||
test('batch guards invalid quantities, busy state, submitted facts and stale mixed SKU selections',()=>{
|
||||
const {value}=setup();value.selectBatchCartons(true)
|
||||
Object.assign(value.batchBox,{length:32,width:24,height:18,weight:3.2})
|
||||
for(const quantity of [0,1.5,2147483648]){
|
||||
value.batchBox.items[0].quantity=quantity;value.applyBatchCartons()
|
||||
assert.equal(value.cartonBoxes[0].items[0].quantity,4)
|
||||
}
|
||||
value.batchBox.items[0].quantity=6;value.countingCartons=true;value.applyBatchCartons()
|
||||
assert.equal(value.cartonBoxes[0].items[0].quantity,4)
|
||||
value.countingCartons=false;value.cartonBoxes[0].items[0].skuCode='B'
|
||||
assert.equal(value.batchTargetBoxes.length,0);value.applyBatchCartons()
|
||||
assert.equal(value.cartonBoxes[0].items[0].quantity,4)
|
||||
value.cartonBoxes[0].items[0].skuCode='A';value.selected.cartons[0].countedAt='now';value.applyBatchCartons()
|
||||
assert.equal(value.cartonBoxes[0].items[0].quantity,4)
|
||||
})
|
||||
|
||||
test('copy uses preceding received same SKU without sharing quantity objects or changing box identity',()=>{
|
||||
const {value}=setup();value.addExtraCarton();value.addExtraCarton()
|
||||
value.cartonBoxes[1].items[0].skuCode='B'
|
||||
value.copyPreviousCarton(1);assert.equal(value.cartonBoxes[1].items[0].quantity,'')
|
||||
const identity=value.cartonBoxes[2].localKey
|
||||
value.copyPreviousCarton(2)
|
||||
assert.equal(value.cartonBoxes[2].length,10)
|
||||
assert.equal(value.cartonBoxes[2].items[0].quantity,4)
|
||||
assert.equal(value.cartonBoxes[2].localKey,identity)
|
||||
value.cartonBoxes[2].items[0].quantity=9
|
||||
assert.equal(value.cartonBoxes[0].items[0].quantity,4)
|
||||
value.cartonBoxes[0].received=false;assert.equal(value.previousMatchingCarton(2),undefined)
|
||||
})
|
||||
|
||||
|
||||
test('pallet totals follow actual box assignments and exclude missing boxes',()=>{
|
||||
const {value}=setup();value.pallets.push({key:'P2',draftId:'P2',palletNo:'PALLET2',generated:true})
|
||||
value.addExtraCarton();Object.assign(value.cartonBoxes[1],{length:40,width:20,height:10,weight:3,transferPalletId:'P2'});value.cartonBoxes[1].items[0].quantity=6
|
||||
assert.equal(value.palletSummary(value.pallets[0]).cartonCount,1)
|
||||
assert.equal(value.palletSummary(value.pallets[1]).volume,0.008)
|
||||
assert.equal(value.totalWeight,'5.00')
|
||||
value.assignCartonPallet(value.cartonBoxes[1],0)
|
||||
assert.equal(value.palletSummary(value.pallets[0]).cartonCount,2)
|
||||
assert.equal(value.palletSummary(value.pallets[1]).cartonCount,0)
|
||||
value.cartonBoxes[1].received=false
|
||||
assert.equal(value.totalWeight,'2.00')
|
||||
value.cartonBoxes[0].transferPalletId='FOREIGN';assert.equal(value.cartonCountReady,false)
|
||||
})
|
||||
|
||||
test('pallet number can be created before measurements and new boxes receive that identity',async()=>{
|
||||
const {value,scope}=setup();const requests=[]
|
||||
value.pallets=[{key:'NEW',generated:false,busy:false}];value.cartonBoxes[0].transferPalletId=''
|
||||
const pallet={id:'CREATED',sequenceNo:1,status:'GENERATED',palletNo:'NEWPALLET'}
|
||||
scope.saveWarehouseTransferPalletDraft=async(no,request)=>{requests.push(request);return {pallets:[{...pallet,status:'DRAFT'}]}}
|
||||
scope.generateWarehouseTransferPallet=async()=>({pallets:[pallet]})
|
||||
await value.generatePallet(value.pallets[0])
|
||||
assert.equal(requests.length,1);assert.equal('lengthCm' in requests[0],false);assert.equal('grossWeightKg' in requests[0],false)
|
||||
assert.equal(value.cartonBoxes[0].transferPalletId,'CREATED')
|
||||
assert.equal(value.pallets[0].palletNo,'NEWPALLET')
|
||||
})
|
||||
Reference in New Issue
Block a user