暂扣 标记合托功能
This commit is contained in:
@@ -195,7 +195,7 @@ CREATE TABLE IF NOT EXISTS ll_overseas_procurement_order (
|
|||||||
purchase_quantity BIGINT NOT NULL COMMENT '采购数量', budget_unit_price DECIMAL(18,2) NULL COMMENT '预算单价',
|
purchase_quantity BIGINT NOT NULL COMMENT '采购数量', budget_unit_price DECIMAL(18,2) NULL COMMENT '预算单价',
|
||||||
currency CHAR(3) NOT NULL DEFAULT 'USD' COMMENT '币种', receiving_address VARCHAR(1000) NULL COMMENT '收货地址',
|
currency CHAR(3) NOT NULL DEFAULT 'USD' COMMENT '币种', receiving_address VARCHAR(1000) NULL COMMENT '收货地址',
|
||||||
contact_name VARCHAR(128) NOT NULL COMMENT '联系人姓名', contact_phone VARCHAR(64) NOT NULL COMMENT '联系人电话',
|
contact_name VARCHAR(128) NOT NULL COMMENT '联系人姓名', contact_phone VARCHAR(64) NOT NULL COMMENT '联系人电话',
|
||||||
purchase_warehouse_id VARCHAR(128) NULL COMMENT '采购入仓仓库ID', purchase_warehouse_name VARCHAR(255) NULL COMMENT '采购入仓仓库名称',
|
purchase_warehouse_id VARCHAR(128) NULL COMMENT '采购入仓仓库ID', purchase_warehouse_name VARCHAR(255) NULL COMMENT '采购入仓仓库名称', outbound_details JSON NULL COMMENT '出库明细',
|
||||||
inbound_quantity BIGINT NOT NULL DEFAULT 0 COMMENT '采购单据累计入库数量', domestic_carrier VARCHAR(128) NULL COMMENT '境内承运商',
|
inbound_quantity BIGINT NOT NULL DEFAULT 0 COMMENT '采购单据累计入库数量', domestic_carrier VARCHAR(128) NULL COMMENT '境内承运商',
|
||||||
domestic_tracking_no VARCHAR(128) NULL COMMENT '境内物流单号', overseas_carrier VARCHAR(128) NULL COMMENT '海外承运商',
|
domestic_tracking_no VARCHAR(128) NULL COMMENT '境内物流单号', overseas_carrier VARCHAR(128) NULL COMMENT '海外承运商',
|
||||||
overseas_tracking_no VARCHAR(128) NULL COMMENT '海外物流单号', estimated_arrival_at DATETIME(3) NULL COMMENT '预计到达时间',
|
overseas_tracking_no VARCHAR(128) NULL COMMENT '海外物流单号', estimated_arrival_at DATETIME(3) NULL COMMENT '预计到达时间',
|
||||||
@@ -211,6 +211,8 @@ CREATE TABLE IF NOT EXISTS ll_overseas_procurement_order (
|
|||||||
KEY idx_ll_overseas_procurement_list(customer_id,status,created_at),
|
KEY idx_ll_overseas_procurement_list(customer_id,status,created_at),
|
||||||
KEY idx_ll_overseas_procurement_warehouse(customer_id,purchase_warehouse_id,created_at)
|
KEY idx_ll_overseas_procurement_warehouse(customer_id,purchase_warehouse_id,created_at)
|
||||||
) ENGINE=InnoDB COMMENT='海外采购订单';
|
) ENGINE=InnoDB COMMENT='海外采购订单';
|
||||||
|
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_overseas_procurement_order' AND column_name='outbound_details'), 'SELECT 1', 'ALTER TABLE ll_overseas_procurement_order ADD COLUMN outbound_details JSON NULL COMMENT ''出库明细'' AFTER inbound_quantity'));
|
||||||
|
PREPARE procurement_outbound_stmt FROM @ddl; EXECUTE procurement_outbound_stmt; DEALLOCATE PREPARE procurement_outbound_stmt;
|
||||||
|
|
||||||
SET @ddl = (SELECT IF(EXISTS (
|
SET @ddl = (SELECT IF(EXISTS (
|
||||||
SELECT 1 FROM information_schema.columns
|
SELECT 1 FROM information_schema.columns
|
||||||
|
|||||||
+11
-1
@@ -56,5 +56,15 @@ public final class OverseasProcurementRequests {
|
|||||||
JsonNode overseasCarrier,
|
JsonNode overseasCarrier,
|
||||||
JsonNode overseasTrackingNo,
|
JsonNode overseasTrackingNo,
|
||||||
JsonNode estimatedArrivalAt,
|
JsonNode estimatedArrivalAt,
|
||||||
JsonNode remark) {}
|
JsonNode remark,
|
||||||
|
JsonNode outboundDetails) {
|
||||||
|
public Update(Long version, String purchaseCategory, String productName, JsonNode productSpecification,
|
||||||
|
JsonNode productUrl, Long inboundQuantity, JsonNode purchaseWarehouseId, JsonNode purchaseWarehouseName,
|
||||||
|
JsonNode domesticCarrier, JsonNode domesticTrackingNo, JsonNode overseasCarrier, JsonNode overseasTrackingNo,
|
||||||
|
JsonNode estimatedArrivalAt, JsonNode remark) {
|
||||||
|
this(version, purchaseCategory, productName, productSpecification, productUrl, inboundQuantity,
|
||||||
|
purchaseWarehouseId, purchaseWarehouseName, domesticCarrier, domesticTrackingNo, overseasCarrier,
|
||||||
|
overseasTrackingNo, estimatedArrivalAt, remark, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -7,6 +7,8 @@ import java.util.List;
|
|||||||
public final class OverseasProcurementResponses {
|
public final class OverseasProcurementResponses {
|
||||||
private OverseasProcurementResponses() {}
|
private OverseasProcurementResponses() {}
|
||||||
|
|
||||||
|
public record OutboundDetail(String id, long quantity, String carrier, String trackingNo, LocalDateTime shippedAt, String remark) {}
|
||||||
|
|
||||||
public record Summary(
|
public record Summary(
|
||||||
Long id, String orderNo, String customerId, String customerName,
|
Long id, String orderNo, String customerId, String customerName,
|
||||||
String purchaseCategory, String productName, String productSpecification,
|
String purchaseCategory, String productName, String productSpecification,
|
||||||
@@ -32,5 +34,5 @@ public final class OverseasProcurementResponses {
|
|||||||
String overseasCarrier, String overseasTrackingNo,
|
String overseasCarrier, String overseasTrackingNo,
|
||||||
LocalDateTime estimatedArrivalAt, String remark,
|
LocalDateTime estimatedArrivalAt, String remark,
|
||||||
String createdBy, String reviewedBy, String reviewRemark, LocalDateTime reviewedAt,
|
String createdBy, String reviewedBy, String reviewRemark, LocalDateTime reviewedAt,
|
||||||
List<History> histories) {}
|
List<History> histories, List<OutboundDetail> outboundDetails) {}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -30,6 +30,7 @@ public class OverseasProcurementOrder {
|
|||||||
@TableField(updateStrategy = FieldStrategy.ALWAYS) private String purchaseWarehouseId;
|
@TableField(updateStrategy = FieldStrategy.ALWAYS) private String purchaseWarehouseId;
|
||||||
@TableField(updateStrategy = FieldStrategy.ALWAYS) private String purchaseWarehouseName;
|
@TableField(updateStrategy = FieldStrategy.ALWAYS) private String purchaseWarehouseName;
|
||||||
private Long inboundQuantity;
|
private Long inboundQuantity;
|
||||||
|
@TableField(updateStrategy = FieldStrategy.ALWAYS) private String outboundDetails;
|
||||||
@TableField(updateStrategy = FieldStrategy.ALWAYS) private String domesticCarrier;
|
@TableField(updateStrategy = FieldStrategy.ALWAYS) private String domesticCarrier;
|
||||||
@TableField(updateStrategy = FieldStrategy.ALWAYS) private String domesticTrackingNo;
|
@TableField(updateStrategy = FieldStrategy.ALWAYS) private String domesticTrackingNo;
|
||||||
@TableField(updateStrategy = FieldStrategy.ALWAYS) private String overseasCarrier;
|
@TableField(updateStrategy = FieldStrategy.ALWAYS) private String overseasCarrier;
|
||||||
|
|||||||
+21
-2
@@ -148,7 +148,7 @@ public class OverseasProcurementService {
|
|||||||
new OverseasProcurementResponses.History(value.getOperationType(), value.getFromStatus(),
|
new OverseasProcurementResponses.History(value.getOperationType(), value.getFromStatus(),
|
||||||
value.getToStatus(), value.getOperatorId(), value.getIdempotencyKey(),
|
value.getToStatus(), value.getOperatorId(), value.getIdempotencyKey(),
|
||||||
value.getChangeDetail(), value.getRemark(),
|
value.getChangeDetail(), value.getRemark(),
|
||||||
value.getCreatedAt())).toList());
|
value.getCreatedAt())).toList(), outboundDetails(order));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -205,6 +205,7 @@ public class OverseasProcurementService {
|
|||||||
patchText(request.overseasTrackingNo(), 128, "overseasTrackingNo", order::setOverseasTrackingNo);
|
patchText(request.overseasTrackingNo(), 128, "overseasTrackingNo", order::setOverseasTrackingNo);
|
||||||
patchDateTime(request.estimatedArrivalAt(), order::setEstimatedArrivalAt);
|
patchDateTime(request.estimatedArrivalAt(), order::setEstimatedArrivalAt);
|
||||||
patchText(request.remark(), 1000, "remark", order::setRemark);
|
patchText(request.remark(), 1000, "remark", order::setRemark);
|
||||||
|
if (request.outboundDetails() != null) order.setOutboundDetails(normalizeOutbound(request.outboundDetails(), order.getInboundQuantity()));
|
||||||
Map<String, Object> after = editableSnapshot(order);
|
Map<String, Object> after = editableSnapshot(order);
|
||||||
if (before.equals(after)) return detail(customerId, orderNo);
|
if (before.equals(after)) return detail(customerId, orderNo);
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
@@ -230,10 +231,11 @@ public class OverseasProcurementService {
|
|||||||
|
|
||||||
private OverseasProcurementResponses.Summary summary(OverseasProcurementOrder order) {
|
private OverseasProcurementResponses.Summary summary(OverseasProcurementOrder order) {
|
||||||
long inbound = value(order.getInboundQuantity());
|
long inbound = value(order.getInboundQuantity());
|
||||||
|
long outbound = outboundDetails(order).stream().mapToLong(OverseasProcurementResponses.OutboundDetail::quantity).sum();
|
||||||
return new OverseasProcurementResponses.Summary(order.getId(), order.getOrderNo(), order.getCustomerId(),
|
return new OverseasProcurementResponses.Summary(order.getId(), order.getOrderNo(), order.getCustomerId(),
|
||||||
order.getCustomerName(), order.getPurchaseCategory(), order.getProductName(),
|
order.getCustomerName(), order.getPurchaseCategory(), order.getProductName(),
|
||||||
order.getProductSpecification(), value(order.getPurchaseQuantity()), order.getBudgetUnitPrice(),
|
order.getProductSpecification(), value(order.getPurchaseQuantity()), order.getBudgetUnitPrice(),
|
||||||
order.getCurrency(), order.getPurchaseWarehouseId(), order.getPurchaseWarehouseName(), inbound, inbound,
|
order.getCurrency(), order.getPurchaseWarehouseId(), order.getPurchaseWarehouseName(), inbound, Math.max(0, inbound - outbound),
|
||||||
order.getStatus(), value(order.getVersion()), order.getCreatedAt(), order.getUpdatedAt());
|
order.getStatus(), value(order.getVersion()), order.getCreatedAt(), order.getUpdatedAt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,9 +338,26 @@ public class OverseasProcurementService {
|
|||||||
result.put("overseasTrackingNo", order.getOverseasTrackingNo());
|
result.put("overseasTrackingNo", order.getOverseasTrackingNo());
|
||||||
result.put("estimatedArrivalAt", order.getEstimatedArrivalAt());
|
result.put("estimatedArrivalAt", order.getEstimatedArrivalAt());
|
||||||
result.put("remark", order.getRemark());
|
result.put("remark", order.getRemark());
|
||||||
|
result.put("outboundDetails", order.getOutboundDetails());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<OverseasProcurementResponses.OutboundDetail> outboundDetails(OverseasProcurementOrder order) {
|
||||||
|
if (!StringUtils.hasText(order.getOutboundDetails())) return List.of();
|
||||||
|
try { return objectMapper.readValue(order.getOutboundDetails(), objectMapper.getTypeFactory().constructCollectionType(List.class, OverseasProcurementResponses.OutboundDetail.class)); }
|
||||||
|
catch (JsonProcessingException e) { return List.of(); }
|
||||||
|
}
|
||||||
|
private String normalizeOutbound(JsonNode node, Long inbound) {
|
||||||
|
if (!node.isArray()) throw badRequest("outboundDetails must be an array");
|
||||||
|
long total = 0;
|
||||||
|
for (JsonNode item : node) {
|
||||||
|
if (!item.isObject() || item.path("quantity").asLong(-1) < 0) throw badRequest("outboundDetails quantity must be non-negative");
|
||||||
|
total += item.path("quantity").asLong();
|
||||||
|
}
|
||||||
|
if (total > value(inbound)) throw badRequest("outbound quantity cannot exceed inbound quantity");
|
||||||
|
try { return objectMapper.writeValueAsString(node); } catch (JsonProcessingException e) { throw badRequest("Invalid outboundDetails"); }
|
||||||
|
}
|
||||||
|
|
||||||
private String changeDetail(Map<String, Object> before, Map<String, Object> after) {
|
private String changeDetail(Map<String, Object> before, Map<String, Object> after) {
|
||||||
Map<String, Object> changes = new LinkedHashMap<>();
|
Map<String, Object> changes = new LinkedHashMap<>();
|
||||||
before.forEach((field, oldValue) -> {
|
before.forEach((field, oldValue) -> {
|
||||||
|
|||||||
@@ -1556,7 +1556,7 @@ CREATE TABLE IF NOT EXISTS ll_overseas_procurement_order (
|
|||||||
purchase_quantity BIGINT NOT NULL COMMENT '采购数量', budget_unit_price DECIMAL(18,2) NULL COMMENT '预算单价',
|
purchase_quantity BIGINT NOT NULL COMMENT '采购数量', budget_unit_price DECIMAL(18,2) NULL COMMENT '预算单价',
|
||||||
currency CHAR(3) NOT NULL DEFAULT 'USD' COMMENT '币种', receiving_address VARCHAR(1000) NULL COMMENT '收货地址',
|
currency CHAR(3) NOT NULL DEFAULT 'USD' COMMENT '币种', receiving_address VARCHAR(1000) NULL COMMENT '收货地址',
|
||||||
contact_name VARCHAR(128) NOT NULL COMMENT '联系人姓名', contact_phone VARCHAR(64) NOT NULL COMMENT '联系人电话',
|
contact_name VARCHAR(128) NOT NULL COMMENT '联系人姓名', contact_phone VARCHAR(64) NOT NULL COMMENT '联系人电话',
|
||||||
purchase_warehouse_id VARCHAR(128) NULL COMMENT '采购入仓仓库ID', purchase_warehouse_name VARCHAR(255) NULL COMMENT '采购入仓仓库名称',
|
purchase_warehouse_id VARCHAR(128) NULL COMMENT '采购入仓仓库ID', purchase_warehouse_name VARCHAR(255) NULL COMMENT '采购入仓仓库名称', outbound_details JSON NULL COMMENT '出库明细',
|
||||||
inbound_quantity BIGINT NOT NULL DEFAULT 0 COMMENT '采购单据累计入库数量',
|
inbound_quantity BIGINT NOT NULL DEFAULT 0 COMMENT '采购单据累计入库数量',
|
||||||
domestic_carrier VARCHAR(128) NULL COMMENT '境内承运商', domestic_tracking_no VARCHAR(128) NULL COMMENT '境内物流单号',
|
domestic_carrier VARCHAR(128) NULL COMMENT '境内承运商', domestic_tracking_no VARCHAR(128) NULL COMMENT '境内物流单号',
|
||||||
overseas_carrier VARCHAR(128) NULL COMMENT '海外承运商', overseas_tracking_no VARCHAR(128) NULL COMMENT '海外物流单号',
|
overseas_carrier VARCHAR(128) NULL COMMENT '海外承运商', overseas_tracking_no VARCHAR(128) NULL COMMENT '海外物流单号',
|
||||||
|
|||||||
@@ -1093,6 +1093,19 @@ components:
|
|||||||
overseasTrackingNo: { $ref: '#/components/schemas/NullableTextPatch' }
|
overseasTrackingNo: { $ref: '#/components/schemas/NullableTextPatch' }
|
||||||
estimatedArrivalAt: { type: string, format: date-time, nullable: true, description: 缺失不修改;null 或空串清空 }
|
estimatedArrivalAt: { type: string, format: date-time, nullable: true, description: 缺失不修改;null 或空串清空 }
|
||||||
remark: { $ref: '#/components/schemas/NullableTextPatch' }
|
remark: { $ref: '#/components/schemas/NullableTextPatch' }
|
||||||
|
outboundDetails:
|
||||||
|
type: array
|
||||||
|
description: 出库明细,可一次提交多条;总出库量不得超过入库量
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required: [quantity]
|
||||||
|
properties:
|
||||||
|
id: { type: string }
|
||||||
|
quantity: { type: integer, format: int64, minimum: 0 }
|
||||||
|
carrier: { type: string, nullable: true, maxLength: 128 }
|
||||||
|
trackingNo: { type: string, nullable: true, maxLength: 128 }
|
||||||
|
shippedAt: { type: string, format: date-time, nullable: true }
|
||||||
|
remark: { type: string, nullable: true, maxLength: 500 }
|
||||||
CustomerOptionResponse:
|
CustomerOptionResponse:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
Reference in New Issue
Block a user