fix(lastleg): resolve transfer storage rent by inbound association

This commit is contained in:
2026-10-26 19:58:07 +08:00
parent 3e0d8d6c88
commit 00616d5930
4 changed files with 24 additions and 2 deletions
@@ -8,4 +8,5 @@ public class StorageRentBusinessSource {
private Long id;
private String businessNo;
private Long lastlegOrderId;
private Long inboundOrderId;
}
@@ -13,9 +13,9 @@ public interface StorageRentBusinessSourceMapper {
@Select("SELECT id,relabel_no AS business_no,lastleg_order_id FROM ll_relabel_application WHERE customer_id=#{customer} AND relabel_no=#{number} LIMIT 1")
StorageRentBusinessSource relabelNo(@Param("customer") String customer,@Param("number") String number);
/** 仓储转运独立业务单归属。 */
@Select("SELECT id,transfer_no AS business_no,lastleg_order_id FROM ll_warehouse_transfer_order WHERE customer_id=#{customer} AND transfer_no=#{number} LIMIT 1")
@Select("SELECT id,transfer_no AS business_no,lastleg_order_id,inbound_order_id FROM ll_warehouse_transfer_order WHERE customer_id=#{customer} AND transfer_no=#{number} LIMIT 1")
StorageRentBusinessSource transfer(@Param("customer") String customer,@Param("number") String number);
/** 原尾程投影映射唯一仓储转运业务。 */
@Select("SELECT id,transfer_no AS business_no,lastleg_order_id FROM ll_warehouse_transfer_order WHERE customer_id=#{customer} AND lastleg_order_id=#{id} LIMIT 1")
@Select("SELECT id,transfer_no AS business_no,lastleg_order_id,inbound_order_id FROM ll_warehouse_transfer_order WHERE customer_id=#{customer} AND lastleg_order_id=#{id} LIMIT 1")
StorageRentBusinessSource transferByTail(@Param("customer") String customer,@Param("id") Long id);
}
@@ -78,6 +78,12 @@ public class StorageRentSourceResolver {
owner=new Owner(customer,null,"RETURN_ORDER",order.getId(),order.getReturnNo(),order.getLastlegOrderId(),null,warehouse);
}else owner=business(customer,null,"LASTLEG_ORDER",null,item.getSourceOrderId(),warehouse,item.getInboundCode());
}else throw conflict("整托预校验应先展开为真实扫码来源");
// 转运的尾程单与入库单独立建号;库存归属必须核对业务单保存的真实入库关联。
if("WAREHOUSE_TRANSFER".equals(owner.businessType())){
var transfer=repository.transfer(customer,owner.businessNo());
if(transfer==null||transfer.getInboundOrderId()==null)throw conflict("转运业务单缺少原入库关联,不能预占仓租");
expectedOrderId=transfer.getInboundOrderId();
}
List<Allocation> allocations;
if(marks!=null){if(request.positionId()!=null)throw conflict("退货扫码不能指定普通库存位置");allocations=returnAllocations(customer,warehouse,marks,sku,pieceQuantity,at);}
else {
@@ -56,6 +56,21 @@ class StorageRentSourceResolverTest {
assertThat(plan.allocations().get(0).quantity()).isEqualByComparingTo("4");assertThat(plan.amount()).isEqualByComparingTo("0.96");
}
/** 转运尾程单与入库单不同号仍能预校验;错入库关联和缺失关联必须拒绝。 */
@Test void transferUsesItsInboundAssociationInsteadOfTailOrderIdentity(){
item.setOrderId(171L);item.setSourceBusinessType("WAREHOUSE_TRANSFER");item.setSourceBusinessNo("ZY-1");
var source=new StorageRentBusinessSource();source.setId(81L);source.setBusinessNo("ZY-1");
source.setLastlegOrderId(171L);source.setInboundOrderId(91L);
when(repository.transfer("101","ZY-1")).thenReturn(source);
var plan=service.resolve("9",request,at);
assertThat(plan.owner().businessNo()).isEqualTo("ZY-1");assertThat(plan.owner().orderId()).isEqualTo(171L);
assertThat(plan.allocations()).hasSize(1);assertThat(plan.allocations().get(0).quantity()).isEqualByComparingTo("4");
source.setInboundOrderId(92L);
assertThatThrownBy(()->service.resolve("9",request,at)).hasMessageContaining("业务单据关联的入库订单");
source.setInboundOrderId(null);
assertThatThrownBy(()->service.resolve("9",request,at)).hasMessageContaining("缺少原入库关联");
}
/** 当前客户覆盖默认价;同一预占消费保存价,余货下次预占读新价且库龄不变。 */
@Test void currentCustomerPricingAndSavedSnapshotKeepOriginalAge(){
var first=customPricing("USD",1,"2","5");when(pricing.current("101")).thenReturn(first);