优化
This commit is contained in:
+3
-2
@@ -37,10 +37,10 @@ public class PlatformOceanBookingController {
|
||||
|
||||
@PostMapping @PreAuthorize("hasAuthority('platform:firstleg:ocean-booking:create')")
|
||||
@BusinessAudit(event="OCEAN_BOOKING_CREATE", resourceType="OCEAN_BOOKING", description="创建海运订舱单", captureBefore=false)
|
||||
public ApiResponse<Detail> create(@AuthenticationPrincipal AuthenticatedUser user, @RequestHeader("Idempotency-Key") String key, @Valid @RequestBody CreateRequest request) { FirstlegScopeGuard.platform(user, request.data().customerId()); return ApiResponse.success(service.create(user.userId(), user.username(), key, request)); }
|
||||
public ApiResponse<Detail> create(@AuthenticationPrincipal AuthenticatedUser user, @RequestHeader("Idempotency-Key") String key, @Valid @RequestBody CreateRequest request) { validateOptionalCustomer(user, request.data().customerId()); return ApiResponse.success(service.create(user.userId(), user.username(), key, request)); }
|
||||
@PutMapping("/{oceanBookingId}") @PreAuthorize("hasAuthority('platform:firstleg:ocean-booking:edit')")
|
||||
@BusinessAudit(event="OCEAN_BOOKING_UPDATE", resourceType="OCEAN_BOOKING", resourceId="#oceanBookingId", description="编辑海运订舱草稿")
|
||||
public ApiResponse<Detail> updateDraft(@AuthenticationPrincipal AuthenticatedUser user, @PathVariable @Positive long oceanBookingId, @RequestHeader("Idempotency-Key") String key, @Valid @RequestBody UpdateDraftRequest request) { FirstlegScopeGuard.platform(user, request.data().customerId()); return ApiResponse.success(service.updateDraft(oceanBookingId, user.userId(), user.username(), key, request)); }
|
||||
public ApiResponse<Detail> updateDraft(@AuthenticationPrincipal AuthenticatedUser user, @PathVariable @Positive long oceanBookingId, @RequestHeader("Idempotency-Key") String key, @Valid @RequestBody UpdateDraftRequest request) { validateOptionalCustomer(user, request.data().customerId()); return ApiResponse.success(service.updateDraft(oceanBookingId, user.userId(), user.username(), key, request)); }
|
||||
@PostMapping("/{oceanBookingId}/submit") @PreAuthorize("hasAuthority('platform:firstleg:ocean-booking:submit')")
|
||||
@BusinessAudit(event="OCEAN_BOOKING_SUBMIT", resourceType="OCEAN_BOOKING", resourceId="#oceanBookingId", description="提交海运订舱")
|
||||
public ApiResponse<Detail> submit(@AuthenticationPrincipal AuthenticatedUser user, @PathVariable @Positive long oceanBookingId, @RequestHeader("Idempotency-Key") String key, @Valid @RequestBody ActionRequest request) { FirstlegScopeGuard.platform(user); return ApiResponse.success(service.submit(oceanBookingId, user.userId(), user.username(), key, request)); }
|
||||
@@ -68,4 +68,5 @@ public class PlatformOceanBookingController {
|
||||
@PostMapping("/{oceanBookingId}/allocations") @PreAuthorize("hasAuthority('platform:firstleg:ocean-booking:allocate')")
|
||||
@BusinessAudit(event="OCEAN_BOOKING_ALLOCATE_CONTAINER", resourceType="OCEAN_BOOKING", resourceId="#oceanBookingId", description="分配订舱柜次")
|
||||
public ApiResponse<Detail> allocate(@AuthenticationPrincipal AuthenticatedUser user, @PathVariable @Positive long oceanBookingId, @RequestHeader("Idempotency-Key") String key, @Valid @RequestBody AllocationRequest request) { FirstlegScopeGuard.platform(user); return ApiResponse.success(service.allocate(oceanBookingId, user.userId(), user.username(), key, request)); }
|
||||
private static void validateOptionalCustomer(AuthenticatedUser user, Long customerId) { FirstlegScopeGuard.platform(user); if (customerId != null) FirstlegScopeGuard.platform(user, customerId); }
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@ public final class OceanBookingDtos {
|
||||
@NotNull @jakarta.validation.constraints.DecimalMin(value = "0", inclusive = false) BigDecimal maxWeightKg,
|
||||
@NotNull @Positive Integer quantity) {}
|
||||
|
||||
public record DraftData(@NotNull @Positive Long customerId,
|
||||
@NotBlank @Size(max = 128) String customerName,
|
||||
public record DraftData(@Positive Long customerId,
|
||||
@Size(max = 128) String customerName,
|
||||
@NotBlank @Size(max = 64) String channelCode,
|
||||
@NotNull @Positive Long warehouseId,
|
||||
@NotBlank @Size(max = 128) String warehouseName,
|
||||
@@ -56,8 +56,8 @@ public final class OceanBookingDtos {
|
||||
@Size(max = 32) String destinationPortCode,
|
||||
@Size(max = 128) String destinationPortName,
|
||||
@Size(max = 128) String placeOfDelivery,
|
||||
@Size(max = 32) String serviceTerm,
|
||||
@Size(max = 32) String freightTerm,
|
||||
@NotBlank @Size(max = 32) String serviceTerm,
|
||||
@NotBlank @Size(max = 32) String freightTerm,
|
||||
LocalDateTime estimatedSailingAt,
|
||||
LocalDateTime estimatedArrivalAt,
|
||||
@Size(max = 1000) String remark,
|
||||
|
||||
+7
-1
@@ -286,6 +286,12 @@ public class OceanBookingService {
|
||||
private static void requireStatus(OceanBookingEntity value, OceanBookingStatus status) { if (!status.name().equals(value.getStatus())) throw conflict("订舱状态不允许当前操作"); }
|
||||
|
||||
private void validateDraftStructure(DraftData data) {
|
||||
boolean hasCustomerId = data.customerId() != null;
|
||||
boolean hasCustomerName = StringUtils.hasText(data.customerName());
|
||||
if (hasCustomerId != hasCustomerName) throw badRequest("客户ID和客户名称必须同时填写或同时为空");
|
||||
if (!StringUtils.hasText(data.serviceTerm()) || !StringUtils.hasText(data.freightTerm())) {
|
||||
throw badRequest("Service Term和Freight Term不能为空");
|
||||
}
|
||||
if (data.estimatedSailingAt() != null || data.estimatedArrivalAt() != null
|
||||
|| StringUtils.hasText(data.billOfLadingNo()) || StringUtils.hasText(data.vesselName())
|
||||
|| StringUtils.hasText(data.voyageNo())) {
|
||||
@@ -329,7 +335,7 @@ public class OceanBookingService {
|
||||
}
|
||||
|
||||
private static void copy(OceanBookingEntity v, DraftData d, String resolvedChannelName) {
|
||||
v.setCustomerId(d.customerId()); v.setCustomerName(d.customerName().trim());
|
||||
v.setCustomerId(d.customerId()); v.setCustomerName(trim(d.customerName()));
|
||||
v.setChannelCode(d.channelCode().trim()); v.setChannelName(resolvedChannelName);
|
||||
v.setWarehouseId(d.warehouseId()); v.setWarehouseName(d.warehouseName().trim());
|
||||
v.setBillOfLadingNo(null);
|
||||
|
||||
@@ -5,8 +5,8 @@ CREATE TABLE IF NOT EXISTS fl_ocean_booking (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '海运订舱ID',
|
||||
booking_no VARCHAR(40) NOT NULL COMMENT '平台海运订舱编号',
|
||||
status VARCHAR(24) NOT NULL DEFAULT 'DRAFT' COMMENT '订舱状态:DRAFT草稿、SUBMITTED已提交、CONFIRMED已确认、RELEASED已放舱、FAILED失败、CHANGE_PENDING船期待变更、CANCELLED已取消',
|
||||
customer_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
|
||||
customer_name VARCHAR(128) NOT NULL COMMENT '客户名称快照',
|
||||
customer_id BIGINT UNSIGNED NULL COMMENT '可选客户ID快照',
|
||||
customer_name VARCHAR(128) NULL COMMENT '可选客户名称快照',
|
||||
channel_code VARCHAR(64) NOT NULL COMMENT '订舱渠道编码快照',
|
||||
channel_name VARCHAR(128) NOT NULL COMMENT '订舱渠道名称快照',
|
||||
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '国内中转仓ID快照',
|
||||
@@ -23,8 +23,8 @@ CREATE TABLE IF NOT EXISTS fl_ocean_booking (
|
||||
destination_port_code VARCHAR(32) NULL COMMENT '目的港编码快照',
|
||||
destination_port_name VARCHAR(128) NULL COMMENT '目的港名称快照',
|
||||
place_of_delivery VARCHAR(128) NULL COMMENT '最终交货地快照',
|
||||
service_term VARCHAR(32) NULL COMMENT '运输服务条款快照',
|
||||
freight_term VARCHAR(32) NULL COMMENT '海运费支付条款快照',
|
||||
service_term VARCHAR(32) NOT NULL COMMENT '运输服务条款快照',
|
||||
freight_term VARCHAR(32) NOT NULL COMMENT '海运费支付条款快照',
|
||||
estimated_sailing_at DATETIME(3) NULL COMMENT '当前确认预计开船时间',
|
||||
estimated_arrival_at DATETIME(3) NULL COMMENT '当前确认预计到港时间',
|
||||
pending_vessel_name VARCHAR(128) NULL COMMENT '待确认变更船名',
|
||||
|
||||
@@ -40,13 +40,15 @@ components:
|
||||
data: {$ref: '#/components/schemas/DraftData'}
|
||||
DraftData:
|
||||
type: object
|
||||
required: [customerId, customerName, channelCode, warehouseId, warehouseName, parties, containerRequirements]
|
||||
required: [channelCode, warehouseId, warehouseName, serviceTerm, freightTerm, parties, containerRequirements]
|
||||
properties:
|
||||
customerId: {type: integer, format: int64, minimum: 1}
|
||||
customerName: {type: string, maxLength: 128}
|
||||
customerId: {type: integer, format: int64, minimum: 1, nullable: true, description: Optional customer snapshot; must be supplied together with customerName.}
|
||||
customerName: {type: string, maxLength: 128, nullable: true, description: Optional customer snapshot; must be supplied together with customerId.}
|
||||
channelCode: {type: string, maxLength: 64, description: Selected from GET /api/platform/v1/ocean-bookings/channels; server validates it against the current ACTIVE price book and freezes channelName.}
|
||||
warehouseId: {type: integer, format: int64, minimum: 1}
|
||||
warehouseName: {type: string, maxLength: 128}
|
||||
serviceTerm: {type: string, maxLength: 32, description: Required free-text Service Term snapshot, for example CY-CY.}
|
||||
freightTerm: {type: string, maxLength: 32, description: Required free-text Freight Term snapshot, for example NINGBO.}
|
||||
billOfLadingNo: {type: string, nullable: true, deprecated: true, description: Must be omitted until release}
|
||||
vesselName: {type: string, nullable: true, deprecated: true, description: Must be omitted until release}
|
||||
voyageNo: {type: string, nullable: true, deprecated: true, description: Must be omitted until release}
|
||||
|
||||
Reference in New Issue
Block a user