fix(firstleg): remove booking document prerequisites from release and trucking
This commit is contained in:
@@ -3,7 +3,8 @@ import jakarta.validation.constraints.*; import java.math.BigDecimal; import jav
|
||||
public final class TruckAppointmentDtos { private TruckAppointmentDtos(){}
|
||||
public record Query(@Size(max=64) String keyword, com.baiyue.firstleg.domain.TruckAppointmentStatus status, @Positive Long oceanBookingId, @Min(1) long page, @Min(1) @Max(200) long size){ public Query{if(page==0)page=1;if(size==0)size=20;} }
|
||||
public record CandidateQuery(@Size(max=64) String keyword,@Min(1) long page,@Min(1) @Max(200) long size){public CandidateQuery{if(page==0)page=1;if(size==0)size=20;}}
|
||||
public record Candidate(Long oceanBookingId,String oceanBookingNo,String billOfLadingNo,Long warehouseId,String warehouseName,String channelCode,String channelName,Boolean bookingDocumentReady){}
|
||||
/** 已放舱订舱候选,预约不依赖订舱附件。 */
|
||||
public record Candidate(Long oceanBookingId,String oceanBookingNo,String billOfLadingNo,Long warehouseId,String warehouseName,String channelCode,String channelName){}
|
||||
public record SaveRequest(@Positive Long outboundOrderId,@NotNull @Positive Long oceanBookingId,@Positive Long warehouseId,@NotNull @Positive Long carrierId,@Size(max=128) String carrierName,@Size(max=128) String billOfLadingNo,@Size(max=64) String fleetContact,@Size(max=32) String fleetPhone,@Size(max=64) String driverName,@Size(max=32) String driverPhone,@Size(max=32) String driverIdCard,@Size(max=32) String vehicleNo,@Size(max=128) String storeName,@Size(max=64) String storeContact,@Size(max=32) String storePhone,@Size(max=255) String storeAddress,@Size(max=64) String storeCity,@Size(max=16) String storeZipcode,@PositiveOrZero Integer packageCount,@DecimalMin("0") BigDecimal grossWeightKg,@DecimalMin("0") BigDecimal volumeCbm,@PositiveOrZero Integer palletCount,@Size(max=255) String poNo,@NotNull LocalDateTime plannedLoadingAt,@PositiveOrZero Integer transitMinutes,@DecimalMin("0") @Digits(integer=16,fraction=2) BigDecimal payableAmount,@Pattern(regexp="RMB") String currency,@Size(max=1000) String remark,@NotNull @PositiveOrZero Integer expectedVersion){}
|
||||
public record ActionRequest(@NotNull @PositiveOrZero Integer expectedVersion,@Size(max=500) String reason){}
|
||||
public record AttachmentRequest(@NotNull @Positive Long fileId,@NotBlank @Pattern(regexp="DISPATCH_ORDER|DRIVER_DOCUMENT|VEHICLE_DOCUMENT|OTHER") String attachmentType,@Size(max=255) String fileName,@Size(max=128) String fileHash){ }
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.baiyue.firstleg.mapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baiyue.firstleg.dto.TruckAppointmentDtos.*; import com.baiyue.firstleg.entity.TruckAppointmentEntity; import org.apache.ibatis.annotations.*;
|
||||
@Mapper public interface TruckAppointmentMapper extends BaseMapper<TruckAppointmentEntity>{
|
||||
/** 查询已放舱且有提单号的可预约订舱,不依赖附件。 */
|
||||
@Select("""
|
||||
<script>
|
||||
SELECT o.id oceanBookingId,o.booking_no oceanBookingNo,o.bill_of_lading_no billOfLadingNo,
|
||||
o.warehouse_id warehouseId,o.warehouse_name warehouseName,o.channel_code channelCode,
|
||||
o.channel_name channelName,TRUE bookingDocumentReady
|
||||
o.channel_name channelName
|
||||
FROM fl_ocean_booking o
|
||||
WHERE EXISTS (SELECT 1 FROM fl_ocean_booking_document d WHERE d.ocean_booking_id=o.id
|
||||
AND d.valid=1 AND d.document_type IN ('BOOKING_CONFIRMATION','BILL_OF_LADING'))
|
||||
AND o.status='RELEASED' AND o.bill_of_lading_no IS NOT NULL AND o.bill_of_lading_no<>''
|
||||
WHERE o.status='RELEASED' AND o.bill_of_lading_no IS NOT NULL AND o.bill_of_lading_no<>''
|
||||
AND NOT EXISTS (SELECT 1 FROM fl_truck_appointment t WHERE t.ocean_booking_id=o.id
|
||||
AND t.status NOT IN ('CANCELLED','EXCEPTION'))
|
||||
AND (#{q.keyword} IS NULL OR o.booking_no LIKE CONCAT('%',#{q.keyword},'%')
|
||||
|
||||
+1
-2
@@ -51,7 +51,6 @@ public class OceanBookingService {
|
||||
@Resource private WarehouseMasterDataClient warehouses;
|
||||
@Resource private WarehousePartnerClient partners;
|
||||
@Resource private FirstlegDocumentNumberGenerator documentNumbers;
|
||||
@Resource private OceanBookingDocumentService documents;
|
||||
@Resource private com.baiyue.firstleg.service.IamCustomerSnapshotService customers;
|
||||
@Value("${baiyue.security.internal-service-token:}") private String internalToken;
|
||||
@Value("${baiyue.warehouse.public-tenant-id:0}") private long publicWarehouseTenantId;
|
||||
@@ -194,6 +193,7 @@ public class OceanBookingService {
|
||||
complete(null, operatorId, action, key, new Detail(before, List.of(), List.of(), List.of(), List.of()));
|
||||
}
|
||||
|
||||
/** 校验完整订舱资料后放舱,不以附件上传作为前置条件。 */
|
||||
@Transactional public Detail release(long id, long operatorId, String name, String key, ReleaseRequest request) {
|
||||
String action = "RELEASE";
|
||||
Detail replay = claimOrReplay(id, operatorId, action, key, hash(action, id, request));
|
||||
@@ -202,7 +202,6 @@ public class OceanBookingService {
|
||||
requireStatus(before, OceanBookingStatus.DRAFT);
|
||||
validateRelease(before, repository.parties(id), repository.requirements(id));
|
||||
validateMasterData(before);
|
||||
documents.requireActiveValidDocument(before);
|
||||
if (repository.transition(id, OceanBookingStatus.DRAFT.name(), OceanBookingStatus.RELEASED.name(),
|
||||
request.expectedVersion(), operatorId, name) != 1) throw concurrent();
|
||||
OceanBookingEntity after = required(id);
|
||||
|
||||
@@ -9,7 +9,6 @@ import com.baiyue.firstleg.dto.TruckAppointmentDtos.*;
|
||||
import com.baiyue.firstleg.entity.*;
|
||||
import com.baiyue.firstleg.oceanbooking.entity.OceanBookingEntity;
|
||||
import com.baiyue.firstleg.oceanbooking.repository.OceanBookingRepository;
|
||||
import com.baiyue.firstleg.oceanbooking.service.OceanBookingDocumentService;
|
||||
import com.baiyue.firstleg.repository.TruckAppointmentRepository;
|
||||
import com.baiyue.firstleg.client.TruckAppointmentFileClient;
|
||||
import jakarta.annotation.Resource;
|
||||
@@ -36,7 +35,6 @@ public class TruckAppointmentService {
|
||||
@Resource TruckAppointmentRepository repo;
|
||||
@Resource TruckAppointmentCompletionService completion;
|
||||
@Resource OceanBookingRepository oceanBookings;
|
||||
@Resource OceanBookingDocumentService oceanBookingDocuments;
|
||||
@Resource TruckAppointmentFileClient files;
|
||||
@Resource WarehouseSupplierSnapshotService suppliers;
|
||||
@Resource FirstlegDocumentNumberGenerator documentNumbers;
|
||||
@@ -64,13 +62,13 @@ public class TruckAppointmentService {
|
||||
return completeOperation(id,action,idem,enrich(required(id)));
|
||||
}
|
||||
@Transactional public TruckAppointmentEntity reschedule(long id,LocalDateTime at,ActionRequest r,String idem,String clientHash,long uid,String name){String action="RESCHEDULE";String requestHash=hash(action,id,new ReschedulePayload(at,r));verifyClientHash(clientHash,requestHash);TruckAppointmentEntity replay=claimOrReplay(id,action,idem,requestHash);if(replay!=null)return replay;TruckAppointmentEntity e=required(id);completion.lockBooking(e.getOceanBookingId());checkVersion(e,r.expectedVersion()); if(e.getStatus()==TruckAppointmentStatus.COMPLETED||e.getStatus()==TruckAppointmentStatus.CANCELLED)throw conflict("当前状态不可改约"); TruckAppointmentEntity active=repo.firstActiveForUpdate(e.getOceanBookingId());if(active!=null&&!Objects.equals(active.getId(),e.getId()))throw existingAppointmentConflict(active);String from=e.getStatus().name(); if(repo.reschedule(id,at,r.reason(),e.getVersion())!=1)throw conflict("状态或版本已变化,请刷新后重试");TruckAppointmentEntity after=enrich(required(id));record(after,from,"RESCHEDULED",action,r.reason(),uid,name);completion.completeForBooking(e.getOceanBookingId());return completeOperation(id,action,idem,enrich(required(id)));}
|
||||
/** 从已放舱订舱校验仓库和提单号,附件不作为预约条件。 */
|
||||
private AssociationContext validateAssociations(SaveRequest r){
|
||||
OceanBookingEntity booking=oceanBookings.find(r.oceanBookingId());
|
||||
if(booking==null)throw new BizException(ResultCode.NOT_FOUND,"关联订舱不存在");
|
||||
if(!"RELEASED".equals(booking.getStatus()))throw conflict("拖车预约只能选择已放舱订舱");
|
||||
Long warehouseId=mergeWarehouse(r.warehouseId(),booking.getWarehouseId(),"订舱");
|
||||
String billOfLadingNo=releasedBookingBill(booking,trim(r.billOfLadingNo()));
|
||||
oceanBookingDocuments.requireActiveValidDocument(booking);
|
||||
return new AssociationContext(booking,warehouseId,billOfLadingNo);
|
||||
}
|
||||
private static void validateRequired(SaveRequest r){if(r.oceanBookingId()==null||r.oceanBookingId()<=0)throw bad("oceanBookingId不能为空");if(r.carrierId()==null||r.carrierId()<=0)throw bad("carrierId不能为空");if(r.plannedLoadingAt()==null)throw bad("plannedLoadingAt不能为空");if(r.expectedVersion()==null||r.expectedVersion()<0)throw bad("expectedVersion不合法");if(r.payableAmount()!=null&&(r.payableAmount().signum()<0||r.payableAmount().scale()>2))throw bad("拖车费必须为非负数且最多两位小数");}
|
||||
@@ -85,13 +83,13 @@ public class TruckAppointmentService {
|
||||
private static void verifyClientHash(String clientHash,String serverHash){if(StringUtils.hasText(clientHash)&&!serverHash.equalsIgnoreCase(clientHash.trim()))throw bad("X-Request-Hash与请求内容不一致");}
|
||||
private static void validateKey(String key){if(!StringUtils.hasText(key)||key.trim().length()>128)throw bad("Idempotency-Key不能为空且不能超过128个字符");}
|
||||
private record ReschedulePayload(LocalDateTime plannedLoadingAt,ActionRequest request){}
|
||||
/** 派车时复核订舱放舱状态及提单号,不要求订舱附件。 */
|
||||
private String requireDispatchReady(TruckAppointmentEntity appointment){
|
||||
if(appointment.getOceanBookingId()==null)throw conflict("拖车预约缺少订舱关联");
|
||||
OceanBookingEntity booking=oceanBookings.find(appointment.getOceanBookingId());
|
||||
if(booking==null)throw new BizException(ResultCode.NOT_FOUND,"关联订舱不存在");
|
||||
if(!"RELEASED".equals(booking.getStatus()))throw conflict("关联订舱尚未放舱");
|
||||
String bill=releasedBookingBill(booking,trim(appointment.getBillOfLadingNo()));
|
||||
oceanBookingDocuments.requireActiveValidDocument(booking);
|
||||
return bill;
|
||||
}
|
||||
private static String releasedBookingBill(OceanBookingEntity booking,String requested){String authoritative=trim(booking.getBillOfLadingNo());if(!StringUtils.hasText(authoritative))throw conflict("关联已放舱订舱缺少提单号");if(StringUtils.hasText(requested)&&!authoritative.equals(requested))throw bad("billOfLadingNo与关联订舱不一致");return authoritative;}
|
||||
|
||||
Reference in New Issue
Block a user