提交
This commit is contained in:
+17
-2
@@ -81,6 +81,21 @@ public class DispatchService {
|
||||
@Resource private ReturnRelabelDispatchStock returnRelabelStock;
|
||||
@Resource private com.baiyue.lastleg.relabel.service.RelabelPalletMeasurementService relabelMeasurements;
|
||||
|
||||
private List<DispatchPalletCandidate> measuredRelabelCandidates(List<DispatchPalletCandidate> rows) {
|
||||
var cache = new java.util.HashMap<String, List<com.baiyue.lastleg.relabel.service.RelabelPalletMeasurementService.Measurement>>();
|
||||
for (var row : rows) {
|
||||
var values = cache.computeIfAbsent(row.customerId() + ":" + row.orderRefs(), ignored -> {
|
||||
var app = relabelApplications.findAnyByRelabelNo(row.orderRefs());
|
||||
return app != null && Objects.equals(app.getCustomerId(), row.customerId()) ? relabelMeasurements.snapshots(app) : List.of();
|
||||
});
|
||||
if (!values.isEmpty()) {
|
||||
var p = values.stream().filter(value -> Objects.equals(value.palletId(), row.warehousePalletId())).findFirst().orElse(null);
|
||||
row.grossWeightKg(p == null ? null : p.grossWeightKg()); row.volumeCbm(p == null ? null : p.volumeCbm());
|
||||
}
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
public String resolveCustomerScopeForPlans(List<Long> planIds) {
|
||||
return requireSingleCustomerScope(candidates.findCustomerScopesByPlanIds(normalizeIds(planIds, "Plan IDs")),
|
||||
"Selected inbound plans");
|
||||
@@ -125,7 +140,7 @@ public class DispatchService {
|
||||
trimToNull(sourceStage), trimToNull(draftToken));
|
||||
if (!StringUtils.hasText(sourceStage) || Set.of("RECEIVED", "RELABEL").contains(sourceStage)) {
|
||||
List<DispatchPalletCandidate> relabel = java.util.stream.Stream.concat(
|
||||
relabelMeasurements.enrich(candidates.relabelAvailable(null, trimToNull(orderNo), null)).stream(),
|
||||
measuredRelabelCandidates(candidates.relabelAvailable(null, trimToNull(orderNo), null)).stream(),
|
||||
returnRelabelStock.candidates(null, trimToNull(orderNo), null).stream()).toList();
|
||||
if (relabel != null && !relabel.isEmpty()) {
|
||||
result = java.util.stream.Stream.concat(result.stream(), relabel.stream().filter(item ->
|
||||
@@ -580,7 +595,7 @@ public class DispatchService {
|
||||
if (!"TRUCK".equals(application.getDeliveryMethod()) || !"WAIT_PRE_DISPATCH".equals(application.getFulfillmentStatus()))
|
||||
throw new ResponseStatusException(HttpStatus.CONFLICT, "换标单不是待排车状态");
|
||||
List<DispatchPalletCandidate> selected = java.util.stream.Stream.concat(
|
||||
relabelMeasurements.enrich(candidates.relabelAvailable(customerId, null, request.relabelNo())).stream(),
|
||||
measuredRelabelCandidates(candidates.relabelAvailable(customerId, null, request.relabelNo())).stream(),
|
||||
returnRelabelStock.candidates(customerId, null, request.relabelNo()).stream()).toList();
|
||||
Set<Long> requested = request.planPalletIds().stream().map(Long::valueOf).collect(Collectors.toSet());
|
||||
if (selected.stream().anyMatch(DispatchPalletCandidate::returnCartonSource)
|
||||
|
||||
+8
-2
@@ -268,7 +268,7 @@ public class PdaPalletOperationService {
|
||||
throw conflict("实际来源托盘库存已变化,请刷新后确认");
|
||||
if (actual != null && application.getOutboundOrderNo() != null && !application.getOutboundOrderNo().isBlank())
|
||||
throw conflict("已生成出库单,请先处理出库单,不能重新分配冻结来源");
|
||||
if (actual != null && marks.stream().anyMatch(boundRelabelMarks(application)::contains))
|
||||
if (actual != null && source.palletId() != target.palletId() && marks.stream().anyMatch(boundRelabelMarks(application)::contains))
|
||||
throw conflict("本批包含本轮已组托的换标箱,请刷新后选择未组托的箱");
|
||||
if ("PROCESSING".equals(application.getStatus())) {
|
||||
var workTask = relabelWorkTasks.find(application.getCustomerId(), application.getId());
|
||||
@@ -309,8 +309,14 @@ public class PdaPalletOperationService {
|
||||
if (marks.stream().anyMatch(bound::contains)) throw conflict("本批包含已绑定箱唛,请刷新后重试");
|
||||
recordRelabelBinding(identity, new RelabelMutation(application, byPosition, Map.of()), retained);
|
||||
}
|
||||
return new PalletOperationResponses.Operation(IdWorker.getId(), "RELABEL_PALLET_RETAIN", request.idempotencyKey(),
|
||||
var result = new PalletOperationResponses.Operation(IdWorker.getId(), "RELABEL_PALLET_DISASSEMBLE", request.idempotencyKey(),
|
||||
"COMPLETED", false, LocalDateTime.now(), List.of(content(identity.overseasWarehouseId(), source)));
|
||||
var operation = new PdaPalletOperation(); operation.setId(result.operationId());
|
||||
operation.setOverseasWarehouseId(identity.overseasWarehouseId()); operation.setOperatorKey(identity.operatorKey());
|
||||
operation.setOperationType(result.operationType()); operation.setIdempotencyKey(request.idempotencyKey());
|
||||
operation.setRequestHash(hash(request)); operation.setStatus("COMPLETED"); operation.setResultJson(write(result));
|
||||
operation.setCreatedAt(result.completedAt()); operation.setUpdatedAt(result.completedAt()); mapper.insert(operation);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
for (RelabelItem item : selected) {
|
||||
|
||||
+6
-4
@@ -10,15 +10,17 @@ public interface RelabelPalletMeasurementMapper {
|
||||
record Original(Long palletId, String palletNo, int packages, BigDecimal lengthCm,
|
||||
BigDecimal widthCm, BigDecimal heightCm, BigDecimal grossWeightKg, BigDecimal volumeCbm) {}
|
||||
@Select("SELECT id FROM ll_warehouse_transfer_order WHERE customer_id=#{customerId} AND relabel_no=#{relabelNo}")
|
||||
Long transfer(String customerId, String relabelNo);
|
||||
Long transfer(@Param("customerId") String customerId, @Param("relabelNo") String relabelNo);
|
||||
@Select("SELECT id,pallet_id palletId,pallet_no palletNo," +
|
||||
"COALESCE(available_packages,0)+COALESCE(hold_packages,0)+COALESCE(allocated_packages,0)+COALESCE(picked_packages,0)+COALESCE(receiving_packages,0) packages,version " +
|
||||
"FROM ll_inventory_position WHERE customer_id=#{customerId} AND overseas_warehouse_id=#{warehouseId} ORDER BY id")
|
||||
List<Stock> stock(String customerId, String warehouseId);
|
||||
List<Stock> stock(@Param("customerId") String customerId, @Param("warehouseId") String warehouseId);
|
||||
@Select("SELECT id FROM ll_inventory_position WHERE customer_id=#{customerId} AND overseas_warehouse_id=#{warehouseId} AND pallet_no=#{palletCode} ORDER BY id FOR UPDATE")
|
||||
List<Long> lockStock(@Param("customerId") String customerId, @Param("warehouseId") String warehouseId, @Param("palletCode") String palletCode);
|
||||
@Select("SELECT warehouse_pallet_id palletId,pallet_no palletNo,carton_count packages,length_cm lengthCm,width_cm widthCm,height_cm heightCm,gross_weight_kg grossWeightKg,volume_cbm volumeCbm " +
|
||||
"FROM ll_warehouse_transfer_pallet WHERE customer_id=#{customerId} AND transfer_order_id=#{transferId} AND status='COMPLETED'")
|
||||
List<Original> originals(String customerId, Long transferId);
|
||||
List<Original> originals(@Param("customerId") String customerId, @Param("transferId") Long transferId);
|
||||
@Select("SELECT COUNT(*) FROM ll_inventory_ledger WHERE customer_id=#{customerId} AND pallet_id=#{palletId} " +
|
||||
"AND business_type IN ('RELABEL_PALLET_DISASSEMBLE','PALLET_ASSEMBLE','PALLET_DISASSEMBLE','PALLET_SWAP','PALLET_UNBIND')")
|
||||
int movements(String customerId, Long palletId);
|
||||
int movements(@Param("customerId") String customerId, @Param("palletId") Long palletId);
|
||||
}
|
||||
|
||||
+6
-19
@@ -7,7 +7,6 @@ import com.baiyue.lastleg.relabel.mapper.*;
|
||||
import com.baiyue.lastleg.relabel.pda.entity.PdaRelabelHistory;
|
||||
import com.baiyue.lastleg.relabel.pda.mapper.*;
|
||||
import com.baiyue.lastleg.pda.security.PdaWarehouseIdentity;
|
||||
import com.baiyue.lastleg.dispatch.model.DispatchPalletCandidate;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.constraints.*;
|
||||
@@ -28,8 +27,8 @@ public class RelabelPalletMeasurementService {
|
||||
@Resource private PdaRelabelHistoryMapper histories;
|
||||
@Resource private PdaRelabelTaskMapper tasks;
|
||||
@Resource private ObjectMapper json;
|
||||
public record Measure(@NotBlank String relabelNo, @NotBlank String palletCode,
|
||||
@NotBlank String idempotencyKey, @NotBlank String stockVersion,
|
||||
public record Measure(@NotBlank @Size(max=64) String relabelNo, @NotBlank @Size(max=128) String palletCode,
|
||||
@NotBlank @Size(max=128) String idempotencyKey, @NotBlank @Size(max=32768) String stockVersion,
|
||||
@NotNull @DecimalMin("0.01") @Digits(integer=6,fraction=2) BigDecimal lengthCm,
|
||||
@NotNull @DecimalMin("0.01") @Digits(integer=6,fraction=2) BigDecimal widthCm,
|
||||
@NotNull @DecimalMin("0.01") @Digits(integer=6,fraction=2) BigDecimal heightCm,
|
||||
@@ -47,7 +46,7 @@ public class RelabelPalletMeasurementService {
|
||||
throw conflict("换标单不属于当前海外仓");
|
||||
return app;
|
||||
}
|
||||
@Transactional
|
||||
@Transactional(isolation=org.springframework.transaction.annotation.Isolation.READ_COMMITTED)
|
||||
public List<Measurement> save(PdaWarehouseIdentity identity, Measure request) {
|
||||
var app = scoped(identity, request.relabelNo(), true);
|
||||
if (!Set.of("PROCESSING", "READY_FOR_OUTBOUND").contains(app.getStatus())
|
||||
@@ -55,7 +54,7 @@ public class RelabelPalletMeasurementService {
|
||||
|| app.getFulfillmentStatus() != null && !Set.of("WAIT_RELABEL", "WAIT_PRE_DISPATCH").contains(app.getFulfillmentStatus()))
|
||||
throw conflict("已排车或出库的换标单不能修改测量");
|
||||
var task = tasks.find(app.getCustomerId(), app.getId());
|
||||
if (task == null || "PROCESSING".equals(app.getStatus()) && !identity.operatorKey().equals(task.getOperatorKey()))
|
||||
if (task == null || "PROCESSING".equals(app.getStatus()) && (!"PROCESSING".equals(task.getStatus()) || !identity.operatorKey().equals(task.getOperatorKey())))
|
||||
throw conflict("请先认领当前换标任务");
|
||||
var records = histories(app);
|
||||
String payload = write(request);
|
||||
@@ -67,6 +66,7 @@ public class RelabelPalletMeasurementService {
|
||||
return snapshots(app);
|
||||
}
|
||||
}
|
||||
mapper.lockStock(app.getCustomerId(), app.getOverseasWarehouseId(), request.palletCode());
|
||||
var current = snapshots(app).stream().filter(p -> p.palletCode().equals(request.palletCode())).findFirst()
|
||||
.orElseThrow(() -> conflict("托盘不属于本换标单或已经清空"));
|
||||
if (!current.stockVersion().equals(request.stockVersion())) throw conflict("托盘库存已变化,请刷新后重新测量");
|
||||
@@ -118,23 +118,10 @@ public class RelabelPalletMeasurementService {
|
||||
}
|
||||
public void requireMeasured(RelabelApplication app) {
|
||||
for (var p : snapshots(app)) if (p.grossWeightKg() == null || p.volumeCbm() == null
|
||||
|| p.lengthCm() == null || p.widthCm() == null || p.heightCm() == null
|
||||
|| p.grossWeightKg().signum() <= 0 || p.volumeCbm().signum() <= 0)
|
||||
throw conflict("托盘 " + p.palletCode() + " 拆合托后尚未确认实测尺寸和重量,请在 PDA 补测(含原托盘剩余货物)");
|
||||
}
|
||||
public List<DispatchPalletCandidate> enrich(List<DispatchPalletCandidate> candidates) {
|
||||
var cache = new HashMap<String,List<Measurement>>();
|
||||
for (var c : candidates) {
|
||||
var values = cache.computeIfAbsent(c.customerId()+":"+c.orderRefs(), ignored -> {
|
||||
var app = applications.findAnyByRelabelNo(c.orderRefs());
|
||||
return app != null && Objects.equals(app.getCustomerId(),c.customerId()) ? snapshots(app) : List.of();
|
||||
});
|
||||
if (!values.isEmpty()) {
|
||||
var p = values.stream().filter(v -> Objects.equals(v.palletId(), c.warehousePalletId())).findFirst().orElse(null);
|
||||
c.grossWeightKg(p == null ? null : p.grossWeightKg()); c.volumeCbm(p == null ? null : p.volumeCbm());
|
||||
}
|
||||
}
|
||||
return candidates;
|
||||
}
|
||||
private List<PdaRelabelHistory> histories(RelabelApplication app) {
|
||||
return histories.selectList(new QueryWrapper<PdaRelabelHistory>().eq("customer_id", app.getCustomerId())
|
||||
.eq("application_id", app.getId()).orderByAsc("created_at","id"));
|
||||
|
||||
Reference in New Issue
Block a user