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;
};