From e61050c4908eccd8f778ed6fd87aed58ba0c1cee Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Fri, 11 Sep 2026 12:12:41 +0800 Subject: [PATCH] feat: precreate dropship pallet codes after measurement --- ...atformDropshipPalletizationController.java | 16 +-- .../dto/DropshipPalletizationDtos.java | 3 - .../dto/InboundMeasurementRequests.java | 6 + .../dto/InboundMeasurementResponses.java | 2 + .../mapper/DropshipPalletizationMapper.java | 31 ++--- .../service/DropshipPalletizationService.java | 66 ++++------- .../InboundCartonLabelPrintService.java | 11 +- .../service/InboundMeasurementService.java | 20 +++- .../service/MeasurementReviewService.java | 4 +- .../openapi/dropship-palletization-v1.yaml | 27 ++--- .../main/resources/openapi/firstleg-v1.yaml | 3 + .../DropshipPalletizationServiceTest.java | 106 +++++------------- .../InboundCartonLabelPrintServiceTest.java | 11 +- 13 files changed, 108 insertions(+), 198 deletions(-) diff --git a/firstleg/src/main/java/com/baiyue/firstleg/controller/PlatformDropshipPalletizationController.java b/firstleg/src/main/java/com/baiyue/firstleg/controller/PlatformDropshipPalletizationController.java index 399f218b6..1ca74b2fa 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/controller/PlatformDropshipPalletizationController.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/controller/PlatformDropshipPalletizationController.java @@ -93,15 +93,6 @@ public class PlatformDropshipPalletizationController { return ApiResponse.success(service.bindPending(taskId, request, user.userId(), user.username())); } - @PostMapping("/tasks/{taskId}/pallets/create-and-bind") - @PreAuthorize("hasAuthority('platform:firstleg:pda:work')") - public ApiResponse createAndBind(@AuthenticationPrincipal AuthenticatedUser user, - @PathVariable @Positive long taskId, - @Valid @RequestBody DropshipPalletizationDtos.CreateAndBindRequest request) { - FirstlegScopeGuard.platform(user); - return ApiResponse.success(service.createAndBind(taskId, request, user.userId(), user.username())); - } - @PostMapping("/tasks/{taskId}/cartons/{cartonId}/move") @PreAuthorize("hasAuthority('platform:firstleg:pda:work')") public ApiResponse moveCarton(@AuthenticationPrincipal AuthenticatedUser user, @@ -130,11 +121,12 @@ public class PlatformDropshipPalletizationController { @RequestParam @Positive long warehouseId, @RequestHeader(value = "X-Request-Id", required = false) String requestId) { FirstlegScopeGuard.platform(user); - Pallet pallet = service.task(taskId, warehouseId, user.userId()).pallets().stream() + Task task = service.task(taskId, warehouseId, user.userId()); + Pallet pallet = task.pallets().stream() .filter(item -> item.palletId() == palletId).findFirst() .orElseThrow(() -> new com.baiyue.common.core.exception.BizException( com.baiyue.common.core.api.ResultCode.NOT_FOUND, "托盘不存在")); - return printService.generateDropshipPallet(pallet, requestId); + return printService.generateDropshipPallet(pallet, task.inboundCode(), requestId); } @GetMapping("/inbound-orders/{inboundId}/pallets") @@ -158,6 +150,6 @@ public class PlatformDropshipPalletizationController { .filter(item -> item.palletId() == palletId).findFirst() .orElseThrow(() -> new com.baiyue.common.core.exception.BizException( com.baiyue.common.core.api.ResultCode.NOT_FOUND, "托盘不存在")); - return printService.generateDropshipPallet(pallet, requestId); + return printService.generateDropshipPallet(pallet, service.inboundCode(accountId, inboundId), requestId); } } diff --git a/firstleg/src/main/java/com/baiyue/firstleg/dto/DropshipPalletizationDtos.java b/firstleg/src/main/java/com/baiyue/firstleg/dto/DropshipPalletizationDtos.java index 78cc53664..75027404b 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/dto/DropshipPalletizationDtos.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/dto/DropshipPalletizationDtos.java @@ -15,9 +15,6 @@ public final class DropshipPalletizationDtos { public record ClaimRequest(@Positive long warehouseId) {} - public record CreateAndBindRequest(@Positive long warehouseId, - @NotBlank @Size(max = 128) String operationId) {} - public enum DiscrepancyAction { MATCH, ACCEPT_VARIANCE } public record CountCartonRequest(@Positive long warehouseId, diff --git a/firstleg/src/main/java/com/baiyue/firstleg/dto/InboundMeasurementRequests.java b/firstleg/src/main/java/com/baiyue/firstleg/dto/InboundMeasurementRequests.java index afefd5038..5488d7cdc 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/dto/InboundMeasurementRequests.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/dto/InboundMeasurementRequests.java @@ -28,8 +28,14 @@ public final class InboundMeasurementRequests { Long measurementId, @NotNull @PositiveOrZero Integer version, @Size(max = 255) String actualGoodsName, + @Positive @Max(1000) Integer expectedPalletCount, @NotEmpty @Size(max = 500) List<@Valid ItemRequest> items ) { + public SaveDraftRequest(Long measurementId, Integer version, String actualGoodsName, + List items) { + this(measurementId, version, actualGoodsName, null, items); + } + @JsonAnySetter public void rejectUnknownField(String fieldName, Object ignored) { throw new IllegalArgumentException("测量草稿不接受字段: " + fieldName); diff --git a/firstleg/src/main/java/com/baiyue/firstleg/dto/InboundMeasurementResponses.java b/firstleg/src/main/java/com/baiyue/firstleg/dto/InboundMeasurementResponses.java index c58ec1b5f..deda6cb94 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/dto/InboundMeasurementResponses.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/dto/InboundMeasurementResponses.java @@ -19,6 +19,8 @@ public final class InboundMeasurementResponses { String companyName, String channelCode, String channelName, + String fulfillmentType, + Integer expectedPalletCount, String processStatus, String measureReviewStatus, @Schema(description = "测量完成后的推荐托盘类型,仅为建议,不代表已分配托盘", diff --git a/firstleg/src/main/java/com/baiyue/firstleg/mapper/DropshipPalletizationMapper.java b/firstleg/src/main/java/com/baiyue/firstleg/mapper/DropshipPalletizationMapper.java index 200815abf..9abb08f91 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/mapper/DropshipPalletizationMapper.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/mapper/DropshipPalletizationMapper.java @@ -13,11 +13,6 @@ import java.util.List; /** 一件代发逐箱清点、待绑托与封托事实。 */ @Mapper public interface DropshipPalletizationMapper { - @Select("SELECT id FROM fl_dropship_pallet_task WHERE id=#{taskId} AND warehouse_id=#{warehouseId} FOR UPDATE") - Long lockTask(@Param("taskId") long taskId,@Param("warehouseId") long warehouseId); - - @Select("SELECT * FROM fl_dropship_pallet WHERE open_operation_id=#{operationId}") - PalletRow palletByOpenOperation(@Param("operationId") String operationId); @Insert(""" INSERT IGNORE INTO fl_dropship_pallet_task (id,tenant_id,inbound_id,warehouse_id,task_status,total_cartons,counted_cartons,allocated_cartons,discrepancy_cartons,version,created_at,updated_at) @@ -69,14 +64,12 @@ public interface DropshipPalletizationMapper { """) PalletRow pallet(@Param("taskId") long taskId,@Param("palletId") long palletId,@Param("warehouseId") long warehouseId); @Select(""" - SELECT DISTINCT p.* FROM fl_dropship_pallet p - JOIN fl_dropship_pallet_carton c ON c.pallet_id=p.id - WHERE c.task_id=#{taskId} ORDER BY p.id + SELECT p.* FROM fl_dropship_pallet p + WHERE p.task_id=#{taskId} ORDER BY p.id """) List pallets(@Param("taskId") long taskId); @Select(""" - SELECT DISTINCT p.* FROM fl_dropship_pallet p - JOIN fl_dropship_pallet_carton c ON c.pallet_id=p.id - WHERE c.tenant_id=#{tenantId} AND c.inbound_id=#{inboundId} ORDER BY p.id + SELECT p.* FROM fl_dropship_pallet p + WHERE p.tenant_id=#{tenantId} AND p.inbound_id=#{inboundId} ORDER BY p.id """) List palletsByInbound(@Param("tenantId") long tenantId,@Param("inboundId") long inboundId); @Select("SELECT inbound_code FROM fl_inbound_order WHERE tenant_id=#{tenantId} AND id=#{inboundId} AND deleted=0") @@ -139,27 +132,19 @@ public interface DropshipPalletizationMapper { completed_by_name=#{operatorName},completed_at=CURRENT_TIMESTAMP(3),version=version+1,updated_at=CURRENT_TIMESTAMP(3) WHERE id=#{palletId} AND warehouse_id=#{warehouseId} AND pallet_status='OPEN' AND version=#{expectedVersion} AND EXISTS(SELECT 1 FROM fl_dropship_pallet_carton c WHERE c.pallet_id=#{palletId}) - AND EXISTS(SELECT 1 FROM fl_dropship_pallet_carton c WHERE c.pallet_id=#{palletId} AND c.task_id=#{taskId}) - AND NOT EXISTS( - SELECT 1 FROM fl_dropship_pallet_task t - WHERE EXISTS(SELECT 1 FROM fl_dropship_pallet_carton c WHERE c.pallet_id=#{palletId} AND c.task_id=t.id) - AND (t.counted_cartons<>t.total_cartons OR t.allocated_cartons<>t.total_cartons - OR EXISTS(SELECT 1 FROM fl_dropship_pallet_carton pending WHERE pending.task_id=t.id AND pending.pallet_id IS NULL)) - )""") + AND EXISTS(SELECT 1 FROM fl_dropship_pallet_carton c WHERE c.pallet_id=#{palletId} AND c.task_id=#{taskId})""") int seal(@Param("taskId") long taskId,@Param("palletId") long palletId,@Param("expectedVersion") int expectedVersion, @Param("warehouseId") long warehouseId,@Param("operationId") String operationId,@Param("operatorId") long operatorId,@Param("operatorName") String operatorName); @Select(""" - SELECT COUNT(DISTINCT p.id) FROM fl_dropship_pallet p - JOIN fl_dropship_pallet_carton c ON c.pallet_id=p.id - WHERE c.task_id=#{taskId} AND p.pallet_status='OPEN' + SELECT COUNT(*) FROM fl_dropship_pallet p + WHERE p.task_id=#{taskId} AND p.pallet_status='OPEN' """) int openPalletCount(@Param("taskId") long taskId); @Select("SELECT DISTINCT task_id FROM fl_dropship_pallet_carton WHERE pallet_id=#{palletId} ORDER BY task_id") List taskIdsByPallet(@Param("palletId") long palletId); @Update(""" UPDATE fl_dropship_pallet_task SET task_status='COMPLETED',completed_at=CURRENT_TIMESTAMP(3),version=version+1,updated_at=CURRENT_TIMESTAMP(3) WHERE id=#{taskId} AND task_status='CLAIMED' AND counted_cartons=total_cartons AND allocated_cartons=total_cartons - AND NOT EXISTS(SELECT 1 FROM fl_dropship_pallet_carton c JOIN fl_dropship_pallet p ON p.id=c.pallet_id - WHERE c.task_id=#{taskId} AND p.pallet_status='OPEN')""") int completeTask(@Param("taskId") long taskId); + AND NOT EXISTS(SELECT 1 FROM fl_dropship_pallet p WHERE p.task_id=#{taskId} AND p.pallet_status='OPEN')""") int completeTask(@Param("taskId") long taskId); @Update(""" UPDATE fl_inbound_order o SET o.process_status='WAIT_SPLIT',o.pallet_count=(SELECT COUNT(DISTINCT p.id) FROM fl_dropship_pallet_carton c JOIN fl_dropship_pallet p ON p.id=c.pallet_id diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/DropshipPalletizationService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/DropshipPalletizationService.java index c8ca1ce2c..c5d59aa5f 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/DropshipPalletizationService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/DropshipPalletizationService.java @@ -9,7 +9,6 @@ import com.baiyue.firstleg.entity.InboundOrderEntity; import com.baiyue.firstleg.mapper.DropshipPalletizationMapper; import com.baiyue.firstleg.mapper.DropshipPalletizationMapper.*; import jakarta.annotation.Resource; -import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; @@ -24,37 +23,16 @@ public class DropshipPalletizationService { @Resource private FirstlegDocumentNumberGenerator documentNumbers; @Transactional - public Task createAndBind(long taskId,CreateAndBindRequest request,long operatorId,String operatorName){ - if(mapper.lockTask(taskId,request.warehouseId())==null) throw new BizException(ResultCode.NOT_FOUND,"未找到当前仓库的一件代发清点组托任务"); - TaskRow task=requireTask(taskId,request.warehouseId()); - if(!Objects.equals(task.getAssigneeId(),operatorId)) throw conflict("任务不属于当前操作员"); - String operation=operation(request.operationId()); - PalletRow replay=mapper.palletByOpenOperation(operation); - if(replay!=null){ - if(!Objects.equals(replay.getTaskId(),taskId)||!Objects.equals(replay.getWarehouseId(),request.warehouseId()) - ||!Objects.equals(replay.getTenantId(),task.getTenantId())) throw conflict("创建托盘幂等号已用于不同任务"); - return view(task); - } - if(!"CLAIMED".equals(task.getTaskStatus())||!"WAIT_PALLETIZE".equals(task.getProcessStatus())) throw conflict("当前任务不允许创建托盘"); - if(!Objects.equals(task.getCountedCartons(),task.getTotalCartons())) throw conflict("请先完成全部箱码清点,再生成托盘码"); - int expected=mapper.unboundCount(taskId); - if(expected==0) throw conflict("当前没有待绑托箱,请先清点箱码"); - long palletId=IdWorker.getId(); - String palletNo=documentNumbers.next("DP"); - mapper.insertPallet(palletId,taskId,task.getTenantId(),task.getInboundId(),task.getWarehouseId(),palletNo,operation,operatorId,operatorName); - int bound=mapper.bindPending(taskId,palletId,operation,operatorId,operatorName); - if(bound!=expected||mapper.adjustBound(taskId,operatorId,bound)!=1) throw conflict("待绑托箱已变化,请刷新后重试"); - if(mapper.seal(taskId,palletId,1,request.warehouseId(),operation,operatorId,operatorName)!=1) - throw conflict("托盘完成状态已变化,请刷新后重试"); - if(mapper.completeTask(taskId)!=1 || mapper.completeInbound(taskId,task.getTenantId(),task.getInboundId(),operatorId)!=1) - throw conflict("一件代发入库完成状态已变化,请刷新后重试"); - return view(requireTask(taskId,request.warehouseId())); - } - - public void createTask(InboundOrderEntity inbound) { + public void createTask(InboundOrderEntity inbound,long operatorId,String operatorName) { if (!"ONE_CLICK_DROPSHIP".equals(inbound.getFulfillmentType())) return; if (inbound.getTotalPackageCount()==null || inbound.getTotalPackageCount()<1) throw invalid("一件代发测量完成箱数无效,不能下发清点组托任务"); - mapper.insertTask(IdWorker.getId(),inbound.getTenantId(),inbound.getId(),inbound.getWarehouseId(),inbound.getTotalPackageCount()); + if (inbound.getPalletCount()==null || inbound.getPalletCount()<1) throw invalid("一件代发预计托数无效,不能生成托盘码"); + long taskId=IdWorker.getId(); + if(mapper.insertTask(taskId,inbound.getTenantId(),inbound.getId(),inbound.getWarehouseId(),inbound.getTotalPackageCount())!=1) return; + for(int sequence=1;sequence<=inbound.getPalletCount();sequence++){ + mapper.insertPallet(IdWorker.getId(),taskId,inbound.getTenantId(),inbound.getId(),inbound.getWarehouseId(), + documentNumbers.next("DP"),"dropship-precreate-"+taskId+"-"+sequence,operatorId,operatorName); + } } public List pending(long operatorId,long warehouseId,String keyword){ return mapper.pending(operatorId,warehouseId,normalize(keyword)); } @@ -104,8 +82,7 @@ public class DropshipPalletizationService { if(!mismatch && request.discrepancyAction()!=DiscrepancyAction.MATCH) throw invalid("实收数量一致时差异动作必须为 MATCH"); if(mismatch && request.discrepancyAction()!=DiscrepancyAction.ACCEPT_VARIANCE) throw conflict("实收数量存在差异,请确认差异处理结果"); if(mismatch && !StringUtils.hasText(remark)) throw invalid("接受数量差异时必须填写处理说明"); - if(StringUtils.hasText(request.palletNo())) throw invalid("逐箱清点阶段不能提前绑定托盘码"); - PalletRow pallet=null; + PalletRow pallet=StringUtils.hasText(request.palletNo())?requireAssignablePallet(task,request.palletNo().trim()):null; long cartonId=IdWorker.getId(); mapper.insertCarton(cartonId,taskId,pallet==null?null:pallet.getId(),task.getTenantId(),task.getInboundId(), label.getInboundDetailId(),label.getCartonLabelId(),label.getSkuCode(),label.getCargoName(),label.getBoxCode(), @@ -118,10 +95,9 @@ public class DropshipPalletizationService { @Transactional public Task bindPending(long taskId,BindPendingRequest request,long operatorId,String operatorName){ TaskRow task=requireWorkingTask(taskId,request.warehouseId(),operatorId); - if(!Objects.equals(task.getCountedCartons(),task.getTotalCartons())) throw conflict("请先完成全部箱码清点,再绑定托盘码"); String operation=operation(request.operationId()); if(mapper.bindOperationCount(taskId,operation)>0) return view(requireTask(taskId,request.warehouseId())); - PalletRow pallet=getOrCreatePallet(task,request.palletNo().trim(),operation,operatorId,operatorName); + PalletRow pallet=requireAssignablePallet(task,request.palletNo().trim()); int expected=mapper.unboundCount(taskId); if(expected==0) throw conflict("当前没有待绑托箱"); int bound=mapper.bindPending(taskId,pallet.getId(),operation,operatorId,operatorName); @@ -136,7 +112,7 @@ public class DropshipPalletizationService { if(carton==null) throw new BizException(ResultCode.NOT_FOUND,"清点箱不存在"); if(carton.getPalletId()!=null) requireOpenPallet(taskId,carton.getPalletId(),request.warehouseId()); PalletRow target=StringUtils.hasText(request.targetPalletNo()) - ? getOrCreatePallet(task,request.targetPalletNo().trim(),operation(request.operationId()),operatorId,operatorName):null; + ? requireAssignablePallet(task,request.targetPalletNo().trim()):null; if(Objects.equals(carton.getPalletId(),target==null?null:target.getId())) return view(task); if(mapper.moveCarton(taskId,cartonId,target==null?null:target.getId(),operation(request.operationId()),operatorId,operatorName)!=1) throw conflict("清点箱已被其他操作修改,请刷新后重试"); @@ -151,7 +127,6 @@ public class DropshipPalletizationService { PalletRow replay=mapper.palletBySealOperation(operation(request.operationId())); if(replay!=null){ if(!Objects.equals(replay.getId(),palletId)||!Objects.equals(replay.getWarehouseId(),request.warehouseId())) throw conflict("封托幂等号已用于其他托盘"); return view(requireTask(taskId,request.warehouseId())); } requireOpenPallet(taskId,palletId,request.warehouseId()); - if(mapper.unboundCount(taskId)>0) throw conflict("仍有已清点待绑托箱,不能封托"); if(mapper.seal(taskId,palletId,request.expectedVersion(),request.warehouseId(),operation(request.operationId()),operatorId,operatorName)!=1) throw conflict("空托盘、托盘状态或版本已变化,请刷新后重试"); for(Long participatingTaskId:mapper.taskIdsByPallet(palletId)){ @@ -170,18 +145,17 @@ public class DropshipPalletizationService { if(code==null) throw new BizException(ResultCode.NOT_FOUND,"入库单不存在"); return mapper.palletsByInbound(tenantId,inboundId).stream().map(p->palletView(p,code)).toList(); } + public String inboundCode(long tenantId,long inboundId){ + String code=mapper.inboundCode(tenantId,inboundId); + if(code==null) throw new BizException(ResultCode.NOT_FOUND,"入库单不存在"); + return code; + } - private PalletRow getOrCreatePallet(TaskRow task,String palletNo,String operation,long operatorId,String operatorName){ + private PalletRow requireAssignablePallet(TaskRow task,String palletNo){ PalletRow existing=mapper.palletByNo(palletNo); - if(existing!=null){ - if(!Objects.equals(existing.getWarehouseId(),task.getWarehouseId())) throw conflict("托盘码属于其他仓库"); - if(!"OPEN".equals(existing.getPalletStatus())) throw conflict("托盘已封托,不能继续绑定箱"); - return existing; - } - try{ mapper.insertPallet(IdWorker.getId(),task.getId(),task.getTenantId(),task.getInboundId(),task.getWarehouseId(),palletNo,operation,operatorId,operatorName); } - catch(DuplicateKeyException e){ existing=mapper.palletByNo(palletNo); if(existing==null) throw conflict("托盘码已被并发占用"); } - existing=mapper.palletByNo(palletNo); - if(existing==null || !Objects.equals(existing.getWarehouseId(),task.getWarehouseId()) || !"OPEN".equals(existing.getPalletStatus())) throw conflict("托盘码已被其他仓库占用或已经封托"); + if(existing==null) throw new BizException(ResultCode.NOT_FOUND,"托盘码不是本单测量审核后生成的托盘码"); + if(!Objects.equals(existing.getTaskId(),task.getId())||!Objects.equals(existing.getWarehouseId(),task.getWarehouseId())) throw conflict("托盘码不属于当前任务"); + if(!"OPEN".equals(existing.getPalletStatus())) throw conflict("托盘已封托,不能继续绑定箱"); return existing; } diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/InboundCartonLabelPrintService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/InboundCartonLabelPrintService.java index 9114087e4..58bfd7def 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/InboundCartonLabelPrintService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/InboundCartonLabelPrintService.java @@ -114,18 +114,19 @@ public class InboundCartonLabelPrintService { } /** 一件代发托盘标签:托盘号、入仓码、SKU箱数和托盘二维码。 */ - public ResponseEntity generateDropshipPallet(Pallet pallet, String requestId) { - if (pallet == null || !"SEALED".equals(pallet.status()) - || !StringUtils.hasText(pallet.palletNo()) || pallet.items().isEmpty()) { - throw new BizException(ResultCode.CONFLICT, "只有已完成且包含货物的一件代发托盘可以打印"); + public ResponseEntity generateDropshipPallet(Pallet pallet, String inboundCode, String requestId) { + if (pallet == null || !StringUtils.hasText(pallet.palletNo())) { + throw new BizException(ResultCode.CONFLICT, "托盘码尚未生成,不能打印"); } String inboundCodes = pallet.items().stream().map(item -> item.inboundCode()) .filter(StringUtils::hasText).distinct().collect(java.util.stream.Collectors.joining("/")); + if (!StringUtils.hasText(inboundCodes)) inboundCodes = inboundCode; String skuSummary = pallet.items().stream() .map(item -> item.skuCode() + "×" + item.cartonCount()) .collect(java.util.stream.Collectors.joining(" / ")); + if (!StringUtils.hasText(skuSummary)) skuSummary = "待归托"; PrintPdfClient.Label label = new PrintPdfClient.Label(pallet.palletNo(), inboundCodes, - "CTNS:" + pallet.cartonCount(), skuSummary, pallet.palletNo(), null); + pallet.cartonCount() == 0 ? "CTNS:—" : "CTNS:" + pallet.cartonCount(), skuSummary, pallet.palletNo(), null); PrintPdfClient.InboundMarkPdfRequest request = new PrintPdfClient.InboundMarkPdfRequest( "INBOUND_MARK_V1", new PrintPdfClient.PageSpec(PAGE_MM, PAGE_MM), pallet.palletNo() + "-托盘唛.pdf", List.of(label)); diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/InboundMeasurementService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/InboundMeasurementService.java index 66a9db379..36200d45d 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/InboundMeasurementService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/InboundMeasurementService.java @@ -131,6 +131,10 @@ public class InboundMeasurementService { throw new BizException(ResultCode.CONFLICT, "测量已提交待审核,不能再保存整批测量数据;如需修改请先退回后重新提交"); } + if ("ONE_CLICK_DROPSHIP".equals(inbound.getFulfillmentType()) + && (request.expectedPalletCount() == null || request.expectedPalletCount() < 1)) { + throw new BizException(ResultCode.VALIDATION_FAILED, "一件代发必须录入预计托数"); + } validateInboundDetails(tenantId, inbound, request.items()); request.items().stream().map(InboundMeasurementRequests.ItemRequest::chargeRuleId) .filter(java.util.Objects::nonNull).distinct().forEach(ruleId -> { @@ -162,6 +166,11 @@ public class InboundMeasurementService { item.overLimitWarning(), item.outerLengthCm(), item.outerWidthCm(), item.outerHeightCm(), item.chargeRuleId(), item.coefficientMode(), item.remark())).toList()); InboundMeasurementEntity saved = batchService.saveBatch(command); + if ("ONE_CLICK_DROPSHIP".equals(inbound.getFulfillmentType())) { + inbound.setPalletCount(request.expectedPalletCount()); + inbound.setUpdatedBy(operatorId); + if (!repository.updateInbound(inbound)) throw concurrentModification(); + } return new InboundMeasurementResponses.DraftSaved(saved.getId(), saved.getVersion(), saved.getStatus()); } @@ -261,7 +270,13 @@ public class InboundMeasurementService { inbound.setMeasureCompletedAt(LocalDateTime.now()); inbound.setActualGrossWeightKg(confirmedTotals.grossWeightKg()); inbound.setActualNetWeightKg(confirmedTotals.netWeightKg()); - inbound.setPalletCount(confirmedTotals.palletCount()); + if ("ONE_CLICK_DROPSHIP".equals(inbound.getFulfillmentType())) { + if (inbound.getPalletCount() == null || inbound.getPalletCount() < 1) { + throw new BizException(ResultCode.VALIDATION_FAILED, "请先录入预计托数并保存,再提交测量审核"); + } + } else { + inbound.setPalletCount(confirmedTotals.palletCount()); + } if (measurement.getTotalVolumeCbm() != null) { inbound.setActualVolumeCbm(measurement.getTotalVolumeCbm()); } @@ -547,7 +562,8 @@ public class InboundMeasurementService { InboundMeasurementResponses.DeclarationSnapshot declaration = latestDeclaration.snapshot(); return new InboundMeasurementResponses.Detail( inbound.getId(), inbound.getInboundCode(), inbound.getCompanyName(), inbound.getChannelCode(), - inbound.getChannelName(), inbound.getProcessStatus(), inbound.getMeasureReviewStatus(), + inbound.getChannelName(), inbound.getFulfillmentType(), inbound.getPalletCount(), + inbound.getProcessStatus(), inbound.getMeasureReviewStatus(), RECOMMENDED_PALLET_TYPE, review == null ? null : review.getReviewReason(), review == null ? null : review.getReviewerId(), review == null ? null : review.getReviewerName(), measurement == null ? null : measurement.getId(), diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/MeasurementReviewService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/MeasurementReviewService.java index 54175a32a..f34ec5bbe 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/MeasurementReviewService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/MeasurementReviewService.java @@ -139,7 +139,7 @@ public class MeasurementReviewService { repository.insertReview(reviewRecord(tenantId, inboundId, request.measurementId(), result, request.reason(), false, null, false, operatorId, operatorName)); if (approved && "ONE_CLICK_DROPSHIP".equals(order.getFulfillmentType())) { - dropshipPalletization.createTask(order); + dropshipPalletization.createTask(order, operatorId, operatorName); } String approvedStatus = "ONE_CLICK_DROPSHIP".equals(order.getFulfillmentType()) ? "WAIT_PALLETIZE" : "WAIT_SPLIT"; @@ -179,7 +179,7 @@ public class MeasurementReviewService { throw concurrentConflict(); } if ("ONE_CLICK_DROPSHIP".equals(order.getFulfillmentType())) { - dropshipPalletization.createTask(order); + dropshipPalletization.createTask(order, operatorId, operatorName); } repository.insertReview(reviewRecord(tenantId, inboundId, request.measurementId(), "REJECTED", null, true, request.reason(), true, operatorId, operatorName)); diff --git a/firstleg/src/main/resources/openapi/dropship-palletization-v1.yaml b/firstleg/src/main/resources/openapi/dropship-palletization-v1.yaml index 83a769ee2..c5b6880e9 100644 --- a/firstleg/src/main/resources/openapi/dropship-palletization-v1.yaml +++ b/firstleg/src/main/resources/openapi/dropship-palletization-v1.yaml @@ -1,8 +1,8 @@ openapi: 3.0.3 info: title: 一件代发国内清点组托 API - version: 2.0.0 - description: 测量、计费后独立下发。先逐箱确认 SKU 实收数量;全部箱码清点完成后才原子生成、绑定并封存正式 DP 托盘码,随后可打印托盘标签。 + version: 3.0.0 + description: 测量环节录入预计托数,审核通过后预生成全部 DP 托盘码并可立即打印。PDA 支持先扫箱或先扫托,逐托封托后完成入库。 paths: /api/platform/v1/first-leg/pda-dropship/tasks/pending: get: @@ -35,7 +35,7 @@ paths: /api/platform/v1/first-leg/pda-dropship/tasks/{taskId}/cartons/count: post: summary: 逐箱确认 SKU 实收数量 - description: 清点阶段只记录箱级实收并进入 COUNTED_UNBOUND,不得提前生成或绑定托盘码。数量不一致必须 ACCEPT_VARIANCE 且填写说明。 + description: 未传 palletNo 时进入待归托区;传入本任务预生成的 OPEN 托盘码时直接归托。数量不一致必须 ACCEPT_VARIANCE 且填写说明。 x-required-authority: platform:firstleg:pda:work parameters: [{$ref: '#/components/parameters/TaskId'}] requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/CountCartonRequest'}}}} @@ -47,14 +47,6 @@ paths: parameters: [{$ref: '#/components/parameters/TaskId'}] requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/BindPendingRequest'}}}} responses: {'200': {description: OK}} - /api/platform/v1/first-leg/pda-dropship/tasks/{taskId}/pallets/create-and-bind: - post: - summary: 完成一件代发入库并生成正式 DP 托盘码 - description: 仅全部箱码已经清点的本人任务可执行;同一事务内生成 DP 托盘码、绑定全部箱、封托并把入仓单推进到待分柜。未完成清点或没有待绑箱时不发码、不建空托。operationId 重放不重复创建;返回已完成 Task。 - x-required-authority: platform:firstleg:pda:work - parameters: [{$ref: '#/components/parameters/TaskId'}] - requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/CreateAndBindRequest'}}}} - responses: {'200': {description: Task}} /api/platform/v1/first-leg/pda-dropship/tasks/{taskId}/cartons/{cartonId}/move: post: summary: 换托,targetPalletNo 为空时退回待绑区 @@ -66,7 +58,7 @@ paths: responses: {'200': {description: OK}} /api/platform/v1/first-leg/pda-dropship/tasks/{taskId}/pallets/{palletId}/seal: post: - summary: 封托;禁止空托、待绑箱、版本冲突和重复归托 + summary: 封托;禁止空托、版本冲突和重复归托 x-required-authority: platform:firstleg:pda:work parameters: - {$ref: '#/components/parameters/TaskId'} @@ -75,8 +67,8 @@ paths: responses: {'200': {description: OK}} /api/platform/v1/first-leg/pda-dropship/tasks/{taskId}/pallets/{palletId}/print: get: - summary: PDA 打印已封托的一件代发托盘码 - description: 仅当前仓库、当前操作员可访问;未封托托盘拒绝打印。返回 100mm × 100mm PDF。 + summary: PDA 打印预生成的一件代发托盘码 + description: 测量审核通过并生成托盘码后即可打印,空托打印“待归托”。仅当前仓库、当前操作员可访问。返回 100mm × 100mm PDF。 x-required-authority: platform:firstleg:pda:view parameters: - {$ref: '#/components/parameters/TaskId'} @@ -143,6 +135,7 @@ components: properties: warehouseId: {type: integer, format: int64} boxCode: {type: string, maxLength: 80} + palletNo: {$ref: '#/components/schemas/NullablePalletNo'} actualSkuQuantity: {type: integer, minimum: 1} discrepancyAction: {type: string, enum: [MATCH, ACCEPT_VARIANCE]} discrepancyRemark: {type: string, maxLength: 500, nullable: true} @@ -169,10 +162,4 @@ components: expectedVersion: {type: integer, minimum: 1} operationId: {type: string, maxLength: 128} PalletNo: {type: string, pattern: '^DP-[0-9]{6}-[0-9]{4}$'} - CreateAndBindRequest: - type: object - required: [warehouseId, operationId] - properties: - warehouseId: {type: integer, format: int64, minimum: 1} - operationId: {type: string, minLength: 1, maxLength: 128} NullablePalletNo: {type: string, pattern: '^DP-[0-9]{6}-[0-9]{4}$', nullable: true} diff --git a/firstleg/src/main/resources/openapi/firstleg-v1.yaml b/firstleg/src/main/resources/openapi/firstleg-v1.yaml index f3389f8c6..a0e04bd50 100644 --- a/firstleg/src/main/resources/openapi/firstleg-v1.yaml +++ b/firstleg/src/main/resources/openapi/firstleg-v1.yaml @@ -1605,6 +1605,8 @@ components: lxCode: {type: string, nullable: true, description: 一件代发线路或履约产品编码快照} channelCode: {type: string, nullable: true} channelName: {type: string, nullable: true} + fulfillmentType: {type: string, nullable: true, enum: [STANDARD, ONE_CLICK_DROPSHIP]} + expectedPalletCount: {type: integer, minimum: 1, maximum: 1000, nullable: true, description: 一件代发预计托数;测量审核通过后按此数量预生成 DP 托盘码} taxMode: {type: string, nullable: true} pricingTaxMode: {type: string, nullable: true} containerMode: {type: string, nullable: true} @@ -2000,6 +2002,7 @@ components: measurementId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true} version: {type: integer, minimum: 0} actualGoodsName: {type: string, maxLength: 255, nullable: true} + expectedPalletCount: {type: integer, minimum: 1, maximum: 1000, nullable: true, description: 一件代发必填;普通入库可不传} items: type: array minItems: 1 diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/DropshipPalletizationServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/DropshipPalletizationServiceTest.java index 8613f5263..010bb6496 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/DropshipPalletizationServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/DropshipPalletizationServiceTest.java @@ -3,9 +3,10 @@ package com.baiyue.firstleg.service; import com.baiyue.common.core.exception.BizException; import com.baiyue.firstleg.dto.DropshipPalletizationDtos.CountCartonRequest; import com.baiyue.firstleg.dto.DropshipPalletizationDtos.DiscrepancyAction; +import com.baiyue.firstleg.entity.InboundOrderEntity; import com.baiyue.firstleg.mapper.DropshipPalletizationMapper; -import com.baiyue.firstleg.mapper.DropshipPalletizationMapper.CartonRow; import com.baiyue.firstleg.mapper.DropshipPalletizationMapper.LabelRow; +import com.baiyue.firstleg.mapper.DropshipPalletizationMapper.CartonRow; import com.baiyue.firstleg.mapper.DropshipPalletizationMapper.PalletRow; import com.baiyue.firstleg.mapper.DropshipPalletizationMapper.TaskRow; import org.junit.jupiter.api.Test; @@ -19,94 +20,45 @@ class DropshipPalletizationServiceTest { private final FirstlegDocumentNumberGenerator numbers=mock(FirstlegDocumentNumberGenerator.class); private final DropshipPalletizationMapper mapper=mock(DropshipPalletizationMapper.class); private final DropshipPalletizationService service=new DropshipPalletizationService(); - DropshipPalletizationServiceTest(){ ReflectionTestUtils.setField(service,"mapper",mapper); ReflectionTestUtils.setField(service,"documentNumbers",numbers); } - @Test void generatesBindsSealsAndCompletesOnlyAfterEveryCartonIsCounted(){ - when(mapper.lockTask(10L,100L)).thenReturn(10L); when(mapper.task(10L,100L)).thenReturn(readyToComplete()); - when(mapper.unboundCount(10L)).thenReturn(2); when(numbers.next("DP")).thenReturn("DP-260909-0001"); - when(mapper.bindPending(eq(10L),anyLong(),eq("create-1"),eq(7L),eq("张三"))).thenReturn(2); - when(mapper.adjustBound(10L,7L,2)).thenReturn(1); - when(mapper.seal(eq(10L),anyLong(),eq(1),eq(100L),eq("create-1"),eq(7L),eq("张三"))).thenReturn(1); - when(mapper.completeTask(10L)).thenReturn(1); when(mapper.completeInbound(10L,1L,30L,7L)).thenReturn(1); - service.createAndBind(10L,new com.baiyue.firstleg.dto.DropshipPalletizationDtos.CreateAndBindRequest(100L,"create-1"),7L,"张三"); - verify(mapper).insertPallet(anyLong(),eq(10L),eq(1L),eq(30L),eq(100L),eq("DP-260909-0001"),eq("create-1"),eq(7L),eq("张三")); - verify(numbers,times(1)).next("DP"); + @Test void reviewCreatesExpectedNumberOfPrintablePalletCodes(){ + InboundOrderEntity inbound=dropshipInbound(); when(mapper.insertTask(anyLong(),eq(1L),eq(30L),eq(100L),eq(8))).thenReturn(1); + when(numbers.next("DP")).thenReturn("DP-260911-0001","DP-260911-0002"); + service.createTask(inbound,7L,"张三"); + verify(mapper,times(2)).insertPallet(anyLong(),anyLong(),eq(1L),eq(30L),eq(100L),startsWith("DP-"),startsWith("dropship-precreate-"),eq(7L),eq("张三")); } - @Test void incompleteCountingNeverAllocatesAPalletNumber(){ - when(mapper.lockTask(10L,100L)).thenReturn(10L); when(mapper.task(10L,100L)).thenReturn(task()); - assertThatThrownBy(()->service.createAndBind(10L,new com.baiyue.firstleg.dto.DropshipPalletizationDtos.CreateAndBindRequest(100L,"early"),7L,"张三")) - .hasMessageContaining("完成全部箱码清点"); - verifyNoInteractions(numbers); - } - - @Test void noPendingCartonsNeverAllocatesNumberOrEmptyPallet(){ - when(mapper.lockTask(10L,100L)).thenReturn(10L); when(mapper.task(10L,100L)).thenReturn(readyToComplete()); - assertThatThrownBy(()->service.createAndBind(10L,new com.baiyue.firstleg.dto.DropshipPalletizationDtos.CreateAndBindRequest(100L,"empty"),7L,"张三")).hasMessageContaining("没有待绑托箱"); - verifyNoInteractions(numbers); - verify(mapper,never()).insertPallet(anyLong(),anyLong(),anyLong(),anyLong(),anyLong(),anyString(),anyString(),anyLong(),anyString()); - } - - @Test void replaysAfterCompletionWithoutGeneratingAnotherPallet(){ - TaskRow completed=task(); completed.setTaskStatus("COMPLETED"); completed.setProcessStatus("WAIT_SPLIT"); - when(mapper.lockTask(10L,100L)).thenReturn(10L); when(mapper.task(10L,100L)).thenReturn(completed); - when(mapper.palletByOpenOperation("replay")).thenReturn(pallet()); - service.createAndBind(10L,new com.baiyue.firstleg.dto.DropshipPalletizationDtos.CreateAndBindRequest(100L,"replay"),7L,"张三"); - verifyNoInteractions(numbers); verify(mapper,never()).unboundCount(anyLong()); - } - - @Test void rejectsOtherOperatorAndCrossTaskReplay(){ - when(mapper.lockTask(10L,100L)).thenReturn(10L); when(mapper.task(10L,100L)).thenReturn(readyToComplete()); - var request=new com.baiyue.firstleg.dto.DropshipPalletizationDtos.CreateAndBindRequest(100L,"replay"); - assertThatThrownBy(()->service.createAndBind(10L,request,8L,"李四")).hasMessageContaining("当前操作员"); - PalletRow other=pallet(); other.setTaskId(11L); when(mapper.palletByOpenOperation("replay")).thenReturn(other); - assertThatThrownBy(()->service.createAndBind(10L,request,7L,"张三")).hasMessageContaining("不同任务"); - verifyNoInteractions(numbers); - } - - @Test void rejectsUnknownWarehouseAndChangedBindCount(){ - var request=new com.baiyue.firstleg.dto.DropshipPalletizationDtos.CreateAndBindRequest(100L,"new"); - assertThatThrownBy(()->service.createAndBind(10L,request,7L,"张三")).hasMessageContaining("当前仓库"); - when(mapper.lockTask(10L,100L)).thenReturn(10L); when(mapper.task(10L,100L)).thenReturn(readyToComplete()); - when(mapper.unboundCount(10L)).thenReturn(2); when(numbers.next("DP")).thenReturn("DP-260909-0002"); - assertThatThrownBy(()->service.createAndBind(10L,request,7L,"张三")).hasMessageContaining("待绑托箱已变化"); - verify(mapper,never()).adjustBound(anyLong(),anyLong(),anyInt()); + @Test void replayedReviewDoesNotGenerateDuplicatePalletCodes(){ + when(mapper.insertTask(anyLong(),anyLong(),anyLong(),anyLong(),anyInt())).thenReturn(0); + service.createTask(dropshipInbound(),7L,"张三"); + verifyNoInteractions(numbers); verify(mapper,never()).insertPallet(anyLong(),anyLong(),anyLong(),anyLong(),anyLong(),anyString(),anyString(),anyLong(),anyString()); } @Test void resolvesUncountedCartonBeforeQuantityConfirmation(){ - TaskRow task=task(); LabelRow label=label(); - when(mapper.task(10L,100L)).thenReturn(task); when(mapper.label(10L,"BOX-1")).thenReturn(label); + when(mapper.task(10L,100L)).thenReturn(task()); when(mapper.label(10L,"BOX-1")).thenReturn(label()); var result=service.resolveCarton(10L,100L,"BOX-1",7L); - assertThat(result.inboundCode()).isEqualTo("IN-1"); - assertThat(result.skuCode()).isEqualTo("SKU-1"); - assertThat(result.expectedSkuQuantity()).isEqualTo(12); - assertThat(result.countStatus()).isEqualTo("UNCOUNTED"); - assertThat(result.canCount()).isTrue(); + assertThat(result.inboundCode()).isEqualTo("IN-1"); assertThat(result.expectedSkuQuantity()).isEqualTo(12); assertThat(result.canCount()).isTrue(); } - @Test void mismatchCannotBeRecordedWithoutAcceptedVarianceAndRemark(){ + @Test void cartonCanBindDirectlyToAPreGeneratedPallet(){ + when(mapper.task(10L,100L)).thenReturn(task()); when(mapper.label(10L,"BOX-1")).thenReturn(label()); when(mapper.palletByNo("DP-260911-0001")).thenReturn(pallet()); + when(mapper.addCounted(10L,7L,1,0)).thenReturn(1); when(mapper.carton(eq(10L),anyLong())).thenReturn(carton()); + when(mapper.pallet(10L,20L,100L)).thenReturn(pallet()); when(mapper.cartons(20L)).thenReturn(java.util.List.of()); + service.countCarton(10L,new CountCartonRequest(100L,"BOX-1",12,DiscrepancyAction.MATCH,null,"DP-260911-0001","op-1"),7L,"张三"); + verify(mapper).insertCarton(anyLong(),eq(10L),eq(20L),eq(1L),eq(30L),eq(40L),eq(50L),eq("SKU-1"),any(),eq("BOX-1"),eq(12),eq(12),eq("MATCH"),isNull(),eq("op-1"),eq(7L),eq("张三")); + } + + @Test void unknownPalletCodeCannotCreateAnAdHocPallet(){ when(mapper.task(10L,100L)).thenReturn(task()); when(mapper.label(10L,"BOX-1")).thenReturn(label()); - var wrongAction=new CountCartonRequest(100L,"BOX-1",11,DiscrepancyAction.MATCH,null,null,"op-1"); - assertThatThrownBy(()->service.countCarton(10L,wrongAction,7L,"张三")) - .isInstanceOf(BizException.class).hasMessageContaining("确认差异处理结果"); - var noRemark=new CountCartonRequest(100L,"BOX-1",11,DiscrepancyAction.ACCEPT_VARIANCE,null,null,"op-2"); - assertThatThrownBy(()->service.countCarton(10L,noRemark,7L,"张三")) - .isInstanceOf(BizException.class).hasMessageContaining("处理说明"); - verify(mapper,never()).insertCarton(anyLong(),anyLong(),any(),anyLong(),anyLong(),anyLong(),anyLong(),any(),any(),any(),anyInt(),anyInt(),any(),any(),any(),anyLong(),any()); + var request=new CountCartonRequest(100L,"BOX-1",12,DiscrepancyAction.MATCH,null,"DP-260911-9999","op-1"); + assertThatThrownBy(()->service.countCarton(10L,request,7L,"张三")).isInstanceOf(BizException.class).hasMessageContaining("测量审核后生成"); + verify(mapper,never()).insertPallet(anyLong(),anyLong(),anyLong(),anyLong(),anyLong(),anyString(),anyString(),anyLong(),anyString()); } - @Test void countingCannotExposeOrBindAPalletNumberEarly(){ - when(mapper.task(10L,100L)).thenReturn(task()); when(mapper.label(10L,"BOX-1")).thenReturn(label()); - var request=new CountCartonRequest(100L,"BOX-1",12,DiscrepancyAction.MATCH,null,"DP-260908-0001","op-1"); - assertThatThrownBy(()->service.countCarton(10L,request,7L,"张三")) - .hasMessageContaining("不能提前绑定托盘码"); - verify(mapper,never()).insertCarton(anyLong(),anyLong(),any(),anyLong(),anyLong(),anyLong(),anyLong(),any(),any(),any(),anyInt(),anyInt(),any(),any(),any(),anyLong(),any()); - } - - private static TaskRow task(){ TaskRow t=new TaskRow();t.setId(10L);t.setTenantId(1L);t.setInboundId(30L);t.setWarehouseId(100L);t.setInboundCode("IN-1");t.setTaskStatus("CLAIMED");t.setAssigneeId(7L);t.setProcessStatus("WAIT_PALLETIZE");t.setTotalCartons(2);t.setCountedCartons(0);t.setAllocatedCartons(0);t.setDiscrepancyCartons(0);t.setVersion(1);return t; } - private static TaskRow readyToComplete(){ TaskRow t=task();t.setCountedCartons(2);return t; } + private static InboundOrderEntity dropshipInbound(){InboundOrderEntity i=new InboundOrderEntity();i.setId(30L);i.setTenantId(1L);i.setWarehouseId(100L);i.setFulfillmentType("ONE_CLICK_DROPSHIP");i.setTotalPackageCount(8);i.setPalletCount(2);return i;} + private static TaskRow task(){TaskRow t=new TaskRow();t.setId(10L);t.setTenantId(1L);t.setInboundId(30L);t.setWarehouseId(100L);t.setInboundCode("IN-1");t.setTaskStatus("CLAIMED");t.setAssigneeId(7L);t.setProcessStatus("WAIT_PALLETIZE");t.setTotalCartons(2);t.setCountedCartons(0);t.setAllocatedCartons(0);t.setDiscrepancyCartons(0);t.setVersion(1);return t;} private static LabelRow label(){LabelRow l=new LabelRow();l.setCartonLabelId(50L);l.setInboundDetailId(40L);l.setSkuCode("SKU-1");l.setCargoName("货物");l.setUnitsPerCarton(12);l.setInboundCode("IN-1");l.setBoxCode("BOX-1");return l;} - private static PalletRow pallet(){PalletRow p=new PalletRow();p.setId(20L);p.setTaskId(10L);p.setTenantId(1L);p.setInboundId(30L);p.setWarehouseId(100L);p.setPalletNo("DP-260908-0001");p.setPalletStatus("OPEN");p.setVersion(1);return p;} - private static CartonRow carton(){CartonRow c=new CartonRow();c.setId(60L);c.setTaskId(10L);c.setPalletId(20L);c.setPalletNo("DP-260908-0001");c.setInboundId(30L);c.setInboundDetailId(40L);c.setSkuCode("SKU-1");c.setCargoName("货物");c.setBoxCode("BOX-1");c.setExpectedSkuQuantity(12);c.setActualSkuQuantity(12);c.setDiscrepancyStatus("MATCH");return c;} + private static PalletRow pallet(){PalletRow p=new PalletRow();p.setId(20L);p.setTaskId(10L);p.setTenantId(1L);p.setInboundId(30L);p.setWarehouseId(100L);p.setPalletNo("DP-260911-0001");p.setPalletStatus("OPEN");p.setVersion(1);return p;} + private static CartonRow carton(){CartonRow c=new CartonRow();c.setId(60L);c.setTaskId(10L);c.setPalletId(20L);c.setInboundId(30L);c.setInboundDetailId(40L);c.setPalletNo("DP-260911-0001");c.setSkuCode("SKU-1");c.setCargoName("货物");c.setBoxCode("BOX-1");c.setExpectedSkuQuantity(12);c.setActualSkuQuantity(12);c.setDiscrepancyStatus("MATCH");return c;} } diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/InboundCartonLabelPrintServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/InboundCartonLabelPrintServiceTest.java index 86c5fff26..ada636328 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/InboundCartonLabelPrintServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/InboundCartonLabelPrintServiceTest.java @@ -38,21 +38,16 @@ class InboundCartonLabelPrintServiceTest { } @Test - void dropshipPalletLabelIsAvailableOnlyAfterSeal() { + void dropshipPalletLabelIsAvailableBeforeSeal() { Pallet open = dropshipPallet("OPEN"); - assertThatThrownBy(() -> service.generateDropshipPallet(open, "request-open")) - .isInstanceOf(BizException.class) - .hasMessageContaining("已完成"); - verifyNoInteractions(print); - HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_PDF); when(print.generateInboundMarks(org.mockito.ArgumentMatchers.anyString(), - org.mockito.ArgumentMatchers.eq("request-sealed"), org.mockito.ArgumentMatchers.any())) + org.mockito.ArgumentMatchers.eq("request-open"), org.mockito.ArgumentMatchers.any())) .thenReturn(new ResponseEntity<>(new byte[] {7, 8, 9}, headers, org.springframework.http.HttpStatus.OK)); - ResponseEntity response = service.generateDropshipPallet(dropshipPallet("SEALED"), "request-sealed"); + ResponseEntity response = service.generateDropshipPallet(open, "PCHK2608040174", "request-open"); assertThat(response.getBody()).containsExactly(7, 8, 9); }