This commit is contained in:
2026-08-08 21:14:39 +08:00
parent e5c6e03033
commit 2dae8b2029
20 changed files with 53421 additions and 17 deletions
@@ -113,9 +113,7 @@ public class LoadingPickService {
history.setOperatorId(operatorId);
history.setOperatorName(operatorName);
repository.insert(history);
if (repository.allPlanItemsPicked(task.getLoadingPlanId())) {
loadingListService.finishFromPda(task.getLoadingPlanId(), taskId, operatorId, operatorName);
}
finishIfResolved(task, operatorId, operatorName);
return view(requiredTask(taskId), request.warehouseId());
}
@@ -137,6 +135,7 @@ public class LoadingPickService {
}
insertHistory(taskId, itemId, operationId, requestHash, "PARTIAL",
request.finalPickedPackageCount(), null, operatorId, operatorName);
finishIfResolved(task, operatorId, operatorName);
return view(requiredTask(taskId), request.warehouseId());
}
@@ -151,16 +150,23 @@ public class LoadingPickService {
assertReplay(replay, taskId, itemId, requestHash);
return view(requiredTask(taskId), request.warehouseId());
}
requiredLoadingTask(taskId);
LoadingPickTaskEntity task = requiredLoadingTask(taskId);
requireWarehouseItem(taskId, itemId, request.warehouseId());
if (repository.skip(itemId, request.version(), request.warehouseId()) != 1) {
throw conflict("跳拣仅允许未开始拣货的待拣明细,或明细版本已变化");
}
insertHistory(taskId, itemId, operationId, requestHash, "SKIP", 0, reason,
operatorId, operatorName);
finishIfResolved(task, operatorId, operatorName);
return view(requiredTask(taskId), request.warehouseId());
}
private void finishIfResolved(LoadingPickTaskEntity task, long operatorId, String operatorName) {
if (repository.allPlanItemsPicked(task.getLoadingPlanId())) {
loadingListService.finishFromPda(task.getLoadingPlanId(), task.getId(), operatorId, operatorName);
}
}
@Transactional
public void remove(long planItemId) {
LoadingPickItemEntity item = repository.itemByPlanItem(planItemId);
@@ -10,6 +10,7 @@ import com.baiyue.firstleg.entity.*;
import com.baiyue.firstleg.oceanbooking.entity.OceanBookingEntity;
import com.baiyue.firstleg.oceanbooking.repository.OceanBookingRepository;
import com.baiyue.firstleg.repository.TruckAppointmentRepository;
import com.baiyue.firstleg.repository.SmartLoadingRepository;
import com.baiyue.firstleg.client.TruckAppointmentFileClient;
import jakarta.annotation.Resource;
import feign.FeignException;
@@ -24,6 +25,7 @@ import org.springframework.web.multipart.MultipartFile;
public class TruckAppointmentService {
@Resource TruckAppointmentRepository repo;
@Resource OceanBookingRepository oceanBookings;
@Resource SmartLoadingRepository loadingPlans;
@Resource TruckAppointmentFileClient files;
@Value("${baiyue.security.internal-service-token}") String internalToken;
public PageResult<TruckAppointmentEntity> page(Query q){return repo.page(q);} public TruckAppointmentEntity detail(long id){return required(id);}
@@ -35,7 +37,8 @@ public class TruckAppointmentService {
@Transactional public TruckAppointmentEntity edit(long id,long uid,String name,SaveRequest r){TruckAppointmentEntity e=required(id); checkVersion(e,r.expectedVersion()); if(!(e.getStatus()==TruckAppointmentStatus.DRAFT||e.getStatus()==TruckAppointmentStatus.PENDING_DISPATCH||e.getStatus()==TruckAppointmentStatus.RESCHEDULED))throw conflict("当前状态不可编辑"); validateBookingLink(r); copy(e,r); if(repo.updateEdit(e,r.expectedVersion())!=1)throw conflict("版本已变化,请刷新后重试"); record(e,e.getStatus().name(),e.getStatus().name(),"EDIT",null,uid,name); return required(id);}
@Transactional public TruckAppointmentEntity action(long id,String action,ActionRequest r,String idem,String hash,long uid,String name){TruckAppointmentEntity e=required(id); checkVersion(e,r.expectedVersion()); if("RESCHEDULE".equals(action))throw conflict("改约请使用专用接口"); TruckAppointmentStatus from=e.getStatus(),to=next(from,action); if(repo.transition(id,from.name(),to.name(),e.getVersion())!=1)throw conflict("状态或版本已变化,请刷新后重试"); e.setStatus(to);e.setVersion(e.getVersion()+1);e.setRevision(e.getRevision()+1); record(e,from.name(),to.name(),action,r.reason(),uid,name); operation(e,action,idem,hash); return e;}
@Transactional public TruckAppointmentEntity reschedule(long id,LocalDateTime at,ActionRequest r,long uid,String name){TruckAppointmentEntity e=required(id);checkVersion(e,r.expectedVersion()); if(e.getStatus()==TruckAppointmentStatus.COMPLETED||e.getStatus()==TruckAppointmentStatus.CANCELLED)throw conflict("当前状态不可改约"); String from=e.getStatus().name(); if(repo.reschedule(id,at,r.reason(),e.getVersion())!=1)throw conflict("状态或版本已变化,请刷新后重试");e.setStatus(TruckAppointmentStatus.RESCHEDULED);e.setPlannedLoadingAt(at);e.setVersion(e.getVersion()+1);e.setRevision(e.getRevision()+1);record(e,from,"RESCHEDULED","RESCHEDULE",r.reason(),uid,name);return e;}
private void validateBookingLink(SaveRequest r){if(r.oceanBookingId()==null||r.oceanBookingId()<=0)throw bad("oceanBookingId不能为空"); OceanBookingEntity b=oceanBookings.find(r.oceanBookingId()); if(b==null)throw new BizException(ResultCode.NOT_FOUND,"关联订舱不存在"); if(!"RELEASED".equals(b.getStatus()))throw conflict("仅已放舱订舱可创建拖车预约"); if(r.customerId()!=null&&r.customerId()>0&&!Objects.equals(r.customerId(),b.getCustomerId()))throw bad("customerId与订舱客户不一致"); if(r.containerBookingId()!=null&&r.containerBookingId()>0){ContainerBookingEntity c=oceanBookings.containerBooking(r.containerBookingId()); if(c==null)throw new BizException(ResultCode.NOT_FOUND,"关联柜体不存在"); boolean allocated=oceanBookings.allocations(r.oceanBookingId()).stream().anyMatch(a->Objects.equals(a.getContainerBookingId(),r.containerBookingId())); if(!allocated)throw bad("containerBookingId未分配至该订舱"); if(r.warehouseId()!=null&&r.warehouseId()>0&&c.getWarehouseId()!=null&&!Objects.equals(r.warehouseId(),c.getWarehouseId()))throw bad("warehouseId与柜体不一致");}}
private void validateBookingLink(SaveRequest r){if(r.oceanBookingId()==null||r.oceanBookingId()<=0)throw bad("oceanBookingId不能为空"); OceanBookingEntity b=oceanBookings.find(r.oceanBookingId()); if(b==null)throw new BizException(ResultCode.NOT_FOUND,"关联订舱不存在"); if(!"RELEASED".equals(b.getStatus()))throw conflict("仅已放舱订舱可创建拖车预约"); if(r.customerId()!=null&&r.customerId()>0&&!Objects.equals(r.customerId(),b.getCustomerId()))throw bad("customerId与订舱客户不一致"); if(r.containerBookingId()!=null&&r.containerBookingId()>0){ContainerBookingEntity c=oceanBookings.containerBooking(r.containerBookingId()); if(c==null)throw new BizException(ResultCode.NOT_FOUND,"关联柜体不存在"); boolean allocated=oceanBookings.allocations(r.oceanBookingId()).stream().anyMatch(a->Objects.equals(a.getContainerBookingId(),r.containerBookingId())); if(!allocated)throw bad("containerBookingId未分配至该订舱"); if(r.warehouseId()!=null&&r.warehouseId()>0&&c.getWarehouseId()!=null&&!Objects.equals(r.warehouseId(),c.getWarehouseId()))throw bad("warehouseId与柜体不一致");} validateLoadingPlanLink(r);}
private void validateLoadingPlanLink(SaveRequest r){if(r.loadingPlanId()==null)return;if(r.loadingPlanId()<=0)throw bad("loadingPlanId必须大于0");if(r.containerBookingId()==null||r.containerBookingId()<=0)throw bad("关联装柜计划时containerBookingId不能为空");LoadingPlanEntity plan=loadingPlans.plan(r.loadingPlanId());if(plan==null)throw new BizException(ResultCode.NOT_FOUND,"关联装柜计划不存在");if(!Objects.equals(plan.getContainerBookingId(),r.containerBookingId()))throw bad("loadingPlanId与柜体不一致");}
private TruckAppointmentStatus next(TruckAppointmentStatus s,String a){return switch(a){case"SUBMIT"->s==TruckAppointmentStatus.DRAFT?TruckAppointmentStatus.PENDING_DISPATCH:badStatus();case"DISPATCH"->s==TruckAppointmentStatus.PENDING_DISPATCH||s==TruckAppointmentStatus.RESCHEDULED?TruckAppointmentStatus.DISPATCHED:badStatus();case"PICKUP"->s==TruckAppointmentStatus.DISPATCHED?TruckAppointmentStatus.PICKUP_IN_PROGRESS:badStatus();case"ARRIVE"->s==TruckAppointmentStatus.PICKUP_IN_PROGRESS?TruckAppointmentStatus.ARRIVED_WAREHOUSE:badStatus();case"LOAD"->s==TruckAppointmentStatus.ARRIVED_WAREHOUSE?TruckAppointmentStatus.LOADING:badStatus();case"DEPART"->s==TruckAppointmentStatus.LOADING?TruckAppointmentStatus.DEPARTED:badStatus();case"COMPLETE"->s==TruckAppointmentStatus.DEPARTED?TruckAppointmentStatus.COMPLETED:badStatus();case"EXCEPTION"->s!=TruckAppointmentStatus.COMPLETED&&s!=TruckAppointmentStatus.CANCELLED?TruckAppointmentStatus.EXCEPTION:badStatus();case"CANCEL"->s!=TruckAppointmentStatus.COMPLETED?TruckAppointmentStatus.CANCELLED:badStatus();default->badStatus();};}
private TruckAppointmentStatus badStatus(){throw conflict("不允许的状态动作");} private TruckAppointmentEntity required(long id){TruckAppointmentEntity e=repo.find(id);if(e==null)throw new BizException(ResultCode.NOT_FOUND,"拖车预约不存在");return e;} private void checkVersion(TruckAppointmentEntity e,int v){if(e.getVersion()!=v)throw conflict("版本已变化,请刷新后重试");} private static BizException conflict(String m){return new BizException(ResultCode.CONFLICT,m);} private static BizException bad(String m){return new BizException(ResultCode.BAD_REQUEST,m);}
private void copy(TruckAppointmentEntity e,SaveRequest r){e.setOutboundOrderId(r.outboundOrderId());e.setOceanBookingId(r.oceanBookingId());e.setContainerBookingId(r.containerBookingId());e.setLoadingPlanId(r.loadingPlanId());e.setWarehouseId(r.warehouseId());e.setCustomerId(r.customerId());e.setCustomerName(r.customerName());e.setCarrierId(r.carrierId());e.setCarrierName(r.carrierName());e.setFleetContact(r.fleetContact());e.setFleetPhone(r.fleetPhone());e.setDriverName(r.driverName());e.setDriverPhone(r.driverPhone());e.setDriverIdCard(r.driverIdCard());e.setVehicleNo(r.vehicleNo());e.setStoreName(r.storeName());e.setStoreContact(r.storeContact());e.setStorePhone(r.storePhone());e.setStoreAddress(r.storeAddress());e.setStoreCity(r.storeCity());e.setStoreZipcode(r.storeZipcode());e.setPackageCount(r.packageCount());e.setGrossWeightKg(r.grossWeightKg());e.setVolumeCbm(r.volumeCbm());e.setPalletCount(r.palletCount());e.setPoNo(r.poNo());e.setPlannedLoadingAt(r.plannedLoadingAt());e.setTransitMinutes(r.transitMinutes());e.setPayableAmount(r.payableAmount());e.setReceivableAmount(r.receivableAmount());e.setCurrency(r.currency()==null?"RMB":r.currency());e.setRemark(r.remark());}