This commit is contained in:
2026-08-10 12:40:47 +08:00
parent 7684f3cfec
commit fc554273b9
22 changed files with 322 additions and 56 deletions
@@ -11,10 +11,67 @@ public interface LoadingInboundMapper {
+ "FROM fl_inbound_order WHERE tenant_id=#{tenantId} AND id=#{inboundId} AND deleted=0")
Snapshot find(@Param("tenantId") long tenantId, @Param("inboundId") long inboundId);
@Select("""
SELECT batch.source_inbound_id AS sourceInboundId,
batch.loaded_child_inbound_id AS loadedChildInboundId,
batch.parent_inbound_id AS rootInboundId,
source.process_status AS sourceStatus, source.version AS sourceVersion,
child.process_status AS loadedChildStatus, child.version AS loadedChildVersion
FROM fl_inbound_split_batch batch
JOIN fl_inbound_order source ON source.id=batch.source_inbound_id
AND source.tenant_id=batch.tenant_id AND source.deleted=0
JOIN fl_inbound_order child ON child.id=batch.loaded_child_inbound_id
AND child.tenant_id=batch.tenant_id AND child.deleted=0
WHERE batch.tenant_id=#{tenantId} AND batch.status='APPLIED'
AND (batch.source_inbound_id=#{inboundId} OR batch.loaded_child_inbound_id=#{inboundId})
ORDER BY batch.id DESC LIMIT 1
""")
CompletionTarget completionTarget(@Param("tenantId") long tenantId,
@Param("inboundId") long inboundId);
@Update("UPDATE fl_inbound_order SET process_status='LOADED', updated_by=#{operatorId}, version=version+1 "
+ "WHERE tenant_id=#{tenantId} AND id=#{inboundId} AND deleted=0 AND process_status='LOADING' AND version=#{expectedVersion}")
int completeLoading(@Param("tenantId") long tenantId, @Param("inboundId") long inboundId,
@Param("operatorId") long operatorId, @Param("expectedVersion") int expectedVersion);
@Update("""
UPDATE fl_inbound_order child
JOIN fl_inbound_split_batch batch ON batch.loaded_child_inbound_id=child.id
AND batch.tenant_id=child.tenant_id AND batch.status='APPLIED'
JOIN fl_inbound_order source ON source.id=batch.source_inbound_id
AND source.tenant_id=batch.tenant_id AND source.deleted=0
SET child.process_status='LOADED', child.updated_by=#{operatorId}, child.version=child.version+1
WHERE child.tenant_id=#{tenantId} AND batch.source_inbound_id=#{sourceInboundId}
AND child.deleted=0 AND child.process_status='LOADING'
AND source.version=#{expectedSourceVersion}
""")
int completeLoadedChild(@Param("tenantId") long tenantId,
@Param("sourceInboundId") long sourceInboundId,
@Param("operatorId") long operatorId,
@Param("expectedSourceVersion") int expectedSourceVersion);
@Update("""
UPDATE fl_inbound_order root
SET root.process_status='LOADED', root.updated_by=#{operatorId}, root.version=root.version+1
WHERE root.tenant_id=#{tenantId} AND root.id=#{rootInboundId} AND root.deleted=0
AND root.inbound_role='MASTER' AND root.process_status IN ('INBOUNDED','LOADING')
AND NOT EXISTS (
SELECT 1 FROM fl_inbound_order remainder
WHERE remainder.tenant_id=root.tenant_id AND remainder.parent_inbound_id=root.id
AND remainder.inbound_role='CHILD' AND remainder.split_purpose='REMAINDER'
AND remainder.split_status='NOT_SPLIT' AND remainder.deleted=0)
AND NOT EXISTS (
SELECT 1 FROM fl_inbound_order loaded
WHERE loaded.tenant_id=root.tenant_id AND loaded.parent_inbound_id=root.id
AND loaded.inbound_role='CHILD' AND loaded.split_purpose='LOADED'
AND loaded.process_status<>'LOADED' AND loaded.deleted=0)
""")
int aggregateRootLoaded(@Param("tenantId") long tenantId,
@Param("rootInboundId") long rootInboundId,
@Param("operatorId") long operatorId);
record Snapshot(Long id, Long tenantId, String processStatus, Integer version) {}
record CompletionTarget(Long sourceInboundId, Long loadedChildInboundId, Long rootInboundId,
String sourceStatus, Integer sourceVersion,
String loadedChildStatus, Integer loadedChildVersion) {}
}
@@ -29,6 +29,19 @@ public class LoadingRepository {
return inbounds.completeLoading(tenantId, inboundId, operatorId, expectedVersion);
}
public LoadingInboundMapper.CompletionTarget completionTarget(long tenantId, long inboundId) {
return inbounds.completionTarget(tenantId, inboundId);
}
public int completeLoadedChild(long tenantId, long sourceInboundId, long operatorId,
int expectedSourceVersion) {
return inbounds.completeLoadedChild(tenantId, sourceInboundId, operatorId, expectedSourceVersion);
}
public int aggregateRootLoaded(long tenantId, long rootInboundId, long operatorId) {
return inbounds.aggregateRootLoaded(tenantId, rootInboundId, operatorId);
}
public List<LoadingEvidenceEntity> listEvidence(long tenantId, long inboundId) {
return evidences.selectList(new LambdaQueryWrapper<LoadingEvidenceEntity>()
.eq(LoadingEvidenceEntity::getTenantId, tenantId)
@@ -14,6 +14,7 @@ import com.baiyue.firstleg.loading.entity.InboundLoadingPickTaskEntity;
import com.baiyue.firstleg.loading.domain.PickingStatus;
import com.baiyue.firstleg.loading.dto.LoadingResponses.PickingResponse;
import com.baiyue.firstleg.loading.mapper.LoadingInboundMapper.Snapshot;
import com.baiyue.firstleg.loading.mapper.LoadingInboundMapper.CompletionTarget;
import com.baiyue.firstleg.loading.bridge.service.LoadingModelBridgeService;
import com.baiyue.firstleg.loading.repository.LoadingRepository;
import com.baiyue.firstleg.repository.LoadingPickRepository;
@@ -98,6 +99,10 @@ public class LoadingDeliveryService {
LoadingActionResponse replay = claimOrReplay(tenantId, inboundId, operatorId, COMPLETE_LOADING, key, hash);
if (replay != null) return replay;
Snapshot inbound = requireInbound(tenantId, inboundId);
CompletionTarget target = repository.completionTarget(tenantId, inboundId);
if (target != null) {
return completeFulfillmentSlice(tenantId, inboundId, operatorId, operatorName, key, request, target);
}
if ("LOADED".equals(inbound.processStatus()) || "DELIVERED".equals(inbound.processStatus())) {
loadingModelBridge.requireCompleted(tenantId, inboundId);
return complete(tenantId, inboundId, operatorId, COMPLETE_LOADING, key,
@@ -114,6 +119,30 @@ public class LoadingDeliveryService {
new LoadingActionResponse("LOADED", evidenceResponse(tenantId, inboundId)));
}
private LoadingActionResponse completeFulfillmentSlice(long tenantId, long evidenceInboundId,
long operatorId, String operatorName, String key,
CompleteLoadingRequest request,
CompletionTarget target) {
if ("LOADED".equals(target.loadedChildStatus())) {
return complete(tenantId, evidenceInboundId, operatorId, COMPLETE_LOADING, key,
new LoadingActionResponse("LOADED", evidenceResponse(tenantId, evidenceInboundId)));
}
if (!"LOADING".equals(target.loadedChildStatus())) {
throw new BizException(ResultCode.CONFLICT, "实装履约分片不在装柜中");
}
loadingModelBridge.requireCompleted(tenantId, target.sourceInboundId());
completionGate.requireBookingTransportAndCustoms(tenantId, target.sourceInboundId());
requireCompletedPicking(tenantId, target.sourceInboundId());
requireCompletionEvidence(tenantId, target.sourceInboundId());
if (repository.completeLoadedChild(tenantId, target.sourceInboundId(), operatorId,
request.expectedVersion()) != 1) throw concurrent();
repository.aggregateRootLoaded(tenantId, target.rootInboundId(), operatorId);
addHistory(tenantId, target.loadedChildInboundId(), "LOADING", "LOADED", COMPLETE_LOADING,
request.remark(), operatorId, operatorName);
return complete(tenantId, evidenceInboundId, operatorId, COMPLETE_LOADING, key,
new LoadingActionResponse("LOADED", evidenceResponse(tenantId, evidenceInboundId)));
}
public EvidenceListResponse evidence(long tenantId, long inboundId) {
requireLoadingStage(tenantId, inboundId);
return evidenceResponse(tenantId, inboundId);
@@ -274,6 +303,8 @@ public class LoadingDeliveryService {
private Snapshot requireLoadingStage(long tenantId, long inboundId) {
Snapshot value = requireInbound(tenantId, inboundId);
CompletionTarget target = repository.completionTarget(tenantId, inboundId);
if (target != null && Set.of("LOADING", "LOADED").contains(target.loadedChildStatus())) return value;
if (!("LOADING".equals(value.processStatus()) || "LOADED".equals(value.processStatus())
|| "DELIVERED".equals(value.processStatus()))) {
throw new BizException(ResultCode.CONFLICT, "订单尚未进入装柜阶段");
@@ -285,6 +316,13 @@ public class LoadingDeliveryService {
* corrections are handled by the offline/manual process defined for phase three. */
private Snapshot requireMutableLoadingStage(long tenantId, long inboundId) {
Snapshot value = requireInbound(tenantId, inboundId);
CompletionTarget target = repository.completionTarget(tenantId, inboundId);
if (target != null) {
if (!"LOADING".equals(target.loadedChildStatus())) {
throw new BizException(ResultCode.CONFLICT, "装柜完成后不允许在线修改证据");
}
return value;
}
if (!"LOADING".equals(value.processStatus())) {
throw new BizException(ResultCode.CONFLICT, "装柜完成后不允许在线修改证据");
}
@@ -44,7 +44,8 @@ public interface InboundSplitSettlementMapper {
actual_net_weight_kg,measure_completed_at,inbounded_at,express_company_code,express_company_name,
express_tracking_no,public_remark,created_by,created_by_name,created_at,updated_by,updated_at,deleted,version,
inbound_role,parent_inbound_id,root_inbound_id,split_sequence,split_status,split_purpose)
SELECT #{childId},tenant_id,task_id,order_id,order_no,#{childInboundCode},'INBOUNDED',order_status_snapshot,
SELECT #{childId},tenant_id,task_id,order_id,order_no,#{childInboundCode},
CASE WHEN #{splitPurpose}='LOADED' THEN 'LOADING' ELSE 'INBOUNDED' END,order_status_snapshot,
'APPROVED',fee_status,fee_review_status,notification_status,expected_arrival_at,customer_id,customer_name,
company_id,company_name,warehouse_id,warehouse_name,delivery_warehouse_id,delivery_warehouse_name,business_type,
channel_code,channel_name,carrier_id,carrier_name,tax_mode,pricing_tax_mode,container_mode,customs_inspection,
@@ -153,7 +153,7 @@ public class UnifiedInboundQueryService {
: "CONFIRMED".equals(preloadStatus) ? null
: preloadStatus == null ? "SMART_SPLIT" : "CONFIRM_PRELOAD";
case "LOADING" -> "COMPLETE_LOADING";
case "LOADED" -> "COMPLETE_DELIVERY";
case "LOADED" -> null;
case "DELIVERED" -> null;
default -> null;
};
@@ -160,13 +160,13 @@ CREATE TABLE IF NOT EXISTS fl_inbound_split_item (
child_inbound_id BIGINT UNSIGNED NOT NULL COMMENT '子入仓单ID',
line_no INT UNSIGNED NOT NULL COMMENT '同一拆分批次内的行号',
source_inbound_detail_id BIGINT UNSIGNED NULL COMMENT '订单货物明细逻辑ID',
source_measurement_id BIGINT UNSIGNED NULL COMMENT '来源测量批次ID',
source_measurement_item_id BIGINT UNSIGNED NULL COMMENT '来源测量箱规明细ID',
source_measurement_id BIGINT UNSIGNED NOT NULL COMMENT '来源测量批次ID',
source_measurement_item_id BIGINT UNSIGNED NOT NULL COMMENT '来源测量箱规明细ID',
package_count INT UNSIGNED NOT NULL COMMENT '分配给子单的箱数',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_inbound_split_batch_line (tenant_id, split_batch_id, line_no),
UNIQUE KEY uk_inbound_split_batch_source_item (tenant_id, split_batch_id, source_measurement_item_id),
UNIQUE KEY uk_inbound_split_batch_source_child (tenant_id, split_batch_id, source_measurement_item_id, child_inbound_id),
KEY idx_inbound_split_detail (tenant_id, source_inbound_detail_id, created_at),
CONSTRAINT chk_inbound_split_item_package CHECK (package_count > 0),
CONSTRAINT fk_inbound_split_item_batch FOREIGN KEY (split_batch_id) REFERENCES fl_inbound_split_batch (id),
@@ -232,6 +232,9 @@ CALL phase3_inbound_add_column(
CALL phase3_inbound_add_column(
'fl_inbound_split_item', 'line_no',
"INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '同一拆分批次内的行号' AFTER child_inbound_id");
ALTER TABLE fl_inbound_split_item
MODIFY source_measurement_id BIGINT UNSIGNED NOT NULL COMMENT '来源测量批次ID',
MODIFY source_measurement_item_id BIGINT UNSIGNED NOT NULL COMMENT '来源测量箱规明细ID';
CALL phase3_inbound_add_column(
'fl_inbound_split_batch', 'loaded_child_inbound_id',
"BIGINT UNSIGNED NULL COMMENT '本批次实装子单ID' AFTER package_count");
@@ -339,6 +342,9 @@ CALL phase3_inbound_add_index(
CALL phase3_inbound_add_index(
'fl_inbound_split_batch', 'idx_inbound_split_loading_plan',
'KEY `idx_inbound_split_loading_plan` (`tenant_id`, `loading_plan_id`, `container_booking_id`, `status`, `id`)');
CALL phase3_inbound_add_index(
'fl_inbound_split_batch', 'uk_inbound_split_source_once',
'UNIQUE KEY `uk_inbound_split_source_once` (`tenant_id`, `source_inbound_id`)');
DROP PROCEDURE IF EXISTS phase3_inbound_drop_split_legacy_index;
DELIMITER $$
@@ -395,6 +401,9 @@ BEGIN
IF NEW.inbound_role = 'MASTER' AND NEW.parent_inbound_id IS NOT NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '主入仓单不能绑定父单';
END IF;
IF NEW.inbound_role = 'MASTER' AND NEW.split_purpose <> 'MASTER' THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '主入仓单用途必须为MASTER';
END IF;
IF NEW.inbound_role = 'CHILD' THEN
IF NEW.parent_inbound_id IS NULL OR NEW.root_inbound_id IS NULL
OR NEW.split_sequence IS NULL OR NEW.package_count IS NULL THEN
@@ -419,7 +428,8 @@ CREATE TRIGGER trg_inbound_order_parent_before_update
BEFORE UPDATE ON fl_inbound_order
FOR EACH ROW
BEGIN
IF NOT (OLD.inbound_role <=> NEW.inbound_role)
IF NOT (OLD.tenant_id <=> NEW.tenant_id)
OR NOT (OLD.inbound_role <=> NEW.inbound_role)
OR NOT (OLD.parent_inbound_id <=> NEW.parent_inbound_id)
OR NOT (OLD.root_inbound_id <=> NEW.root_inbound_id)
OR NOT (OLD.split_sequence <=> NEW.split_sequence)
@@ -436,8 +446,9 @@ BEGIN
IF NEW.split_status NOT IN ('NOT_SPLIT', 'PARTIALLY_SPLIT', 'FULLY_SPLIT') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '入仓单拆分状态非法';
END IF;
IF NEW.inbound_role = 'CHILD' AND NEW.split_purpose = 'MASTER' THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '子入仓单用途非法';
IF (NEW.inbound_role = 'CHILD' AND NEW.split_purpose = 'MASTER')
OR (NEW.inbound_role = 'MASTER' AND NEW.split_purpose <> 'MASTER') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '入仓单层级与用途不一致';
END IF;
IF NEW.inbound_role = 'MASTER'
AND ((NEW.package_count = 0 AND NEW.split_status <> 'FULLY_SPLIT')
@@ -450,6 +461,9 @@ CREATE TRIGGER trg_inbound_split_item_before_insert
BEFORE INSERT ON fl_inbound_split_item
FOR EACH ROW
BEGIN
IF NEW.source_measurement_id IS NULL OR NEW.source_measurement_item_id IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分明细必须绑定真实测量来源';
END IF;
IF NOT EXISTS (
SELECT 1
FROM fl_inbound_split_batch batch
@@ -467,7 +481,7 @@ BEGIN
AND child_order.parent_inbound_id = NEW.parent_inbound_id
AND child_order.package_count >= NEW.package_count
AND child_order.deleted = 0
AND (NEW.source_measurement_item_id IS NULL OR EXISTS (
AND EXISTS (
SELECT 1
FROM fl_inbound_measurement_item source_item
JOIN fl_inbound_measurement source_batch ON source_batch.id = source_item.measurement_id
@@ -475,7 +489,7 @@ BEGIN
AND source_item.tenant_id = NEW.tenant_id
AND source_item.measurement_id = NEW.source_measurement_id
AND source_batch.inbound_id = COALESCE(batch.source_inbound_id, batch.parent_inbound_id)
))
)
) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分明细与批次、主单或子单不一致';
END IF;
@@ -497,23 +511,32 @@ BEGIN
) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分批次主单不存在或客户归属不一致';
END IF;
IF NEW.source_inbound_id IS NOT NULL AND NOT EXISTS (
IF NEW.source_inbound_id IS NULL OR NOT EXISTS (
SELECT 1 FROM fl_inbound_order source_order
WHERE source_order.id = NEW.source_inbound_id
AND source_order.tenant_id = NEW.tenant_id
AND source_order.deleted = 0
AND (source_order.id = NEW.parent_inbound_id OR
AND source_order.package_count = NEW.package_count
AND ((source_order.id = NEW.parent_inbound_id
AND source_order.inbound_role = 'MASTER'
AND source_order.split_status = 'NOT_SPLIT') OR
(source_order.inbound_role = 'CHILD'
AND source_order.parent_inbound_id = NEW.parent_inbound_id
AND source_order.split_purpose = 'REMAINDER'))
AND source_order.split_purpose = 'REMAINDER'
AND source_order.split_status = 'NOT_SPLIT'))
) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分批次来源必须是根主单或其余量子单';
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分批次来源必须是箱数匹配且未消费的根主单或余量子单';
END IF;
IF NEW.loaded_package_count > 0 AND (
NEW.loading_plan_id IS NULL OR NEW.container_booking_id IS NULL OR NOT EXISTS (
SELECT 1 FROM fl_loading_plan plan
WHERE plan.id = NEW.loading_plan_id
AND plan.container_booking_id = NEW.container_booking_id
AND EXISTS (SELECT 1 FROM fl_loading_plan_item plan_item
WHERE plan_item.loading_plan_id = plan.id
AND plan_item.account_id = NEW.tenant_id
AND plan_item.inbound_id = NEW.source_inbound_id
AND plan_item.deleted = 0)
)
) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '实装拆分批次必须绑定匹配的装柜计划和柜次';
@@ -544,13 +567,23 @@ BEGIN
NEW.loading_plan_id IS NULL OR NEW.container_booking_id IS NULL OR NOT EXISTS (
SELECT 1 FROM fl_loading_plan plan
WHERE plan.id = NEW.loading_plan_id
AND plan.container_booking_id = NEW.container_booking_id)))
AND plan.container_booking_id = NEW.container_booking_id
AND EXISTS (SELECT 1 FROM fl_loading_plan_item plan_item
WHERE plan_item.loading_plan_id = plan.id
AND plan_item.account_id = NEW.tenant_id
AND plan_item.inbound_id = NEW.source_inbound_id
AND plan_item.deleted = 0)))
OR NOT EXISTS (
SELECT 1 FROM fl_inbound_order parent_order
WHERE parent_order.id = NEW.parent_inbound_id
AND parent_order.tenant_id = NEW.tenant_id
AND parent_order.inbound_role = 'MASTER'
AND parent_order.version > NEW.expected_parent_version
) OR NOT EXISTS (
SELECT 1 FROM fl_inbound_order source_order
WHERE source_order.id = NEW.source_inbound_id
AND source_order.tenant_id = NEW.tenant_id
AND source_order.split_status = 'FULLY_SPLIT'
) OR
(SELECT COALESCE(SUM(item.package_count), 0)
FROM fl_inbound_split_item item
@@ -126,7 +126,7 @@ CREATE TABLE IF NOT EXISTS fl_inbound_split_detail (
source_package_count > 1 AND locked_package_count > 0
AND locked_package_count < source_package_count
),
CONSTRAINT chk_inbound_split_status CHECK (status IN ('LOCKED', 'COMPLETED')),
CONSTRAINT chk_legacy_inbound_split_status CHECK (status IN ('LOCKED', 'COMPLETED')),
CONSTRAINT chk_inbound_split_completion CHECK (
(status = 'LOCKED' AND child_inbound_id IS NULL AND completed_at IS NULL)
OR (status = 'COMPLETED' AND child_inbound_id IS NOT NULL AND completed_at IS NOT NULL)
@@ -143,39 +143,14 @@ CREATE TRIGGER trg_inbound_split_detail_before_insert
BEFORE INSERT ON fl_inbound_split_detail
FOR EACH ROW
BEGIN
DECLARE v_parent_tenant BIGINT UNSIGNED;
DECLARE v_parent_parent BIGINT UNSIGNED;
SELECT tenant_id, parent_inbound_id INTO v_parent_tenant, v_parent_parent
FROM fl_inbound_order WHERE id = NEW.parent_inbound_id AND deleted = 0;
IF v_parent_tenant <> NEW.tenant_id OR v_parent_parent IS NOT NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '部分锁定只能发生在客户所属主入库单';
END IF;
IF NEW.status <> 'LOCKED' OR NEW.child_inbound_id IS NOT NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '部分锁定创建时不能提前绑定二级子入库单';
END IF;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '旧部分锁定台账已退役,请使用主子分片批次';
END$$
CREATE TRIGGER trg_inbound_split_detail_before_update
BEFORE UPDATE ON fl_inbound_split_detail
FOR EACH ROW
BEGIN
DECLARE v_child_tenant BIGINT UNSIGNED;
DECLARE v_child_parent BIGINT UNSIGNED;
IF NEW.tenant_id <> OLD.tenant_id OR NEW.parent_inbound_id <> OLD.parent_inbound_id
OR NEW.inbound_detail_id <> OLD.inbound_detail_id
OR NEW.source_package_count <> OLD.source_package_count
OR NEW.locked_package_count <> OLD.locked_package_count
OR NEW.operation_id <> OLD.operation_id THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '部分锁定的归属和箱数创建后不可修改';
END IF;
IF OLD.status <> 'LOCKED' OR NEW.status <> 'COMPLETED' OR NEW.child_inbound_id IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '部分锁定只允许完成并绑定二级子入库单';
END IF;
SELECT tenant_id, parent_inbound_id INTO v_child_tenant, v_child_parent
FROM fl_inbound_order WHERE id = NEW.child_inbound_id AND deleted = 0;
IF v_child_tenant <> NEW.tenant_id OR v_child_parent <> NEW.parent_inbound_id THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '剩余箱数必须绑定主单唯一二级子入库单';
END IF;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '旧部分锁定台账只读,不允许更新';
END$$
CREATE TRIGGER trg_inbound_split_detail_before_delete
@@ -52,8 +52,7 @@ class UnifiedInboundQueryServiceTest {
assertThat(UnifiedInboundQueryService.nextAction("INBOUNDED", "INBOUNDED", "CONFIRMED")).isNull();
assertThat(UnifiedInboundQueryService.nextAction("INBOUNDED", "WAIT_SPLIT", null))
.isEqualTo("SMART_SPLIT");
assertThat(UnifiedInboundQueryService.nextAction("LOADED", "LOADED", null))
.isEqualTo("COMPLETE_DELIVERY");
assertThat(UnifiedInboundQueryService.nextAction("LOADED", "LOADED", null)).isNull();
assertThat(UnifiedInboundQueryService.nextAction("DELIVERED", "DELIVERED", null)).isNull();
}