fix: complete dropship container after pallet receipt
This commit is contained in:
+1
@@ -927,6 +927,7 @@ public class ReceivingContainerService {
|
||||
private void validateFbaSkuBalance(String customerId, String containerNo) {
|
||||
for (InboundRef ref : refs(customerId, containerNo)) {
|
||||
if (!"FBA".equals(destinationType(ref.line(), ref.order()))) continue;
|
||||
if ("ONE_CLICK_DROPSHIP".equals(ref.order().getOrderType())) continue;
|
||||
List<SkuExpectation> skuCodes = skuExpectations(ref);
|
||||
int received = 0;
|
||||
for (SkuExpectation sku : skuCodes) {
|
||||
|
||||
+18
@@ -448,6 +448,24 @@ class ReceivingContainerServiceBehaviorTest {
|
||||
verify(workflow, never()).completeContainer(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void dropshipWholePalletCanCompleteWithoutBulkSkuReceiptRows() {
|
||||
stubCurrent("FBA", "CONT-A");
|
||||
LastlegOrder dropshipOrder = order("FBA");
|
||||
dropshipOrder.setOrderType("ONE_CLICK_DROPSHIP");
|
||||
when(orders.selectById(1L)).thenReturn(dropshipOrder);
|
||||
InboundPlanPalletAllocation received = new InboundPlanPalletAllocation();
|
||||
received.setLineId(10L); received.setPickedPackageCount(2);
|
||||
when(allocations.selectList(any())).thenReturn(List.of(received));
|
||||
when(sessions.updateById(any(ReceivingContainerSession.class))).thenReturn(1);
|
||||
|
||||
var completed = service.complete("7", new ReceivingContainerRequests.Action("dropship-complete"));
|
||||
|
||||
assertThat(completed.status()).isEqualTo("COMPLETED");
|
||||
verifyNoInteractions(skuReceipts);
|
||||
verify(workflow).completeContainer(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void completedRequestReplaysWithoutAnActiveCustomerSession() {
|
||||
ReceivingContainerOperation operation = new ReceivingContainerOperation();
|
||||
|
||||
@@ -41,6 +41,10 @@ test('module covers the public tail-order write surface before PDA receiving', (
|
||||
assert.match(source, /currency === 'CNY'/)
|
||||
assert.match(source, /reviewStatus === 'PENDING'/)
|
||||
assert.match(source, /'Idempotency-Key': `\$\{context\.marker\}-tail-fee`/)
|
||||
assert.match(source, /ensureCurrentUsdRate/)
|
||||
assert.match(source, /monthFrom=\$\{month\}&monthTo=\$\{month\}/)
|
||||
assert.match(source, /existing\?\.status === 'ACTIVE'/)
|
||||
assert.match(source, /businessDate: `\$\{feeMonth\}-01`/)
|
||||
assert.doesNotMatch(source, /supplierDescription/)
|
||||
})
|
||||
|
||||
|
||||
@@ -63,6 +63,26 @@ async function detail(context, row, name = '读取尾程订单即时详情') {
|
||||
return api(context, 'GET', name,
|
||||
query(`${ORDERS}/${encodeURIComponent(id(row.id))}`, { customerId: id(row.customerId) }))
|
||||
}
|
||||
async function ensureCurrentUsdRate(context) {
|
||||
const month = new Date().toISOString().slice(0, 7)
|
||||
const path = `/api/platform/v1/last-leg/master-data/exchange-rates?page=1&size=20&monthFrom=${month}&monthTo=${month}`
|
||||
const listed = await api(context, 'GET', '查询尾程费用业务月汇率', path)
|
||||
const existing = records(listed.data).find((row) => row?.month === month)
|
||||
if (existing?.status === 'ACTIVE' && Number(existing?.usdToCnyAverage) > 0) return month
|
||||
if (existing) {
|
||||
blocker(context, '尾程费用业务月汇率', `业务月${month}汇率存在但不是ACTIVE,拒绝覆盖既有主数据`, listed.response)
|
||||
return null
|
||||
}
|
||||
const created = await api(context, 'POST', '补齐尾程费用业务月汇率',
|
||||
'/api/platform/v1/last-leg/master-data/exchange-rates', {
|
||||
month, usdToCnyAverage: 7.1, remark: `${context.marker} acceptance rate`,
|
||||
})
|
||||
context.assert(MODULE, '尾程费用业务月汇率可用于USD兑CNY', created.response,
|
||||
created.data?.month === month && created.data?.status === 'ACTIVE'
|
||||
&& Number(created.data?.usdToCnyAverage) > 0,
|
||||
`month=${month}, status=${created.data?.status || 'missing'}`, OPTIONS)
|
||||
return created.data?.status === 'ACTIVE' ? month : null
|
||||
}
|
||||
async function verifyReceivingWarehouseChange(context, producer, details) {
|
||||
const bookingId = id(producer.containerBookingId)
|
||||
if (!bookingId) {
|
||||
@@ -168,11 +188,13 @@ async function verifyDestinationMergeFeeAndExport(context, details, producer) {
|
||||
{ orderIds: allIds, palletMergeRequired: false })
|
||||
context.assert(MODULE, '批量合托分组取消成功', batchCleared.response, batchCleared.data == null, trace(batchCleared.response), OPTIONS)
|
||||
|
||||
const feeMonth = await ensureCurrentUsdRate(context)
|
||||
if (!feeMonth) return false
|
||||
const feeItem = `${context.marker}-TAIL-FEE`.slice(0, 128)
|
||||
const fee = await api(context, 'POST', '新增本轮尾程订单费用',
|
||||
query(`${ORDERS}/${encodeURIComponent(id(representative.id))}/fees`, { customerId: id(representative.customerId) }),
|
||||
{ feeItemCode: feeItem.slice(0, 64), feeItemName: feeItem, direction: 'RECEIVABLE',
|
||||
currency: 'USD', amount: 0.01, businessDate: new Date().toISOString().slice(0, 10) },
|
||||
currency: 'USD', amount: 0.01, businessDate: `${feeMonth}-01` },
|
||||
{ 'Idempotency-Key': `${context.marker}-tail-fee`.slice(0, 128) })
|
||||
context.assert(MODULE, '尾程费用冻结币种金额和审核状态', fee.response,
|
||||
id(fee.data?.orderId) === id(representative.id) && fee.data?.feeItemName === feeItem
|
||||
|
||||
Reference in New Issue
Block a user