优化
This commit is contained in:
@@ -23,7 +23,7 @@ public interface WarehouseSupplierClient {
|
||||
@RequestParam String carrierCode);
|
||||
|
||||
record Snapshot(long supplierId, String name, String category, String status,
|
||||
List<String> carrierCodes) {}
|
||||
List<String> carrierCodes, String truckingScope) {}
|
||||
|
||||
@GetMapping("/{supplierId}/trucking-contact")
|
||||
ApiResponse<TruckingContact> truckingContact(@RequestHeader("X-Internal-Service-Token") String token,
|
||||
|
||||
@@ -92,12 +92,17 @@ public final class SmartLoadingDtos { private SmartLoadingDtos(){}
|
||||
Integer inboundFragmentCount,Integer fullPackageCount,List<Long> memberInboundIds) {
|
||||
public PlanCoLoadGroup { memberInboundIds=memberInboundIds==null?List.of():List.copyOf(memberInboundIds); }
|
||||
}
|
||||
public record PlanPalletMembers(Long palletId,List<GroupMemberCandidate> members) {
|
||||
public PlanPalletMembers { members=members==null?List.of():List.copyOf(members); }
|
||||
}
|
||||
public record Plan(Long id,String planNo,String status,Long bookingId,String containerNo,String voyageNo,
|
||||
Integer version,Boolean canAssign,Boolean canEdit,String blockedReason,String finalCompletionStatus,
|
||||
Long pdaTaskId,String pdaTaskStatus,Integer pdaTaskVersion,List<PlanCoLoadGroup> coLoadGroups,
|
||||
List<PlanPalletMembers> palletMembers,
|
||||
List<LoadingPlanItemEntity> items) {
|
||||
public Plan {
|
||||
coLoadGroups=coLoadGroups==null?List.of():List.copyOf(coLoadGroups);
|
||||
palletMembers=palletMembers==null?List.of():List.copyOf(palletMembers);
|
||||
items=items==null?List.of():List.copyOf(items);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.apache.ibatis.annotations.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/** 一件代发逐箱清点、待绑托与封托事实。 */
|
||||
@@ -282,6 +283,21 @@ public interface DropshipPalletizationMapper {
|
||||
ORDER BY o.inbound_code,o.id
|
||||
""") List<GroupMemberCandidate> palletInboundMembers(@Param("palletId") long palletId);
|
||||
|
||||
@Select("""
|
||||
<script>
|
||||
SELECT c.pallet_id palletId,o.tenant_id accountId,o.id inboundId,o.order_id orderId,o.order_no orderNo,
|
||||
o.inbound_code inboundCode,o.customer_name customerName,COUNT(DISTINCT c.id) availablePackageCount,
|
||||
o.process_status orderStatusSnapshot,o.expected_arrival_at expectedArrivalAt
|
||||
FROM fl_dropship_pallet_carton c
|
||||
JOIN fl_inbound_order o ON o.id=c.inbound_id AND o.tenant_id=c.tenant_id
|
||||
WHERE c.pallet_id IN
|
||||
<foreach collection="palletIds" item="palletId" open="(" separator="," close=")">#{palletId}</foreach>
|
||||
GROUP BY c.pallet_id,o.tenant_id,o.id,o.order_id,o.order_no,o.inbound_code,o.customer_name,
|
||||
o.process_status,o.expected_arrival_at
|
||||
ORDER BY c.pallet_id,o.inbound_code,o.id
|
||||
</script>
|
||||
""") List<PlanPalletMemberRow> palletInboundMembersByPalletIds(@Param("palletIds") Collection<Long> palletIds);
|
||||
|
||||
@Select("""
|
||||
SELECT p.id pallet_id,p.pallet_no,'SEALED_PALLET' unit_type,TRUE indivisible,COUNT(DISTINCT c.id) carton_count,
|
||||
(SELECT COUNT(DISTINCT sku.sku_code) FROM fl_dropship_pallet_carton pc
|
||||
@@ -318,6 +334,7 @@ public interface DropshipPalletizationMapper {
|
||||
|
||||
@Getter @Setter class TaskRow { private Long id,tenantId,inboundId,warehouseId,assigneeId; private String inboundCode,customerName,warehouseName,taskStatus,assigneeName,processStatus,fulfillmentType; private Integer totalCartons,countedCartons,allocatedCartons,discrepancyCartons,expectedPalletCount,version; }
|
||||
@Getter @Setter class PalletRow { private Long id,taskId,tenantId,inboundId,warehouseId; private String palletNo,palletStatus,sealOperationId; private Integer version; private LocalDateTime completedAt; }
|
||||
@Getter @Setter class PlanPalletMemberRow { private Long palletId,accountId,inboundId,orderId; private String orderNo,inboundCode,customerName,orderStatusSnapshot; private Integer availablePackageCount; private LocalDateTime expectedArrivalAt; }
|
||||
@Getter @Setter class LabelRow { private Long cartonLabelId,inboundDetailId; private String skuCode,cargoName,inboundCode,boxCode; private Integer unitsPerCarton; }
|
||||
@Getter @Setter class LabelSkuRow { private Long inboundDetailId; private String skuCode,cargoName; private Integer expectedQuantity,lineNo; }
|
||||
@Getter @Setter class CartonRow { private Long id,taskId,palletId,inboundId,inboundDetailId; private String palletNo,inboundCode,skuCode,cargoName,boxCode,discrepancyStatus,discrepancyRemark; private Integer expectedSkuQuantity,actualSkuQuantity; }
|
||||
|
||||
@@ -149,7 +149,7 @@ public class ContainerService {
|
||||
validateSchedule(request.data());
|
||||
ContainerSpecificationCatalog.requireMatch(request.data().containerType(), request.data().capacityCbm(), request.data().maxWeightKg());
|
||||
WarehouseMasterDataClient.Warehouse warehouse = requireDomesticTransitWarehouse(request.data().warehouseId());
|
||||
var trucking = suppliers.trucking(request.data().terminalTruckingCompanyId(), request.data().terminalTruckingCompany());
|
||||
var trucking = suppliers.overseasTrucking(request.data().terminalTruckingCompanyId(), request.data().terminalTruckingCompany());
|
||||
copy(current, request.data());
|
||||
current.setWarehouseId(warehouse.id()); current.setWarehouseName(warehouse.warehouseName());
|
||||
current.setTerminalTruckingCompanyId(trucking == null ? null : trucking.supplierId());
|
||||
|
||||
@@ -1663,7 +1663,22 @@ public class SmartLoadingService {
|
||||
: "COMPLETED".equals(task.taskStatus()) ? "COMPLETED" : "IN_PROGRESS";
|
||||
return new Plan(p.getId(),p.getPlanNo(),p.getPlanStatus(),p.getContainerBookingId(),
|
||||
b.getContainerNo(),b.getVoyageNo(),p.getVersion(),mutable,mutable,blockedReason,finalStatus,
|
||||
task.taskId(),task.taskStatus(),task.taskVersion(),planCoLoadGroups(p.getId()),collapsePalletUnits(items));
|
||||
task.taskId(),task.taskStatus(),task.taskVersion(),planCoLoadGroups(p.getId()),planPalletMembers(items),
|
||||
collapsePalletUnits(items));
|
||||
}
|
||||
private List<PlanPalletMembers> planPalletMembers(List<LoadingPlanItemEntity> items) {
|
||||
List<Long> palletIds=items.stream().map(LoadingPlanItemEntity::getPalletId).filter(Objects::nonNull)
|
||||
.distinct().toList();
|
||||
if(palletIds.isEmpty()) return List.of();
|
||||
return dropshipPallets.palletInboundMembersByPalletIds(palletIds).stream()
|
||||
.collect(java.util.stream.Collectors.groupingBy(
|
||||
com.baiyue.firstleg.mapper.DropshipPalletizationMapper.PlanPalletMemberRow::getPalletId,
|
||||
LinkedHashMap::new,java.util.stream.Collectors.toList()))
|
||||
.entrySet().stream().map(entry->new PlanPalletMembers(entry.getKey(),entry.getValue().stream()
|
||||
.map(row->new GroupMemberCandidate(row.getAccountId(),row.getInboundId(),row.getOrderId(),
|
||||
row.getOrderNo(),row.getInboundCode(),row.getCustomerName(),row.getAvailablePackageCount(),
|
||||
row.getOrderStatusSnapshot(),row.getExpectedArrivalAt()))
|
||||
.toList())).toList();
|
||||
}
|
||||
private List<LoadingPlanItemEntity> collapsePalletUnits(List<LoadingPlanItemEntity> items) {
|
||||
List<LoadingPlanItemEntity> result = new ArrayList<>();
|
||||
|
||||
@@ -34,7 +34,7 @@ public class TruckAppointmentFeeService {
|
||||
if (item == null || !"ACTIVE".equals(item.getStatus()) || !Boolean.TRUE.equals(item.getPickupPayable())) {
|
||||
throw conflict("国内拖车费项目不存在、已停用或未启用应付");
|
||||
}
|
||||
suppliers.trucking(appointment.getCarrierId(), null);
|
||||
suppliers.domesticTrucking(appointment.getCarrierId(), null);
|
||||
List<Share> shares = allocate(total, rows);
|
||||
Map<Long, List<Share>> plans = new LinkedHashMap<>();
|
||||
shares.forEach(share -> plans.computeIfAbsent(share.owner().planId(), ignored -> new ArrayList<>()).add(share));
|
||||
|
||||
@@ -47,8 +47,8 @@ public class TruckAppointmentService {
|
||||
@Transactional public TruckAppointmentAttachmentEntity upload(long id,String type,MultipartFile file,long uid){String attachmentType=attachmentType(type);required(id);try{var response=files.upload(internalToken,uid,0L,"TRUCK_APPOINTMENT_ATTACHMENT",Long.toString(id),file);if(response==null||!response.successful()||response.data()==null)throw bad("附件上传失败");var m=response.data();TruckAppointmentAttachmentEntity a=new TruckAppointmentAttachmentEntity();a.setId(IdWorker.getId());a.setAppointmentId(id);a.setFileId(m.fileId());a.setAttachmentType(attachmentType);a.setFileName(m.fileName());a.setFileHash(m.sha256());a.setVisibility("PLATFORM");a.setUploadedBy(uid);a.setUploadedAt(LocalDateTime.now());repo.attachment(a);return a;}catch(FeignException ex){throw new BizException(ResultCode.SERVICE_UNAVAILABLE,"文件服务暂不可用");}}
|
||||
@Transactional public TruckAppointmentAttachmentEntity attach(long id,AttachmentRequest r,long uid){String attachmentType=attachmentType(r.attachmentType());required(id);TruckAppointmentFileClient.Metadata metadata;try{var response=files.metadata(internalToken,0L,"TRUCK_APPOINTMENT_ATTACHMENT",Long.toString(id),r.fileId());if(response==null||!response.successful()||response.data()==null)throw bad("附件不存在或归属不匹配");metadata=response.data();}catch(FeignException ex){throw new BizException(ResultCode.SERVICE_UNAVAILABLE,"文件服务暂不可用");} TruckAppointmentAttachmentEntity a=new TruckAppointmentAttachmentEntity();a.setId(IdWorker.getId());a.setAppointmentId(id);a.setFileId(metadata.fileId());a.setAttachmentType(attachmentType);a.setFileName(metadata.fileName());a.setFileHash(metadata.sha256());a.setVisibility("PLATFORM");a.setUploadedBy(uid);a.setUploadedAt(LocalDateTime.now());repo.attachment(a);return a;}
|
||||
@Transactional public void deleteAttachment(long id,long attachmentId){required(id);if(repo.deleteAttachment(id,attachmentId)!=1)throw new BizException(ResultCode.NOT_FOUND,"附件引用不存在");}
|
||||
@Transactional public TruckAppointmentEntity create(long uid,String name,SaveRequest r){if(r.expectedVersion()==null||r.expectedVersion()!=0)throw bad("新增 expectedVersion 必须为0");validateRequired(r);completion.lockBooking(r.oceanBookingId());TruckAppointmentEntity active=repo.firstActiveForUpdate(r.oceanBookingId());if(active!=null)throw existingAppointmentConflict(active);AssociationContext links=validateAssociations(r);var carrier=suppliers.trucking(r.carrierId(),r.carrierName());TruckAppointmentEntity e=new TruckAppointmentEntity();e.setId(IdWorker.getId());e.setAppointmentNo(documentNumbers.next("TA"));e.setStatus(TruckAppointmentStatus.DRAFT);e.setRevision(0);e.setVersion(0);e.setCreatedAt(LocalDateTime.now());e.setUpdatedAt(e.getCreatedAt());copy(e,r,links,carrier.name());try{repo.insert(e);}catch(DuplicateKeyException exception){if(exception.getMessage()!=null&&exception.getMessage().contains("uk_truck_active_ocean_booking"))throw existingAppointmentConflict(repo.firstActiveForUpdate(r.oceanBookingId()));throw exception;}record(e,null,e.getStatus().name(),"CREATE",null,uid,name);completion.completeForBooking(e.getOceanBookingId());return enrich(required(e.getId()));}
|
||||
@Transactional public TruckAppointmentEntity edit(long id,long uid,String name,SaveRequest r){validateRequired(r);TruckAppointmentEntity e=required(id);completion.lockBooking(Math.min(e.getOceanBookingId(),r.oceanBookingId()));if(!Objects.equals(e.getOceanBookingId(),r.oceanBookingId()))completion.lockBooking(Math.max(e.getOceanBookingId(),r.oceanBookingId()));checkVersion(e,r.expectedVersion());if(!(e.getStatus()==TruckAppointmentStatus.DRAFT||e.getStatus()==TruckAppointmentStatus.PENDING_DISPATCH||e.getStatus()==TruckAppointmentStatus.RESCHEDULED))throw conflict("当前状态不可编辑");TruckAppointmentEntity active=repo.firstActiveForUpdate(r.oceanBookingId());if(active!=null&&!Objects.equals(active.getId(),e.getId()))throw existingAppointmentConflict(active);AssociationContext links=validateAssociations(r);var carrier=suppliers.trucking(r.carrierId(),r.carrierName());copy(e,r,links,carrier.name());try{if(repo.updateEdit(e,r.expectedVersion())!=1)throw conflict("版本已变化,请刷新后重试");}catch(DuplicateKeyException exception){if(exception.getMessage()!=null&&exception.getMessage().contains("uk_truck_active_ocean_booking"))throw existingAppointmentConflict(repo.firstActiveForUpdate(r.oceanBookingId()));throw exception;}record(e,e.getStatus().name(),e.getStatus().name(),"EDIT",null,uid,name);completion.completeForBooking(e.getOceanBookingId());return enrich(required(id));}
|
||||
@Transactional public TruckAppointmentEntity create(long uid,String name,SaveRequest r){if(r.expectedVersion()==null||r.expectedVersion()!=0)throw bad("新增 expectedVersion 必须为0");validateRequired(r);completion.lockBooking(r.oceanBookingId());TruckAppointmentEntity active=repo.firstActiveForUpdate(r.oceanBookingId());if(active!=null)throw existingAppointmentConflict(active);AssociationContext links=validateAssociations(r);var carrier=suppliers.domesticTrucking(r.carrierId(),r.carrierName());TruckAppointmentEntity e=new TruckAppointmentEntity();e.setId(IdWorker.getId());e.setAppointmentNo(documentNumbers.next("TA"));e.setStatus(TruckAppointmentStatus.DRAFT);e.setRevision(0);e.setVersion(0);e.setCreatedAt(LocalDateTime.now());e.setUpdatedAt(e.getCreatedAt());copy(e,r,links,carrier.name());try{repo.insert(e);}catch(DuplicateKeyException exception){if(exception.getMessage()!=null&&exception.getMessage().contains("uk_truck_active_ocean_booking"))throw existingAppointmentConflict(repo.firstActiveForUpdate(r.oceanBookingId()));throw exception;}record(e,null,e.getStatus().name(),"CREATE",null,uid,name);completion.completeForBooking(e.getOceanBookingId());return enrich(required(e.getId()));}
|
||||
@Transactional public TruckAppointmentEntity edit(long id,long uid,String name,SaveRequest r){validateRequired(r);TruckAppointmentEntity e=required(id);completion.lockBooking(Math.min(e.getOceanBookingId(),r.oceanBookingId()));if(!Objects.equals(e.getOceanBookingId(),r.oceanBookingId()))completion.lockBooking(Math.max(e.getOceanBookingId(),r.oceanBookingId()));checkVersion(e,r.expectedVersion());if(!(e.getStatus()==TruckAppointmentStatus.DRAFT||e.getStatus()==TruckAppointmentStatus.PENDING_DISPATCH||e.getStatus()==TruckAppointmentStatus.RESCHEDULED))throw conflict("当前状态不可编辑");TruckAppointmentEntity active=repo.firstActiveForUpdate(r.oceanBookingId());if(active!=null&&!Objects.equals(active.getId(),e.getId()))throw existingAppointmentConflict(active);AssociationContext links=validateAssociations(r);var carrier=suppliers.domesticTrucking(r.carrierId(),r.carrierName());copy(e,r,links,carrier.name());try{if(repo.updateEdit(e,r.expectedVersion())!=1)throw conflict("版本已变化,请刷新后重试");}catch(DuplicateKeyException exception){if(exception.getMessage()!=null&&exception.getMessage().contains("uk_truck_active_ocean_booking"))throw existingAppointmentConflict(repo.firstActiveForUpdate(r.oceanBookingId()));throw exception;}record(e,e.getStatus().name(),e.getStatus().name(),"EDIT",null,uid,name);completion.completeForBooking(e.getOceanBookingId());return enrich(required(id));}
|
||||
@Transactional
|
||||
public TruckAppointmentEntity action(long id,String action,ActionRequest r,String idem,String clientHash,long uid,String name){
|
||||
String requestHash=hash(action,id,r);verifyClientHash(clientHash,requestHash);
|
||||
|
||||
+15
-2
@@ -31,8 +31,21 @@ public class WarehouseSupplierSnapshotService {
|
||||
}
|
||||
}
|
||||
|
||||
public WarehouseSupplierClient.Snapshot trucking(Long supplierId, String suppliedName) {
|
||||
return resolve(supplierId, suppliedName, "TRUCKING");
|
||||
public WarehouseSupplierClient.Snapshot domesticTrucking(Long supplierId, String suppliedName) {
|
||||
return trucking(supplierId, suppliedName, "DOMESTIC");
|
||||
}
|
||||
|
||||
public WarehouseSupplierClient.Snapshot overseasTrucking(Long supplierId, String suppliedName) {
|
||||
return trucking(supplierId, suppliedName, "OVERSEAS");
|
||||
}
|
||||
|
||||
private WarehouseSupplierClient.Snapshot trucking(Long supplierId, String suppliedName, String scope) {
|
||||
var snapshot = resolve(supplierId, suppliedName, "TRUCKING");
|
||||
if (snapshot != null && !scope.equals(snapshot.truckingScope())) {
|
||||
throw new BizException(ResultCode.CONFLICT, "DOMESTIC".equals(scope)
|
||||
? "国内拖车只能使用国内拖车供应商" : "清关提柜只能使用海外车队");
|
||||
}
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
public WarehouseSupplierClient.Snapshot customs(Long supplierId, String suppliedName) {
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ public class TerminalDrayageService {
|
||||
TerminalDrayageEntity value = mapper.lock(containerBookingId);
|
||||
requireVersion(value, request.expectedVersion());
|
||||
if (actualPickupAt(context, value) != null) throw conflict("实际提柜后不可更换码头车队");
|
||||
var fleet = suppliers.trucking(request.fleetSupplierId(), request.fleetSupplierName());
|
||||
var fleet = suppliers.overseasTrucking(request.fleetSupplierId(), request.fleetSupplierName());
|
||||
if (value != null && Objects.equals(value.getFleetSupplierId(), fleet.supplierId())) return view(context, value);
|
||||
if (value != null && value.getFleetSupplierId() != null) {
|
||||
mails.replaceFleet(containerBookingId, context.base().containerNo(), value.getFleetSupplierId(), fleet.supplierId(), operatorId);
|
||||
|
||||
Reference in New Issue
Block a user