优化
This commit is contained in:
@@ -2,6 +2,7 @@ package com.baiyue.firstleg.dto;
|
||||
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.entity.InboundTransportSnapshotEntity;
|
||||
import com.baiyue.firstleg.entity.InboundPickupSnapshotEntity;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
@@ -12,7 +13,7 @@ public record InboundOrderSummary(
|
||||
String processStatus, String orderStatusSnapshot, String measureReviewStatus,
|
||||
String feeStatus, String feeReviewStatus, String notificationStatus,
|
||||
Integer version,
|
||||
LocalDateTime expectedArrivalAt,
|
||||
LocalDateTime expectedArrivalAt, LocalDateTime requestedPickupAt,
|
||||
Long customerId, String customerName, Long companyId, String companyName,
|
||||
Long warehouseId, String warehouseName,
|
||||
Long deliveryWarehouseId, String deliveryWarehouseName,
|
||||
@@ -26,18 +27,20 @@ public record InboundOrderSummary(
|
||||
String locationCodes,
|
||||
LocalDateTime measureCompletedAt, LocalDateTime inboundedAt,
|
||||
String expressCompanyCode, String expressCompanyName, String expressTrackingNo,
|
||||
String loadingStatus, String containerNo, String cabinetNo,
|
||||
String containerNo, String cabinetNo,
|
||||
String vesselName, String voyageNo, LocalDateTime sailingAt, LocalDateTime portArrivalAt,
|
||||
LocalDateTime createdAt, LocalDateTime updatedAt
|
||||
) {
|
||||
public static InboundOrderSummary from(
|
||||
InboundOrderEntity order, InboundTransportSnapshotEntity transport, String locationCodes) {
|
||||
InboundOrderEntity order, InboundTransportSnapshotEntity transport,
|
||||
InboundPickupSnapshotEntity pickup, String locationCodes) {
|
||||
return new InboundOrderSummary(
|
||||
order.getId(), order.getTenantId(), order.getOrderId(), order.getOrderNo(), order.getInboundCode(),
|
||||
order.getProcessStatus(), order.getOrderStatusSnapshot(), order.getMeasureReviewStatus(),
|
||||
order.getFeeStatus(), order.getFeeReviewStatus(), order.getNotificationStatus(),
|
||||
order.getVersion(),
|
||||
order.getExpectedArrivalAt(), order.getCustomerId(), order.getCustomerName(),
|
||||
order.getExpectedArrivalAt(), pickup == null ? null : pickup.getPickupAt(),
|
||||
order.getCustomerId(), order.getCustomerName(),
|
||||
order.getCompanyId(), order.getCompanyName(), order.getWarehouseId(), order.getWarehouseName(),
|
||||
order.getDeliveryWarehouseId(), order.getDeliveryWarehouseName(), order.getBusinessType(),
|
||||
order.getChannelCode(), order.getChannelName(), order.getTaxMode(), order.getPricingTaxMode(),
|
||||
@@ -50,7 +53,6 @@ public record InboundOrderSummary(
|
||||
locationCodes,
|
||||
order.getMeasureCompletedAt(), order.getInboundedAt(), order.getExpressCompanyCode(),
|
||||
order.getExpressCompanyName(), order.getExpressTrackingNo(),
|
||||
transport == null ? null : transport.getLoadingStatus(),
|
||||
transport == null ? null : transport.getContainerNo(),
|
||||
transport == null ? null : transport.getCabinetNo(),
|
||||
transport == null ? null : transport.getVesselName(),
|
||||
|
||||
@@ -166,9 +166,12 @@ public final class LoadingListDtos {
|
||||
Long itemId,
|
||||
Long accountId,
|
||||
String customerName,
|
||||
Long orderId,
|
||||
String orderNo,
|
||||
Long inboundId,
|
||||
Long inboundDetailId,
|
||||
String inboundCode,
|
||||
String containerNo,
|
||||
String skuCode,
|
||||
String destinationWarehouse,
|
||||
String chineseName,
|
||||
|
||||
@@ -31,8 +31,25 @@ public record OrderApprovedInboundCommand(
|
||||
String publicRemark,
|
||||
String expressCompanyName,
|
||||
String expressTrackingNo,
|
||||
Integer totalPackageCount
|
||||
Integer totalPackageCount,
|
||||
String pickupMethod,
|
||||
LocalDateTime requestedPickupAt
|
||||
) {
|
||||
public OrderApprovedInboundCommand(
|
||||
long tenantId, long orderId, String orderNo, String inboundCode, Long customerId, String customerName,
|
||||
Long warehouseId, String warehouseName, Long deliveryWarehouseId, String deliveryWarehouseName,
|
||||
LocalDateTime expectedArrivalAt, String businessType, String channelCode, String channelName,
|
||||
Long carrierId, String carrierName, String taxMode, String pricingTaxMode, String containerMode,
|
||||
Boolean customsInspection, String destinationType, Long destinationWarehouseId, String destinationCode,
|
||||
String destinationName, String publicRemark, String expressCompanyName, String expressTrackingNo,
|
||||
Integer totalPackageCount
|
||||
) {
|
||||
this(tenantId, orderId, orderNo, inboundCode, customerId, customerName, warehouseId, warehouseName,
|
||||
deliveryWarehouseId, deliveryWarehouseName, expectedArrivalAt, businessType, channelCode, channelName,
|
||||
carrierId, carrierName, taxMode, pricingTaxMode, containerMode, customsInspection, destinationType,
|
||||
destinationWarehouseId, destinationCode, destinationName, publicRemark, expressCompanyName,
|
||||
expressTrackingNo, totalPackageCount, null, null);
|
||||
}
|
||||
/** 兼容尚未携带订单总箱数的历史事件。 */
|
||||
public OrderApprovedInboundCommand(
|
||||
long tenantId, long orderId, String orderNo, String inboundCode, Long customerId, String customerName,
|
||||
@@ -46,7 +63,7 @@ public record OrderApprovedInboundCommand(
|
||||
deliveryWarehouseId, deliveryWarehouseName, expectedArrivalAt, businessType, channelCode, channelName,
|
||||
carrierId, carrierName, taxMode, pricingTaxMode, containerMode, customsInspection, destinationType,
|
||||
destinationWarehouseId, destinationCode, destinationName, publicRemark, expressCompanyName,
|
||||
expressTrackingNo, null);
|
||||
expressTrackingNo, null, null, null);
|
||||
}
|
||||
|
||||
/** 兼容未携带报价包税维度的历史调用方。 */
|
||||
@@ -62,6 +79,6 @@ public record OrderApprovedInboundCommand(
|
||||
deliveryWarehouseId, deliveryWarehouseName, expectedArrivalAt, businessType, channelCode, channelName,
|
||||
carrierId, carrierName, taxMode, null, containerMode, customsInspection, destinationType,
|
||||
destinationWarehouseId, destinationCode, destinationName, publicRemark, expressCompanyName,
|
||||
expressTrackingNo, null);
|
||||
expressTrackingNo, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,5 +62,11 @@ public class ContainerBookingEntity {
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt;
|
||||
@Version @TableField(fill = FieldFill.INSERT) private Integer version;
|
||||
@TableField(exist = false) private Long planId;
|
||||
@TableField(exist = false) private String planNo;
|
||||
@TableField(exist = false) private String planStatus;
|
||||
@TableField(exist = false) private Boolean exceptionActive;
|
||||
@TableField(exist = false) private String destinationClearanceDocumentStatus;
|
||||
@TableField(exist = false) private String customsDeclarationDocumentStatus;
|
||||
@TableField(exist = false) private String deliveryOrderDocumentStatus;
|
||||
@TableField(exist = false) private String pickupOrderDocumentStatus;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.baiyue.firstleg.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/** 客户上门提货要求在入库域的快照。 */
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("fl_inbound_pickup_snapshot")
|
||||
public class InboundPickupSnapshotEntity {
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
private Long tenantId;
|
||||
private Long inboundId;
|
||||
private String pickupMethod;
|
||||
private LocalDateTime pickupAt;
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
@@ -62,4 +62,5 @@ public class TruckAppointmentEntity {
|
||||
@TableField(exist = false) private String bookingAgentName;
|
||||
@TableField(exist = false) private String cabinetNo;
|
||||
@TableField(exist = false) private String containerNo;
|
||||
@TableField(exist = false) private Long attachmentCount;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,20 @@ import org.apache.ibatis.annotations.Update;
|
||||
public interface ContainerBookingMapper extends BaseMapper<ContainerBookingEntity> {
|
||||
@Select("""
|
||||
<script>
|
||||
SELECT b.*, p.id AS plan_id,
|
||||
SELECT b.*, p.id AS plan_id, p.plan_no AS plan_no,
|
||||
CASE WHEN (SELECT eh.action FROM fl_container_exception_history eh
|
||||
WHERE eh.container_booking_id=b.id ORDER BY eh.occurred_at DESC,eh.id DESC LIMIT 1)='MARK'
|
||||
THEN TRUE ELSE FALSE END AS exception_active,
|
||||
COALESCE((SELECT CASE WHEN d.completed_at IS NOT NULL THEN 'COMPLETED' ELSE 'UPLOADED' END
|
||||
FROM fl_container_document d WHERE d.container_booking_id=b.id
|
||||
AND d.document_type='DESTINATION_CLEARANCE' LIMIT 1),'MISSING') AS destination_clearance_document_status,
|
||||
COALESCE((SELECT CASE WHEN d.completed_at IS NOT NULL THEN 'COMPLETED' ELSE 'UPLOADED' END
|
||||
FROM fl_container_document d WHERE d.container_booking_id=b.id
|
||||
AND d.document_type='CUSTOMS_DECLARATION' LIMIT 1),'MISSING') AS customs_declaration_document_status,
|
||||
COALESCE((SELECT 'UPLOADED' FROM fl_container_document d WHERE d.container_booking_id=b.id
|
||||
AND d.document_type='DELIVERY_ORDER' LIMIT 1),'MISSING') AS delivery_order_document_status,
|
||||
COALESCE((SELECT 'UPLOADED' FROM fl_container_document d WHERE d.container_booking_id=b.id
|
||||
AND d.document_type='PICKUP_ORDER' LIMIT 1),'MISSING') AS pickup_order_document_status,
|
||||
CASE WHEN p.id IS NULL THEN 'WAIT_LOADING'
|
||||
WHEN p.plan_status != 'COMPLETED' AND NOT EXISTS (
|
||||
SELECT 1 FROM fl_loading_plan_item active_item
|
||||
@@ -61,7 +74,20 @@ public interface ContainerBookingMapper extends BaseMapper<ContainerBookingEntit
|
||||
Page<ContainerBookingEntity> selectBookingPage(Page<ContainerBookingEntity> page, @Param("query") Query query);
|
||||
|
||||
@Select("""
|
||||
SELECT b.*, p.id AS plan_id,
|
||||
SELECT b.*, p.id AS plan_id, p.plan_no AS plan_no,
|
||||
CASE WHEN (SELECT eh.action FROM fl_container_exception_history eh
|
||||
WHERE eh.container_booking_id=b.id ORDER BY eh.occurred_at DESC,eh.id DESC LIMIT 1)='MARK'
|
||||
THEN TRUE ELSE FALSE END AS exception_active,
|
||||
COALESCE((SELECT CASE WHEN d.completed_at IS NOT NULL THEN 'COMPLETED' ELSE 'UPLOADED' END
|
||||
FROM fl_container_document d WHERE d.container_booking_id=b.id
|
||||
AND d.document_type='DESTINATION_CLEARANCE' LIMIT 1),'MISSING') AS destination_clearance_document_status,
|
||||
COALESCE((SELECT CASE WHEN d.completed_at IS NOT NULL THEN 'COMPLETED' ELSE 'UPLOADED' END
|
||||
FROM fl_container_document d WHERE d.container_booking_id=b.id
|
||||
AND d.document_type='CUSTOMS_DECLARATION' LIMIT 1),'MISSING') AS customs_declaration_document_status,
|
||||
COALESCE((SELECT 'UPLOADED' FROM fl_container_document d WHERE d.container_booking_id=b.id
|
||||
AND d.document_type='DELIVERY_ORDER' LIMIT 1),'MISSING') AS delivery_order_document_status,
|
||||
COALESCE((SELECT 'UPLOADED' FROM fl_container_document d WHERE d.container_booking_id=b.id
|
||||
AND d.document_type='PICKUP_ORDER' LIMIT 1),'MISSING') AS pickup_order_document_status,
|
||||
CASE WHEN p.id IS NULL THEN 'WAIT_LOADING'
|
||||
WHEN p.plan_status != 'COMPLETED' AND NOT EXISTS (
|
||||
SELECT 1 FROM fl_loading_plan_item active_item
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.baiyue.firstleg.mapper;
|
||||
|
||||
import com.baiyue.firstleg.entity.InboundPickupSnapshotEntity;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
public interface InboundPickupSnapshotMapper extends BaseMapper<InboundPickupSnapshotEntity> {
|
||||
}
|
||||
@@ -171,16 +171,19 @@ public interface LoadingListQueryMapper {
|
||||
@Param("operatorName") String operatorName);
|
||||
|
||||
@Select("""
|
||||
SELECT id AS item_id, account_id, customer_name, inbound_id, inbound_detail_id,
|
||||
inbound_code, sku_code, destination_warehouse_name, product_name_zh,
|
||||
SELECT i.id AS item_id, i.account_id, i.customer_name, i.order_id, i.order_no,
|
||||
i.inbound_id, i.inbound_detail_id, i.inbound_code, b.container_no,
|
||||
i.sku_code, i.destination_warehouse_name, i.product_name_zh,
|
||||
product_name_en, product_image_url, package_count, pallet_count,
|
||||
gross_weight_kg, net_weight_kg, volume_cbm, dimensional_weight_kg,
|
||||
product_quantity, units_per_carton, fba_tracking_no, shipment_no,
|
||||
shipping_mark, internal_remark, customer_remark, warehouse_remark,
|
||||
load_sequence, frozen_at
|
||||
FROM fl_loading_plan_item
|
||||
WHERE loading_plan_id = #{planId} AND deleted = 0
|
||||
ORDER BY load_sequence, id
|
||||
FROM fl_loading_plan_item i
|
||||
JOIN fl_loading_plan p ON p.id=i.loading_plan_id
|
||||
JOIN fl_container_booking b ON b.id=p.container_booking_id AND b.record_status='ACTIVE'
|
||||
WHERE i.loading_plan_id = #{planId} AND i.deleted = 0
|
||||
ORDER BY i.load_sequence, i.id
|
||||
""")
|
||||
List<ItemRow> selectItems(@Param("planId") long planId);
|
||||
|
||||
@@ -337,9 +340,12 @@ public interface LoadingListQueryMapper {
|
||||
private Long itemId;
|
||||
private Long accountId;
|
||||
private String customerName;
|
||||
private Long orderId;
|
||||
private String orderNo;
|
||||
private Long inboundId;
|
||||
private Long inboundDetailId;
|
||||
private String inboundCode;
|
||||
private String containerNo;
|
||||
private String skuCode;
|
||||
private String destinationWarehouseName;
|
||||
private String productNameZh;
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.baiyue.firstleg.mapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baiyue.firstleg.dto.TruckAppointmentDtos.Query; import com.baiyue.firstleg.entity.TruckAppointmentEntity; import org.apache.ibatis.annotations.*;
|
||||
@Mapper public interface TruckAppointmentMapper extends BaseMapper<TruckAppointmentEntity>{
|
||||
@Select("SELECT * FROM fl_truck_appointment WHERE container_booking_id=#{containerBookingId} AND status NOT IN ('COMPLETED','CANCELLED','EXCEPTION') ORDER BY id FOR UPDATE") java.util.List<TruckAppointmentEntity> activeForUpdate(@Param("containerBookingId") long containerBookingId);
|
||||
@Select("<script>SELECT * FROM fl_truck_appointment WHERE (#{q.keyword} IS NULL OR appointment_no LIKE CONCAT('%',#{q.keyword},'%') OR vehicle_no LIKE CONCAT('%',#{q.keyword},'%') OR carrier_name LIKE CONCAT('%',#{q.keyword},'%')) AND (#{q.status} IS NULL OR status=#{q.status}) AND (#{q.customerId} IS NULL OR customer_id=#{q.customerId}) AND (#{q.containerBookingId} IS NULL OR container_booking_id=#{q.containerBookingId}) ORDER BY updated_at DESC,id DESC</script>") Page<TruckAppointmentEntity> page(Page<TruckAppointmentEntity> p,@Param("q") Query q);
|
||||
@Select("<script>SELECT a.*,o.booking_no ocean_booking_no,COALESCE(o.warehouse_name,c.warehouse_name) warehouse_name,o.shipping_company_id,o.shipping_company_name,o.booking_agent_id,o.booking_agent_name,c.cabinet_no,c.container_no,(SELECT COUNT(*) FROM fl_truck_appointment_attachment x WHERE x.appointment_id=a.id) attachment_count FROM fl_truck_appointment a LEFT JOIN fl_ocean_booking o ON o.id=a.ocean_booking_id LEFT JOIN fl_container_booking c ON c.id=a.container_booking_id AND c.record_status='ACTIVE' WHERE (#{q.keyword} IS NULL OR a.appointment_no LIKE CONCAT('%',#{q.keyword},'%') OR a.vehicle_no LIKE CONCAT('%',#{q.keyword},'%') OR a.carrier_name LIKE CONCAT('%',#{q.keyword},'%')) AND (#{q.status} IS NULL OR a.status=#{q.status}) AND (#{q.customerId} IS NULL OR a.customer_id=#{q.customerId}) AND (#{q.containerBookingId} IS NULL OR a.container_booking_id=#{q.containerBookingId}) ORDER BY a.updated_at DESC,a.id DESC</script>") Page<TruckAppointmentEntity> page(Page<TruckAppointmentEntity> p,@Param("q") Query q);
|
||||
@Update("UPDATE fl_truck_appointment SET status=#{toStatus}, actual_arrived_warehouse_at=CASE WHEN #{toStatus}='ARRIVED_WAREHOUSE' THEN CURRENT_TIMESTAMP(3) ELSE actual_arrived_warehouse_at END, actual_loading_at=CASE WHEN #{toStatus}='LOADING' THEN CURRENT_TIMESTAMP(3) ELSE actual_loading_at END, actual_departed_at=CASE WHEN #{toStatus}='DEPARTED' THEN CURRENT_TIMESTAMP(3) ELSE actual_departed_at END, revision=revision+1, version=version+1, updated_at=CURRENT_TIMESTAMP(3) WHERE id=#{id} AND status=#{fromStatus} AND version=#{version}") int transition(@Param("id") long id,@Param("fromStatus") String from,@Param("toStatus") String to,@Param("version") int version);
|
||||
@Update("UPDATE fl_truck_appointment SET status='COMPLETED',actual_loading_at=COALESCE(actual_loading_at,CURRENT_TIMESTAMP(3)),revision=revision+1,version=version+1,updated_at=CURRENT_TIMESTAMP(3) WHERE id=#{id} AND status=#{fromStatus} AND version=#{version}") int completeLoadingFromPda(@Param("id") long id,@Param("fromStatus") String fromStatus,@Param("version") int version);
|
||||
@Update("UPDATE fl_truck_appointment SET planned_loading_at=#{at}, revision=revision+1, version=version+1, status='RESCHEDULED', remark=#{reason}, updated_at=CURRENT_TIMESTAMP(3) WHERE id=#{id} AND version=#{version}") int reschedule(@Param("id") long id,@Param("at") java.time.LocalDateTime at,@Param("reason") String reason,@Param("version") int version);
|
||||
|
||||
@@ -54,4 +54,7 @@ public class OceanBookingEntity {
|
||||
private String updatedByName;
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedAt;
|
||||
@Version @TableField(fill = FieldFill.INSERT) private Integer version;
|
||||
@TableField(exist = false) private String shipperName;
|
||||
@TableField(exist = false) private String consigneeName;
|
||||
@TableField(exist = false) private Long containerCount;
|
||||
}
|
||||
|
||||
+18
-10
@@ -15,16 +15,24 @@ import java.time.LocalDateTime;
|
||||
public interface OceanBookingMapper extends BaseMapper<OceanBookingEntity> {
|
||||
@Select("""
|
||||
<script>
|
||||
SELECT * FROM fl_ocean_booking
|
||||
WHERE (#{query.customerId} IS NULL OR customer_id=#{query.customerId})
|
||||
AND status IN ('CONFIRMED','CHANGE_PENDING','RELEASED','CANCELLED')
|
||||
AND (#{query.status} IS NULL OR status=#{query.status})
|
||||
AND (#{query.keyword} IS NULL OR booking_no LIKE CONCAT('%',#{query.keyword},'%')
|
||||
OR customer_name LIKE CONCAT('%',#{query.keyword},'%')
|
||||
OR bill_of_lading_no LIKE CONCAT('%',#{query.keyword},'%')
|
||||
OR vessel_name LIKE CONCAT('%',#{query.keyword},'%')
|
||||
OR voyage_no LIKE CONCAT('%',#{query.keyword},'%'))
|
||||
ORDER BY updated_at DESC,id DESC
|
||||
SELECT booking.*,
|
||||
(SELECT party.party_name FROM fl_ocean_booking_party party
|
||||
WHERE party.ocean_booking_id=booking.id AND party.party_type='SHIPPER' LIMIT 1) shipper_name,
|
||||
(SELECT party.party_name FROM fl_ocean_booking_party party
|
||||
WHERE party.ocean_booking_id=booking.id AND party.party_type='CONSIGNEE' LIMIT 1) consignee_name,
|
||||
(SELECT COUNT(*) FROM fl_ocean_booking_container_allocation allocation
|
||||
JOIN fl_container_booking container ON container.id=allocation.container_booking_id
|
||||
WHERE allocation.ocean_booking_id=booking.id AND container.record_status='ACTIVE') container_count
|
||||
FROM fl_ocean_booking booking
|
||||
WHERE (#{query.customerId} IS NULL OR booking.customer_id=#{query.customerId})
|
||||
AND booking.status IN ('CONFIRMED','CHANGE_PENDING','RELEASED','CANCELLED')
|
||||
AND (#{query.status} IS NULL OR booking.status=#{query.status})
|
||||
AND (#{query.keyword} IS NULL OR booking.booking_no LIKE CONCAT('%',#{query.keyword},'%')
|
||||
OR booking.customer_name LIKE CONCAT('%',#{query.keyword},'%')
|
||||
OR booking.bill_of_lading_no LIKE CONCAT('%',#{query.keyword},'%')
|
||||
OR booking.vessel_name LIKE CONCAT('%',#{query.keyword},'%')
|
||||
OR booking.voyage_no LIKE CONCAT('%',#{query.keyword},'%'))
|
||||
ORDER BY booking.updated_at DESC,booking.id DESC
|
||||
</script>
|
||||
""")
|
||||
Page<OceanBookingEntity> selectPage(Page<OceanBookingEntity> page, @Param("query") Query query);
|
||||
|
||||
+2
-1
@@ -20,7 +20,8 @@ public final class OutboundDispatchDtos {
|
||||
|
||||
public record Aggregate(Long orderId, String orderNo, Long inboundId, String inboundCode, Long tenantId,
|
||||
Long customerId, String customerName, String inboundStatus,
|
||||
Long containerBookingId, String containerNo, Long loadingPlanId, String loadingPlanStatus,
|
||||
Long containerBookingId, String cabinetNo, String containerNo,
|
||||
Long loadingPlanId, String loadingPlanStatus,
|
||||
Long pickTaskId, String pickTaskStatus, Long oceanBookingId, String oceanBookingStatus,
|
||||
Long truckAppointmentId, String truckAppointmentStatus,
|
||||
String dispatchStatus, Integer version, GateResult gate) {}
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ public interface OutboundDispatchReadMapper {
|
||||
SELECT DISTINCT inbound.order_id orderId,inbound.order_no orderNo,inbound.id inboundId,
|
||||
inbound.inbound_code inboundCode,inbound.tenant_id tenantId,inbound.customer_id customerId,
|
||||
inbound.customer_name customerName,inbound.process_status inboundStatus,
|
||||
booking.id containerBookingId,booking.container_no containerNo,
|
||||
booking.id containerBookingId,booking.cabinet_no cabinetNo,booking.container_no containerNo,
|
||||
plan.id loadingPlanId,plan.plan_status loadingPlanStatus
|
||||
FROM fl_loading_plan_item item
|
||||
JOIN fl_loading_plan plan ON plan.id=item.loading_plan_id
|
||||
@@ -100,7 +100,7 @@ public interface OutboundDispatchReadMapper {
|
||||
|
||||
record Binding(Long orderId, String orderNo, Long inboundId, String inboundCode, Long tenantId,
|
||||
Long customerId, String customerName, String inboundStatus, Long containerBookingId,
|
||||
String containerNo, Long loadingPlanId, String loadingPlanStatus) {}
|
||||
String cabinetNo, String containerNo, Long loadingPlanId, String loadingPlanStatus) {}
|
||||
record IdStatus(Long id, String status) {}
|
||||
record Evidence(Integer evidenceCount, Integer validSeal) {}
|
||||
}
|
||||
|
||||
+2
-1
@@ -109,7 +109,8 @@ public class OutboundDispatchService {
|
||||
GateResult gate = gate(binding, pick, ocean, truck, evidence);
|
||||
return new Aggregate(binding.orderId(), binding.orderNo(), binding.inboundId(), binding.inboundCode(),
|
||||
binding.tenantId(), binding.customerId(), binding.customerName(), binding.inboundStatus(),
|
||||
binding.containerBookingId(), binding.containerNo(), binding.loadingPlanId(), binding.loadingPlanStatus(),
|
||||
binding.containerBookingId(), binding.cabinetNo(), binding.containerNo(),
|
||||
binding.loadingPlanId(), binding.loadingPlanStatus(),
|
||||
id(pick), status(pick), id(ocean), status(ocean), id(truck), status(truck),
|
||||
dispatch == null ? OutboundDispatchStatus.READY_FOR_DISPATCH.name() : dispatch.getStatus(),
|
||||
dispatch == null ? 0 : dispatch.getVersion(), gate);
|
||||
|
||||
@@ -14,12 +14,14 @@ import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.entity.InboundPalletAllocationEntity;
|
||||
import com.baiyue.firstleg.entity.InboundStatusHistoryEntity;
|
||||
import com.baiyue.firstleg.entity.InboundTransportSnapshotEntity;
|
||||
import com.baiyue.firstleg.entity.InboundPickupSnapshotEntity;
|
||||
import com.baiyue.firstleg.mapper.InboundFileMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundInternalNoteMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundOrderMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundPalletAllocationMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundStatusHistoryMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundTransportSnapshotMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundPickupSnapshotMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -37,6 +39,8 @@ public class InboundOrderRepository {
|
||||
@Resource
|
||||
private InboundTransportSnapshotMapper transports;
|
||||
@Resource
|
||||
private InboundPickupSnapshotMapper pickupSnapshots;
|
||||
@Resource
|
||||
private InboundPalletAllocationMapper pallets;
|
||||
@Resource
|
||||
private InboundFileMapper files;
|
||||
@@ -82,9 +86,11 @@ public class InboundOrderRepository {
|
||||
Map<Long, Long> tenantByInbound = result.getRecords().stream()
|
||||
.collect(Collectors.toMap(InboundOrderEntity::getId, InboundOrderEntity::getTenantId));
|
||||
Map<Long, InboundTransportSnapshotEntity> transportByInbound = transportMap(tenantId, tenantByInbound);
|
||||
Map<Long, InboundPickupSnapshotEntity> pickupByInbound = pickupMap(tenantId, tenantByInbound);
|
||||
Map<Long, String> locationCodesByInbound = locationCodesMap(tenantId, tenantByInbound);
|
||||
List<InboundOrderSummary> records = result.getRecords().stream()
|
||||
.map(order -> InboundOrderSummary.from(order, transportByInbound.get(order.getId()),
|
||||
pickupByInbound.get(order.getId()),
|
||||
locationCodesByInbound.get(order.getId())))
|
||||
.toList();
|
||||
return new PageResult<>(records, result.getCurrent(), result.getSize(), result.getTotal(), result.getPages());
|
||||
@@ -191,6 +197,9 @@ public class InboundOrderRepository {
|
||||
InboundTransportSnapshotEntity transport = transports.selectOne(
|
||||
owned(InboundTransportSnapshotEntity::getTenantId,
|
||||
InboundTransportSnapshotEntity::getInboundId, tenantId, inboundId));
|
||||
InboundPickupSnapshotEntity pickup = pickupSnapshots.selectOne(
|
||||
owned(InboundPickupSnapshotEntity::getTenantId,
|
||||
InboundPickupSnapshotEntity::getInboundId, tenantId, inboundId));
|
||||
List<InboundPalletAllocationEntity> palletAllocations = pallets.selectList(
|
||||
owned(InboundPalletAllocationEntity::getTenantId,
|
||||
InboundPalletAllocationEntity::getInboundId, tenantId, inboundId)
|
||||
@@ -228,7 +237,7 @@ public class InboundOrderRepository {
|
||||
.map(InboundPalletAllocationEntity::getLocationCode)
|
||||
.filter(StringUtils::hasText)
|
||||
.collect(Collectors.joining("、"));
|
||||
return new InboundOrderDetail(InboundOrderSummary.from(order, transport, locationCodes),
|
||||
return new InboundOrderDetail(InboundOrderSummary.from(order, transport, pickup, locationCodes),
|
||||
order.getPublicRemark(),
|
||||
palletSummaries, fileSummaries, noteSummaries, historySummaries);
|
||||
}
|
||||
@@ -247,6 +256,17 @@ public class InboundOrderRepository {
|
||||
Function.identity(), (left, right) -> left));
|
||||
}
|
||||
|
||||
public Map<Long, InboundPickupSnapshotEntity> pickupMap(
|
||||
Long tenantId, Map<Long, Long> tenantByInbound) {
|
||||
if (tenantByInbound.isEmpty()) return Map.of();
|
||||
return pickupSnapshots.selectList(new LambdaQueryWrapper<InboundPickupSnapshotEntity>()
|
||||
.eq(tenantId != null, InboundPickupSnapshotEntity::getTenantId, tenantId)
|
||||
.in(InboundPickupSnapshotEntity::getInboundId, tenantByInbound.keySet()))
|
||||
.stream().filter(item -> owns(tenantByInbound, item.getInboundId(), item.getTenantId()))
|
||||
.collect(Collectors.toMap(InboundPickupSnapshotEntity::getInboundId,
|
||||
Function.identity(), (left, right) -> left));
|
||||
}
|
||||
|
||||
public Map<Long, String> locationCodesMap(Long tenantId, Map<Long, Long> tenantByInbound) {
|
||||
if (tenantByInbound.isEmpty()) {
|
||||
return Map.of();
|
||||
|
||||
@@ -171,7 +171,8 @@ public class LoadingListRepository {
|
||||
|
||||
private List<Item> items(List<ItemRow> rows) {
|
||||
return rows.stream().map(row -> new Item(row.getItemId(), row.getAccountId(), row.getCustomerName(),
|
||||
row.getInboundId(), row.getInboundDetailId(), row.getInboundCode(), row.getSkuCode(),
|
||||
row.getOrderId(), row.getOrderNo(), row.getInboundId(), row.getInboundDetailId(),
|
||||
row.getInboundCode(), row.getContainerNo(), row.getSkuCode(),
|
||||
row.getDestinationWarehouseName(), row.getProductNameZh(), row.getProductNameEn(),
|
||||
row.getProductImageUrl(), integer(row.getPackageCount()), integer(row.getPalletCount()),
|
||||
decimal(row.getGrossWeightKg()), decimal(row.getNetWeightKg()), decimal(row.getVolumeCbm()),
|
||||
|
||||
@@ -9,8 +9,10 @@ import com.baiyue.firstleg.dto.OrderApprovedInboundCommand;
|
||||
import com.baiyue.firstleg.dto.InboundOrderReference;
|
||||
import com.baiyue.firstleg.entity.FulfillmentTaskEntity;
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.entity.InboundPickupSnapshotEntity;
|
||||
import com.baiyue.firstleg.entity.InboundStatusHistoryEntity;
|
||||
import com.baiyue.firstleg.mapper.InboundOrderMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundPickupSnapshotMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundStatusHistoryMapper;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -27,6 +29,8 @@ public class InboundOrderCreationService {
|
||||
@Resource
|
||||
private InboundStatusHistoryMapper histories;
|
||||
@Resource
|
||||
private InboundPickupSnapshotMapper pickupSnapshots;
|
||||
@Resource
|
||||
private FulfillmentTaskProvisioningService fulfillmentTasks;
|
||||
|
||||
@Transactional
|
||||
@@ -37,6 +41,7 @@ public class InboundOrderCreationService {
|
||||
FulfillmentTaskEntity task = fulfillmentTasks.provision(command, LocalDateTime.now());
|
||||
linkTask(existing, task.getId());
|
||||
upgradePreparing(existing, command);
|
||||
savePickupSnapshot(existing.getId(), command, LocalDateTime.now());
|
||||
return inboundId;
|
||||
}
|
||||
|
||||
@@ -87,6 +92,7 @@ public class InboundOrderCreationService {
|
||||
inbound.setVersion(0);
|
||||
try {
|
||||
orders.insert(inbound);
|
||||
savePickupSnapshot(inbound.getId(), command, now);
|
||||
} catch (DuplicateKeyException duplicate) {
|
||||
InboundOrderEntity winner = findByOrder(command.tenantId(), command.orderId(), true);
|
||||
if (winner == null) {
|
||||
@@ -119,6 +125,7 @@ public class InboundOrderCreationService {
|
||||
if (existing != null) {
|
||||
long inboundId = requireMatchingInboundCode(existing, command.inboundCode());
|
||||
refreshPreparing(existing, command);
|
||||
savePickupSnapshot(existing.getId(), command, LocalDateTime.now());
|
||||
return inboundId;
|
||||
}
|
||||
|
||||
@@ -126,6 +133,7 @@ public class InboundOrderCreationService {
|
||||
InboundOrderEntity inbound = newInbound(command, now, null, "PREPARING", "DRAFT");
|
||||
try {
|
||||
orders.insert(inbound);
|
||||
savePickupSnapshot(inbound.getId(), command, now);
|
||||
} catch (DuplicateKeyException duplicate) {
|
||||
InboundOrderEntity winner = findByOrder(command.tenantId(), command.orderId(), true);
|
||||
if (winner == null) {
|
||||
@@ -248,6 +256,27 @@ public class InboundOrderCreationService {
|
||||
histories.insert(history);
|
||||
}
|
||||
|
||||
private void savePickupSnapshot(long inboundId, OrderApprovedInboundCommand command, LocalDateTime now) {
|
||||
InboundPickupSnapshotEntity existing = pickupSnapshots.selectOne(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<InboundPickupSnapshotEntity>()
|
||||
.eq(InboundPickupSnapshotEntity::getTenantId, command.tenantId())
|
||||
.eq(InboundPickupSnapshotEntity::getInboundId, inboundId));
|
||||
if (existing == null) {
|
||||
InboundPickupSnapshotEntity snapshot = new InboundPickupSnapshotEntity();
|
||||
snapshot.setId(IdWorker.getId());
|
||||
snapshot.setTenantId(command.tenantId());
|
||||
snapshot.setInboundId(inboundId);
|
||||
snapshot.setPickupMethod(command.pickupMethod());
|
||||
snapshot.setPickupAt(command.requestedPickupAt());
|
||||
snapshot.setCreatedAt(now);
|
||||
pickupSnapshots.insert(snapshot);
|
||||
} else if ("PREPARING".equals(findByOrder(command.tenantId(), command.orderId(), false).getProcessStatus())) {
|
||||
existing.setPickupMethod(command.pickupMethod());
|
||||
existing.setPickupAt(command.requestedPickupAt());
|
||||
pickupSnapshots.updateById(existing);
|
||||
}
|
||||
}
|
||||
|
||||
private InboundOrderEntity findByOrder(long tenantId, long orderId, boolean currentRead) {
|
||||
var query = new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<InboundOrderEntity>()
|
||||
.eq(InboundOrderEntity::getTenantId, tenantId)
|
||||
|
||||
@@ -51,7 +51,7 @@ public class TruckAppointmentService {
|
||||
private BookingLink validateBookingLink(SaveRequest r){if(r.oceanBookingId()==null||r.oceanBookingId()<=0)throw bad("oceanBookingId不能为空"); if(r.containerBookingId()==null||r.containerBookingId()<=0)throw bad("containerBookingId不能为空"); 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与订舱客户快照不一致"); 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与柜体不一致"); LoadingPlanEntity plan=loadingPlans.planByBooking(r.containerBookingId()); if(plan==null)throw conflict("关联柜次尚未建立装柜计划"); if(r.loadingPlanId()!=null&&!Objects.equals(r.loadingPlanId(),plan.getId()))throw bad("loadingPlanId与柜体当前装柜计划不一致"); return new BookingLink(b,plan);}
|
||||
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=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 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());}}value.setAttachmentCount((long)repo.attachments(value.getId()).size());return value;}
|
||||
private void copy(TruckAppointmentEntity e,SaveRequest r,BookingLink link,String carrierName){OceanBookingEntity booking=link.booking();e.setOutboundOrderId(r.outboundOrderId());e.setOceanBookingId(r.oceanBookingId());e.setContainerBookingId(r.containerBookingId());e.setLoadingPlanId(link.plan().getId());e.setWarehouseId(r.warehouseId());e.setCustomerId(booking.getCustomerId());e.setCustomerName(booking.getCustomerName());e.setCarrierId(r.carrierId());e.setCarrierName(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);}}
|
||||
|
||||
@@ -77,7 +77,8 @@ public class UnifiedInboundQueryService {
|
||||
}
|
||||
InboundTransportSnapshotEntity transport = includePhaseThree
|
||||
? operations.findTransport(tenantId, inbound.getId()) : null;
|
||||
return new UnifiedInboundDetail(summary(inbound, detail, preload, pick, evidence, deliveryAt, transport, null), timeline);
|
||||
return new UnifiedInboundDetail(summary(inbound, detail, preload, pick, evidence, deliveryAt,
|
||||
transport, null, null), timeline);
|
||||
}
|
||||
|
||||
private List<UnifiedInboundSummary> summaries(List<InboundOrderEntity> records) {
|
||||
@@ -93,17 +94,19 @@ public class UnifiedInboundQueryService {
|
||||
Map<Long, Long> owners = records.stream().collect(Collectors.toMap(
|
||||
InboundOrderEntity::getId, InboundOrderEntity::getTenantId, (left, right) -> left));
|
||||
var locationCodes = inbounds.locationCodesMap(null, owners);
|
||||
var pickups = inbounds.pickupMap(null, owners);
|
||||
return records.stream().map(inbound -> summary(inbound, null, preloads.get(inbound.getId()),
|
||||
picks.get(inbound.getId()), evidences.getOrDefault(inbound.getId(), List.of()),
|
||||
deliveries.get(inbound.getId()) == null ? null : deliveries.get(inbound.getId()).getOccurredAt(),
|
||||
transports.get(inbound.getId()), locationCodes.get(inbound.getId()))).toList();
|
||||
transports.get(inbound.getId()), locationCodes.get(inbound.getId()), pickups.get(inbound.getId()))).toList();
|
||||
}
|
||||
|
||||
private UnifiedInboundSummary summary(InboundOrderEntity inbound, InboundOrderDetail detail,
|
||||
com.baiyue.firstleg.split.entity.PreloadPlanEntity preload,
|
||||
com.baiyue.firstleg.loading.entity.InboundLoadingPickTaskEntity pick,
|
||||
List<LoadingEvidenceEntity> evidence, LocalDateTime deliveryAt,
|
||||
InboundTransportSnapshotEntity transport, String locationCodes) {
|
||||
InboundTransportSnapshotEntity transport, String locationCodes,
|
||||
com.baiyue.firstleg.entity.InboundPickupSnapshotEntity pickup) {
|
||||
String mainStatus = mainStatus(inbound.getProcessStatus());
|
||||
List<LoadingEvidenceEntity> activeEvidence = evidence.stream()
|
||||
.filter(item -> item.getStatus() == null || "ACTIVE".equals(item.getStatus())).toList();
|
||||
@@ -122,7 +125,7 @@ public class UnifiedInboundQueryService {
|
||||
"DELIVERED".equals(mainStatus) ? "COMPLETED" : "PENDING", deliveryAt,
|
||||
inbound.getExpressTrackingNo()) : null;
|
||||
var inboundSummary = detail == null
|
||||
? com.baiyue.firstleg.dto.InboundOrderSummary.from(inbound, transport, locationCodes) : detail.summary();
|
||||
? com.baiyue.firstleg.dto.InboundOrderSummary.from(inbound, transport, pickup, locationCodes) : detail.summary();
|
||||
return new UnifiedInboundSummary(inboundSummary, mainStatus,
|
||||
nextAction(mainStatus, inbound.getProcessStatus(), preload == null ? null : preload.getStatus()),
|
||||
preloadSummary, loadingSummary, deliverySummary);
|
||||
|
||||
@@ -1011,6 +1011,7 @@ components:
|
||||
notificationStatus: {type: string, nullable: true}
|
||||
version: {type: integer, nullable: true}
|
||||
expectedArrivalAt: {type: string, format: date-time, nullable: true}
|
||||
requestedPickupAt: {type: string, format: date-time, nullable: true, description: Customer-requested pickup appointment from fl_inbound_pickup_snapshot.pickup_at}
|
||||
customerId: {type: integer, format: int64, nullable: true}
|
||||
customerName: {type: string, nullable: true}
|
||||
companyId: {type: integer, format: int64, nullable: true}
|
||||
@@ -1045,7 +1046,6 @@ components:
|
||||
inboundedAt: {type: string, format: date-time, nullable: true}
|
||||
expressCompanyCode: {type: string, nullable: true}
|
||||
expressCompanyName: {type: string, nullable: true}
|
||||
loadingStatus: {type: string, nullable: true}
|
||||
containerNo: {type: string, nullable: true}
|
||||
cabinetNo: {type: string, nullable: true}
|
||||
vesselName: {type: string, nullable: true}
|
||||
@@ -1053,6 +1053,8 @@ components:
|
||||
sailingAt: {type: string, format: date-time, nullable: true}
|
||||
portArrivalAt: {type: string, format: date-time, nullable: true}
|
||||
expressTrackingNo: {type: string, nullable: true}
|
||||
pickupMethod: {type: string, enum: [SELF_EXPRESS, PICKUP, SELF_TRUCK], nullable: true}
|
||||
requestedPickupAt: {type: string, format: date-time, nullable: true, description: 客户要求平台上门提货的预约时间}
|
||||
createdByName: {type: string, nullable: true}
|
||||
createdAt: {type: string, format: date-time, nullable: true}
|
||||
updatedAt: {type: string, format: date-time, nullable: true}
|
||||
@@ -1370,10 +1372,11 @@ components:
|
||||
pages: {type: string, pattern: '^[0-9]+$'}
|
||||
ContainerBooking:
|
||||
type: object
|
||||
required: [id, bookingNo, cabinetNo, sourceType, recordStatus, warehouseId, warehouseName, containerType, capacityCbm, maxWeightKg, planStatus, version]
|
||||
required: [id, bookingNo, cabinetNo, sourceType, recordStatus, warehouseId, warehouseName, containerType, capacityCbm, maxWeightKg, planStatus, exceptionActive, destinationClearanceDocumentStatus, customsDeclarationDocumentStatus, deliveryOrderDocumentStatus, pickupOrderDocumentStatus, version]
|
||||
properties:
|
||||
id: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
planId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true, description: 关联智能装柜计划ID;未创建计划时为空}
|
||||
planNo: {type: string, nullable: true, description: 装柜清单号;未创建计划时为空}
|
||||
bookingNo: {type: string, maxLength: 40}
|
||||
containerNo: {type: string, maxLength: 64, nullable: true}
|
||||
cabinetNo: {type: string, maxLength: 64}
|
||||
@@ -1410,7 +1413,16 @@ components:
|
||||
estimatedWarehouseArrivalAt: {type: string, format: date-time, nullable: true}
|
||||
actualWarehouseArrivalAt: {type: string, format: date-time, nullable: true}
|
||||
planStatus: {type: string, enum: [WAIT_LOADING, EDITING, LOADING, COMPLETED]}
|
||||
exceptionActive: {type: boolean, description: 最新异常历史动作是否为 MARK}
|
||||
destinationClearanceDocumentStatus: {$ref: '#/components/schemas/ContainerDocumentStatus'}
|
||||
customsDeclarationDocumentStatus: {$ref: '#/components/schemas/ContainerDocumentStatus'}
|
||||
deliveryOrderDocumentStatus: {$ref: '#/components/schemas/ContainerDocumentStatus'}
|
||||
pickupOrderDocumentStatus: {$ref: '#/components/schemas/ContainerDocumentStatus'}
|
||||
version: {type: integer, minimum: 0}
|
||||
ContainerDocumentStatus:
|
||||
type: string
|
||||
enum: [MISSING, UPLOADED, COMPLETED]
|
||||
description: 单证聚合状态;DO/PU 无完成动作,因此只返回 MISSING 或 UPLOADED
|
||||
ContainerSaveRequest:
|
||||
type: object
|
||||
required: [cabinetNo, warehouseId, warehouseName, containerType, capacityCbm, maxWeightKg]
|
||||
|
||||
@@ -369,14 +369,17 @@ components:
|
||||
version: {type: integer, format: int32, minimum: 0, description: 乐观锁版本}
|
||||
LoadingItem:
|
||||
type: object
|
||||
required: [itemId, accountId, inboundId, inboundDetailId, packageCount, palletCount, grossWeightKg, netWeightKg, volumeCbm, dimensionalWeightKg, productQuantity, unitsPerPackage, loadSequence]
|
||||
required: [itemId, accountId, orderId, orderNo, inboundId, inboundDetailId, packageCount, palletCount, grossWeightKg, netWeightKg, volumeCbm, dimensionalWeightKg, productQuantity, unitsPerPackage, loadSequence]
|
||||
properties:
|
||||
itemId: {$ref: '#/components/schemas/LongId'}
|
||||
accountId: {$ref: '#/components/schemas/LongId'}
|
||||
customerName: {type: string, nullable: true, description: 客户名称快照}
|
||||
orderId: {$ref: '#/components/schemas/LongId'}
|
||||
orderNo: {type: string, description: 订单号快照}
|
||||
inboundId: {$ref: '#/components/schemas/LongId'}
|
||||
inboundDetailId: {$ref: '#/components/schemas/LongId'}
|
||||
inboundCode: {type: string, nullable: true, description: 入仓码}
|
||||
containerNo: {type: string, nullable: true, description: 当前 ACTIVE 柜次的真实集装箱号}
|
||||
skuCode: {type: string, nullable: true, description: SKU 编码快照}
|
||||
destinationWarehouse: {type: string, nullable: true, description: 目的仓名称快照}
|
||||
chineseName: {type: string, nullable: true, description: 中文品名快照}
|
||||
|
||||
@@ -18,7 +18,18 @@ paths:
|
||||
- {name: keyword, in: query, schema: {type: string, maxLength: 128}}
|
||||
- {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}
|
||||
- {name: size, in: query, schema: {type: integer, minimum: 1, maximum: 200, default: 20}}
|
||||
responses: {'200': {description: Operational real booking page}}
|
||||
responses:
|
||||
'200':
|
||||
description: Operational real booking page; each record follows OceanBookingSummary
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
records: {type: array, items: {$ref: '#/components/schemas/OceanBookingSummary'}}
|
||||
post:
|
||||
summary: Register an offline-confirmed ocean booking with complete transport snapshots
|
||||
description: 'Requires platform:firstleg:ocean-booking:create. Registers every real container unit atomically, creates one stable fl_container_booking plus one requirement/allocation per container, and persists the booking directly as CONFIRMED. RELEASED remains a separate later action.'
|
||||
@@ -64,6 +75,34 @@ components:
|
||||
OceanBookingId: {name: oceanBookingId, in: path, required: true, schema: {type: integer, format: int64, minimum: 1}}
|
||||
IdempotencyKey: {name: Idempotency-Key, in: header, required: true, schema: {type: string, maxLength: 128}}
|
||||
schemas:
|
||||
OceanBookingSummary:
|
||||
type: object
|
||||
required: [id, bookingNo, status, billOfLadingNo, vesselName, voyageNo, estimatedSailingAt, estimatedArrivalAt, containerCount, version]
|
||||
properties:
|
||||
id: {type: integer, format: int64}
|
||||
bookingNo: {type: string}
|
||||
status: {type: string, enum: [CONFIRMED, CHANGE_PENDING, RELEASED, CANCELLED]}
|
||||
customerId: {type: integer, format: int64, nullable: true}
|
||||
customerName: {type: string, nullable: true}
|
||||
billOfLadingNo: {type: string}
|
||||
shipperName: {type: string, nullable: true, description: SHIPPER party snapshot}
|
||||
consigneeName: {type: string, nullable: true, description: CONSIGNEE party snapshot}
|
||||
shippingCompanyId: {type: integer, format: int64, nullable: true}
|
||||
shippingCompanyName: {type: string, nullable: true}
|
||||
bookingAgentId: {type: integer, format: int64, nullable: true}
|
||||
bookingAgentName: {type: string, nullable: true}
|
||||
vesselName: {type: string}
|
||||
voyageNo: {type: string}
|
||||
departurePortCode: {type: string, nullable: true}
|
||||
departurePortName: {type: string, nullable: true}
|
||||
destinationPortCode: {type: string, nullable: true}
|
||||
destinationPortName: {type: string, nullable: true}
|
||||
estimatedSailingAt: {type: string, format: date-time}
|
||||
estimatedArrivalAt: {type: string, format: date-time}
|
||||
containerCount: {type: integer, format: int64, minimum: 0, description: ACTIVE real container units allocated to the booking}
|
||||
createdByName: {type: string, nullable: true}
|
||||
updatedAt: {type: string, format: date-time}
|
||||
version: {type: integer, minimum: 0}
|
||||
CreateRequest:
|
||||
type: object
|
||||
required: [expectedVersion, data]
|
||||
|
||||
@@ -11,7 +11,14 @@ paths:
|
||||
- {$ref: '#/components/parameters/InboundId'}
|
||||
- {$ref: '#/components/parameters/ContainerBookingId'}
|
||||
responses:
|
||||
'200': {description: Business envelope containing matching aggregates}
|
||||
'200':
|
||||
description: Business envelope containing matching aggregates, each with stable cabinetNo and real containerNo
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data: {type: array, items: {$ref: '#/components/schemas/Aggregate'}}
|
||||
/api/platform/v1/first-leg/outbound-dispatches/detail:
|
||||
get:
|
||||
summary: Query one aggregate and its unified timeline
|
||||
@@ -20,7 +27,17 @@ paths:
|
||||
- {$ref: '#/components/parameters/InboundId'}
|
||||
- {$ref: '#/components/parameters/ContainerBookingId'}
|
||||
responses:
|
||||
'200': {description: Business envelope containing aggregate detail}
|
||||
'200':
|
||||
description: Business envelope containing aggregate detail
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
aggregate: {$ref: '#/components/schemas/Aggregate'}
|
||||
/api/platform/v1/first-leg/outbound-dispatches/check-gate:
|
||||
get:
|
||||
summary: Evaluate the fail-closed domestic outbound gate
|
||||
@@ -59,6 +76,32 @@ components:
|
||||
ContainerBookingId: {name: containerBookingId, in: query, schema: {type: integer, format: int64, minimum: 1}}
|
||||
IdempotencyKey: {name: Idempotency-Key, in: header, required: true, schema: {type: string, maxLength: 128}}
|
||||
schemas:
|
||||
Aggregate:
|
||||
type: object
|
||||
required: [orderId, orderNo, inboundId, inboundCode, tenantId, inboundStatus, containerBookingId, cabinetNo, loadingPlanId, loadingPlanStatus, dispatchStatus, version, gate]
|
||||
properties:
|
||||
orderId: {type: integer, format: int64}
|
||||
orderNo: {type: string}
|
||||
inboundId: {type: integer, format: int64}
|
||||
inboundCode: {type: string}
|
||||
tenantId: {type: integer, format: int64}
|
||||
customerId: {type: integer, format: int64, nullable: true}
|
||||
customerName: {type: string, nullable: true}
|
||||
inboundStatus: {type: string}
|
||||
containerBookingId: {type: integer, format: int64}
|
||||
cabinetNo: {type: string, description: 稳定柜次号}
|
||||
containerNo: {type: string, nullable: true, description: 真实集装箱号}
|
||||
loadingPlanId: {type: integer, format: int64}
|
||||
loadingPlanStatus: {type: string}
|
||||
pickTaskId: {type: integer, format: int64, nullable: true}
|
||||
pickTaskStatus: {type: string, nullable: true}
|
||||
oceanBookingId: {type: integer, format: int64, nullable: true}
|
||||
oceanBookingStatus: {type: string, nullable: true}
|
||||
truckAppointmentId: {type: integer, format: int64, nullable: true}
|
||||
truckAppointmentStatus: {type: string, nullable: true}
|
||||
dispatchStatus: {type: string}
|
||||
version: {type: integer, minimum: 0}
|
||||
gate: {type: object}
|
||||
ActionRequest:
|
||||
type: object
|
||||
required: [inboundId, containerBookingId, expectedVersion]
|
||||
|
||||
@@ -10,7 +10,17 @@ paths:
|
||||
parameters:
|
||||
- {name: customerId, in: query, description: Filter by customer, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
responses:
|
||||
'200': {description: Paged truck appointments}
|
||||
'200':
|
||||
description: Paged truck appointments with stable booking/container snapshots and attachment count
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
records: {type: array, items: {$ref: '#/components/schemas/DetailStableReferences'}}
|
||||
post:
|
||||
summary: Create a truck appointment linked to a released ocean booking
|
||||
requestBody:
|
||||
@@ -185,3 +195,4 @@ components:
|
||||
bookingAgentName: {type: string}
|
||||
carrierId: {type: integer, format: int64}
|
||||
carrierName: {type: string}
|
||||
attachmentCount: {type: integer, format: int64, minimum: 0, description: Number of attachment references owned by this appointment}
|
||||
|
||||
+3
@@ -51,6 +51,9 @@ class InboundOrderControllerContractTest {
|
||||
.contains("required: false")
|
||||
.contains("InboundOrderSummary:")
|
||||
.contains("required: [id, tenantId]")
|
||||
.contains("actualNetWeightKg: {type: number, nullable: true}")
|
||||
.contains("chargeableVolumeCbm: {type: number, nullable: true}")
|
||||
.contains("measureCompletedAt: {type: string, format: date-time, nullable: true}")
|
||||
.contains("pricingTaxMode: {type: string, enum: [TAX_INCLUDED, TAX_EXCLUDED]")
|
||||
.contains("tenantId: {type: string, pattern: '^[1-9][0-9]*$', description:")
|
||||
.contains("[WAIT_MEASURE, WAIT_REVIEW, WAIT_FEE_SEND, WAIT_SPLIT]")
|
||||
|
||||
+2
-2
@@ -40,8 +40,8 @@ class UnifiedInboundOpenApiContractTest {
|
||||
"businessType", "channelCode", "pricingTaxMode", "containerMode", "destinationType",
|
||||
"holdFlag", "actualGrossWeightKg", "actualNetWeightKg", "actualVolumeCbm",
|
||||
"volumeWeightKg", "chargeableWeightKg", "chargeableVolumeCbm", "palletCount",
|
||||
"inboundedAt", "expressCompanyCode", "expressCompanyName", "loadingStatus", "containerNo",
|
||||
"cabinetNo", "sailingAt", "portArrivalAt", "createdAt", "updatedAt");
|
||||
"inboundedAt", "requestedPickupAt", "expressCompanyCode", "expressCompanyName", "containerNo",
|
||||
"cabinetNo", "sailingAt", "portArrivalAt", "createdByName", "createdAt", "updatedAt");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
+6
-4
@@ -16,10 +16,12 @@ class OceanBookingMapperContractTest {
|
||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page.class,
|
||||
com.baiyue.firstleg.oceanbooking.dto.OceanBookingDtos.Query.class)
|
||||
.getAnnotation(Select.class).value());
|
||||
assertThat(sql).contains("customer_id=#{query.customerId}")
|
||||
.contains("status=#{query.status}")
|
||||
.contains("booking_no LIKE")
|
||||
.contains("ORDER BY updated_at DESC,id DESC");
|
||||
assertThat(sql).contains("booking.customer_id=#{query.customerId}")
|
||||
.contains("booking.status=#{query.status}")
|
||||
.contains("booking.booking_no LIKE")
|
||||
.contains("party.party_type='SHIPPER'", "party.party_type='CONSIGNEE'")
|
||||
.contains("fl_ocean_booking_container_allocation", "container.record_status='ACTIVE'", "container_count")
|
||||
.contains("ORDER BY booking.updated_at DESC,booking.id DESC");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+8
@@ -7,6 +7,14 @@ import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class OutboundDispatchReadMapperContractTest {
|
||||
@Test
|
||||
void bindingProjectsStableCabinetAndRealContainerNumbersSeparately() throws Exception {
|
||||
String sql = String.join("\n", OutboundDispatchReadMapper.class
|
||||
.getMethod("bindings", Long.class, Long.class, Long.class)
|
||||
.getAnnotation(Select.class).value());
|
||||
assertThat(sql).contains("booking.cabinet_no cabinetNo", "booking.container_no containerNo");
|
||||
}
|
||||
|
||||
@Test
|
||||
void pickTaskQueryOrdersByTheSchemaStartedAtColumn() throws Exception {
|
||||
String sql = OutboundDispatchReadMapper.class.getMethod("pick", long.class)
|
||||
|
||||
+1
-1
@@ -129,7 +129,7 @@ class OutboundDispatchServiceTest {
|
||||
|
||||
private static OutboundDispatchReadMapper.Binding binding() {
|
||||
return new OutboundDispatchReadMapper.Binding(10L, "O-10", 11L, "I-11", 7L, 8L, "客户A",
|
||||
"LOADED", 22L, "C-22", 44L, "COMPLETED");
|
||||
"LOADED", 22L, "CAB-22", "C-22", 44L, "COMPLETED");
|
||||
}
|
||||
|
||||
private static OutboundDispatchGateContributor passing(String code) {
|
||||
|
||||
+4
@@ -24,6 +24,10 @@ class ContainerBookingMapperContractTest {
|
||||
assertThat(select)
|
||||
.contains("fl_loading_plan")
|
||||
.contains("p.id AS plan_id")
|
||||
.contains("p.plan_no AS plan_no")
|
||||
.contains("fl_container_exception_history")
|
||||
.contains("destination_clearance_document_status")
|
||||
.contains("delivery_order_document_status")
|
||||
.contains("CASE WHEN p.id IS NULL THEN 'WAIT_LOADING'")
|
||||
.contains("plan_status")
|
||||
.contains("p.plan_status != 'COMPLETED'")
|
||||
|
||||
+2
-2
@@ -16,6 +16,7 @@ import com.baiyue.firstleg.mapper.InboundOrderMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundPalletAllocationMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundStatusHistoryMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundTransportSnapshotMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundPickupSnapshotMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
@@ -37,6 +38,7 @@ import static org.mockito.Mockito.when;
|
||||
class InboundOrderRepositoryTest {
|
||||
@MockBean private InboundOrderMapper orders;
|
||||
@MockBean private InboundTransportSnapshotMapper transports;
|
||||
@MockBean private InboundPickupSnapshotMapper pickupSnapshots;
|
||||
@MockBean private InboundPalletAllocationMapper pallets;
|
||||
@MockBean private InboundFileMapper files;
|
||||
@MockBean private InboundInternalNoteMapper notes;
|
||||
@@ -162,8 +164,6 @@ class InboundOrderRepositoryTest {
|
||||
|
||||
assertThat(result.records()).extracting(record -> record.tenantId())
|
||||
.containsExactly(10001L, 10002L);
|
||||
assertThat(result.records()).extracting(record -> record.loadingStatus())
|
||||
.containsExactly("T1", "T2");
|
||||
assertThat(result.records()).extracting(record -> record.locationCodes())
|
||||
.containsExactly("A1", "B1");
|
||||
ArgumentCaptor<Wrapper<InboundOrderEntity>> orderCaptor = ArgumentCaptor.forClass(Wrapper.class);
|
||||
|
||||
+10
@@ -54,6 +54,16 @@ class LoadingListQueryMapperContractTest {
|
||||
.doesNotContain("fl_loading_list");
|
||||
}
|
||||
|
||||
@Test
|
||||
void detailItemsExposeFrozenOrderAndActiveContainerFacts() throws Exception {
|
||||
String items = sql("selectItems", Select.class);
|
||||
assertThat(items)
|
||||
.contains("i.order_id", "i.order_no", "b.container_no")
|
||||
.contains("b.record_status='ACTIVE'")
|
||||
.contains("i.loading_plan_id = #{planId}")
|
||||
.contains("i.deleted = 0");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mutationsShouldUseStatusAndOptimisticVersionConditions() throws Exception {
|
||||
String touch = sql("touchEditable", Update.class);
|
||||
|
||||
+2
-1
@@ -13,7 +13,8 @@ class TruckAppointmentMapperContractTest {
|
||||
@Test void mapsToPhase3TableAndUsesOptimisticGuards() throws Exception {
|
||||
assertThat(TruckAppointmentEntity.class.getAnnotation(TableName.class).value()).isEqualTo("fl_truck_appointment");
|
||||
String page = TruckAppointmentMapper.class.getMethod("page", com.baomidou.mybatisplus.extension.plugins.pagination.Page.class, com.baiyue.firstleg.dto.TruckAppointmentDtos.Query.class).getAnnotation(Select.class).value()[0];
|
||||
assertThat(page).contains("fl_truck_appointment", "appointment_no", "vehicle_no", "status=#{q.status}", "customer_id=#{q.customerId}", "container_booking_id=#{q.containerBookingId}");
|
||||
assertThat(page).contains("fl_truck_appointment", "appointment_no", "vehicle_no", "status=#{q.status}", "customer_id=#{q.customerId}", "container_booking_id=#{q.containerBookingId}",
|
||||
"fl_ocean_booking", "fl_container_booking", "record_status='ACTIVE'", "cabinet_no", "container_no", "fl_truck_appointment_attachment", "attachment_count");
|
||||
String transition = TruckAppointmentMapper.class.getMethod("transition", long.class, String.class, String.class, int.class).getAnnotation(Update.class).value()[0];
|
||||
assertThat(transition).contains("status=#{toStatus}", "status=#{fromStatus}", "version=#{version}", "revision=revision+1", "version=version+1");
|
||||
String active = TruckAppointmentMapper.class.getMethod("activeForUpdate", long.class).getAnnotation(Select.class).value()[0];
|
||||
|
||||
+3
@@ -11,6 +11,7 @@ import com.baiyue.firstleg.entity.InboundStatusHistoryEntity;
|
||||
import com.baiyue.firstleg.entity.FulfillmentTaskEntity;
|
||||
import com.baiyue.firstleg.mapper.InboundOrderMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundStatusHistoryMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundPickupSnapshotMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -42,6 +43,8 @@ class InboundOrderCreationServiceTest {
|
||||
@Mock
|
||||
private InboundStatusHistoryMapper histories;
|
||||
@Mock
|
||||
private InboundPickupSnapshotMapper pickupSnapshots;
|
||||
@Mock
|
||||
private FulfillmentTaskProvisioningService fulfillmentTasks;
|
||||
@InjectMocks
|
||||
private InboundOrderCreationService service;
|
||||
|
||||
Reference in New Issue
Block a user