Merge remote-tracking branch 'origin/test' into test
This commit is contained in:
@@ -1422,7 +1422,6 @@ CREATE TABLE fl_consumed_event (
|
|||||||
|
|
||||||
CREATE TABLE fl_container_booking (
|
CREATE TABLE fl_container_booking (
|
||||||
id bigint unsigned NOT NULL COMMENT '货柜预订ID(雪花ID)',
|
id bigint unsigned NOT NULL COMMENT '货柜预订ID(雪花ID)',
|
||||||
booking_no varchar(40) NOT NULL COMMENT '平台唯一货柜预订单号',
|
|
||||||
container_no varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '真实集装箱号权威快照;同一订舱内唯一,不同提单允许复用;确认前允许修订',
|
container_no varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '真实集装箱号权威快照;同一订舱内唯一,不同提单允许复用;确认前允许修订',
|
||||||
cabinet_no varchar(64) NOT NULL COMMENT '平台唯一内部柜号',
|
cabinet_no varchar(64) NOT NULL COMMENT '平台唯一内部柜号',
|
||||||
source_type varchar(24) NOT NULL DEFAULT 'SIMULATION' COMMENT '记录来源:SIMULATION内部模拟柜、OCEAN_BOOKING订舱真实柜',
|
source_type varchar(24) NOT NULL DEFAULT 'SIMULATION' COMMENT '记录来源:SIMULATION内部模拟柜、OCEAN_BOOKING订舱真实柜',
|
||||||
@@ -1477,7 +1476,6 @@ CREATE TABLE fl_container_booking (
|
|||||||
updated_at datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '货柜资料最后更新时间',
|
updated_at datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '货柜资料最后更新时间',
|
||||||
version int unsigned NOT NULL DEFAULT '0' COMMENT '乐观锁版本号',
|
version int unsigned NOT NULL DEFAULT '0' COMMENT '乐观锁版本号',
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
UNIQUE KEY uk_container_booking_no (booking_no),
|
|
||||||
UNIQUE KEY uk_container_booking_cabinet (cabinet_no),
|
UNIQUE KEY uk_container_booking_cabinet (cabinet_no),
|
||||||
UNIQUE KEY uk_container_booking_ocean_container (ocean_booking_id,container_no),
|
UNIQUE KEY uk_container_booking_ocean_container (ocean_booking_id,container_no),
|
||||||
KEY idx_container_booking_container_no (container_no,updated_at,id),
|
KEY idx_container_booking_container_no (container_no,updated_at,id),
|
||||||
@@ -5337,7 +5335,7 @@ CREATE TRIGGER trg_container_booking_before_update BEFORE UPDATE ON fl_container
|
|||||||
SELECT MAX(plan_status) INTO current_plan_status
|
SELECT MAX(plan_status) INTO current_plan_status
|
||||||
FROM baiyue_firstleg.fl_loading_plan WHERE container_booking_id = OLD.id;
|
FROM baiyue_firstleg.fl_loading_plan WHERE container_booking_id = OLD.id;
|
||||||
IF current_plan_status IN ('LOADING', 'COMPLETED') AND (
|
IF current_plan_status IN ('LOADING', 'COMPLETED') AND (
|
||||||
NOT (OLD.id <=> NEW.id) OR NOT (OLD.booking_no <=> NEW.booking_no)
|
NOT (OLD.id <=> NEW.id)
|
||||||
OR NOT (OLD.cabinet_no <=> NEW.cabinet_no)
|
OR NOT (OLD.cabinet_no <=> NEW.cabinet_no)
|
||||||
OR NOT (OLD.channel_group_code <=> NEW.channel_group_code)
|
OR NOT (OLD.channel_group_code <=> NEW.channel_group_code)
|
||||||
OR NOT (OLD.channel_code <=> NEW.channel_code) OR NOT (OLD.channel_name <=> NEW.channel_name)
|
OR NOT (OLD.channel_code <=> NEW.channel_code) OR NOT (OLD.channel_name <=> NEW.channel_name)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public final class ContainerOverviewDtos {
|
|||||||
public record Overview(ContainerBookingEntityView container, Long loadingPlanId, PdaSummary pda,
|
public record Overview(ContainerBookingEntityView container, Long loadingPlanId, PdaSummary pda,
|
||||||
List<Document> documents, ExceptionState exception, List<ExceptionHistory> exceptionHistory,
|
List<Document> documents, ExceptionState exception, List<ExceptionHistory> exceptionHistory,
|
||||||
List<TimelineEntry> timeline) {}
|
List<TimelineEntry> timeline) {}
|
||||||
public record ContainerBookingEntityView(Long id, String bookingNo, String cabinetNo, String containerNo,
|
public record ContainerBookingEntityView(Long id, String cabinetNo, String containerNo,
|
||||||
String status, Long warehouseId, String warehouseName, String voyageNo, String vesselName,
|
String status, Long warehouseId, String warehouseName, String voyageNo, String vesselName,
|
||||||
String billOfLadingNo, Long shippingCompanyId, String shippingCompanyName,
|
String billOfLadingNo, Long shippingCompanyId, String shippingCompanyName,
|
||||||
String departurePortCode, String departurePortName, String destinationPortCode,
|
String departurePortCode, String departurePortName, String destinationPortCode,
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public final class SmartLoadingDtos { private SmartLoadingDtos(){}
|
|||||||
if (size == 0) size = 20;
|
if (size == 0) size = 20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public record WorkbenchContainer(Long bookingId, String bookingNo, String cabinetNo, String containerNo,
|
public record WorkbenchContainer(Long bookingId, String cabinetNo, String containerNo,
|
||||||
Long warehouseId, String warehouseName, String channelGroupCode, String channelCode, String channelName, String containerType,
|
Long warehouseId, String warehouseName, String channelGroupCode, String channelCode, String channelName, String containerType,
|
||||||
BigDecimal capacityCbm, BigDecimal maxWeightKg,
|
BigDecimal capacityCbm, BigDecimal maxWeightKg,
|
||||||
Long planId, String planNo, String planStatus, Integer version) {}
|
Long planId, String planNo, String planStatus, Integer version) {}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import java.time.LocalDateTime;
|
|||||||
@TableName("fl_container_booking")
|
@TableName("fl_container_booking")
|
||||||
public class ContainerBookingEntity {
|
public class ContainerBookingEntity {
|
||||||
@TableId(type = IdType.ASSIGN_ID) private Long id;
|
@TableId(type = IdType.ASSIGN_ID) private Long id;
|
||||||
private String bookingNo;
|
|
||||||
private String containerNo;
|
private String containerNo;
|
||||||
private String cabinetNo;
|
private String cabinetNo;
|
||||||
private String sourceType;
|
private String sourceType;
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ba
|
|||||||
|
|
||||||
@Select("""
|
@Select("""
|
||||||
<script>
|
<script>
|
||||||
SELECT b.id bookingId,b.booking_no bookingNo,b.cabinet_no cabinetNo,b.container_no containerNo,
|
SELECT b.id bookingId,b.cabinet_no cabinetNo,b.container_no containerNo,
|
||||||
b.warehouse_id warehouseId,b.warehouse_name warehouseName,b.channel_group_code channelGroupCode,b.channel_code channelCode,
|
b.warehouse_id warehouseId,b.warehouse_name warehouseName,b.channel_group_code channelGroupCode,b.channel_code channelCode,
|
||||||
b.channel_name channelName,b.container_type containerType,b.capacity_cbm capacityCbm,
|
b.channel_name channelName,b.container_type containerType,b.capacity_cbm capacityCbm,
|
||||||
b.max_weight_kg maxWeightKg,p.id planId,p.plan_no planNo,
|
b.max_weight_kg maxWeightKg,p.id planId,p.plan_no planNo,
|
||||||
|
|||||||
+1
-1
@@ -2,6 +2,6 @@ package com.baiyue.firstleg.portschedule.dto;
|
|||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
public record ArrivalCalendarEntry(Long containerBookingId, String bookingNo, String containerNo,
|
public record ArrivalCalendarEntry(Long containerBookingId, String cabinetNo, String containerNo,
|
||||||
String vesselName, String voyageNo, String destinationPortName, String destinationWarehouseCode,
|
String vesselName, String voyageNo, String destinationPortName, String destinationWarehouseCode,
|
||||||
LocalDateTime arrivalAt, String arrivalType) {}
|
LocalDateTime arrivalAt, String arrivalType) {}
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import org.apache.ibatis.annotations.Update;
|
|||||||
@Mapper
|
@Mapper
|
||||||
public interface PortScheduleMapper extends BaseMapper<PortScheduleEntity> {
|
public interface PortScheduleMapper extends BaseMapper<PortScheduleEntity> {
|
||||||
@Select("""
|
@Select("""
|
||||||
SELECT c.id containerBookingId,c.booking_no bookingNo,c.container_no containerNo,
|
SELECT c.id containerBookingId,c.cabinet_no cabinetNo,c.container_no containerNo,
|
||||||
c.vessel_name vesselName,c.voyage_no voyageNo,c.destination_port_name destinationPortName,
|
c.vessel_name vesselName,c.voyage_no voyageNo,c.destination_port_name destinationPortName,
|
||||||
c.destination_warehouse_code destinationWarehouseCode,
|
c.destination_warehouse_code destinationWarehouseCode,
|
||||||
COALESCE(n.actual_at,c.actual_port_arrival_at,c.estimated_port_arrival_at) arrivalAt,
|
COALESCE(n.actual_at,c.actual_port_arrival_at,c.estimated_port_arrival_at) arrivalAt,
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public class ContainerOverviewService {
|
|||||||
.toList();
|
.toList();
|
||||||
PdaSummary pda = task == null ? null : pda(task);
|
PdaSummary pda = task == null ? null : pda(task);
|
||||||
List<TimelineEntry> timeline = timeline(id, task == null ? null : task.id(), exceptionHistory);
|
List<TimelineEntry> timeline = timeline(id, task == null ? null : task.id(), exceptionHistory);
|
||||||
return new Overview(new ContainerBookingEntityView(booking.getId(), booking.getBookingNo(),
|
return new Overview(new ContainerBookingEntityView(booking.getId(),
|
||||||
booking.getCabinetNo(), booking.getContainerNo(), booking.getPlanStatus(), booking.getWarehouseId(),
|
booking.getCabinetNo(), booking.getContainerNo(), booking.getPlanStatus(), booking.getWarehouseId(),
|
||||||
booking.getWarehouseName(), booking.getVoyageNo(), booking.getVesselName(), booking.getBillOfLadingNo(),
|
booking.getWarehouseName(), booking.getVoyageNo(), booking.getVesselName(), booking.getBillOfLadingNo(),
|
||||||
booking.getShippingCompanyId(), booking.getShippingCompanyName(), booking.getDeparturePortCode(),
|
booking.getShippingCompanyId(), booking.getShippingCompanyName(), booking.getDeparturePortCode(),
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class ContainerService {
|
|||||||
.map(ChannelRow::getChannelCode).anyMatch(channelGroup.channelCodes()::contains);
|
.map(ChannelRow::getChannelCode).anyMatch(channelGroup.channelCodes()::contains);
|
||||||
if (!activeGroup) throw conflict("所选物流渠道分组在当前仓库已失效,请重新选择");
|
if (!activeGroup) throw conflict("所选物流渠道分组在当前仓库已失效,请重新选择");
|
||||||
ContainerBookingEntity value = new ContainerBookingEntity(); value.setId(IdWorker.getId());
|
ContainerBookingEntity value = new ContainerBookingEntity(); value.setId(IdWorker.getId());
|
||||||
value.setBookingNo(documentNumbers.next("CB")); value.setCabinetNo(documentNumbers.nextCabinetNo());
|
value.setCabinetNo(documentNumbers.nextCabinetNo());
|
||||||
value.setSourceType("SIMULATION"); value.setRecordStatus("ACTIVE");
|
value.setSourceType("SIMULATION"); value.setRecordStatus("ACTIVE");
|
||||||
value.setChannelGroupCode(channelGroup.code()); value.setChannelCode(null); value.setChannelName(null);
|
value.setChannelGroupCode(channelGroup.code()); value.setChannelCode(null); value.setChannelName(null);
|
||||||
value.setWarehouseId(warehouse.id()); value.setWarehouseName(warehouse.warehouseName());
|
value.setWarehouseId(warehouse.id()); value.setWarehouseName(warehouse.warehouseName());
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ import java.util.Set;
|
|||||||
public class FirstlegDocumentNumberGenerator {
|
public class FirstlegDocumentNumberGenerator {
|
||||||
private static final ZoneId BUSINESS_ZONE = ZoneId.of("Asia/Shanghai");
|
private static final ZoneId BUSINESS_ZONE = ZoneId.of("Asia/Shanghai");
|
||||||
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyMMdd", Locale.ROOT);
|
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyMMdd", Locale.ROOT);
|
||||||
private static final Set<String> SUPPORTED_PREFIXES = Set.of("OB", "TA", "CB", "LP", "DP");
|
private static final Set<String> SUPPORTED_PREFIXES = Set.of("OB", "TA", "LP", "DP");
|
||||||
private static final long MAX_DAILY_SEQUENCE = 9_999L;
|
private static final long MAX_DAILY_SEQUENCE = 9_999L;
|
||||||
|
|
||||||
private final JdbcTemplate jdbc;
|
private final JdbcTemplate jdbc;
|
||||||
|
|||||||
+1
-1
@@ -3,6 +3,6 @@ package com.baiyue.firstleg.terminaldrayage.dto;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/** Original pickup appointment wall time; the source does not establish a port time zone. */
|
/** Original pickup appointment wall time; the source does not establish a port time zone. */
|
||||||
public record PickupCalendarEntry(Long containerBookingId, String bookingNo, String containerNo,
|
public record PickupCalendarEntry(Long containerBookingId, String cabinetNo, String containerNo,
|
||||||
String destinationPortName, String destinationWarehouseCode, String fleetSupplierName,
|
String destinationPortName, String destinationWarehouseCode, String fleetSupplierName,
|
||||||
LocalDateTime pickupAppointmentAt, LocalDateTime actualPickupAt) { }
|
LocalDateTime pickupAppointmentAt, LocalDateTime actualPickupAt) { }
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ import java.util.List;
|
|||||||
@Mapper
|
@Mapper
|
||||||
public interface TerminalDrayageMapper extends BaseMapper<TerminalDrayageEntity> {
|
public interface TerminalDrayageMapper extends BaseMapper<TerminalDrayageEntity> {
|
||||||
@Select("""
|
@Select("""
|
||||||
SELECT c.id containerBookingId,c.booking_no bookingNo,c.container_no containerNo,
|
SELECT c.id containerBookingId,c.cabinet_no cabinetNo,c.container_no containerNo,
|
||||||
c.destination_port_name destinationPortName,c.destination_warehouse_code destinationWarehouseCode,
|
c.destination_port_name destinationPortName,c.destination_warehouse_code destinationWarehouseCode,
|
||||||
t.fleet_supplier_name fleetSupplierName,t.pickup_appointment_at pickupAppointmentAt,NULL actualPickupAt
|
t.fleet_supplier_name fleetSupplierName,t.pickup_appointment_at pickupAppointmentAt,NULL actualPickupAt
|
||||||
FROM fl_terminal_drayage t JOIN fl_container_booking c ON c.id=t.container_booking_id
|
FROM fl_terminal_drayage t JOIN fl_container_booking c ON c.id=t.container_booking_id
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ public class TerminalDrayageCalendarService {
|
|||||||
for(var fact:shipping.containerActualFacts(ids.subList(start,Math.min(start+200,ids.size()))))
|
for(var fact:shipping.containerActualFacts(ids.subList(start,Math.min(start+200,ids.size()))))
|
||||||
if(fact.pickedUpAt()!=null) actual.put(fact.containerBookingId(),fact.pickedUpAt());
|
if(fact.pickedUpAt()!=null) actual.put(fact.containerBookingId(),fact.pickedUpAt());
|
||||||
}
|
}
|
||||||
var enriched=records.stream().map(row->new PickupCalendarEntry(row.containerBookingId(),row.bookingNo(),row.containerNo(),
|
var enriched=records.stream().map(row->new PickupCalendarEntry(row.containerBookingId(),row.cabinetNo(),row.containerNo(),
|
||||||
row.destinationPortName(),row.destinationWarehouseCode(),row.fleetSupplierName(),row.pickupAppointmentAt(),actual.get(row.containerBookingId()))).toList();
|
row.destinationPortName(),row.destinationWarehouseCode(),row.fleetSupplierName(),row.pickupAppointmentAt(),actual.get(row.containerBookingId()))).toList();
|
||||||
return result(enriched,rows.size()>1000,unknown);
|
return result(enriched,rows.size()>1000,unknown);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ BEGIN
|
|||||||
SELECT MAX(plan_status) INTO current_plan_status
|
SELECT MAX(plan_status) INTO current_plan_status
|
||||||
FROM fl_loading_plan WHERE container_booking_id = OLD.id;
|
FROM fl_loading_plan WHERE container_booking_id = OLD.id;
|
||||||
IF current_plan_status IN ('LOADING', 'COMPLETED') AND (
|
IF current_plan_status IN ('LOADING', 'COMPLETED') AND (
|
||||||
NOT (OLD.id <=> NEW.id) OR NOT (OLD.booking_no <=> NEW.booking_no)
|
NOT (OLD.id <=> NEW.id)
|
||||||
OR NOT (OLD.cabinet_no <=> NEW.cabinet_no)
|
OR NOT (OLD.cabinet_no <=> NEW.cabinet_no)
|
||||||
OR NOT (OLD.channel_group_code <=> NEW.channel_group_code)
|
OR NOT (OLD.channel_group_code <=> NEW.channel_group_code)
|
||||||
OR NOT (OLD.channel_code <=> NEW.channel_code) OR NOT (OLD.channel_name <=> NEW.channel_name)
|
OR NOT (OLD.channel_code <=> NEW.channel_code) OR NOT (OLD.channel_name <=> NEW.channel_name)
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ CREATE TABLE IF NOT EXISTS fl_document_sequence (
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS fl_container_booking (
|
CREATE TABLE IF NOT EXISTS fl_container_booking (
|
||||||
id BIGINT UNSIGNED NOT NULL COMMENT '货柜预订ID(雪花ID)',
|
id BIGINT UNSIGNED NOT NULL COMMENT '货柜预订ID(雪花ID)',
|
||||||
booking_no VARCHAR(40) NOT NULL COMMENT '平台唯一货柜预订单号',
|
|
||||||
container_no VARCHAR(64) NULL COMMENT '国内柜次真实集装箱号权威快照;ISO 6346标准格式;同一订舱内唯一,不同提单允许复用;订舱关联可选写入、提柜后可原子补录、预装纠错命令可修改',
|
container_no VARCHAR(64) NULL COMMENT '国内柜次真实集装箱号权威快照;ISO 6346标准格式;同一订舱内唯一,不同提单允许复用;订舱关联可选写入、提柜后可原子补录、预装纠错命令可修改',
|
||||||
cabinet_no VARCHAR(64) NOT NULL COMMENT '平台唯一内部柜号',
|
cabinet_no VARCHAR(64) NOT NULL COMMENT '平台唯一内部柜号',
|
||||||
source_type VARCHAR(24) NOT NULL DEFAULT 'SIMULATION' COMMENT '记录来源:SIMULATION内部模拟柜、OCEAN_BOOKING订舱真实柜',
|
source_type VARCHAR(24) NOT NULL DEFAULT 'SIMULATION' COMMENT '记录来源:SIMULATION内部模拟柜、OCEAN_BOOKING订舱真实柜',
|
||||||
@@ -90,7 +89,6 @@ CREATE TABLE IF NOT EXISTS fl_container_booking (
|
|||||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '货柜资料最后更新时间',
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '货柜资料最后更新时间',
|
||||||
version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
UNIQUE KEY uk_container_booking_no (booking_no),
|
|
||||||
UNIQUE KEY uk_container_booking_cabinet (cabinet_no),
|
UNIQUE KEY uk_container_booking_cabinet (cabinet_no),
|
||||||
UNIQUE KEY uk_container_booking_ocean_container (ocean_booking_id,container_no),
|
UNIQUE KEY uk_container_booking_ocean_container (ocean_booking_id,container_no),
|
||||||
KEY idx_container_booking_container_no (container_no,updated_at,id),
|
KEY idx_container_booking_container_no (container_no,updated_at,id),
|
||||||
@@ -895,7 +893,7 @@ BEGIN
|
|||||||
SELECT MAX(plan_status) INTO current_plan_status
|
SELECT MAX(plan_status) INTO current_plan_status
|
||||||
FROM fl_loading_plan WHERE container_booking_id = OLD.id;
|
FROM fl_loading_plan WHERE container_booking_id = OLD.id;
|
||||||
IF current_plan_status IN ('LOADING', 'COMPLETED') AND (
|
IF current_plan_status IN ('LOADING', 'COMPLETED') AND (
|
||||||
NOT (OLD.id <=> NEW.id) OR NOT (OLD.booking_no <=> NEW.booking_no)
|
NOT (OLD.id <=> NEW.id)
|
||||||
OR NOT (OLD.cabinet_no <=> NEW.cabinet_no)
|
OR NOT (OLD.cabinet_no <=> NEW.cabinet_no)
|
||||||
OR NOT (OLD.channel_code <=> NEW.channel_code)
|
OR NOT (OLD.channel_code <=> NEW.channel_code)
|
||||||
OR NOT (OLD.channel_name <=> NEW.channel_name)
|
OR NOT (OLD.channel_name <=> NEW.channel_name)
|
||||||
@@ -1542,9 +1540,9 @@ BEGIN
|
|||||||
END IF;
|
END IF;
|
||||||
IF (SELECT COUNT(*) FROM information_schema.columns
|
IF (SELECT COUNT(*) FROM information_schema.columns
|
||||||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_container_booking'
|
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_container_booking'
|
||||||
AND column_name IN ('booking_no', 'cabinet_no', 'warehouse_id', 'bill_of_lading_no',
|
AND column_name IN ('cabinet_no', 'warehouse_id', 'bill_of_lading_no',
|
||||||
'vessel_name', 'voyage_no', 'container_type', 'capacity_cbm',
|
'vessel_name', 'voyage_no', 'container_type', 'capacity_cbm',
|
||||||
'max_weight_kg', 'terminal_trucking_company_id', 'terminal_trucking_company')) <> 11 THEN
|
'max_weight_kg', 'terminal_trucking_company_id', 'terminal_trucking_company')) <> 10 THEN
|
||||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:货柜原型字段缺失';
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:货柜原型字段缺失';
|
||||||
END IF;
|
END IF;
|
||||||
IF (SELECT COUNT(*) FROM information_schema.columns
|
IF (SELECT COUNT(*) FROM information_schema.columns
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ paths:
|
|||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
containerBookingId: {type: string}
|
containerBookingId: {type: string}
|
||||||
bookingNo: {type: string}
|
cabinetNo: {type: string}
|
||||||
containerNo: {type: string, nullable: true}
|
containerNo: {type: string, nullable: true}
|
||||||
vesselName: {type: string, nullable: true}
|
vesselName: {type: string, nullable: true}
|
||||||
voyageNo: {type: string, nullable: true}
|
voyageNo: {type: string, nullable: true}
|
||||||
|
|||||||
@@ -2323,13 +2323,12 @@ components:
|
|||||||
allowedActions: {type: array, items: {type: string, enum: [SELECT_FLEET, SCHEDULE_PICKUP, RECORD_EMPTY_RETURN, SEND_PICKUP_EMAIL]}}
|
allowedActions: {type: array, items: {type: string, enum: [SELECT_FLEET, SCHEDULE_PICKUP, RECORD_EMPTY_RETURN, SEND_PICKUP_EMAIL]}}
|
||||||
ContainerBooking:
|
ContainerBooking:
|
||||||
type: object
|
type: object
|
||||||
required: [id, bookingNo, cabinetNo, sourceType, recordStatus, warehouseId, warehouseName, channelGroupCode, containerType, capacityCbm, maxWeightKg, planStatus, exceptionActive, destinationClearanceDocumentStatus, customsDeclarationDocumentStatus, deliveryOrderDocumentStatus, version]
|
required: [id, cabinetNo, sourceType, recordStatus, warehouseId, warehouseName, channelGroupCode, containerType, capacityCbm, maxWeightKg, planStatus, exceptionActive, destinationClearanceDocumentStatus, customsDeclarationDocumentStatus, deliveryOrderDocumentStatus, version]
|
||||||
properties:
|
properties:
|
||||||
id: {type: string, pattern: '^[1-9][0-9]*$'}
|
id: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||||
currentPortScheduleId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true, readOnly: true, description: 当前运输读模型由 latestForDispatch 选中的船期记录 ID;无匹配时为空,仅用于定位关联船期,不作为业务编号展示}
|
currentPortScheduleId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true, readOnly: true, description: 当前运输读模型由 latestForDispatch 选中的船期记录 ID;无匹配时为空,仅用于定位关联船期,不作为业务编号展示}
|
||||||
planId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true, description: 关联智能装柜计划ID;未创建计划时为空}
|
planId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true, description: 关联智能装柜计划ID;未创建计划时为空}
|
||||||
planNo: {type: string, nullable: true, pattern: '^LP-[0-9]{6}-[0-9]{4}$', example: LP-260818-0001, description: 预装与确认装柜清单共用的稳定编号;未创建计划时为空}
|
planNo: {type: string, nullable: true, pattern: '^LP-[0-9]{6}-[0-9]{4}$', example: LP-260818-0001, description: 预装与确认装柜清单共用的稳定编号;未创建计划时为空}
|
||||||
bookingNo: {type: string, pattern: '^CB-[0-9]{6}-[0-9]{4}$', example: CB-260818-0001, description: 平台内部货柜登记号}
|
|
||||||
containerNo: {type: string, maxLength: 64, nullable: true}
|
containerNo: {type: string, maxLength: 64, nullable: true}
|
||||||
cabinetNo: {type: string, pattern: '^D[0-9]{4,}$', example: D0001, description: 平台全局连续且不按日期重置的稳定柜次号}
|
cabinetNo: {type: string, pattern: '^D[0-9]{4,}$', example: D0001, description: 平台全局连续且不按日期重置的稳定柜次号}
|
||||||
sourceType: {type: string, enum: [SIMULATION, OCEAN_BOOKING], description: SIMULATION 为内部模拟柜;OCEAN_BOOKING 为订舱登记直接生成的真实柜}
|
sourceType: {type: string, enum: [SIMULATION, OCEAN_BOOKING], description: SIMULATION 为内部模拟柜;OCEAN_BOOKING 为订舱登记直接生成的真实柜}
|
||||||
@@ -2606,11 +2605,10 @@ components:
|
|||||||
pages: {type: string, pattern: '^[0-9]+$'}
|
pages: {type: string, pattern: '^[0-9]+$'}
|
||||||
SmartLoadingWorkbenchContainer:
|
SmartLoadingWorkbenchContainer:
|
||||||
type: object
|
type: object
|
||||||
required: [bookingId, bookingNo, cabinetNo, warehouseId, warehouseName, channelGroupCode,
|
required: [bookingId, cabinetNo, warehouseId, warehouseName, channelGroupCode,
|
||||||
containerType, capacityCbm, maxWeightKg, planStatus, version]
|
containerType, capacityCbm, maxWeightKg, planStatus, version]
|
||||||
properties:
|
properties:
|
||||||
bookingId: {type: string, pattern: '^[1-9][0-9]*$', description: containerBookingId 技术关联}
|
bookingId: {type: string, pattern: '^[1-9][0-9]*$', description: containerBookingId 技术关联}
|
||||||
bookingNo: {type: string, description: 货柜登记业务号}
|
|
||||||
cabinetNo: {type: string, description: 稳定柜次业务号}
|
cabinetNo: {type: string, description: 稳定柜次业务号}
|
||||||
containerNo: {type: string, nullable: true, description: 真实集装箱号,允许在装柜前后补}
|
containerNo: {type: string, nullable: true, description: 真实集装箱号,允许在装柜前后补}
|
||||||
warehouseId: {type: string, pattern: '^[1-9][0-9]*$'}
|
warehouseId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ components:
|
|||||||
exception: {$ref: '#/components/schemas/ExceptionState'}
|
exception: {$ref: '#/components/schemas/ExceptionState'}
|
||||||
exceptionHistory: {type: array, items: {$ref: '#/components/schemas/ExceptionHistory'}}
|
exceptionHistory: {type: array, items: {$ref: '#/components/schemas/ExceptionHistory'}}
|
||||||
timeline: {type: array, items: {$ref: '#/components/schemas/TimelineEntry'}}
|
timeline: {type: array, items: {$ref: '#/components/schemas/TimelineEntry'}}
|
||||||
Container: {type: object, properties: {id: {type: integer, format: int64}, bookingNo: {type: string, pattern: '^CB-[0-9]{6}-[0-9]{4}$', example: CB-260818-0001}, cabinetNo: {type: string, pattern: '^D[0-9]{4,}$', example: D0001}, containerNo: {type: string}, status: {type: string}, warehouseId: {type: integer, format: int64}, warehouseName: {type: string}, voyageNo: {type: string}, vesselName: {type: string}, pickupCode: {type: string, pattern: '^[0-9]{1,64}$', nullable: true}, pickupCodeUpdatedBy: {type: integer, format: int64, nullable: true}, pickupCodeUpdatedByName: {type: string, nullable: true}, pickupCodeUpdatedAt: {type: string, format: date-time, nullable: true}, version: {type: integer, minimum: 0}}}
|
Container: {type: object, properties: {id: {type: integer, format: int64}, cabinetNo: {type: string, pattern: '^D[0-9]{4,}$', example: D0001}, containerNo: {type: string}, status: {type: string}, warehouseId: {type: integer, format: int64}, warehouseName: {type: string}, voyageNo: {type: string}, vesselName: {type: string}, pickupCode: {type: string, pattern: '^[0-9]{1,64}$', nullable: true}, pickupCodeUpdatedBy: {type: integer, format: int64, nullable: true}, pickupCodeUpdatedByName: {type: string, nullable: true}, pickupCodeUpdatedAt: {type: string, format: date-time, nullable: true}, version: {type: integer, minimum: 0}}}
|
||||||
PdaSummary: {type: object, properties: {taskId: {type: integer, format: int64}, loadingPlanId: {type: integer, format: int64}, containerBookingId: {type: integer, format: int64}, taskStatus: {type: string, description: '持久化任务态:LOADING/COMPLETED'}, workflowStatus: {type: string, enum: [IN_PROGRESS, AWAITING_REVIEW, COMPLETED], description: 'PDA作业展示态'}, taskVersion: {type: integer}, itemCount: {type: integer}, completedItemCount: {type: integer}, unresolvedItemCount: {type: integer}, photoCounts: {type: array, items: {$ref: '#/components/schemas/PhotoCount'}}, photos: {type: array, items: {$ref: '#/components/schemas/Photo'}}, exceptionReasons: {type: array, items: {type: string}}}}
|
PdaSummary: {type: object, properties: {taskId: {type: integer, format: int64}, loadingPlanId: {type: integer, format: int64}, containerBookingId: {type: integer, format: int64}, taskStatus: {type: string, description: '持久化任务态:LOADING/COMPLETED'}, workflowStatus: {type: string, enum: [IN_PROGRESS, AWAITING_REVIEW, COMPLETED], description: 'PDA作业展示态'}, taskVersion: {type: integer}, itemCount: {type: integer}, completedItemCount: {type: integer}, unresolvedItemCount: {type: integer}, photoCounts: {type: array, items: {$ref: '#/components/schemas/PhotoCount'}}, photos: {type: array, items: {$ref: '#/components/schemas/Photo'}}, exceptionReasons: {type: array, items: {type: string}}}}
|
||||||
PhotoCount: {type: object, properties: {evidenceType: {type: string}, count: {type: integer}}}
|
PhotoCount: {type: object, properties: {evidenceType: {type: string}, count: {type: integer}}}
|
||||||
Photo: {type: object, properties: {evidenceId: {type: integer, format: int64}, tenantId: {type: integer, format: int64}, inboundId: {type: integer, format: int64}, evidenceType: {type: string}, fileId: {type: integer, format: int64}, fileName: {type: string}, status: {type: string, enum: [ACTIVE, VOID]}, downloadPath: {type: string, nullable: true, description: '仅 ACTIVE 照片提供鉴权下载路径;VOID 历史照片为空'}, uploadedAt: {type: string, format: date-time}}}
|
Photo: {type: object, properties: {evidenceId: {type: integer, format: int64}, tenantId: {type: integer, format: int64}, inboundId: {type: integer, format: int64}, evidenceType: {type: string}, fileId: {type: integer, format: int64}, fileName: {type: string}, status: {type: string, enum: [ACTIVE, VOID]}, downloadPath: {type: string, nullable: true, description: '仅 ACTIVE 照片提供鉴权下载路径;VOID 历史照片为空'}, uploadedAt: {type: string, format: date-time}}}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ paths:
|
|||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
containerBookingId: {type: string, description: 仅用于来源详情定位}
|
containerBookingId: {type: string, description: 仅用于来源详情定位}
|
||||||
bookingNo: {type: string}
|
cabinetNo: {type: string}
|
||||||
containerNo: {type: string, nullable: true}
|
containerNo: {type: string, nullable: true}
|
||||||
destinationPortName: {type: string, nullable: true}
|
destinationPortName: {type: string, nullable: true}
|
||||||
destinationWarehouseCode: {type: string, nullable: true}
|
destinationWarehouseCode: {type: string, nullable: true}
|
||||||
|
|||||||
+1
-1
@@ -128,7 +128,7 @@ class ContainerControllerContractTest {
|
|||||||
.contains("required: [oceanBookingId, requirementId, expectedVersion]")
|
.contains("required: [oceanBookingId, requirementId, expectedVersion]")
|
||||||
.contains("containerNo: {type: string, nullable: true")
|
.contains("containerNo: {type: string, nullable: true")
|
||||||
.doesNotContain("required: [oceanBookingId, requirementId, containerNo, expectedVersion]")
|
.doesNotContain("required: [oceanBookingId, requirementId, containerNo, expectedVersion]")
|
||||||
.contains("required: [id, bookingNo, cabinetNo, sourceType, recordStatus")
|
.contains("required: [id, cabinetNo, sourceType, recordStatus")
|
||||||
.contains("sourceType: {type: string, enum: [SIMULATION, OCEAN_BOOKING]")
|
.contains("sourceType: {type: string, enum: [SIMULATION, OCEAN_BOOKING]")
|
||||||
.contains("recordStatus: {type: string, enum: [ACTIVE, MERGED]")
|
.contains("recordStatus: {type: string, enum: [ACTIVE, MERGED]")
|
||||||
.contains("mergedIntoContainerBookingId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true");
|
.contains("mergedIntoContainerBookingId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true");
|
||||||
|
|||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
package com.baiyue.firstleg.portschedule.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
||||||
|
import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
|
||||||
|
import org.apache.ibatis.mapping.Environment;
|
||||||
|
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
|
||||||
|
import org.h2.jdbcx.JdbcDataSource;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
class ArrivalCalendarMapperTest {
|
||||||
|
@Test
|
||||||
|
void readsTheExistingCabinetNumberWithoutASecondContainerNumberColumn() throws Exception {
|
||||||
|
var ds = new JdbcDataSource();
|
||||||
|
ds.setURL("jdbc:h2:mem:arrival-cabinet-number;MODE=MySQL;DB_CLOSE_DELAY=-1");
|
||||||
|
try (var connection = ds.getConnection(); var sql = connection.createStatement()) {
|
||||||
|
sql.execute("CREATE TABLE fl_container_booking(id BIGINT,cabinet_no VARCHAR,container_no VARCHAR," +
|
||||||
|
"vessel_name VARCHAR,voyage_no VARCHAR,destination_port_name VARCHAR,destination_warehouse_code VARCHAR," +
|
||||||
|
"actual_port_arrival_at TIMESTAMP,estimated_port_arrival_at TIMESTAMP,record_status VARCHAR)");
|
||||||
|
sql.execute("CREATE TABLE fl_carrier_schedule_node_fact(id BIGINT,container_booking_id BIGINT," +
|
||||||
|
"standard_node VARCHAR,actual_at TIMESTAMP,observed_at TIMESTAMP)");
|
||||||
|
sql.execute("INSERT INTO fl_container_booking VALUES(1,'D0007','TEST-CONT','Vessel','Voyage','Port'," +
|
||||||
|
"'US-W',NULL,'2026-11-25 08:00:00','ACTIVE')");
|
||||||
|
}
|
||||||
|
var config = new MybatisConfiguration();
|
||||||
|
config.setEnvironment(new Environment("test", new JdbcTransactionFactory(), ds));
|
||||||
|
config.addMapper(PortScheduleMapper.class);
|
||||||
|
try (var session = new MybatisSqlSessionFactoryBuilder().build(config).openSession()) {
|
||||||
|
var rows = session.getMapper(PortScheduleMapper.class).arrivalCalendar(
|
||||||
|
LocalDateTime.parse("2026-11-01T00:00:00"), LocalDateTime.parse("2026-12-01T00:00:00"));
|
||||||
|
assertEquals(1, rows.size());
|
||||||
|
assertEquals("D0007", rows.get(0).cabinetNo());
|
||||||
|
assertEquals(1L, rows.get(0).containerBookingId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-8
@@ -13,6 +13,7 @@ import org.mockito.MockitoAnnotations;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -25,6 +26,7 @@ import static org.mockito.Mockito.when;
|
|||||||
class SailingCalendarServiceTest {
|
class SailingCalendarServiceTest {
|
||||||
@Mock private SailingCalendarRepository repository;
|
@Mock private SailingCalendarRepository repository;
|
||||||
@InjectMocks private SailingCalendarService service;
|
@InjectMocks private SailingCalendarService service;
|
||||||
|
private final LocalDateTime copiedDeparture = LocalDateTime.now(ZoneId.of("Asia/Shanghai")).plusDays(14);
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
@@ -33,8 +35,8 @@ class SailingCalendarServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void replaysAnExistingCopyInsteadOfReturningAnInternalError() {
|
void replaysAnExistingCopyInsteadOfReturningAnInternalError() {
|
||||||
SailingEntity source = sailing(1L, "SL-SOURCE", "MANUAL", "QA-20261005", LocalDateTime.of(2026, 10, 5, 10, 0));
|
SailingEntity source = sailing(1L, "SL-SOURCE", "MANUAL", "QA-20261005", copiedDeparture.minusDays(7));
|
||||||
SailingEntity existing = sailing(2L, "SL-COPY", "COPY", "QA-20261005", LocalDateTime.of(2026, 10, 12, 10, 0));
|
SailingEntity existing = sailing(2L, "SL-COPY", "COPY", "QA-20261005", copiedDeparture);
|
||||||
SailingHistoryEntity history = new SailingHistoryEntity();
|
SailingHistoryEntity history = new SailingHistoryEntity();
|
||||||
history.setAction("COPY"); history.setReason("复制自SL-SOURCE"); history.setSailingId(2L);
|
history.setAction("COPY"); history.setReason("复制自SL-SOURCE"); history.setSailingId(2L);
|
||||||
when(repository.sailing(1L)).thenReturn(source);
|
when(repository.sailing(1L)).thenReturn(source);
|
||||||
@@ -45,7 +47,7 @@ class SailingCalendarServiceTest {
|
|||||||
when(repository.bookingSummary(any(SailingEntity.class))).thenReturn(null);
|
when(repository.bookingSummary(any(SailingEntity.class))).thenReturn(null);
|
||||||
|
|
||||||
var result = service.copy(1L, 7L, "admin",
|
var result = service.copy(1L, 7L, "admin",
|
||||||
new CopyRequest(existing.getEtdAt(), LocalDateTime.of(2026, 10, 9, 18, 0)));
|
new CopyRequest(existing.getEtdAt(), copiedDeparture.minusDays(3)));
|
||||||
|
|
||||||
assertThat(result.sailing().id()).isEqualTo(2L);
|
assertThat(result.sailing().id()).isEqualTo(2L);
|
||||||
verify(repository, never()).insert(any(SailingEntity.class));
|
verify(repository, never()).insert(any(SailingEntity.class));
|
||||||
@@ -53,13 +55,13 @@ class SailingCalendarServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void reportsBusinessConflictForAnUnrelatedExistingSailing() {
|
void reportsBusinessConflictForAnUnrelatedExistingSailing() {
|
||||||
SailingEntity source = sailing(1L, "SL-SOURCE", "MANUAL", "QA-20261005", LocalDateTime.of(2026, 10, 5, 10, 0));
|
SailingEntity source = sailing(1L, "SL-SOURCE", "MANUAL", "QA-20261005", copiedDeparture.minusDays(7));
|
||||||
SailingEntity existing = sailing(2L, "SL-OTHER", "TEMPLATE", "QA-20261005", LocalDateTime.of(2026, 10, 12, 10, 0));
|
SailingEntity existing = sailing(2L, "SL-OTHER", "TEMPLATE", "QA-20261005", copiedDeparture);
|
||||||
when(repository.sailing(1L)).thenReturn(source);
|
when(repository.sailing(1L)).thenReturn(source);
|
||||||
when(repository.sailingByBusinessKey(8L, "MATSON", "CNNGB", "USLGB", existing.getEtdAt(), "QA-20261005")).thenReturn(existing);
|
when(repository.sailingByBusinessKey(8L, "MATSON", "CNNGB", "USLGB", existing.getEtdAt(), "QA-20261005")).thenReturn(existing);
|
||||||
|
|
||||||
assertThatThrownBy(() -> service.copy(1L, 7L, "admin",
|
assertThatThrownBy(() -> service.copy(1L, 7L, "admin",
|
||||||
new CopyRequest(existing.getEtdAt(), LocalDateTime.of(2026, 10, 9, 18, 0))))
|
new CopyRequest(existing.getEtdAt(), copiedDeparture.minusDays(3))))
|
||||||
.isInstanceOf(BizException.class)
|
.isInstanceOf(BizException.class)
|
||||||
.hasMessageContaining("已存在航次 QA-20261005");
|
.hasMessageContaining("已存在航次 QA-20261005");
|
||||||
verify(repository, never()).insert(any(SailingEntity.class));
|
verify(repository, never()).insert(any(SailingEntity.class));
|
||||||
@@ -67,11 +69,11 @@ class SailingCalendarServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void rejectsCutoffAtOrAfterCopiedDeparture() {
|
void rejectsCutoffAtOrAfterCopiedDeparture() {
|
||||||
SailingEntity source = sailing(1L, "SL-SOURCE", "MANUAL", "QA-20261005", LocalDateTime.of(2026, 10, 5, 10, 0));
|
SailingEntity source = sailing(1L, "SL-SOURCE", "MANUAL", "QA-20261005", copiedDeparture.minusDays(7));
|
||||||
when(repository.sailing(1L)).thenReturn(source);
|
when(repository.sailing(1L)).thenReturn(source);
|
||||||
|
|
||||||
assertThatThrownBy(() -> service.copy(1L, 7L, "admin",
|
assertThatThrownBy(() -> service.copy(1L, 7L, "admin",
|
||||||
new CopyRequest(LocalDateTime.of(2026, 10, 12, 10, 0), LocalDateTime.of(2026, 10, 12, 10, 0))))
|
new CopyRequest(copiedDeparture, copiedDeparture)))
|
||||||
.isInstanceOf(BizException.class)
|
.isInstanceOf(BizException.class)
|
||||||
.hasMessageContaining("收货截止必须早于开船");
|
.hasMessageContaining("收货截止必须早于开船");
|
||||||
verify(repository, never()).insert(any(SailingEntity.class));
|
verify(repository, never()).insert(any(SailingEntity.class));
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ class ContainerServiceTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUpWarehouse() {
|
void setUpWarehouse() {
|
||||||
when(documentNumbers.next("CB")).thenReturn("CB-260818-0001");
|
|
||||||
when(documentNumbers.nextCabinetNo()).thenReturn("D0001");
|
when(documentNumbers.nextCabinetNo()).thenReturn("D0001");
|
||||||
when(smartLoadingService.createForContainer(anyLong(), anyLong(), anyString())).thenAnswer(invocation ->
|
when(smartLoadingService.createForContainer(anyLong(), anyLong(), anyString())).thenAnswer(invocation ->
|
||||||
new com.baiyue.firstleg.dto.SmartLoadingDtos.Plan(501L, "LP-260818-0001", "EDITING",
|
new com.baiyue.firstleg.dto.SmartLoadingDtos.Plan(501L, "LP-260818-0001", "EDITING",
|
||||||
@@ -76,8 +75,9 @@ class ContainerServiceTest {
|
|||||||
verify(repository).insert(captor.capture());
|
verify(repository).insert(captor.capture());
|
||||||
ContainerBookingEntity saved = captor.getValue();
|
ContainerBookingEntity saved = captor.getValue();
|
||||||
assertThat(created).isSameAs(saved);
|
assertThat(created).isSameAs(saved);
|
||||||
assertThat(saved.getBookingNo()).isEqualTo("CB-260818-0001");
|
|
||||||
assertThat(saved.getCabinetNo()).isEqualTo("D0001");
|
assertThat(saved.getCabinetNo()).isEqualTo("D0001");
|
||||||
|
verify(documentNumbers).nextCabinetNo();
|
||||||
|
verify(documentNumbers, never()).next("CB");
|
||||||
assertThat(saved.getContainerNo()).isNull();
|
assertThat(saved.getContainerNo()).isNull();
|
||||||
assertThat(saved.getOceanBookingId()).isNull();
|
assertThat(saved.getOceanBookingId()).isNull();
|
||||||
assertThat(saved.getChannelGroupCode()).isEqualTo("MATSON_CLX");
|
assertThat(saved.getChannelGroupCode()).isEqualTo("MATSON_CLX");
|
||||||
|
|||||||
+1
-1
@@ -41,7 +41,7 @@ class FirstlegDocumentNumberGeneratorTest {
|
|||||||
|
|
||||||
assertThat(generator.next("OB")).isEqualTo("OB-260818-0001");
|
assertThat(generator.next("OB")).isEqualTo("OB-260818-0001");
|
||||||
assertThat(generator.next("TA")).isEqualTo("TA-260818-0001");
|
assertThat(generator.next("TA")).isEqualTo("TA-260818-0001");
|
||||||
assertThat(generator.next("CB")).isEqualTo("CB-260818-0001");
|
assertThatThrownBy(() -> generator.next("CB")).isInstanceOf(IllegalArgumentException.class);
|
||||||
assertThat(generator.next("LP")).isEqualTo("LP-260818-0001");
|
assertThat(generator.next("LP")).isEqualTo("LP-260818-0001");
|
||||||
assertThat(generator.nextCabinetNo()).isEqualTo("D0001");
|
assertThat(generator.nextCabinetNo()).isEqualTo("D0001");
|
||||||
|
|
||||||
|
|||||||
@@ -627,7 +627,7 @@ class SmartLoadingServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void pagesWorkbenchContainersWithTheSameGlobalFilters() {
|
void pagesWorkbenchContainersWithTheSameGlobalFilters() {
|
||||||
WorkbenchContainer container = new WorkbenchContainer(99L, "CB-1", "CAB-1", null,
|
WorkbenchContainer container = new WorkbenchContainer(99L, "D0001", null,
|
||||||
100L, "义乌仓", "MATSON_CLX", null, null, "40HQ",
|
100L, "义乌仓", "MATSON_CLX", null, null, "40HQ",
|
||||||
new BigDecimal("68"), new BigDecimal("19500"),
|
new BigDecimal("68"), new BigDecimal("19500"),
|
||||||
1L, "LP-1", "EDITING", 2);
|
1L, "LP-1", "EDITING", 2);
|
||||||
|
|||||||
+3
-3
@@ -71,10 +71,10 @@ class TaillegRealProducerAcceptanceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void seedCompletedLoadingPlan() {
|
private void seedCompletedLoadingPlan() {
|
||||||
jdbc.update("INSERT IGNORE INTO fl_container_booking(id,booking_no,container_no,cabinet_no,warehouse_id," +
|
jdbc.update("INSERT IGNORE INTO fl_container_booking(id,container_no,cabinet_no,warehouse_id," +
|
||||||
"warehouse_name,customer_id,customer_name,estimated_port_arrival_at,container_type,created_by,updated_by) " +
|
"warehouse_name,customer_id,customer_name,estimated_port_arrival_at,container_type,created_by,updated_by) " +
|
||||||
"VALUES(?,?,?,?,?,?,?,?,?,?,1,1)",
|
"VALUES(?,?,?,?,?,?,?,?,?,1,1)",
|
||||||
BOOKING, MARKER + "-BOOK", MARKER + "-CNTR", MARKER + "-CAB", 92L, "真实验收海外仓",
|
BOOKING, MARKER + "-CNTR", MARKER + "-CAB", 92L, "真实验收海外仓",
|
||||||
CUSTOMER, "真实验收客户", java.time.LocalDateTime.of(2026, 9, 30, 12, 0), "40HQ");
|
CUSTOMER, "真实验收客户", java.time.LocalDateTime.of(2026, 9, 30, 12, 0), "40HQ");
|
||||||
jdbc.update("INSERT IGNORE INTO fl_loading_plan(id,plan_no,container_booking_id,plan_status,created_by," +
|
jdbc.update("INSERT IGNORE INTO fl_loading_plan(id,plan_no,container_booking_id,plan_status,created_by," +
|
||||||
"updated_by,version) VALUES(?,?,?,'LOADING',1,1,0)", PLAN, MARKER + "-PLAN", BOOKING);
|
"updated_by,version) VALUES(?,?,?,'LOADING',1,1,0)", PLAN, MARKER + "-PLAN", BOOKING);
|
||||||
|
|||||||
+3
-2
@@ -14,11 +14,11 @@ class TerminalDrayageCalendarMapperTest {
|
|||||||
@Test void respectsExclusiveRangeActiveDepartureWithoutDuplicatingContainersOrOwningShippingFacts() throws Exception {
|
@Test void respectsExclusiveRangeActiveDepartureWithoutDuplicatingContainersOrOwningShippingFacts() throws Exception {
|
||||||
var ds=new JdbcDataSource();ds.setURL("jdbc:h2:mem:pickup-calendar;MODE=MySQL;DB_CLOSE_DELAY=-1");
|
var ds=new JdbcDataSource();ds.setURL("jdbc:h2:mem:pickup-calendar;MODE=MySQL;DB_CLOSE_DELAY=-1");
|
||||||
try(var c=ds.getConnection();var s=c.createStatement()) {
|
try(var c=ds.getConnection();var s=c.createStatement()) {
|
||||||
s.execute("CREATE TABLE fl_container_booking(id BIGINT,booking_no VARCHAR,container_no VARCHAR,destination_port_name VARCHAR,destination_warehouse_code VARCHAR,record_status VARCHAR)");
|
s.execute("CREATE TABLE fl_container_booking(id BIGINT,cabinet_no VARCHAR,container_no VARCHAR,destination_port_name VARCHAR,destination_warehouse_code VARCHAR,record_status VARCHAR)");
|
||||||
s.execute("CREATE TABLE fl_terminal_drayage(container_booking_id BIGINT,fleet_supplier_name VARCHAR,pickup_appointment_at TIMESTAMP)");
|
s.execute("CREATE TABLE fl_terminal_drayage(container_booking_id BIGINT,fleet_supplier_name VARCHAR,pickup_appointment_at TIMESTAMP)");
|
||||||
s.execute("CREATE TABLE fl_outbound_dispatch(container_booking_id BIGINT,confirmed_at TIMESTAMP,reversed_at TIMESTAMP,status VARCHAR)");
|
s.execute("CREATE TABLE fl_outbound_dispatch(container_booking_id BIGINT,confirmed_at TIMESTAMP,reversed_at TIMESTAMP,status VARCHAR)");
|
||||||
for(int id=1;id<=5;id++) {
|
for(int id=1;id<=5;id++) {
|
||||||
s.execute("INSERT INTO fl_container_booking VALUES("+id+",'CB','CONT','Port','US-W','"+(id==4?"CANCELLED":"ACTIVE")+"')");
|
s.execute("INSERT INTO fl_container_booking VALUES("+id+",'D000"+id+"','CONT','Port','US-W','"+(id==4?"CANCELLED":"ACTIVE")+"')");
|
||||||
s.execute("INSERT INTO fl_terminal_drayage VALUES("+id+",'Fleet','"+(id==3?"2026-11-01 00:00:00":"2026-10-01 09:00:00")+"')");
|
s.execute("INSERT INTO fl_terminal_drayage VALUES("+id+",'Fleet','"+(id==3?"2026-11-01 00:00:00":"2026-10-01 09:00:00")+"')");
|
||||||
s.execute("INSERT INTO fl_outbound_dispatch VALUES("+id+",'2026-09-01',"+(id==5?"'2026-09-02'":"NULL")+",'WAITING_FOR_LOADING')");
|
s.execute("INSERT INTO fl_outbound_dispatch VALUES("+id+",'2026-09-01',"+(id==5?"'2026-09-02'":"NULL")+",'WAITING_FOR_LOADING')");
|
||||||
}
|
}
|
||||||
@@ -28,6 +28,7 @@ class TerminalDrayageCalendarMapperTest {
|
|||||||
try(var session=new MybatisSqlSessionFactoryBuilder().build(config).openSession()) {
|
try(var session=new MybatisSqlSessionFactoryBuilder().build(config).openSession()) {
|
||||||
var rows=session.getMapper(TerminalDrayageMapper.class).calendar(LocalDateTime.parse("2026-10-01T00:00:00"),LocalDateTime.parse("2026-11-01T00:00:00"),1001);
|
var rows=session.getMapper(TerminalDrayageMapper.class).calendar(LocalDateTime.parse("2026-10-01T00:00:00"),LocalDateTime.parse("2026-11-01T00:00:00"),1001);
|
||||||
assertEquals(List.of(1L,2L),rows.stream().map(r->r.containerBookingId()).toList());assertNull(rows.get(0).actualPickupAt());
|
assertEquals(List.of(1L,2L),rows.stream().map(r->r.containerBookingId()).toList());assertNull(rows.get(0).actualPickupAt());
|
||||||
|
assertEquals("D0001", rows.get(0).cabinetNo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ class TerminalDrayageCalendarServiceTest {
|
|||||||
final com.baiyue.firstleg.portschedule.service.CarrierScheduleQueryService shipping=mock(com.baiyue.firstleg.portschedule.service.CarrierScheduleQueryService.class);
|
final com.baiyue.firstleg.portschedule.service.CarrierScheduleQueryService shipping=mock(com.baiyue.firstleg.portschedule.service.CarrierScheduleQueryService.class);
|
||||||
final TerminalDrayageCalendarService service=new TerminalDrayageCalendarService(mapper,warehouses,shipping,"test");
|
final TerminalDrayageCalendarService service=new TerminalDrayageCalendarService(mapper,warehouses,shipping,"test");
|
||||||
final LocalDate from=LocalDate.of(2026,10,1),to=from.plusDays(31);
|
final LocalDate from=LocalDate.of(2026,10,1),to=from.plusDays(31);
|
||||||
PickupCalendarEntry row(long id,String code) {return new PickupCalendarEntry(id,"CB-"+id,"TEST-CONT","Port",code,"Fleet",from.atTime(9,0),null);}
|
PickupCalendarEntry row(long id,String code) {return new PickupCalendarEntry(id,"D000"+id,"TEST-CONT","Port",code,"Fleet",from.atTime(9,0),null);}
|
||||||
@Test void batchesTheCatalogAndKeepsUnknownScopeVisibleWithoutGuessingPortTimeZone() {
|
@Test void batchesTheCatalogAndKeepsUnknownScopeVisibleWithoutGuessingPortTimeZone() {
|
||||||
when(mapper.calendar(any(),any(),eq(1001))).thenReturn(List.of(row(1,"US-W"),row(2,"CA-W"),row(3,"UNKNOWN")));
|
when(mapper.calendar(any(),any(),eq(1001))).thenReturn(List.of(row(1,"US-W"),row(2,"CA-W"),row(3,"UNKNOWN")));
|
||||||
when(warehouses.catalog("test")).thenReturn(ApiResponse.success(List.of(
|
when(warehouses.catalog("test")).thenReturn(ApiResponse.success(List.of(
|
||||||
|
|||||||
Reference in New Issue
Block a user