From 7cb5da753ed162d5b5eb6a3e7ac6ea8c27d07291 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Fri, 14 Aug 2026 21:14:42 +0800 Subject: [PATCH] fix(firstleg): keep truck links on container ownership --- .../repository/OceanBookingRepository.java | 2 ++ .../repository/ContainerRepository.java | 6 ++++++ .../service/TruckAppointmentService.java | 6 ++++-- .../OceanBookingMapperContractTest.java | 3 +-- ...BookingTruckPermissionSqlContractTest.java | 20 ++++++++++++++----- .../service/TruckAppointmentServiceTest.java | 8 +++++--- 6 files changed, 33 insertions(+), 12 deletions(-) diff --git a/firstleg/src/main/java/com/baiyue/firstleg/oceanbooking/repository/OceanBookingRepository.java b/firstleg/src/main/java/com/baiyue/firstleg/oceanbooking/repository/OceanBookingRepository.java index 6084081c2..beb615403 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/oceanbooking/repository/OceanBookingRepository.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/oceanbooking/repository/OceanBookingRepository.java @@ -7,6 +7,7 @@ import com.baiyue.firstleg.oceanbooking.dto.OceanBookingDtos.Query; import com.baiyue.firstleg.oceanbooking.dto.OceanBookingDtos.ReleaseRequest; import com.baiyue.firstleg.oceanbooking.entity.*; import com.baiyue.firstleg.oceanbooking.mapper.*; +import com.baiyue.firstleg.repository.ContainerRepository; import jakarta.annotation.Resource; import org.springframework.stereotype.Repository; @@ -20,6 +21,7 @@ public class OceanBookingRepository { @Resource private OceanBookingContainerAllocationMapper allocations; @Resource private OceanBookingStatusHistoryMapper histories; @Resource private OceanBookingOperationMapper operations; + @Resource private ContainerRepository containerBookings; public PageResult page(Query query) { return PageResult.from(bookings.selectPage(new Page<>(query.page(), query.size()), query)); diff --git a/firstleg/src/main/java/com/baiyue/firstleg/repository/ContainerRepository.java b/firstleg/src/main/java/com/baiyue/firstleg/repository/ContainerRepository.java index 1aef2fc6b..bbc06aa40 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/repository/ContainerRepository.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/repository/ContainerRepository.java @@ -43,4 +43,10 @@ public class ContainerRepository { long operatorId, String operatorName) { return mapper.updateTransport(id, containerNo, voyageNo, version, operatorId, operatorName); } + public int syncReleasedTransport(long oceanBookingId, String billOfLadingNo, String vesselName, + String voyageNo, java.time.LocalDateTime estimatedSailingAt, + long operatorId, String operatorName) { + return mapper.syncReleasedTransport(oceanBookingId, billOfLadingNo, vesselName, voyageNo, + estimatedSailingAt, operatorId, operatorName); + } } diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/TruckAppointmentService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/TruckAppointmentService.java index c4f8c8295..798ce846d 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/TruckAppointmentService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/TruckAppointmentService.java @@ -11,6 +11,7 @@ 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.repository.ContainerRepository; import com.baiyue.firstleg.client.TruckAppointmentFileClient; import jakarta.annotation.Resource; import feign.FeignException; @@ -32,6 +33,7 @@ public class TruckAppointmentService { @Resource TruckAppointmentRepository repo; @Resource OceanBookingRepository oceanBookings; @Resource SmartLoadingRepository loadingPlans; + @Resource ContainerRepository containers; @Resource TruckAppointmentFileClient files; @Resource ObjectMapper objectMapper; @Value("${baiyue.security.internal-service-token}") String internalToken; @@ -44,11 +46,11 @@ 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("当前状态不可编辑"); OceanBookingEntity booking=validateBookingLink(r); copy(e,r,booking); 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 clientHash,long uid,String name){String requestHash=hash(action,id,r);verifyClientHash(clientHash,requestHash);TruckAppointmentEntity replay=claimOrReplay(id,action,idem,requestHash);if(replay!=null)return replay;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("状态或版本已变化,请刷新后重试"); TruckAppointmentEntity after=required(id);record(after,from.name(),to.name(),action,r.reason(),uid,name);return completeOperation(id,action,idem,after);} @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);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("状态或版本已变化,请刷新后重试");TruckAppointmentEntity after=required(id);record(after,from,"RESCHEDULED",action,r.reason(),uid,name);return completeOperation(id,action,idem,after);} - private OceanBookingEntity 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(b.getCustomerId()==null||!StringUtils.hasText(b.getCustomerName()))throw conflict("关联订舱缺少客户快照"); if(r.customerId()!=null&&r.customerId()>0&&!Objects.equals(r.customerId(),b.getCustomerId()))throw bad("customerId与订舱客户不一致"); if(StringUtils.hasText(r.customerName())&&!r.customerName().trim().equals(b.getCustomerName()))throw bad("customerName与订舱客户快照不一致"); 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);return b;} + private OceanBookingEntity 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(b.getCustomerId()==null||!StringUtils.hasText(b.getCustomerName()))throw conflict("关联订舱缺少客户快照"); if(r.customerId()!=null&&r.customerId()>0&&!Objects.equals(r.customerId(),b.getCustomerId()))throw bad("customerId与订舱客户不一致"); if(StringUtils.hasText(r.customerName())&&!r.customerName().trim().equals(b.getCustomerName()))throw bad("customerName与订舱客户快照不一致"); if(r.containerBookingId()!=null&&r.containerBookingId()>0){ContainerBookingEntity c=containers.find(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);return b;} 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 TruckAppointmentEntity enrich(TruckAppointmentEntity value){OceanBookingEntity booking=oceanBookings.find(value.getOceanBookingId());if(booking!=null){value.setOceanBookingNo(booking.getBookingNo());value.setWarehouseName(booking.getWarehouseName());value.setShippingCompanyId(booking.getShippingCompanyId());value.setShippingCompanyName(booking.getShippingCompanyName());value.setBookingAgentId(booking.getBookingAgentId());value.setBookingAgentName(booking.getBookingAgentName());}if(value.getContainerBookingId()!=null){ContainerBookingEntity container=oceanBookings.containerBooking(value.getContainerBookingId());if(container!=null){value.setCabinetNo(container.getCabinetNo());value.setContainerNo(container.getContainerNo());if(!StringUtils.hasText(value.getWarehouseName()))value.setWarehouseName(container.getWarehouseName());}}return value;} + private TruckAppointmentEntity enrich(TruckAppointmentEntity value){OceanBookingEntity booking=oceanBookings.find(value.getOceanBookingId());if(booking!=null){value.setOceanBookingNo(booking.getBookingNo());value.setWarehouseName(booking.getWarehouseName());value.setShippingCompanyId(booking.getShippingCompanyId());value.setShippingCompanyName(booking.getShippingCompanyName());value.setBookingAgentId(booking.getBookingAgentId());value.setBookingAgentName(booking.getBookingAgentName());}if(value.getContainerBookingId()!=null){ContainerBookingEntity container=containers.find(value.getContainerBookingId());if(container!=null){value.setCabinetNo(container.getCabinetNo());value.setContainerNo(container.getContainerNo());if(!StringUtils.hasText(value.getWarehouseName()))value.setWarehouseName(container.getWarehouseName());}}return value;} private void copy(TruckAppointmentEntity e,SaveRequest r,OceanBookingEntity booking){e.setOutboundOrderId(r.outboundOrderId());e.setOceanBookingId(r.oceanBookingId());e.setContainerBookingId(r.containerBookingId());e.setLoadingPlanId(r.loadingPlanId());e.setWarehouseId(r.warehouseId());e.setCustomerId(booking.getCustomerId());e.setCustomerName(booking.getCustomerName());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());} private TruckAppointmentEntity claimOrReplay(long id,String action,String key,String hash){validateKey(key);String normalized=key.trim();if(repo.claimOperation(IdWorker.getId(),id,action,normalized,hash))return null;TruckAppointmentOperationEntity existing=repo.operation(normalized);if(existing==null||!Objects.equals(existing.getAppointmentId(),id)||!action.equals(existing.getAction())||!hash.equals(existing.getRequestHash()))throw conflict("Idempotency-Key已用于不同请求");if(!StringUtils.hasText(existing.getResponseSnapshot()))throw conflict("相同请求正在处理中,请稍后重试");try{return objectMapper.readValue(existing.getResponseSnapshot(),TruckAppointmentEntity.class);}catch(JsonProcessingException ex){throw new IllegalStateException("无法读取拖车预约幂等结果",ex);}} private TruckAppointmentEntity completeOperation(long id,String action,String key,TruckAppointmentEntity result){try{String normalized=key.trim();if(repo.completeOperation(id,action,normalized,objectMapper.writeValueAsString(result))!=1)throw conflict("拖车预约幂等请求完成状态冲突");return result;}catch(JsonProcessingException ex){throw new IllegalStateException("无法保存拖车预约幂等结果",ex);}} diff --git a/firstleg/src/test/java/com/baiyue/firstleg/oceanbooking/repository/OceanBookingMapperContractTest.java b/firstleg/src/test/java/com/baiyue/firstleg/oceanbooking/repository/OceanBookingMapperContractTest.java index 3fd18bf26..fa744e503 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/oceanbooking/repository/OceanBookingMapperContractTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/oceanbooking/repository/OceanBookingMapperContractTest.java @@ -33,7 +33,6 @@ class OceanBookingMapperContractTest { .contains("status='DRAFT' AND version=#{expectedVersion}") .contains("status=#{fromStatus} AND version=#{expectedVersion}") .contains("status='CONFIRMED' AND version=#{expectedVersion}") - .contains("status='CHANGE_PENDING' AND version=#{expectedVersion}") - .contains("status IN ('SUBMITTED','CONFIRMED','CHANGE_PENDING')"); + .contains("status='CHANGE_PENDING' AND version=#{expectedVersion}"); } } diff --git a/firstleg/src/test/java/com/baiyue/firstleg/repository/Phase3BookingTruckPermissionSqlContractTest.java b/firstleg/src/test/java/com/baiyue/firstleg/repository/Phase3BookingTruckPermissionSqlContractTest.java index 4bdc611a2..8f4556b2a 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/repository/Phase3BookingTruckPermissionSqlContractTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/repository/Phase3BookingTruckPermissionSqlContractTest.java @@ -22,7 +22,17 @@ class Phase3BookingTruckPermissionSqlContractTest { private static final Pattern OCEAN_CODE = Pattern.compile("platform:firstleg:ocean-booking:[a-z-]+"); private static final Pattern TRUCK_CODE = Pattern.compile("platform:firstleg:truck-appointment:[a-z-]+"); - private static final Set OCEAN_PERMISSIONS = Set.of( + private static final Set OCEAN_CONTROLLER_PERMISSIONS = Set.of( + "platform:firstleg:ocean-booking:list", + "platform:firstleg:ocean-booking:create", + "platform:firstleg:ocean-booking:edit", + "platform:firstleg:ocean-booking:submit", + "platform:firstleg:ocean-booking:confirm", + "platform:firstleg:ocean-booking:release", + "platform:firstleg:ocean-booking:cancel", + "platform:firstleg:ocean-booking:change"); + + private static final Set OCEAN_SQL_PERMISSIONS = Set.of( "platform:firstleg:ocean-booking:list", "platform:firstleg:ocean-booking:create", "platform:firstleg:ocean-booking:edit", @@ -40,16 +50,16 @@ class Phase3BookingTruckPermissionSqlContractTest { "platform:firstleg:truck-appointment:operate"); @Test - void controllerAuthoritiesExactlyMatchModuleAndUnifiedPermissionCodes() throws Exception { - assertThat(authorities(PlatformOceanBookingController.class)).isEqualTo(OCEAN_PERMISSIONS); + void controllerAuthoritiesAndPersistedPermissionCodesMatchTheirActiveContracts() throws Exception { + assertThat(authorities(PlatformOceanBookingController.class)).isEqualTo(OCEAN_CONTROLLER_PERMISSIONS); assertThat(authorities(PlatformTruckAppointmentController.class)).isEqualTo(TRUCK_PERMISSIONS); String oceanModule = resource("db/phase3-ocean-booking-schema.sql"); String truckModule = resource("db/phase3-truck-appointment-schema.sql"); String unified = unifiedSql(); - assertThat(codes(oceanModule, OCEAN_CODE)).isEqualTo(OCEAN_PERMISSIONS); + assertThat(codes(oceanModule, OCEAN_CODE)).isEqualTo(OCEAN_SQL_PERMISSIONS); assertThat(codes(truckModule, TRUCK_CODE)).isEqualTo(TRUCK_PERMISSIONS); - assertThat(codes(unified, OCEAN_CODE)).isEqualTo(OCEAN_PERMISSIONS); + assertThat(codes(unified, OCEAN_CODE)).isEqualTo(OCEAN_SQL_PERMISSIONS); assertThat(codes(unified, TRUCK_CODE)).isEqualTo(TRUCK_PERMISSIONS); } diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/TruckAppointmentServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/TruckAppointmentServiceTest.java index bcc97f03b..ca13a6894 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/TruckAppointmentServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/TruckAppointmentServiceTest.java @@ -11,6 +11,7 @@ import com.baiyue.firstleg.entity.LoadingPlanEntity; import com.baiyue.firstleg.entity.ContainerBookingEntity; import com.baiyue.firstleg.repository.TruckAppointmentRepository; import com.baiyue.firstleg.repository.SmartLoadingRepository; +import com.baiyue.firstleg.repository.ContainerRepository; import com.baiyue.firstleg.oceanbooking.repository.OceanBookingRepository; import com.baiyue.firstleg.oceanbooking.entity.OceanBookingEntity; import com.baiyue.firstleg.oceanbooking.entity.OceanBookingContainerAllocationEntity; @@ -36,6 +37,7 @@ class TruckAppointmentServiceTest { @Mock TruckAppointmentRepository repository; @Mock OceanBookingRepository oceanBookings; @Mock SmartLoadingRepository loadingPlans; + @Mock ContainerRepository containers; @Spy ObjectMapper objectMapper = JsonMapper.builder().findAndAddModules().build(); @InjectMocks TruckAppointmentService service; @@ -51,7 +53,7 @@ class TruckAppointmentServiceTest { when(oceanBookings.find(61L)).thenReturn(booking); ContainerBookingEntity container = new ContainerBookingEntity(); container.setId(71L); container.setCabinetNo("CAB-71"); container.setContainerNo("MSCU1234567"); - when(oceanBookings.containerBooking(71L)).thenReturn(container); + when(containers.find(71L)).thenReturn(container); TruckAppointmentEntity detail = service.detail(51L); @@ -104,7 +106,7 @@ class TruckAppointmentServiceTest { OceanBookingEntity booking = new OceanBookingEntity(); booking.setId(99L); booking.setStatus("RELEASED"); booking.setCustomerId(7L); booking.setCustomerName("Canonical Customer"); when(oceanBookings.find(99L)).thenReturn(booking); ContainerBookingEntity container = new ContainerBookingEntity(); container.setId(88L); - when(oceanBookings.containerBooking(88L)).thenReturn(container); + when(containers.find(88L)).thenReturn(container); var allocation = new OceanBookingContainerAllocationEntity(); allocation.setContainerBookingId(88L); when(oceanBookings.allocations(99L)).thenReturn(java.util.List.of(allocation)); @@ -125,7 +127,7 @@ class TruckAppointmentServiceTest { OceanBookingEntity booking = new OceanBookingEntity(); booking.setId(99L); booking.setStatus("RELEASED"); booking.setCustomerId(7L); booking.setCustomerName("Canonical Customer"); when(oceanBookings.find(99L)).thenReturn(booking); ContainerBookingEntity container = new ContainerBookingEntity(); container.setId(88L); - when(oceanBookings.containerBooking(88L)).thenReturn(container); + when(containers.find(88L)).thenReturn(container); var allocation = new OceanBookingContainerAllocationEntity(); allocation.setContainerBookingId(88L); when(oceanBookings.allocations(99L)).thenReturn(java.util.List.of(allocation));