提交
This commit is contained in:
@@ -100,8 +100,8 @@ public interface ContainerBookingMapper extends BaseMapper<ContainerBookingEntit
|
||||
WHERE departure.container_booking_id=b.id
|
||||
AND departure.confirmed_at IS NOT NULL AND departure.reversed_at IS NULL
|
||||
AND departure.status='WAITING_FOR_LOADING')
|
||||
AND ((#{query.scope}='ACTIVE' AND b.actual_empty_reported_at IS NULL)
|
||||
OR (#{query.scope}='HISTORY' AND b.actual_empty_reported_at IS NOT NULL))))
|
||||
AND ((#{query.scope}='ACTIVE' AND NOT EXISTS (SELECT 1 FROM fl_terminal_drayage returned WHERE returned.container_booking_id=b.id AND returned.actual_empty_return_at IS NOT NULL UNION ALL SELECT 1 FROM fl_carrier_schedule_node_fact returned_node WHERE returned_node.container_booking_id=b.id AND returned_node.standard_node='EMPTY_RETURNED' AND returned_node.actual_at IS NOT NULL))
|
||||
OR (#{query.scope}='HISTORY' AND EXISTS (SELECT 1 FROM fl_terminal_drayage returned WHERE returned.container_booking_id=b.id AND returned.actual_empty_return_at IS NOT NULL UNION ALL SELECT 1 FROM fl_carrier_schedule_node_fact returned_node WHERE returned_node.container_booking_id=b.id AND returned_node.standard_node='EMPTY_RETURNED' AND returned_node.actual_at IS NOT NULL)))))
|
||||
AND (#{query.keyword} IS NULL OR b.container_no LIKE CONCAT('%', #{query.keyword}, '%')
|
||||
OR b.cabinet_no LIKE CONCAT('%', #{query.keyword}, '%')
|
||||
OR b.bill_of_lading_no LIKE CONCAT('%', #{query.keyword}, '%')
|
||||
|
||||
@@ -379,6 +379,26 @@ public interface DropshipPalletizationMapper {
|
||||
ORDER BY inbound_detail_id
|
||||
""") List<PalletLine> sealedPalletLines(@Param("palletId") long palletId);
|
||||
|
||||
/** 未装托盘标签按物理箱身份转移,保留原箱码不重新编号。 */
|
||||
@Update("""
|
||||
<script>UPDATE fl_inbound_carton_label SET inbound_id=#{child},order_id=#{order},inbound_code=#{code},
|
||||
total_carton_count=#{packages},detail_package_count=LEAST(detail_package_count,#{packages})
|
||||
WHERE tenant_id=#{tenant} AND inbound_id=#{source} AND batch_status='ACTIVE'
|
||||
AND id IN (SELECT c.carton_label_id FROM fl_dropship_pallet_carton c
|
||||
WHERE c.tenant_id=#{tenant} AND c.inbound_id=#{source} AND c.pallet_id IS NOT NULL
|
||||
AND c.pallet_id NOT IN <foreach collection="picked" item="id" open="(" separator="," close=")">#{id}</foreach>)
|
||||
</script>""")
|
||||
int transferRemainderLabels(@Param("tenant") long tenant,@Param("source") long source,@Param("child") long child,
|
||||
@Param("order") long order,@Param("code") String code,@Param("packages") int packages,@Param("picked") List<Long> picked);
|
||||
/** 实箱随余量单转移,已装托与跨客户托内其他成员保持原归属。 */
|
||||
@Update("""
|
||||
<script>UPDATE fl_dropship_pallet_carton SET inbound_id=#{child}
|
||||
WHERE tenant_id=#{tenant} AND inbound_id=#{source} AND pallet_id IS NOT NULL
|
||||
AND pallet_id NOT IN <foreach collection="picked" item="id" open="(" separator="," close=")">#{id}</foreach>
|
||||
</script>""")
|
||||
int transferRemainderCartons(@Param("tenant") long tenant,@Param("source") long source,
|
||||
@Param("child") long child,@Param("picked") List<Long> picked);
|
||||
|
||||
@Getter @Setter class TaskRow { private Long id,tenantId,inboundId,warehouseId,assigneeId; private String inboundCode,customerName,warehouseName,taskStatus,assigneeName,processStatus,fulfillmentType; private Integer totalCartons,countedCartons,allocatedCartons,discrepancyCartons,expectedPalletCount,version; }
|
||||
@Getter @Setter class PalletRow { private Long id,taskId,tenantId,inboundId,warehouseId; private String palletNo,palletStatus,sealOperationId; private Integer version; private LocalDateTime completedAt; }
|
||||
@Getter @Setter class PlanPalletMemberRow { private Long palletId,accountId,inboundId,orderId; private String orderNo,inboundCode,customerName,orderStatusSnapshot; private Integer availablePackageCount; private LocalDateTime expectedArrivalAt; }
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.baiyue.firstleg.repository;
|
||||
|
||||
import com.baiyue.firstleg.mapper.DropshipPalletizationMapper;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.util.List;
|
||||
|
||||
/** 分托装柜余量的实箱归属迁移。 */
|
||||
@Repository
|
||||
public class DropshipSplitRepository {
|
||||
private final DropshipPalletizationMapper mapper;
|
||||
/** 复用一件代发实箱账本,不另建库存。 */
|
||||
public DropshipSplitRepository(DropshipPalletizationMapper mapper) { this.mapper = mapper; }
|
||||
/** 排除本柜已拣托盘,逐箱迁移到余量入仓单;数量不一致回滚本地结算。 */
|
||||
public void transferRemainder(long tenant, long source, long child, long order, String code,
|
||||
int packages, List<Long> pickedPallets) {
|
||||
if (pickedPallets.isEmpty()) throw new BizException(ResultCode.CONFLICT, "缺少已装整托事实");
|
||||
if (mapper.transferRemainderLabels(tenant, source, child, order, code, packages, pickedPallets) != packages
|
||||
|| mapper.transferRemainderCartons(tenant, source, child, pickedPallets) != packages)
|
||||
throw new BizException(ResultCode.CONFLICT, "未装托盘箱数与余量不一致,请刷新后重试");
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,8 @@ public class PdaPickSettlementService {
|
||||
private InboundHoldGuard inboundHoldGuard;
|
||||
@Resource
|
||||
private DropshipPalletizationMapper dropshipPallets;
|
||||
@Resource
|
||||
private com.baiyue.firstleg.repository.DropshipSplitRepository dropshipSplits;
|
||||
@Value("${baiyue.security.internal-service-token}")
|
||||
private String internalToken;
|
||||
|
||||
@@ -121,6 +123,7 @@ public class PdaPickSettlementService {
|
||||
}
|
||||
}
|
||||
|
||||
/** 按柜次实拣数量结算,一件代发保留未装整托供后续柜次使用。 */
|
||||
private boolean settleInbound(long parentInboundId, int pickedPackageCount,
|
||||
List<LoadingPickItemEntity> taskItems, long taskId,
|
||||
long operatorId, String operatorName) {
|
||||
@@ -184,9 +187,7 @@ public class PdaPickSettlementService {
|
||||
&& pickedByDetail.values().stream().mapToInt(Integer::intValue).sum() != pickedPackageCount) {
|
||||
throw conflict("PDA 已拣明细与入库单已拣箱数不一致");
|
||||
}
|
||||
if (dropshipWholePallet && childPackageCount != 0) {
|
||||
throw conflict("一件代发现场托盘必须整票装柜,不能生成余量分片");
|
||||
}
|
||||
|
||||
List<MeasurementSplitLine> measurementLines = dropshipWholePallet
|
||||
? wholePalletMeasurementLines(measurements, pickedPackageCount, parentAvailable)
|
||||
: measurementLines(measurements, pickedByDetail);
|
||||
@@ -219,8 +220,17 @@ public class PdaPickSettlementService {
|
||||
requireAffected(splits.cloneChildWithPurpose(parent.tenantId(), parentInboundId, rootInboundId, remainderChildId,
|
||||
orderSplit.remainderChild().orderId(), orderSplit.remainderChild().orderNo(),
|
||||
remainderChildCode, childPackageCount, sequence, "REMAINDER", operatorId, operatorName), "余量子入库单");
|
||||
splits.transferRemainingCartonLabels(parent.tenantId(), parentInboundId, remainderChildId,
|
||||
orderSplit.remainderChild().orderId(), remainderChildCode, pickedPackageCount, childPackageCount);
|
||||
if (dropshipWholePallet) {
|
||||
var pickedPalletIds = taskItems.stream().filter(item -> "PICKED".equals(item.getItemStatus())
|
||||
&& "SEALED_PALLET".equals(item.getUnitType())).map(LoadingPickItemEntity::getPalletId)
|
||||
.filter(Objects::nonNull).distinct().toList();
|
||||
// 托内箱按实际箱唛移动,不能按箱序号截取,否则会移错已装托盘。
|
||||
dropshipSplits.transferRemainder(parent.tenantId(), parentInboundId, remainderChildId,
|
||||
orderSplit.remainderChild().orderId(), remainderChildCode, childPackageCount, pickedPalletIds);
|
||||
} else {
|
||||
splits.transferRemainingCartonLabels(parent.tenantId(), parentInboundId, remainderChildId,
|
||||
orderSplit.remainderChild().orderId(), remainderChildCode, pickedPackageCount, childPackageCount);
|
||||
}
|
||||
splits.normalizeLoadedCartonLabels(parent.tenantId(), parentInboundId, pickedPackageCount);
|
||||
}
|
||||
requireAffected(splits.insertBatchWithChildren(batchId, parent.tenantId(), rootInboundId, operationId, parentInboundId,
|
||||
@@ -408,17 +418,24 @@ public class PdaPickSettlementService {
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 一件代发逐箱封托已经冻结 SKU 归属;测量批次只承担整票体积重量,不再冒充 SKU 明细。 */
|
||||
/** 整托箱数守恒,测量行按箱数分摊重量体积;真实SKU组成仍由封托箱账本冻结。 */
|
||||
private static List<MeasurementSplitLine> wholePalletMeasurementLines(List<MeasurementItemRow> measurements,
|
||||
int pickedPackageCount,
|
||||
int parentAvailable) {
|
||||
int measuredPackages = measurements.stream()
|
||||
.mapToInt(item -> count(item.packageCount(), "测量明细箱数")).sum();
|
||||
if (pickedPackageCount != parentAvailable || measuredPackages != parentAvailable) {
|
||||
if (pickedPackageCount <= 0 || pickedPackageCount > parentAvailable || measuredPackages != parentAvailable) {
|
||||
throw conflict("一件代发整托箱数与入库单、测量批次不守恒");
|
||||
}
|
||||
return measurements.stream().map(item -> new MeasurementSplitLine(item,
|
||||
count(item.packageCount(), "测量明细箱数"), 0)).toList();
|
||||
int left = pickedPackageCount;
|
||||
List<MeasurementSplitLine> result = new ArrayList<>();
|
||||
for (var item : measurements) {
|
||||
int total = count(item.packageCount(), "测量明细箱数");
|
||||
int picked = Math.min(total, left);
|
||||
result.add(new MeasurementSplitLine(item, picked, total - picked));
|
||||
left -= picked;
|
||||
}
|
||||
return List.copyOf(result);
|
||||
}
|
||||
|
||||
private static Map<Long, Integer> measurementQuantities(List<MeasurementSplitLine> lines) {
|
||||
|
||||
@@ -72,7 +72,7 @@ public class SplitPreloadService {
|
||||
@Transactional
|
||||
public void ensurePendingForLoadingAllocation(long tenantId, long inboundId, long operatorId,
|
||||
String operatorName) {
|
||||
ensureLoadingAllocationLifecycle(tenantId, inboundId, operatorId, operatorName, false);
|
||||
ensureLoadingAllocationLifecycle(tenantId, inboundId, operatorId, operatorName);
|
||||
}
|
||||
|
||||
/** Creates a provisional preload lifecycle for an order selected before it reaches WAIT_SPLIT. */
|
||||
@@ -113,16 +113,17 @@ public class SplitPreloadService {
|
||||
@Transactional
|
||||
public void ensureForRunningLoadingAllocation(long tenantId, long inboundId, long operatorId,
|
||||
String operatorName) {
|
||||
ensureLoadingAllocationLifecycle(tenantId, inboundId, operatorId, operatorName, true);
|
||||
ensureLoadingAllocationLifecycle(tenantId, inboundId, operatorId, operatorName);
|
||||
}
|
||||
|
||||
/** 复用既有预装计划;同一入仓单其他未分配整托可继续进入不同柜次。 */
|
||||
private void ensureLoadingAllocationLifecycle(long tenantId, long inboundId, long operatorId,
|
||||
String operatorName, boolean running) {
|
||||
String operatorName) {
|
||||
InboundSnapshot inbound = requireInbound(tenantId, inboundId);
|
||||
PreloadPlanEntity plan = repository.findPlan(tenantId, inboundId);
|
||||
boolean waitingSplit = isWaitingSplit(inbound.processStatus());
|
||||
boolean loading = "LOADING".equals(inbound.processStatus());
|
||||
if (!waitingSplit && !(running && loading)) {
|
||||
if (!waitingSplit && !loading) {
|
||||
throw new BizException(ResultCode.CONFLICT, "仅待分柜订单可以建立智能装柜预装计划");
|
||||
}
|
||||
if (loading && plan == null) {
|
||||
|
||||
+23
@@ -28,6 +28,29 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
@DisplayName("货柜数据库映射契约")
|
||||
class ContainerBookingMapperContractTest {
|
||||
/** 卸货不等于还柜;人工还柜及船司实际还柜都进入历史页签,两个集合互斥。 */
|
||||
@Test void completedScopeUsesActualEmptyReturnInsteadOfUnloadingReport() throws Exception {
|
||||
String page = String.join("\n", ContainerBookingMapper.class
|
||||
.getDeclaredMethod("selectBookingPage", com.baomidou.mybatisplus.extension.plugins.pagination.Page.class,
|
||||
com.baiyue.firstleg.dto.ContainerDtos.Query.class, String.class)
|
||||
.getAnnotation(Select.class).value());
|
||||
int start = page.indexOf("SELECT 1 FROM fl_terminal_drayage returned");
|
||||
String returned = page.substring(start, page.indexOf("))", start));
|
||||
var data = new JdbcDataSource();
|
||||
data.setURL("jdbc:h2:mem:return-scope-" + java.util.UUID.randomUUID() + ";MODE=MySQL;DB_CLOSE_DELAY=-1");
|
||||
var db = new JdbcTemplate(data);
|
||||
db.execute("CREATE TABLE fl_container_booking(id BIGINT,actual_empty_reported_at TIMESTAMP)");
|
||||
db.execute("CREATE TABLE fl_terminal_drayage(container_booking_id BIGINT,actual_empty_return_at TIMESTAMP)");
|
||||
db.execute("CREATE TABLE fl_carrier_schedule_node_fact(container_booking_id BIGINT,standard_node VARCHAR(40),actual_at TIMESTAMP)");
|
||||
db.execute("INSERT INTO fl_container_booking VALUES(1,CURRENT_TIMESTAMP),(2,NULL),(3,NULL),(4,NULL)");
|
||||
db.execute("INSERT INTO fl_terminal_drayage VALUES(2,CURRENT_TIMESTAMP)");
|
||||
db.execute("INSERT INTO fl_carrier_schedule_node_fact VALUES(3,'EMPTY_RETURNED',CURRENT_TIMESTAMP),(4,'EMPTY_RETURNED',NULL)");
|
||||
assertThat(db.queryForList("SELECT b.id FROM fl_container_booking b WHERE EXISTS ("+returned+") ORDER BY b.id",Long.class))
|
||||
.containsExactly(2L,3L);
|
||||
assertThat(db.queryForList("SELECT b.id FROM fl_container_booking b WHERE NOT EXISTS ("+returned+") ORDER BY b.id",Long.class))
|
||||
.containsExactly(1L,4L);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("货柜映射平台级最终表且状态只从装柜计划读取")
|
||||
void mapsFinalBookingContract() throws Exception {
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.baiyue.firstleg.repository;
|
||||
|
||||
import com.baiyue.firstleg.mapper.DropshipPalletizationMapper;
|
||||
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
||||
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/** 分托结算直接验证实际Mapper,箱序号不代表物理已装托盘。 */
|
||||
class DropshipSplitRepositoryTest {
|
||||
/** 已装箱位于序号末尾时,仍只迁移另一托的箱,跨客户同码不受影响。 */
|
||||
@Test void transfersOnlyUnloadedPhysicalCartons() throws Exception {
|
||||
var data = new DriverManagerDataSource("jdbc:h2:mem:"+UUID.randomUUID()+";MODE=MySQL;DB_CLOSE_DELAY=-1", "sa", "");
|
||||
var db = new JdbcTemplate(data);
|
||||
db.execute("CREATE TABLE fl_inbound_carton_label(id BIGINT,tenant_id BIGINT,inbound_id BIGINT,order_id BIGINT,inbound_code VARCHAR(50),batch_status VARCHAR(20),total_carton_count INT,detail_package_count INT,box_code VARCHAR(50))");
|
||||
db.execute("CREATE TABLE fl_dropship_pallet_carton(id BIGINT,tenant_id BIGINT,inbound_id BIGINT,pallet_id BIGINT,carton_label_id BIGINT)");
|
||||
db.update("INSERT INTO fl_inbound_carton_label VALUES(1,10,31,100,'IN-1','ACTIVE',4,4,'BOX-1'),(2,10,31,100,'IN-1','ACTIVE',4,4,'BOX-2'),(3,10,31,100,'IN-1','ACTIVE',4,4,'BOX-3'),(4,10,31,100,'IN-1','ACTIVE',4,4,'BOX-4'),(5,20,31,200,'IN-2','ACTIVE',1,1,'BOX-1')");
|
||||
db.update("INSERT INTO fl_dropship_pallet_carton VALUES(11,10,31,802,1),(12,10,31,802,2),(13,10,31,801,3),(14,10,31,801,4),(15,20,31,802,5)");
|
||||
var config = new MybatisConfiguration(); config.addMapper(DropshipPalletizationMapper.class);
|
||||
var factory = new MybatisSqlSessionFactoryBean(); factory.setDataSource(data); factory.setConfiguration(config);
|
||||
var mapper = new SqlSessionTemplate(factory.getObject()).getMapper(DropshipPalletizationMapper.class);
|
||||
new DropshipSplitRepository(mapper).transferRemainder(10,31,32,101,"IN-1-1",2,List.of(801L));
|
||||
assertThat(db.queryForList("SELECT id FROM fl_inbound_carton_label WHERE inbound_id=32 ORDER BY id",Long.class)).containsExactly(1L,2L);
|
||||
assertThat(db.queryForList("SELECT id FROM fl_dropship_pallet_carton WHERE inbound_id=32 ORDER BY id",Long.class)).containsExactly(11L,12L);
|
||||
assertThat(db.queryForObject("SELECT inbound_id FROM fl_inbound_carton_label WHERE id=5",Long.class)).isEqualTo(31L);
|
||||
assertThat(db.queryForList("SELECT box_code FROM fl_inbound_carton_label WHERE inbound_id=32 ORDER BY id",String.class)).containsExactly("BOX-1","BOX-2");
|
||||
// 下一柜重新读取封托内容时,货物身份必须归到余量子入库单和余量子订单。
|
||||
db.execute("CREATE TABLE fl_dropship_pallet(id BIGINT,pallet_no VARCHAR(50),pallet_status VARCHAR(20))");
|
||||
db.execute("INSERT INTO fl_dropship_pallet VALUES(802,'DP-802','SEALED')");
|
||||
db.execute("ALTER TABLE fl_dropship_pallet_carton ADD inbound_detail_id BIGINT DEFAULT 41");
|
||||
db.execute("ALTER TABLE fl_dropship_pallet_carton ADD sku_code VARCHAR(30) DEFAULT 'SKU-1'");
|
||||
db.execute("ALTER TABLE fl_dropship_pallet_carton ADD cargo_name VARCHAR(30) DEFAULT '货物'");
|
||||
db.execute("ALTER TABLE fl_dropship_pallet_carton ADD actual_sku_quantity INT DEFAULT 1");
|
||||
db.execute("CREATE TABLE fl_dropship_pallet_carton_sku(carton_id BIGINT,inbound_detail_id BIGINT,sku_code VARCHAR(30),cargo_name VARCHAR(30),actual_quantity INT)");
|
||||
db.execute("CREATE TABLE fl_inbound_order(id BIGINT,tenant_id BIGINT,order_id BIGINT,order_no VARCHAR(50),inbound_code VARCHAR(50),warehouse_id BIGINT,channel_code VARCHAR(30),channel_name VARCHAR(30),destination_warehouse_id BIGINT,destination_code VARCHAR(30),destination_name VARCHAR(30),customer_name VARCHAR(30),actual_gross_weight_kg DECIMAL,actual_net_weight_kg DECIMAL,actual_volume_cbm DECIMAL,total_package_count INT)");
|
||||
db.execute("INSERT INTO fl_inbound_order(id,tenant_id,order_id,order_no,inbound_code,total_package_count) VALUES(32,10,101,'ORDER-1-1','IN-1-1',2)");
|
||||
var remainder = mapper.sealedPalletLines(802);
|
||||
assertThat(remainder).hasSize(1);
|
||||
assertThat(remainder.get(0).getInboundId()).isEqualTo(32L);
|
||||
assertThat(remainder.get(0).getOrderId()).isEqualTo(101L);
|
||||
assertThat(remainder.get(0).getInboundDetailId()).isEqualTo(41L);
|
||||
assertThat(remainder.get(0).getCartonCount()).isEqualTo(2);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ class PdaPickSettlementServiceTest {
|
||||
@MockBean private OrderFulfillmentSplitClient orderSplits;
|
||||
@MockBean private InboundHoldGuard inboundHoldGuard;
|
||||
@MockBean private DropshipPalletizationMapper dropshipPallets;
|
||||
@MockBean private com.baiyue.firstleg.repository.DropshipSplitRepository dropshipSplits;
|
||||
@Resource private PdaPickSettlementService service;
|
||||
|
||||
@Test
|
||||
@@ -266,6 +267,29 @@ class PdaPickSettlementServiceTest {
|
||||
&& request.lines().size() == 1 && request.lines().get(0).packageCount() == 20));
|
||||
}
|
||||
|
||||
@Test
|
||||
void settlesOneSealedPalletAndMovesOnlyUnloadedPalletsToRemainder() {
|
||||
var picked = item(11L, 21L, 31L, 41L, 2, 2, "PICKED");
|
||||
picked.setUnitType("SEALED_PALLET"); picked.setPalletId(801L); picked.setPalletNo("DP-1");
|
||||
resolved(List.of(picked));
|
||||
var physical = new DropshipPalletizationMapper.PlanPalletMemberRow();
|
||||
physical.setPalletId(801L); physical.setInboundId(31L); physical.setAccountId(10001L);
|
||||
physical.setAvailablePackageCount(2);
|
||||
when(dropshipPallets.palletInboundMembersByPalletIds(any())).thenReturn(List.of(physical));
|
||||
when(splits.lockParent(31L)).thenReturn(parent(4));
|
||||
when(splits.fulfillmentType(10001L, 31L)).thenReturn("ONE_CLICK_DROPSHIP");
|
||||
when(splits.lockLatestApprovedItemsForInbound(10001L, 31L))
|
||||
.thenReturn(List.of(new MeasurementItemRow(51L, 61L, 41L, 4)));
|
||||
when(allocations.lockConfirmed(10001L, 31L)).thenReturn(List.of(allocation(1L, 1, 501L, 4)));
|
||||
writes(2, 2);
|
||||
service.settle(1L, 9L, "operator");
|
||||
verify(dropshipSplits).transferRemainder(eq(10001L), eq(31L), anyLong(), eq(1002L),
|
||||
eq("IN-001-1"), eq(2), eq(List.of(801L)));
|
||||
verify(splits, never()).transferRemainingCartonLabels(anyLong(), anyLong(), anyLong(), anyLong(), anyString(), anyInt(), anyInt());
|
||||
verify(splits).updateMeasurementItemForLoaded(10001L, 51L, 2);
|
||||
verify(splits).markSourceLoaded(10001L, 31L, 2, 9L, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void onlyPureSkippedInboundRestoresCandidate() {
|
||||
LoadingPickItemEntity item = item(12L, 22L, 32L, 42L, 8, 0, "SKIPPED");
|
||||
|
||||
+2
-3
@@ -148,14 +148,13 @@ class SplitPreloadServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void ordinaryLoadingAllocationStillRequiresWaitingSplit() {
|
||||
void otherCabinetMayReuseExistingPreloadWhileSourceIsLoading() {
|
||||
when(repository.findInbound(10, 20)).thenReturn(new InboundSnapshot(20L, 10L, "LOADING", 3));
|
||||
PreloadPlanEntity plan = new PreloadPlanEntity();
|
||||
plan.setStatus("PENDING");
|
||||
when(repository.findPlan(10, 20)).thenReturn(plan);
|
||||
|
||||
assertThatThrownBy(() -> service.ensurePendingForLoadingAllocation(10, 20, 7, "admin"))
|
||||
.hasMessageContaining("仅待分柜订单");
|
||||
service.ensurePendingForLoadingAllocation(10, 20, 7, "admin");
|
||||
|
||||
verify(repository, never()).createPlan(any());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user