贴标申请,仓储转运
This commit is contained in:
+3
-1
@@ -516,6 +516,8 @@ public class DeliveryTransferService {
|
|||||||
existing = outboundOrders.findByIdempotency(customerId, request.idempotencyKey().trim());
|
existing = outboundOrders.findByIdempotency(customerId, request.idempotencyKey().trim());
|
||||||
if (existing != null) return replayReturnOutbound(customerId, existing, requestHash);
|
if (existing != null) return replayReturnOutbound(customerId, existing, requestHash);
|
||||||
for (ReturnInventoryCarton carton : locked) {
|
for (ReturnInventoryCarton carton : locked) {
|
||||||
|
if (StringUtils.hasText(request.skuCode()) && !"PARCEL".equals(carton.getSourceUnitType()))
|
||||||
|
throw conflict("单SKU出库只允许散件库存;箱内库存请按箱或托盘出库");
|
||||||
if ("PARCEL".equals(carton.getSourceUnitType()) && !StringUtils.hasText(request.skuCode()))
|
if ("PARCEL".equals(carton.getSourceUnitType()) && !StringUtils.hasText(request.skuCode()))
|
||||||
throw conflict("包裹散件只能按 SKU 出库,不能按箱号或托盘出库");
|
throw conflict("包裹散件只能按 SKU 出库,不能按箱号或托盘出库");
|
||||||
com.baiyue.lastleg.returnreceipt.service.ReturnCartonCountGuard.requireConfirmed(carton);
|
com.baiyue.lastleg.returnreceipt.service.ReturnCartonCountGuard.requireConfirmed(carton);
|
||||||
@@ -525,7 +527,7 @@ public class DeliveryTransferService {
|
|||||||
throw conflict("退货箱缺少明细或已被合箱计划锁定:" + carton.getCartonMark());
|
throw conflict("退货箱缺少明细或已被合箱计划锁定:" + carton.getCartonMark());
|
||||||
if (StringUtils.hasText(request.skuCode()) && (contents.size() != 1
|
if (StringUtils.hasText(request.skuCode()) && (contents.size() != 1
|
||||||
|| !request.skuCode().trim().equals(contents.get(0).getSkuCode())))
|
|| !request.skuCode().trim().equals(contents.get(0).getSkuCode())))
|
||||||
throw conflict("单SKU出库只支持箱内仅有指定SKU的库存;混合箱请先拆箱");
|
throw conflict("所选散件来源必须仅包含指定SKU");
|
||||||
if ("PALLET".equals(request.unitType()) && !StringUtils.hasText(carton.getPalletCode()))
|
if ("PALLET".equals(request.unitType()) && !StringUtils.hasText(carton.getPalletCode()))
|
||||||
throw conflict("整托出库必须存在托盘绑定");
|
throw conflict("整托出库必须存在托盘绑定");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -825,7 +825,7 @@ paths:
|
|||||||
/api/platform/v1/last-leg/outbound-orders/return:
|
/api/platform/v1/last-leg/outbound-orders/return:
|
||||||
post:
|
post:
|
||||||
summary: 创建退货出库单,支持单SKU全部或部分件数
|
summary: 创建退货出库单,支持单SKU全部或部分件数
|
||||||
description: 权限 platform:overseas-warehouse:outbound:create;单SKU来源须为纯SKU可用箱或散件。混合SKU箱须先拆箱。按箱唛排序分配件数,未拣货前占用整个使用来源;拣货后原箱余数恢复可用。相同幂等键改数量拒绝。
|
description: 权限 platform:overseas-warehouse:outbound:create;单SKU来源仅允许PARCEL散件可用库存,不包含箱内库存;实体箱按箱或托盘出库。按散件来源排序分配件数,未拣货前占用整个使用来源;拣货后来源余数恢复可用。相同幂等键改数量拒绝。
|
||||||
security: [{ bearerAuth: [] }]
|
security: [{ bearerAuth: [] }]
|
||||||
parameters: [{ name: customerId, in: query, required: true, schema: { type: string } }]
|
parameters: [{ name: customerId, in: query, required: true, schema: { type: string } }]
|
||||||
requestBody:
|
requestBody:
|
||||||
|
|||||||
+9
-11
@@ -240,6 +240,7 @@ class DeliveryTransferServiceTest {
|
|||||||
void partialSkuOutboundDistributesSixPiecesAcrossTwoFivePieceSources() {
|
void partialSkuOutboundDistributesSixPiecesAcrossTwoFivePieceSources() {
|
||||||
var first = returnCarton("RC-1", null); first.setId(901L); first.setTotalQuantity(5L);
|
var first = returnCarton("RC-1", null); first.setId(901L); first.setTotalQuantity(5L);
|
||||||
var second = returnCarton("RC-2", null); second.setId(902L); second.setTotalQuantity(5L);
|
var second = returnCarton("RC-2", null); second.setId(902L); second.setTotalQuantity(5L);
|
||||||
|
first.setSourceUnitType("PARCEL"); second.setSourceUnitType("PARCEL");
|
||||||
when(returnCartons.lockMark("RC-1")).thenReturn(first); when(returnCartons.lockMark("RC-2")).thenReturn(second);
|
when(returnCartons.lockMark("RC-1")).thenReturn(first); when(returnCartons.lockMark("RC-2")).thenReturn(second);
|
||||||
var line = new ReturnInventoryCartonItem(); line.setSkuCode("SKU-A"); line.setQuantity(5L);
|
var line = new ReturnInventoryCartonItem(); line.setSkuCode("SKU-A"); line.setQuantity(5L);
|
||||||
when(returnCartonItems.lockCarton(901L)).thenReturn(List.of(line));
|
when(returnCartonItems.lockCarton(901L)).thenReturn(List.of(line));
|
||||||
@@ -252,25 +253,22 @@ class DeliveryTransferServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void singleSkuReturnOutboundAcceptsPackedSingleSkuButKeepsCartonScanning() {
|
void singleSkuReturnOutboundRejectsPackedSingleSkuWithoutReservingInventory() {
|
||||||
ReturnInventoryCarton carton = returnCarton("RC-BOX", "PAL-1");
|
ReturnInventoryCarton carton = returnCarton("RC-BOX", "PAL-1");
|
||||||
carton.setSourceUnitType("BOX"); carton.setTotalQuantity(5L);
|
carton.setSourceUnitType("BOX"); carton.setTotalQuantity(5L);
|
||||||
ReturnInventoryCartonItem line = new ReturnInventoryCartonItem();
|
|
||||||
line.setSkuCode("SKU-A"); line.setQuantity(5L);
|
|
||||||
when(returnCartons.lockMark("RC-BOX")).thenReturn(carton);
|
when(returnCartons.lockMark("RC-BOX")).thenReturn(carton);
|
||||||
when(returnCartonItems.lockCarton(carton.getId())).thenReturn(List.of(line));
|
var error = assertThrows(ResponseStatusException.class, () -> service.createReturnOutbound("TENANT-A", "U-1",
|
||||||
service.createReturnOutbound("TENANT-A", "U-1",
|
new DeliveryRequests.ReturnOutbound("receiver", "WH-1", "RT-1", List.of("RC-BOX"), null, "packed-sku", "SKU-A")));
|
||||||
new DeliveryRequests.ReturnOutbound("receiver", "WH-1", "RT-1", List.of("RC-BOX"), null, "packed-sku", "SKU-A"));
|
assertTrue(error.getReason().contains("单SKU出库只允许散件库存"));
|
||||||
ArgumentCaptor<OutboundPalletItem> item = ArgumentCaptor.forClass(OutboundPalletItem.class);
|
verify(outboundOrders, never()).insert(any(OutboundOrder.class));
|
||||||
verify(outboundPallets).insert(item.capture());
|
verify(returnCartons, never()).updateById(any(ReturnInventoryCarton.class));
|
||||||
assertNull(item.getValue().getSkuCode());
|
assertEquals("AVAILABLE", carton.getStatus());
|
||||||
assertEquals("RC-BOX", item.getValue().getCartonMarks());
|
|
||||||
assertEquals("OUTBOUND_PENDING", carton.getStatus());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void singleSkuReturnOutboundRejectsMixedCarton() {
|
void singleSkuReturnOutboundRejectsMixedCarton() {
|
||||||
ReturnInventoryCarton mixed = returnCarton("RC-MIXED", null);
|
ReturnInventoryCarton mixed = returnCarton("RC-MIXED", null);
|
||||||
|
mixed.setSourceUnitType("PARCEL");
|
||||||
mixed.setId(901L); mixed.setTotalQuantity(5L);
|
mixed.setId(901L); mixed.setTotalQuantity(5L);
|
||||||
ReturnInventoryCartonItem skuA = new ReturnInventoryCartonItem(); skuA.setSkuCode("SKU-A"); skuA.setQuantity(3L);
|
ReturnInventoryCartonItem skuA = new ReturnInventoryCartonItem(); skuA.setSkuCode("SKU-A"); skuA.setQuantity(3L);
|
||||||
ReturnInventoryCartonItem skuB = new ReturnInventoryCartonItem(); skuB.setSkuCode("SKU-B"); skuB.setQuantity(2L);
|
ReturnInventoryCartonItem skuB = new ReturnInventoryCartonItem(); skuB.setSkuCode("SKU-B"); skuB.setQuantity(2L);
|
||||||
|
|||||||
Reference in New Issue
Block a user