feat: precreate dropship pallet codes after measurement
This commit is contained in:
+4
-12
@@ -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<Task> 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<Task> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<ItemRequest> items) {
|
||||
this(measurementId, version, actualGoodsName, null, items);
|
||||
}
|
||||
|
||||
@JsonAnySetter
|
||||
public void rejectUnknownField(String fieldName, Object ignored) {
|
||||
throw new IllegalArgumentException("测量草稿不接受字段: " + fieldName);
|
||||
|
||||
@@ -19,6 +19,8 @@ public final class InboundMeasurementResponses {
|
||||
String companyName,
|
||||
String channelCode,
|
||||
String channelName,
|
||||
String fulfillmentType,
|
||||
Integer expectedPalletCount,
|
||||
String processStatus,
|
||||
String measureReviewStatus,
|
||||
@Schema(description = "测量完成后的推荐托盘类型,仅为建议,不代表已分配托盘",
|
||||
|
||||
@@ -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<PalletRow> 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<PalletRow> 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<Long> 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
|
||||
|
||||
+20
-46
@@ -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<PendingTask> 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;
|
||||
}
|
||||
|
||||
|
||||
+6
-5
@@ -114,18 +114,19 @@ public class InboundCartonLabelPrintService {
|
||||
}
|
||||
|
||||
/** 一件代发托盘标签:托盘号、入仓码、SKU箱数和托盘二维码。 */
|
||||
public ResponseEntity<byte[]> 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<byte[]> 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));
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
+29
-77
@@ -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;}
|
||||
}
|
||||
|
||||
+3
-8
@@ -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<byte[]> response = service.generateDropshipPallet(dropshipPallet("SEALED"), "request-sealed");
|
||||
ResponseEntity<byte[]> response = service.generateDropshipPallet(open, "PCHK2608040174", "request-open");
|
||||
assertThat(response.getBody()).containsExactly(7, 8, 9);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user