This commit is contained in:
2026-08-15 09:47:17 +08:00
parent 1982a7dd69
commit 20907e4685
22 changed files with 236 additions and 327 deletions
@@ -30,7 +30,7 @@ class CustomerTransitStatisticsContractTest {
.findFirst().orElseThrow().getAnnotation(org.apache.ibatis.annotations.Select.class).value();
var statement = String.join("\n", sql);
assertThat(statement).contains("actual_sailing_at IS NOT NULL", "actual_warehouse_arrival_at IS NULL",
"status NOT IN ('CANCELLED', 'FAILED')", "DISTINCT x.customer_id, x.container_booking_id",
"status <> 'CANCELLED'", "DISTINCT x.customer_id, x.container_booking_id",
"b.customer_id", "i.account_id", "i.deleted = 0", "NOT EXISTS",
"x.customer_id = #{customerId}", "LIKE '20%'", "THEN 1.0",
"LIKE '40%'", "THEN 2.0", "LIKE '45%'", "THEN 2.25", "ELSE NULL");
@@ -23,15 +23,10 @@ class PlatformOceanBookingControllerContractTest {
Map.entry("channels", "platform:firstleg:ocean-booking:list"),
Map.entry("detail", "platform:firstleg:ocean-booking:list"),
Map.entry("create", "platform:firstleg:ocean-booking:create"),
Map.entry("updateDraft", "platform:firstleg:ocean-booking:edit"),
Map.entry("submit", "platform:firstleg:ocean-booking:submit"),
Map.entry("confirm", "platform:firstleg:ocean-booking:confirm"),
Map.entry("fail", "platform:firstleg:ocean-booking:confirm"),
Map.entry("release", "platform:firstleg:ocean-booking:release"),
Map.entry("cancel", "platform:firstleg:ocean-booking:cancel"),
Map.entry("requestChange", "platform:firstleg:ocean-booking:change"),
Map.entry("confirmChange", "platform:firstleg:ocean-booking:change"),
Map.entry("failChange", "platform:firstleg:ocean-booking:change"));
Map.entry("confirmChange", "platform:firstleg:ocean-booking:change"));
permissions.forEach((name, permission) -> {
Method method = method(name);
assertThat(method.getAnnotation(PreAuthorize.class).value())
@@ -56,13 +51,19 @@ class PlatformOceanBookingControllerContractTest {
String yaml = Files.readString(Path.of("src/main/resources/openapi/ocean-bookings-v1.yaml"));
assertThat(yaml).contains("/api/platform/v1/ocean-bookings/channels:",
"originWarehouseId", "platform:firstleg:ocean-booking:list", "ChannelOption")
.contains("required: [channelCode, warehouseId, warehouseName, serviceTerm, freightTerm, parties, containerRequirements]")
.contains("required: [channelCode, warehouseId, warehouseName, billOfLadingNo, vesselName, voyageNo, serviceTerm, freightTerm, estimatedSailingAt, estimatedArrivalAt, parties, containerRequirements]")
.contains("registration persists it directly as CONFIRMED")
.contains("RELEASED remains a separate later action")
.contains("request must repeat the same bill of lading, vessel, voyage, ETD and ETA values; mismatches are rejected")
.contains("CONFIRMED, CHANGE_PENDING, RELEASED, CANCELLED")
.contains("DRAFT, SUBMITTED and FAILED are excluded")
.contains("DRAFT is internal to the create transaction and legacy SUBMITTED/FAILED values are invalid")
.contains("customerId: {type: integer, format: int64, minimum: 1, nullable: true")
.contains("customerName: {type: string, maxLength: 128, nullable: true")
.contains("serviceTerm: {type: string, maxLength: 32, description: Required free-text")
.contains("freightTerm: {type: string, maxLength: 32, description: Required free-text")
.contains("billOfLadingNo: {type: string, maxLength: 128, description: Required offline-confirmed")
.contains("estimatedArrivalAt: {type: string, format: date-time, description: Required offline-confirmed ETA")
.doesNotContain("Must be omitted until release")
.doesNotContain("required: [customerId, customerName, channelCode, channelName");
}
@@ -30,9 +30,10 @@ class OceanBookingMapperContractTest {
.flatMap(annotation -> Arrays.stream(annotation.value()))
.reduce("", (left, right) -> left + '\n' + right);
assertThat(sql)
.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='CHANGE_PENDING' AND version=#{expectedVersion}")
.doesNotContain("SUBMITTED")
.doesNotContain("FAILED");
}
}
@@ -32,9 +32,9 @@ class OceanBookingSqlContractTest {
@Test
void enforcesStateIdempotencyAndAuditContracts() throws Exception {
assertThat(sql())
.contains("OLD.status='DRAFT' AND NEW.status IN ('SUBMITTED','CANCELLED')")
.contains("OLD.status='DRAFT' AND NEW.status='CONFIRMED'")
.contains("OLD.status='CONFIRMED' AND NEW.status IN ('RELEASED','CHANGE_PENDING','CANCELLED')")
.contains("OLD.status='CHANGE_PENDING' AND NEW.status IN ('CONFIRMED','FAILED','CANCELLED')")
.contains("OLD.status='CHANGE_PENDING' AND NEW.status IN ('CONFIRMED','CANCELLED')")
.contains("OLD.status IN ('RELEASED','CANCELLED')")
.contains("UNIQUE KEY uk_ocean_operation (operator_id,operation,idempotency_key)")
.contains("request_hash CHAR(64) NOT NULL")
@@ -47,9 +47,6 @@ class OceanBookingSqlContractTest {
assertThat(sql())
.contains("platform:firstleg:ocean-booking:list")
.contains("platform:firstleg:ocean-booking:create")
.contains("platform:firstleg:ocean-booking:edit")
.contains("platform:firstleg:ocean-booking:submit")
.contains("platform:firstleg:ocean-booking:confirm")
.contains("platform:firstleg:ocean-booking:release")
.contains("platform:firstleg:ocean-booking:cancel")
.contains("platform:firstleg:ocean-booking:change")
@@ -10,7 +10,6 @@ import com.baiyue.firstleg.oceanbooking.dto.OceanBookingDtos.DraftData;
import com.baiyue.firstleg.oceanbooking.dto.OceanBookingDtos.Query;
import com.baiyue.firstleg.oceanbooking.dto.OceanBookingDtos.PartyRequest;
import com.baiyue.firstleg.oceanbooking.dto.OceanBookingDtos.ReleaseRequest;
import com.baiyue.firstleg.oceanbooking.dto.OceanBookingDtos.UpdateDraftRequest;
import com.baiyue.firstleg.service.LoadingPickService;
import com.baiyue.firstleg.oceanbooking.entity.OceanBookingContainerRequirementEntity;
import com.baiyue.firstleg.oceanbooking.entity.OceanBookingContainerAllocationEntity;
@@ -27,6 +26,7 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.ArgumentCaptor;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.BeanUtils;
import java.time.LocalDateTime;
import java.math.BigDecimal;
@@ -55,27 +55,8 @@ class OceanBookingServiceTest {
when(repository.histories(anyLong())).thenReturn(List.of());
when(repository.claimOperation(any(), anyLong(), anyString(), anyString(), anyString())).thenReturn(true);
when(repository.completeOperation(anyLong(), anyLong(), anyString(), anyString(), anyString())).thenReturn(1);
}
@Test
void advancesDraftToSubmittedWithVersionAndHistory() {
when(repository.find(1L)).thenReturn(booking("DRAFT", 2), booking("SUBMITTED", 3));
var shipper = new com.baiyue.firstleg.oceanbooking.entity.OceanBookingPartyEntity(); shipper.setPartyType("SHIPPER");
var consignee = new com.baiyue.firstleg.oceanbooking.entity.OceanBookingPartyEntity(); consignee.setPartyType("CONSIGNEE");
var notify = new com.baiyue.firstleg.oceanbooking.entity.OceanBookingPartyEntity(); notify.setPartyType("NOTIFY_PARTY");
when(repository.parties(1L)).thenReturn(List.of(shipper, consignee, notify));
when(repository.requirements(1L)).thenReturn(List.of(new com.baiyue.firstleg.oceanbooking.entity.OceanBookingContainerRequirementEntity()));
when(repository.transition(1L, "DRAFT", "SUBMITTED", null, null, 2, 9L, "admin")).thenReturn(1);
Detail result = service.submit(1L, 9L, "admin", "submit-1", new ActionRequest(2, "提交"));
assertThat(result.oceanBooking().getStatus()).isEqualTo("SUBMITTED");
ArgumentCaptor<OceanBookingStatusHistoryEntity> history =
ArgumentCaptor.forClass(OceanBookingStatusHistoryEntity.class);
verify(repository).insert(history.capture());
assertThat(history.getValue().getFromStatus()).isEqualTo("DRAFT");
assertThat(history.getValue().getToStatus()).isEqualTo("SUBMITTED");
assertThat(history.getValue().getAction()).isEqualTo("SUBMIT");
when(repository.transition(anyLong(), eq("DRAFT"), eq("CONFIRMED"), isNull(), eq(0),
anyLong(), anyString())).thenReturn(1);
}
@Test
@@ -86,12 +67,16 @@ class OceanBookingServiceTest {
new ActionRequest(4, "错误"))).isInstanceOf(BizException.class)
.hasMessageContaining("不可逆");
verify(repository, never()).transition(anyLong(), anyString(), anyString(), any(), any(), anyInt(), anyLong(), anyString());
verify(repository, never()).transition(anyLong(), anyString(), anyString(), any(), anyInt(), anyLong(), anyString());
}
@Test
void opensAllocatedContainerPdaTasksAfterRelease() {
OceanBookingEntity confirmed = booking("CONFIRMED", 3);
confirmed.setBillOfLadingNo("BL-001"); confirmed.setVesselName("VESSEL");
confirmed.setVoyageNo("V001");
confirmed.setEstimatedSailingAt(LocalDateTime.of(2026, 9, 1, 0, 0));
confirmed.setEstimatedArrivalAt(LocalDateTime.of(2026, 9, 20, 0, 0));
OceanBookingEntity released = booking("RELEASED", 4);
var allocation = new OceanBookingContainerAllocationEntity();
allocation.setContainerBookingId(12L);
@@ -107,6 +92,25 @@ class OceanBookingServiceTest {
verify(loadingPickService).beginIfReady(12L, 9L, "admin");
}
@Test
void rejectsReleaseWhenTransportFieldsDifferFromRegisteredSnapshot() {
OceanBookingEntity confirmed = booking("CONFIRMED", 3);
confirmed.setBillOfLadingNo("BL-001"); confirmed.setVesselName("VESSEL");
confirmed.setVoyageNo("V001");
confirmed.setEstimatedSailingAt(LocalDateTime.of(2026, 9, 1, 0, 0));
confirmed.setEstimatedArrivalAt(LocalDateTime.of(2026, 9, 20, 0, 0));
when(repository.find(1L)).thenReturn(confirmed);
var request = new ReleaseRequest(3, "BL-CHANGED", "VESSEL", "V001",
LocalDateTime.of(2026, 9, 1, 0, 0), LocalDateTime.of(2026, 9, 20, 0, 0), "放舱");
assertThatThrownBy(() -> service.release(1L, 9L, "admin", "release-mismatch", request))
.isInstanceOf(BizException.class).hasMessageContaining("必须与已登记");
verify(repository, never()).release(anyLong(), any(), anyLong(), anyString());
verifyNoInteractions(loadingPickService);
}
@Test
void keepsCurrentVoyagePendingUntilChangeConfirmation() {
OceanBookingEntity current = booking("CONFIRMED", 5);
@@ -126,27 +130,11 @@ class OceanBookingServiceTest {
assertThat(result.oceanBooking().getPendingVesselName()).isEqualTo("NEW");
}
@Test
void replaysCompletedRequestBeforeVersionValidation() throws Exception {
OceanBookingEntity submitted = booking("SUBMITTED", 3);
Detail replay = new Detail(submitted, List.of(), List.of(), List.of(), List.of());
OceanBookingOperationEntity operation = new OceanBookingOperationEntity();
operation.setRequestHash(hashForSubmit()); operation.setStatus("SUCCESS");
operation.setResultJson(new ObjectMapper().findAndRegisterModules().writeValueAsString(replay));
when(repository.claimOperation(eq(1L), eq(9L), eq("SUBMIT"), eq("submit-replay"), anyString())).thenReturn(false);
when(repository.operation(9L, "SUBMIT", "submit-replay")).thenReturn(operation);
Detail result = service.submit(1L, 9L, "admin", "submit-replay", new ActionRequest(2, "提交"));
assertThat(result.oceanBooking().getStatus()).isEqualTo("SUBMITTED");
verify(repository, never()).find(anyLong());
}
@Test
void rejectsDraftAndSubmittedStatusesFromOperationalList() {
for (String status : List.of("DRAFT", "SUBMITTED", "FAILED")) {
assertThatThrownBy(() -> service.page(new Query(null, status, null, 1, 20)))
.isInstanceOf(BizException.class).hasMessageContaining("仅支持");
.isInstanceOf(BizException.class).hasMessageContaining("状态");
}
verify(repository, never()).page(any());
}
@@ -176,19 +164,33 @@ class OceanBookingServiceTest {
}
@Test
void freezesAuthoritativeChannelNameWhenCreatingDraft() {
void registersOfflineBookingDirectlyAsConfirmedWithCompleteTransportSnapshot() {
ChannelRow channel = channel("SEA-US", "价格簿美西海运");
when(priceBooks.activeVersionId()).thenReturn(51L);
when(priceBooks.channels(51L, 701L)).thenReturn(List.of(channel));
AtomicReference<OceanBookingEntity> inserted = new AtomicReference<>();
doAnswer(invocation -> { inserted.set(invocation.getArgument(0)); return null; })
.when(repository).insert(any(OceanBookingEntity.class));
when(repository.find(anyLong())).thenAnswer(invocation -> inserted.get());
AtomicReference<OceanBookingEntity> inserted = stubSuccessfulCreation();
Detail result = service.create(9L, "admin", "create-channel", new CreateRequest(0, draft()));
assertThat(inserted.get().getStatus()).isEqualTo("DRAFT");
assertThat(result.oceanBooking().getStatus()).isEqualTo("CONFIRMED");
assertThat(result.oceanBooking().getChannelCode()).isEqualTo("SEA-US");
assertThat(result.oceanBooking().getChannelName()).isEqualTo("价格簿美西海运");
assertThat(result.oceanBooking().getBillOfLadingNo()).isEqualTo("BL-001");
assertThat(result.oceanBooking().getVesselName()).isEqualTo("VESSEL");
assertThat(result.oceanBooking().getVoyageNo()).isEqualTo("V001");
assertThat(result.oceanBooking().getEstimatedSailingAt())
.isEqualTo(LocalDateTime.of(2026, 9, 1, 0, 0));
assertThat(result.oceanBooking().getEstimatedArrivalAt())
.isEqualTo(LocalDateTime.of(2026, 9, 20, 0, 0));
ArgumentCaptor<OceanBookingStatusHistoryEntity> history =
ArgumentCaptor.forClass(OceanBookingStatusHistoryEntity.class);
verify(repository).insert(history.capture());
assertThat(history.getValue().getFromStatus()).isEqualTo("DRAFT");
assertThat(history.getValue().getToStatus()).isEqualTo("CONFIRMED");
assertThat(history.getValue().getAction()).isEqualTo("CREATE");
verify(repository).transition(inserted.get().getId(), "DRAFT", "CONFIRMED", null, 0, 9L,
"admin");
}
@Test
@@ -196,10 +198,7 @@ class OceanBookingServiceTest {
ChannelRow channel = channel("SEA-US", "价格簿美西海运");
when(priceBooks.activeVersionId()).thenReturn(51L);
when(priceBooks.channels(51L, 701L)).thenReturn(List.of(channel));
AtomicReference<OceanBookingEntity> inserted = new AtomicReference<>();
doAnswer(invocation -> { inserted.set(invocation.getArgument(0)); return null; })
.when(repository).insert(any(OceanBookingEntity.class));
when(repository.find(anyLong())).thenAnswer(invocation -> inserted.get());
stubSuccessfulCreation();
Detail result = service.create(9L, "admin", "create-without-customer",
new CreateRequest(0, draft(null, null, "CY-CY", "NINGBO")));
@@ -234,16 +233,48 @@ class OceanBookingServiceTest {
verifyNoInteractions(priceBooks);
}
@Test
void rejectsOfflineBookingWhenEtaIsEarlierThanEtd() {
DraftData source = draft();
DraftData invalid = new DraftData(source.customerId(), source.customerName(), source.channelCode(),
source.warehouseId(), source.warehouseName(), source.billOfLadingNo(), source.shippingCompanyId(),
source.shippingCompanyName(), source.bookingAgentId(), source.bookingAgentName(),
source.vesselName(), source.voyageNo(), source.departurePortCode(), source.departurePortName(),
source.destinationPortCode(), source.destinationPortName(), source.placeOfDelivery(),
source.serviceTerm(), source.freightTerm(), source.estimatedArrivalAt(), source.estimatedSailingAt(),
source.remark(), source.parties(), source.containerRequirements());
assertThatThrownBy(() -> service.create(9L, "admin", "invalid-range", new CreateRequest(0, invalid)))
.isInstanceOf(BizException.class).hasMessageContaining("预计到港时间不能早于预计开船时间");
verifyNoInteractions(priceBooks);
}
@Test
void rejectsOfflineBookingWithoutCompleteTransportSnapshot() {
DraftData source = draft();
DraftData missingBill = new DraftData(source.customerId(), source.customerName(), source.channelCode(),
source.warehouseId(), source.warehouseName(), null, source.shippingCompanyId(),
source.shippingCompanyName(), source.bookingAgentId(), source.bookingAgentName(),
source.vesselName(), source.voyageNo(), source.departurePortCode(), source.departurePortName(),
source.destinationPortCode(), source.destinationPortName(), source.placeOfDelivery(),
source.serviceTerm(), source.freightTerm(), source.estimatedSailingAt(), source.estimatedArrivalAt(),
source.remark(), source.parties(), source.containerRequirements());
assertThatThrownBy(() -> service.create(9L, "admin", "missing-transport",
new CreateRequest(0, missingBill))).isInstanceOf(BizException.class)
.hasMessageContaining("提单号、船名、航次、ETD和ETA不能为空");
verifyNoInteractions(priceBooks);
}
@Test
void replaysCreateAfterChannelIsNoLongerActive() throws Exception {
ChannelRow channel = channel("SEA-US", "价格簿美西海运");
CreateRequest request = new CreateRequest(0, draft());
when(priceBooks.activeVersionId()).thenReturn(51L, (Long) null);
when(priceBooks.channels(51L, 701L)).thenReturn(List.of(channel));
AtomicReference<OceanBookingEntity> inserted = new AtomicReference<>();
doAnswer(invocation -> { inserted.set(invocation.getArgument(0)); return null; })
.when(repository).insert(any(OceanBookingEntity.class));
when(repository.find(anyLong())).thenAnswer(invocation -> inserted.get());
stubSuccessfulCreation();
Detail created = service.create(9L, "admin", "create-replay-channel", request);
@@ -260,40 +291,6 @@ class OceanBookingServiceTest {
verify(priceBooks, times(1)).activeVersionId();
}
@Test
void replaysDraftUpdateAfterChannelIsNoLongerActive() throws Exception {
UpdateDraftRequest request = new UpdateDraftRequest(5, draft());
Detail expected = new Detail(booking("DRAFT", 6), List.of(), List.of(), List.of(), List.of());
OceanBookingOperationEntity operation = new OceanBookingOperationEntity();
operation.setRequestHash(hashForUpdate(request)); operation.setStatus("SUCCESS");
operation.setResultJson(new ObjectMapper().findAndRegisterModules().writeValueAsString(expected));
when(repository.claimOperation(eq(1L), eq(9L), eq("UPDATE_DRAFT"), eq("update-replay-channel"), anyString()))
.thenReturn(false);
when(repository.operation(9L, "UPDATE_DRAFT", "update-replay-channel")).thenReturn(operation);
Detail replay = service.updateDraft(1L, 9L, "admin", "update-replay-channel", request);
assertThat(replay.oceanBooking().getVersion()).isEqualTo(6);
verifyNoInteractions(priceBooks);
verify(repository, never()).find(anyLong());
}
@Test
void rejectsConfirmationWhenFrozenChannelIsNoLongerActive() {
OceanBookingEntity submitted = booking("SUBMITTED", 3);
submitted.setWarehouseId(701L); submitted.setWarehouseName("深圳仓"); submitted.setChannelName("美西海运");
OceanBookingContainerRequirementEntity requirement = new OceanBookingContainerRequirementEntity();
requirement.setCapacityCbm(java.math.BigDecimal.ONE); requirement.setMaxWeightKg(java.math.BigDecimal.ONE);
when(repository.find(1L)).thenReturn(submitted);
when(repository.requirements(1L)).thenReturn(List.of(requirement));
when(priceBooks.activeVersionId()).thenReturn(null);
assertThatThrownBy(() -> service.confirm(1L, 9L, "admin", "confirm-channel", new ActionRequest(3, "确认")))
.isInstanceOf(BizException.class).hasMessageContaining("ACTIVE");
verify(repository, never()).transition(anyLong(), anyString(), anyString(), any(), any(), anyInt(), anyLong(), anyString());
}
private static ChannelRow channel(String code, String name) {
ChannelRow value = new ChannelRow(); value.setPriceBookVersionId(51L); value.setChannelCode(code);
value.setChannelName(name); value.setPriceModel("FBA_WAREHOUSE_RATE"); return value;
@@ -310,15 +307,24 @@ class OceanBookingServiceTest {
new PartyRequest("NOTIFY_PARTY", "通知人", null, null, null));
List<ContainerRequirementRequest> requirements = List.of(
new ContainerRequirementRequest("40HQ", "DRY", BigDecimal.ONE, BigDecimal.TEN, 1));
return new DraftData(customerId, customerName, "SEA-US", 701L, "深圳仓", null,
81L, "船公司", null, null, null, null, "CNSZX", "深圳", "USLAX", "洛杉矶",
null, serviceTerm, freightTerm, null, null, null, parties, requirements);
return new DraftData(customerId, customerName, "SEA-US", 701L, "深圳仓", "BL-001",
81L, "船公司", null, null, "VESSEL", "V001", "CNSZX", "深圳", "USLAX", "洛杉矶",
null, serviceTerm, freightTerm, LocalDateTime.of(2026, 9, 1, 0, 0),
LocalDateTime.of(2026, 9, 20, 0, 0), null, parties, requirements);
}
private String hashForSubmit() throws Exception {
var method = OceanBookingService.class.getDeclaredMethod("hash", String.class, Long.class, Object.class);
method.setAccessible(true);
return (String) method.invoke(service, "SUBMIT", 1L, new ActionRequest(2, "提交"));
private AtomicReference<OceanBookingEntity> stubSuccessfulCreation() {
AtomicReference<OceanBookingEntity> inserted = new AtomicReference<>();
doAnswer(invocation -> { inserted.set(invocation.getArgument(0)); return null; })
.when(repository).insert(any(OceanBookingEntity.class));
when(repository.find(anyLong())).thenAnswer(invocation -> {
OceanBookingEntity confirmed = new OceanBookingEntity();
BeanUtils.copyProperties(inserted.get(), confirmed);
confirmed.setStatus("CONFIRMED");
confirmed.setVersion(1);
return confirmed;
});
return inserted;
}
private String hashForCreate(CreateRequest request) throws Exception {
@@ -327,12 +333,6 @@ class OceanBookingServiceTest {
return (String) method.invoke(service, "CREATE", (Long) null, request);
}
private String hashForUpdate(UpdateDraftRequest request) throws Exception {
var method = OceanBookingService.class.getDeclaredMethod("hash", String.class, Long.class, Object.class);
method.setAccessible(true);
return (String) method.invoke(service, "UPDATE_DRAFT", 1L, request);
}
private static OceanBookingEntity booking(String status, int version) {
OceanBookingEntity value = new OceanBookingEntity(); value.setId(1L); value.setBookingNo("OB1");
value.setStatus(status); value.setCustomerId(100L); value.setCustomerName("客户");
@@ -25,9 +25,6 @@ class Phase3BookingTruckPermissionSqlContractTest {
private static final Set<String> 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");
@@ -35,9 +32,6 @@ class Phase3BookingTruckPermissionSqlContractTest {
private static final Set<String> OCEAN_SQL_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",