fix(firstleg): transfer carton labels to remainder inbound
This commit is contained in:
@@ -149,6 +149,20 @@ public interface InboundSplitSettlementMapper {
|
|||||||
@Param("childMeasurementItemId") long childMeasurementItemId,
|
@Param("childMeasurementItemId") long childMeasurementItemId,
|
||||||
@Param("lineNo") int lineNo, @Param("packageCount") int packageCount);
|
@Param("lineNo") int lineNo, @Param("packageCount") int packageCount);
|
||||||
|
|
||||||
|
@Update("""
|
||||||
|
UPDATE fl_inbound_carton_label
|
||||||
|
SET inbound_id=#{childInboundId}, order_id=#{childOrderId}, inbound_code=#{childInboundCode}
|
||||||
|
WHERE tenant_id=#{accountId} AND inbound_id=#{sourceInboundId} AND batch_status='ACTIVE'
|
||||||
|
ORDER BY carton_index DESC
|
||||||
|
LIMIT #{remainingPackageCount}
|
||||||
|
""")
|
||||||
|
int transferRemainingCartonLabels(@Param("accountId") long accountId,
|
||||||
|
@Param("sourceInboundId") long sourceInboundId,
|
||||||
|
@Param("childInboundId") long childInboundId,
|
||||||
|
@Param("childOrderId") long childOrderId,
|
||||||
|
@Param("childInboundCode") String childInboundCode,
|
||||||
|
@Param("remainingPackageCount") int remainingPackageCount);
|
||||||
|
|
||||||
@Update("""
|
@Update("""
|
||||||
UPDATE fl_inbound_order
|
UPDATE fl_inbound_order
|
||||||
SET package_count = GREATEST(COALESCE(package_count, total_package_count) - #{packageCount}, 0),
|
SET package_count = GREATEST(COALESCE(package_count, total_package_count) - #{packageCount}, 0),
|
||||||
|
|||||||
@@ -185,6 +185,8 @@ public class PdaPickSettlementService {
|
|||||||
requireAffected(splits.cloneChildWithPurpose(parent.tenantId(), parentInboundId, rootInboundId, remainderChildId,
|
requireAffected(splits.cloneChildWithPurpose(parent.tenantId(), parentInboundId, rootInboundId, remainderChildId,
|
||||||
orderSplit.remainderChild().orderId(), orderSplit.remainderChild().orderNo(),
|
orderSplit.remainderChild().orderId(), orderSplit.remainderChild().orderNo(),
|
||||||
remainderChildCode, childPackageCount, sequence, "REMAINDER", operatorId, operatorName), "余量子入库单");
|
remainderChildCode, childPackageCount, sequence, "REMAINDER", operatorId, operatorName), "余量子入库单");
|
||||||
|
splits.transferRemainingCartonLabels(parent.tenantId(), parentInboundId, remainderChildId,
|
||||||
|
orderSplit.remainderChild().orderId(), remainderChildCode, childPackageCount);
|
||||||
}
|
}
|
||||||
requireAffected(splits.insertBatchWithChildren(batchId, parent.tenantId(), rootInboundId, operationId, parentInboundId,
|
requireAffected(splits.insertBatchWithChildren(batchId, parent.tenantId(), rootInboundId, operationId, parentInboundId,
|
||||||
idempotencyKey, rootVersion, parentAvailable, null, remainderChildId == 0L ? null : remainderChildId,
|
idempotencyKey, rootVersion, parentAvailable, null, remainderChildId == 0L ? null : remainderChildId,
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ class PdaPickSettlementServiceTest {
|
|||||||
verify(splits).cloneChildWithPurpose(eq(10001L), eq(31L), eq(31L), anyLong(),
|
verify(splits).cloneChildWithPurpose(eq(10001L), eq(31L), eq(31L), anyLong(),
|
||||||
eq(1002L), eq("ORDER-REMAINDER"), eq("IN-001-1"), eq(12),
|
eq(1002L), eq("ORDER-REMAINDER"), eq("IN-001-1"), eq(12),
|
||||||
eq(1), eq("REMAINDER"), eq(9L), eq("operator"));
|
eq(1), eq("REMAINDER"), eq(9L), eq("operator"));
|
||||||
|
verify(splits).transferRemainingCartonLabels(eq(10001L), eq(31L), anyLong(),
|
||||||
|
eq(1002L), eq("IN-001-1"), eq(12));
|
||||||
verify(splits).markSourceLoaded(10001L, 31L, 8, 9L, 3);
|
verify(splits).markSourceLoaded(10001L, 31L, 8, 9L, 3);
|
||||||
verify(allocations).consume(10001L, 31L, 1L, 8);
|
verify(allocations).consume(10001L, 31L, 1L, 8);
|
||||||
verify(warehouse).settle(eq("internal-token"), org.mockito.ArgumentMatchers.argThat(request ->
|
verify(warehouse).settle(eq("internal-token"), org.mockito.ArgumentMatchers.argThat(request ->
|
||||||
|
|||||||
@@ -425,6 +425,21 @@ export async function run(context, matrix = context.createdResources.manualState
|
|||||||
const completed = await complete(context, await pickAll(context,
|
const completed = await complete(context, await pickAll(context,
|
||||||
await claim(context, await createPlanTask(context, 'DONE'), 'DONE'), 'DONE'), 'DONE')
|
await claim(context, await createPlanTask(context, 'DONE'), 'DONE'), 'DONE'), 'DONE')
|
||||||
|
|
||||||
|
const loadingOrderId = id(inProgress.source?.detail?.summary?.orderId)
|
||||||
|
const loadingTenantId = id(inProgress.source?.tenantId)
|
||||||
|
const loadingOrderResponse = await context.request('GET',
|
||||||
|
`/api/platform/v1/orders/${encodeURIComponent(loadingOrderId)}?tenantId=${encodeURIComponent(loadingTenantId)}`)
|
||||||
|
const loadingOrder = context.apiSuccess(MODULE, '读取人工 PROGRESS 对应 LOADING 统一订单', loadingOrderResponse, '', OPTIONS)
|
||||||
|
context.assert(MODULE, '人工 PROGRESS 稳定提供统一订单 LOADING 样本', loadingOrderResponse,
|
||||||
|
id(loadingOrder?.summary?.orderId) === loadingOrderId && loadingOrder?.summary?.mainStatus === 'LOADING',
|
||||||
|
`orderId=${loadingOrderId || 'missing'}, status=${loadingOrder?.summary?.mainStatus || 'missing'}`, OPTIONS)
|
||||||
|
if (loadingOrderId && loadingOrder?.summary?.mainStatus === 'LOADING') {
|
||||||
|
matrix.pages.unifiedOrders.fixtures.LOADING = {
|
||||||
|
id: loadingOrderId, status: 'LOADING', inboundId: inProgress.source.inboundId,
|
||||||
|
detailPath: `/orders/${loadingOrderId}`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const chains = { EDITING: editing, LOADING: inProgress, COMPLETED: completed }
|
const chains = { EDITING: editing, LOADING: inProgress, COMPLETED: completed }
|
||||||
for (const [status, chain] of Object.entries(chains)) {
|
for (const [status, chain] of Object.entries(chains)) {
|
||||||
matrix.pages.containerLoading.fixtures[status] = fixture(chain.containerId, status,
|
matrix.pages.containerLoading.fixtures[status] = fixture(chain.containerId, status,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { normalizeModuleOrder, parseArguments } from '../admin-test-env-acceptan
|
|||||||
|
|
||||||
const entry = readFileSync(new URL('../admin-test-env-acceptance.mjs', import.meta.url), 'utf8')
|
const entry = readFileSync(new URL('../admin-test-env-acceptance.mjs', import.meta.url), 'utf8')
|
||||||
const source = readFileSync(new URL('./manual-state-matrix.mjs', import.meta.url), 'utf8')
|
const source = readFileSync(new URL('./manual-state-matrix.mjs', import.meta.url), 'utf8')
|
||||||
|
const loadingSource = readFileSync(new URL('./manual-state-loading-pda.mjs', import.meta.url), 'utf8')
|
||||||
|
|
||||||
test('default full acceptance includes the retained manual state matrix after lifecycle modules', () => {
|
test('default full acceptance includes the retained manual state matrix after lifecycle modules', () => {
|
||||||
assert.match(entry, /'manual-state-matrix'/)
|
assert.match(entry, /'manual-state-matrix'/)
|
||||||
@@ -19,8 +20,8 @@ test('focused matrix execution injects real container lifecycle prerequisites an
|
|||||||
'phase3-container-loading',
|
'phase3-container-loading',
|
||||||
'phase3-loading',
|
'phase3-loading',
|
||||||
'ocean-bookings',
|
'ocean-bookings',
|
||||||
'phase3-customs',
|
|
||||||
'phase3-loading-finalize',
|
'phase3-loading-finalize',
|
||||||
|
'phase3-customs',
|
||||||
'manual-state-matrix',
|
'manual-state-matrix',
|
||||||
]
|
]
|
||||||
assert.deepEqual(normalizeModuleOrder(['order-inbound-status-fixtures', 'manual-state-matrix']), expected)
|
assert.deepEqual(normalizeModuleOrder(['order-inbound-status-fixtures', 'manual-state-matrix']), expected)
|
||||||
@@ -36,8 +37,8 @@ test('focused splitting and manual groups resolve producers before consumers wit
|
|||||||
'phase3-loading',
|
'phase3-loading',
|
||||||
'phase3-order-splitting',
|
'phase3-order-splitting',
|
||||||
'ocean-bookings',
|
'ocean-bookings',
|
||||||
'phase3-customs',
|
|
||||||
'phase3-loading-finalize',
|
'phase3-loading-finalize',
|
||||||
|
'phase3-customs',
|
||||||
'manual-state-matrix',
|
'manual-state-matrix',
|
||||||
]
|
]
|
||||||
assert.deepEqual(normalizeModuleOrder([
|
assert.deepEqual(normalizeModuleOrder([
|
||||||
@@ -60,7 +61,7 @@ test('matrix delegates bounded groups and asserts every declared status has a re
|
|||||||
|
|
||||||
test('fixture-unavailable statuses stay supported without becoming hard requirements', () => {
|
test('fixture-unavailable statuses stay supported without becoming hard requirements', () => {
|
||||||
const matrix = { pages: {
|
const matrix = { pages: {
|
||||||
inbounds: { requiredStatuses: ['WAIT_MEASURE', 'WAIT_PRICING', 'FEE_CONFIRMING', 'INBOUNDING', 'VOIDED'], fixtures: {
|
inbounds: { requiredStatuses: ['WAIT_MEASURE', 'MEASURE_REJECTED', 'WAIT_PRICING', 'FEE_CONFIRMING', 'INBOUNDING', 'VOIDED'], fixtures: {
|
||||||
WAIT_MEASURE: { id: '1' },
|
WAIT_MEASURE: { id: '1' },
|
||||||
} },
|
} },
|
||||||
unifiedOrders: { requiredStatuses: ['WAIT_SPLIT', 'LOADING', 'LOADED', 'DELIVERED'], fixtures: {
|
unifiedOrders: { requiredStatuses: ['WAIT_SPLIT', 'LOADING', 'LOADED', 'DELIVERED'], fixtures: {
|
||||||
@@ -71,7 +72,7 @@ test('fixture-unavailable statuses stay supported without becoming hard requirem
|
|||||||
normalizeStateRequirements(matrix)
|
normalizeStateRequirements(matrix)
|
||||||
|
|
||||||
assert.deepEqual(matrix.pages.inbounds.supportedStatuses,
|
assert.deepEqual(matrix.pages.inbounds.supportedStatuses,
|
||||||
['WAIT_MEASURE', 'WAIT_PRICING', 'FEE_CONFIRMING', 'INBOUNDING', 'VOIDED'])
|
['WAIT_MEASURE', 'MEASURE_REJECTED', 'WAIT_PRICING', 'FEE_CONFIRMING', 'INBOUNDING', 'VOIDED'])
|
||||||
assert.deepEqual(matrix.pages.inbounds.requiredStatuses, ['WAIT_MEASURE'])
|
assert.deepEqual(matrix.pages.inbounds.requiredStatuses, ['WAIT_MEASURE'])
|
||||||
assert.deepEqual(matrix.pages.unifiedOrders.requiredStatuses, ['WAIT_SPLIT', 'LOADING', 'LOADED'])
|
assert.deepEqual(matrix.pages.unifiedOrders.requiredStatuses, ['WAIT_SPLIT', 'LOADING', 'LOADED'])
|
||||||
assert.equal(matrix.pages.inbounds.coverageGaps.WAIT_PRICING.category, 'fixture-unavailable')
|
assert.equal(matrix.pages.inbounds.coverageGaps.WAIT_PRICING.category, 'fixture-unavailable')
|
||||||
@@ -93,7 +94,8 @@ test('unknown missing status is never swallowed by the known coverage-gap allowl
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('LOADING and LOADED fixtures are resolved through inbound and unified-order details', () => {
|
test('LOADING and LOADED fixtures are resolved through inbound and unified-order details', () => {
|
||||||
assert.match(source, /attachUnifiedOrderFixture\(context, matrix, 'phase3ContainerLoading', 'LOADING'\)/)
|
assert.match(loadingSource, /matrix\.pages\.unifiedOrders\.fixtures\.LOADING/)
|
||||||
|
assert.match(loadingSource, /loadingOrder\?\.summary\?\.mainStatus === 'LOADING'/)
|
||||||
assert.match(source, /attachUnifiedOrderFixture\(context, matrix, 'phase3Loading', 'LOADED'\)/)
|
assert.match(source, /attachUnifiedOrderFixture\(context, matrix, 'phase3Loading', 'LOADED'\)/)
|
||||||
assert.match(source, /\/api\/platform\/inbounds\/\$\{encodeURIComponent\(inboundId\)\}/)
|
assert.match(source, /\/api\/platform\/inbounds\/\$\{encodeURIComponent\(inboundId\)\}/)
|
||||||
assert.match(source, /id\(inbound\?\.summary\?\.id\) === inboundId/)
|
assert.match(source, /id\(inbound\?\.summary\?\.id\) === inboundId/)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ const GROUPS = [
|
|||||||
|
|
||||||
const FIXTURE_UNAVAILABLE = {
|
const FIXTURE_UNAVAILABLE = {
|
||||||
inbounds: {
|
inbounds: {
|
||||||
|
MEASURE_REJECTED: '当前稳定 Admin 契约未开放测量审核驳回接口,无法稳定构造该状态',
|
||||||
WAIT_PRICING: '自动计费会继续推进,无法稳定保留 WAIT_PRICING',
|
WAIT_PRICING: '自动计费会继续推进,无法稳定保留 WAIT_PRICING',
|
||||||
FEE_CONFIRMING: '当前无可稳定保留的费用确认前公开生成链路',
|
FEE_CONFIRMING: '当前无可稳定保留的费用确认前公开生成链路',
|
||||||
INBOUNDING: '自动入库在同一调用内继续推进 WAIT_SPLIT,无可暂停 API',
|
INBOUNDING: '自动入库在同一调用内继续推进 WAIT_SPLIT,无可暂停 API',
|
||||||
@@ -112,7 +113,6 @@ export async function run(context) {
|
|||||||
await extension.run(context, matrix)
|
await extension.run(context, matrix)
|
||||||
}
|
}
|
||||||
|
|
||||||
await attachUnifiedOrderFixture(context, matrix, 'phase3ContainerLoading', 'LOADING')
|
|
||||||
await attachUnifiedOrderFixture(context, matrix, 'phase3Loading', 'LOADED')
|
await attachUnifiedOrderFixture(context, matrix, 'phase3Loading', 'LOADED')
|
||||||
normalizeStateRequirements(matrix)
|
normalizeStateRequirements(matrix)
|
||||||
registerFixtureUnavailableGaps(context, matrix)
|
registerFixtureUnavailableGaps(context, matrix)
|
||||||
|
|||||||
Reference in New Issue
Block a user