Test #1

Merged
admin merged 1726 commits from test into main 2026-09-17 11:52:45 +08:00
8 changed files with 48 additions and 6 deletions
Showing only changes of commit 666add1cf9 - Show all commits
@@ -267,7 +267,8 @@ public class PdaPalletOperationService {
InventoryPosition position, String idempotencyKey, long before, long delta, long after,
String sourcePallet, String targetPallet, String reason) {
InventoryLedger ledger = new InventoryLedger(); ledger.setId(IdWorker.getId());
ledger.setCustomerId(balance.getCustomerId()); ledger.setBalanceId(balance.getId());
ledger.setCustomerId(balance.getCustomerId()); ledger.setCustomerName(balance.getCustomerName());
ledger.setBalanceId(balance.getId());
ledger.setPositionId(position.getId()); ledger.setOverseasWarehouseId(balance.getOverseasWarehouseId());
ledger.setDestinationWarehouseCode(balance.getDestinationWarehouseCode());
ledger.setInboundOrderId(balance.getInboundOrderId()); ledger.setPalletId(position.getPalletId());
@@ -151,6 +151,7 @@ public class PdaInventoryMoveService {
private void ledger(PdaInventoryMove operation, InventoryPosition position, InventoryBalance balance,
String operator, String key, String reason, LocalDateTime now) {
InventoryLedger row = new InventoryLedger(); row.setId(IdWorker.getId()); row.setCustomerId(position.getCustomerId());
row.setCustomerName(balance.getCustomerName());
row.setBalanceId(balance.getId()); row.setPositionId(position.getId());
row.setOverseasWarehouseId(String.valueOf(operation.getOverseasWarehouseId()));
row.setDestinationWarehouseCode(balance.getDestinationWarehouseCode()); row.setInboundOrderId(balance.getInboundOrderId());
@@ -281,7 +281,8 @@ public class PdaStocktakeService {
InventoryBalance balance, String operator, String key, String reason,
long before, long delta, long after, LocalDateTime now) {
InventoryLedger row = new InventoryLedger();
row.setId(IdWorker.getId()); row.setCustomerId(item.getCustomerId()); row.setBalanceId(balance.getId());
row.setId(IdWorker.getId()); row.setCustomerId(item.getCustomerId()); row.setCustomerName(balance.getCustomerName());
row.setBalanceId(balance.getId());
row.setPositionId(position.getId()); row.setOverseasWarehouseId(String.valueOf(task.getOverseasWarehouseId()));
row.setDestinationWarehouseCode(balance.getDestinationWarehouseCode()); row.setInboundOrderId(balance.getInboundOrderId());
row.setPalletId(position.getPalletId()); row.setPalletNo(position.getPalletNo()); row.setBatchNo(position.getBatchNo());
@@ -101,6 +101,7 @@ class PdaPalletOperationServiceTest {
@Test void inventoryLedgerStoresStateSemanticsInsteadOfLongPalletCodes() {
InventoryBalance balance = new InventoryBalance(); balance.setId(200L); balance.setCustomerId("100");
balance.setCustomerName("客户甲");
balance.setOverseasWarehouseId("88"); balance.setInboundOrderId(300L); balance.setInboundCode("IN-1");
InventoryPosition position = new InventoryPosition(); position.setId(100L); position.setPalletId(20L);
position.setPalletNo("PDAOPS-ADMIN-API-20260825095854036-SWAP-TARGET");
@@ -118,6 +119,7 @@ class PdaPalletOperationServiceTest {
assertEquals("OCCUPIED", ledger.getValue().getStatusFrom());
assertEquals("OCCUPIED", ledger.getValue().getStatusTo());
assertEquals("PDAOPS-LONG-LOCATION-CODE", ledger.getValue().getWarehouseLocationCode());
assertEquals("客户甲", ledger.getValue().getCustomerName());
}
@Test void exactReplayReturnsStoredResultBeforeValidatingChangedPalletVersions() throws Exception {
@@ -71,6 +71,7 @@ class PdaInventoryMoveServiceTest {
position.setPickedPackages(0L); position.setReceivingPackages(0L); position.setVersion(4L);
when(moves.lockPositions("900", 30L)).thenReturn(List.of(position));
InventoryBalance balance = new InventoryBalance(); balance.setId(10L); balance.setCustomerId("100");
balance.setCustomerName("客户甲");
balance.setOverseasWarehouseId("900"); balance.setInboundOrderId(50L); balance.setInboundCode("IN-1");
when(balances.selectById(10L)).thenReturn(balance);
when(physical.apply(eq(900L), any(PalletPhysicalGateway.PalletReference.class), eq("OCCUPIED"),
@@ -94,6 +95,7 @@ class PdaInventoryMoveServiceTest {
assertThat(ledger.getValue().getStatusFrom()).isEqualTo("OCCUPIED");
assertThat(ledger.getValue().getStatusTo()).isEqualTo("OCCUPIED");
assertThat(ledger.getValue().getWarehouseLocationCode()).isEqualTo(targetLocationCode);
assertThat(ledger.getValue().getCustomerName()).isEqualTo("客户甲");
verify(moves).updateById(any(PdaInventoryMove.class));
}
@@ -123,6 +123,7 @@ class PdaStocktakeServiceTest {
position.setAllocatedPackages(0L); position.setPickedPackages(0L); position.setReceivingPackages(0L);
position.setVersion(3L);
InventoryBalance balance = new InventoryBalance(); balance.setId(10L); balance.setCustomerId("100");
balance.setCustomerName("客户甲");
balance.setOverseasWarehouseId("900"); balance.setAvailablePackages(5L); balance.setVersion(8L);
when(inventory.lockPosition(11L, "100", "900")).thenReturn(position);
when(inventory.lockBalance(10L, "100", "900")).thenReturn(balance);
@@ -141,6 +142,7 @@ class PdaStocktakeServiceTest {
assertThat(ledger.getValue().getDeltaPackages()).isEqualTo(2L);
assertThat(ledger.getValue().getAfterPackages()).isEqualTo(7L);
assertThat(ledger.getValue().getBusinessType()).isEqualTo("STOCKTAKE_ADJUST");
assertThat(ledger.getValue().getCustomerName()).isEqualTo("客户甲");
assertThat(response.task().status()).isEqualTo("SUBMITTED");
}
}
@@ -4,7 +4,7 @@ import path from 'node:path'
import test from 'node:test'
import { fileURLToPath } from 'node:url'
import { run } from './phase4-overseas-pda.mjs'
import { expandOverseasCartonCandidates, run } from './phase4-overseas-pda.mjs'
const here = path.dirname(fileURLToPath(import.meta.url))
const source = fs.readFileSync(path.join(here, 'phase4-overseas-pda.mjs'), 'utf8')
@@ -61,7 +61,8 @@ test('PDA module covers the container-number receiving contract and excludes out
assert.match(source, /const cartonCandidates =/)
assert.doesNotMatch(source, /current\/skus\/resolve/)
assert.doesNotMatch(source, /skuCode:/)
assert.match(source, /FBA和OVERSEAS箱码resolve都必须HTTP 200\/code 200并返回当前柜唯一入仓码/)
assert.match(source, /FBA箱码与OVERSEAS真实manifest箱码必须HTTP 200\/code 200并返回当前柜唯一入仓码/)
assert.match(source, /排除未实装箱码候选/)
assert.match(source, /const matches = inbounds\.filter/)
assert.match(source, /!Array\.isArray\(resolved\?\.inboundCode\)/)
assert.match(source, /matches\.length === 1/)
@@ -102,6 +103,19 @@ test('PDA module covers the container-number receiving contract and excludes out
assert.doesNotMatch(source, /awaitProducerCandidates/)
})
test('OVERSEAS carton discovery probes the frozen sequence and lets the server exclude skipped cartons', () => {
assert.deepEqual(expandOverseasCartonCandidates([
{ inboundCode: 'NYEXX2609020042', destinationType: 'OVERSEAS' },
{ inboundCode: 'FBA2609020001', destinationType: 'FBA' },
], ['NYEXX2609020042#8-5', 'NYEXX2609020042#8-2', 'NYEXX2609020042#8-1']), [
'NYEXX2609020042#8-1', 'NYEXX2609020042#8-2', 'NYEXX2609020042#8-3', 'NYEXX2609020042#8-4',
'NYEXX2609020042#8-5', 'NYEXX2609020042#8-6', 'NYEXX2609020042#8-7', 'NYEXX2609020042#8-8',
])
assert.deepEqual(expandOverseasCartonCandidates([
{ inboundCode: 'NYEXX2609020042', destinationType: 'OVERSEAS' },
], ['NYEXX2609020042#2001-1']), [])
})
test('real-device legacy FBA carton rejection is retained as regression evidence', () => {
const evidence = {
http: 200,
@@ -34,6 +34,19 @@ function receivingSnapshot(data) {
})
}
export function expandOverseasCartonCandidates(inbounds, producerCartonMarks = []) {
const marks = (Array.isArray(producerCartonMarks) ? producerCartonMarks : [producerCartonMarks])
.map(id).filter(nonBlank)
return inbounds.filter((item) => item?.destinationType === 'OVERSEAS').flatMap((inbound) => {
const patterns = marks.map((cartonMark) => ({ cartonMark, match: /^(.*)#(\d+)-(\d+)$/.exec(cartonMark) }))
.filter(({ match }) => match && match[1] === inbound.inboundCode)
const totals = [...new Set(patterns.map(({ match }) => Number(match[2]))
.filter((total) => Number.isSafeInteger(total) && total > 0 && total <= 2000))]
if (totals.length !== 1) return []
return Array.from({ length: totals[0] }, (_, index) => `${inbound.inboundCode}#${totals[0]}-${index + 1}`)
})
}
function blockerGap(context, name, reason, category = 'fixture-unavailable', response = null) {
context.addCoverageGap(MODULE, SCENARIO, name, reason, category, { deploymentBlocker: true })
context.assert(MODULE, `${name}覆盖前置`, response, false, reason, OPTIONS)
@@ -364,7 +377,7 @@ async function resolveCartonFixtures(context, token, inbounds, producerCartonMar
.map(id).filter(nonBlank)
const fbaCartons = inbounds.filter((item) => item.destinationType === 'FBA')
.map((item, index) => `${item.inboundCode}#PDA-CONTRACT-${index + 1}`)
const overseasCartons = inbounds.some((item) => item.destinationType === 'OVERSEAS') ? manifestCartons : []
const overseasCartons = expandOverseasCartonCandidates(inbounds, manifestCartons)
const cartonCandidates = [...new Set([...fbaCartons, ...overseasCartons])]
if (!cartonCandidates.length) {
blockerGap(context, '统一箱码解析链', 'FBA缺少当前柜入仓码或OVERSEAS缺少真实manifest箱码')
@@ -374,6 +387,12 @@ async function resolveCartonFixtures(context, token, inbounds, producerCartonMar
for (const [index, cartonMark] of cartonCandidates.entries()) {
const response = await context.requestOverseas('POST',
'/api/pda/v1/last-leg/receiving-containers/current/cartons/resolve', { cartonMark }, {}, token)
if (overseasCartons.includes(cartonMark)
&& a0404Message(response, /^Carton mark was not found$/)) {
context.addStep(MODULE, `排除未实装箱码候选${index + 1}`, response, true,
`cartonMark=${cartonMark}; ${trace(response)}`, OPTIONS)
continue
}
const resolved = response.body?.data
const matches = inbounds.filter((item) => item.inboundCode === resolved?.inboundCode)
const destinations = new Set(matches.map((item) => item?.destinationType).filter(nonBlank))
@@ -385,7 +404,7 @@ async function resolveCartonFixtures(context, token, inbounds, producerCartonMar
unique, `cartonMark=${cartonMark}, inboundCode=${resolved?.inboundCode || 'missing'}, matches=${matches.length}; ${trace(response)}`, OPTIONS)
if (!unique) {
blockerGap(context, `箱码${cartonMark}唯一归属`,
`FBA和OVERSEAS箱码resolve都必须HTTP 200/code 200并返回当前柜唯一入仓码;inboundCode=${resolved?.inboundCode || 'missing'}, matches=${matches.length}`,
`FBA箱码与OVERSEAS真实manifest箱码必须HTTP 200/code 200并返回当前柜唯一入仓码;inboundCode=${resolved?.inboundCode || 'missing'}, matches=${matches.length}`,
'fixture-mismatch', response)
return null
}