CREATE TABLE mixed_pilot.control ( id int NOT NULL PRIMARY KEY CHECK(id=1), version varchar(30) NOT NULL, installed bit NOT NULL DEFAULT 1, enabled bit NOT NULL DEFAULT 0, all_projects_may_mix bit NOT NULL DEFAULT 0, min_free_e_slots int NOT NULL DEFAULT 2 CHECK(min_free_e_slots>=2) ); INSERT mixed_pilot.control(id,version,enabled,all_projects_may_mix) VALUES(1,'20260910-1',0,0); CREATE TABLE mixed_pilot.lane ( warehouse_id varchar(80) NOT NULL, lane_code varchar(80) NOT NULL, enabled bit NOT NULL DEFAULT 0, physical_fit_confirmed bit NOT NULL DEFAULT 0, protected bit NOT NULL DEFAULT 0, PRIMARY KEY(warehouse_id,lane_code) ); INSERT mixed_pilot.lane(warehouse_id,lane_code) VALUES('01','C1203'),('01','C0204'),('01','C0205'); CREATE TABLE mixed_pilot.module_backup ( object_name sysname NOT NULL PRIMARY KEY, original_definition nvarchar(max) NOT NULL, original_hash varbinary(32) NOT NULL, installed_hash varbinary(32) NULL, ansi_nulls bit NOT NULL, quoted_identifier bit NOT NULL ); CREATE TABLE mixed_pilot.installed_module ( object_name nvarchar(260) NOT NULL PRIMARY KEY, definition_hash varbinary(32) NOT NULL ); CREATE TABLE mixed_pilot.admission ( job_id varchar(255) NOT NULL PRIMARY KEY, lane_code varchar(80) NOT NULL, cargo_space_id varchar(80) NOT NULL, tray_code varchar(255) NOT NULL, resident_project varchar(255) NOT NULL, guest_project varchar(255) NOT NULL, created_at datetime2 NOT NULL DEFAULT SYSUTCDATETIME() ); CREATE TABLE mixed_pilot.move_audit ( job_id varchar(255) NOT NULL PRIMARY KEY, source_slot varchar(255) NOT NULL, target_slot varchar(255) NOT NULL, tray_code varchar(255) NOT NULL, completed_at datetime2 NULL ); CREATE TABLE mixed_pilot.dispatch_hold ( job_id varchar(255) NOT NULL PRIMARY KEY, created_at datetime2 NOT NULL DEFAULT SYSUTCDATETIME(), released_at datetime2 NULL ); GO -- A source position is inaccessible while ANY outer position has cargo or a live task. CREATE VIEW mixed_pilot.blocked_jobs AS SELECT j.job_id FROM dbo.mydo_job j JOIN dbo.bas_cargo_space s ON s.cargo_space_id=j.cargo_space_id JOIN mixed_pilot.lane l ON l.warehouse_id=s.warehouse_id AND l.lane_code=s.group_coding_no AND l.protected=1 WHERE j.in_or_out>=20 AND EXISTS ( SELECT 1 FROM dbo.bas_cargo_space b WHERE b.warehouse_id=s.warehouse_id AND b.group_coding_no=s.group_coding_no AND TRY_CONVERT(int,b.group_coding)>TRY_CONVERT(int,s.group_coding) AND (ISNULL(b.status,'')<>'1' OR ISNULL(b.locked,'')<>'N' OR NULLIF(b.tray_code,'') IS NOT NULL OR EXISTS(SELECT 1 FROM dbo.bas_stock x WHERE x.cargo_space_id=b.cargo_space_id) OR EXISTS(SELECT 1 FROM dbo.mydo_job x WHERE x.cargo_space_id=b.cargo_space_id OR x.target_cargo_space_id=b.cargo_space_id)) ); GO CREATE PROCEDURE mixed_pilot.release_ready_jobs AS BEGIN SET NOCOUNT ON; -- Clearing only a slot flag is insufficient: inventory and front tasks must also be gone. UPDATE j SET status='1' FROM dbo.mydo_job j JOIN mixed_pilot.dispatch_hold h ON h.job_id=j.job_id AND h.released_at IS NULL JOIN dbo.bas_cargo_space s ON s.cargo_space_id=j.cargo_space_id WHERE j.status='8' AND s.status='4' AND s.tray_code=j.tray_code AND EXISTS(SELECT 1 FROM dbo.bas_stock x WHERE x.cargo_space_id=s.cargo_space_id AND x.tray_code=j.tray_code) AND NOT EXISTS(SELECT 1 FROM mixed_pilot.blocked_jobs b WHERE b.job_id=j.job_id); UPDATE h SET released_at=SYSUTCDATETIME() FROM mixed_pilot.dispatch_hold h WHERE h.released_at IS NULL AND NOT EXISTS(SELECT 1 FROM dbo.mydo_job j WHERE j.job_id=h.job_id AND j.status='8'); END; GO CREATE TRIGGER dbo.tr_mixed_pilot_job_guard ON dbo.mydo_job AFTER INSERT,UPDATE,DELETE AS BEGIN SET NOCOUNT ON; IF TRIGGER_NESTLEVEL(OBJECT_ID('dbo.tr_mixed_pilot_job_guard'))>1 RETURN; IF NOT EXISTS(SELECT 1 FROM mixed_pilot.lane WHERE enabled=1 OR protected=1) RETURN; -- Coordinate with inbound reservation before checking whether a lane has just become mixed. DECLARE @locked int; SELECT @locked=COUNT(*) FROM dbo.bas_cargo_space s WITH(UPDLOCK,HOLDLOCK) JOIN mixed_pilot.lane l ON l.warehouse_id=s.warehouse_id AND l.lane_code=s.group_coding_no WHERE (l.enabled=1 OR l.protected=1) AND EXISTS( SELECT 1 FROM inserted i JOIN dbo.bas_cargo_space origin ON origin.cargo_space_id=i.cargo_space_id WHERE origin.warehouse_id=s.warehouse_id AND origin.group_coding_no=s.group_coding_no AND i.in_or_out>=20); IF EXISTS(SELECT 1 FROM inserted i JOIN mixed_pilot.blocked_jobs blocked ON blocked.job_id=i.job_id JOIN dbo.bas_cargo_space s ON s.cargo_space_id=i.cargo_space_id JOIN dbo.bas_cargo_space front ON front.warehouse_id=s.warehouse_id AND front.group_coding_no=s.group_coding_no AND TRY_CONVERT(int,front.group_coding)>TRY_CONVERT(int,s.group_coding) WHERE i.status='1' AND NOT EXISTS(SELECT 1 FROM dbo.mydo_job j WITH(UPDLOCK,HOLDLOCK) WHERE j.cargo_space_id=front.cargo_space_id AND j.tray_code=front.tray_code AND j.in_or_out>=20 AND j.status IN('1','3'))) THROW 51126,N'外侧尚未安排腾挪,请使用自动分配出库;外侧正在入库时请稍后重试。',1; INSERT mixed_pilot.dispatch_hold(job_id) SELECT DISTINCT i.job_id FROM inserted i JOIN mixed_pilot.blocked_jobs b ON b.job_id=i.job_id WHERE i.status='1' AND NOT EXISTS(SELECT 1 FROM mixed_pilot.dispatch_hold h WITH(UPDLOCK,HOLDLOCK) WHERE h.job_id=i.job_id); UPDATE j SET status='8' FROM dbo.mydo_job j JOIN inserted i ON i.job_id=j.job_id JOIN mixed_pilot.blocked_jobs b ON b.job_id=j.job_id WHERE j.status='1'; EXEC mixed_pilot.release_ready_jobs; END; GO CREATE TRIGGER dbo.tr_mixed_pilot_slot_release ON dbo.bas_cargo_space AFTER UPDATE AS BEGIN SET NOCOUNT ON; IF NOT EXISTS(SELECT 1 FROM inserted i JOIN mixed_pilot.lane l ON l.warehouse_id=i.warehouse_id AND l.lane_code=i.group_coding_no AND l.protected=1) RETURN; EXEC mixed_pilot.release_ready_jobs; END; GO CREATE TRIGGER dbo.tr_mixed_pilot_stock_release ON dbo.bas_stock AFTER UPDATE,DELETE AS BEGIN SET NOCOUNT ON; IF NOT EXISTS(SELECT 1 FROM deleted d JOIN dbo.bas_cargo_space s ON s.cargo_space_id=d.cargo_space_id JOIN mixed_pilot.lane l ON l.warehouse_id=s.warehouse_id AND l.lane_code=s.group_coding_no AND l.protected=1) RETURN; EXEC mixed_pilot.release_ready_jobs; END; GO CREATE PROCEDURE mixed_pilot.check_inbound @job_id varchar(255),@slot varchar(80) AS BEGIN SET NOCOUNT ON; IF @@TRANCOUNT=0 OR ISNULL(APPLOCK_MODE('public','FT546.mixed_pilot.inbound','Transaction'),'NoLock')<>'Exclusive' THROW 51129,N'试点入库校验必须由受保护的分配入口调用。',1; DECLARE @lane varchar(80),@warehouse varchar(80),@depth int,@project varchar(255),@tray varchar(255),@resident varchar(255),@rear varchar(80),@floor int; SELECT @lane=s.group_coding_no,@warehouse=s.warehouse_id,@depth=TRY_CONVERT(int,s.group_coding),@floor=s.the_floor FROM dbo.bas_cargo_space s JOIN mixed_pilot.lane l ON l.warehouse_id=s.warehouse_id AND l.lane_code=s.group_coding_no WHERE s.cargo_space_id=@slot AND (l.enabled=1 OR l.protected=1); IF @lane IS NULL RETURN; SELECT @project=line_id,@tray=tray_code FROM dbo.mydo_job WHERE job_id=@job_id AND warehouse_id=@warehouse AND in_or_out<20; IF @project IS NULL OR @project IN ('','999') OR @tray IS NULL THROW 51101,N'试点货位的任务项目或仓库不明确,请核对入库任务。',1; IF (SELECT COUNT(*) FROM dbo.bas_cargo_space WHERE warehouse_id=@warehouse AND group_coding_no=@lane)<>2 OR (SELECT COUNT(*) FROM dbo.bas_cargo_space WHERE warehouse_id=@warehouse AND group_coding_no=@lane AND TRY_CONVERT(int,group_coding)=1)<>1 OR (SELECT COUNT(*) FROM dbo.bas_cargo_space WHERE warehouse_id=@warehouse AND group_coding_no=@lane AND TRY_CONVERT(int,group_coding)=2)<>1 OR EXISTS(SELECT 1 FROM dbo.bas_cargo_space WHERE warehouse_id=@warehouse AND group_coding_no=@lane AND (this_cargo_area<>'C' OR TRY_CONVERT(int,group_coding) NOT IN(1,2) OR TRY_CONVERT(int,group_coding) IS NULL)) THROW 51102,N'试点仅支持已指定的双深C区通道。',1; IF NOT EXISTS(SELECT 1 FROM dbo.bas_cargo_space WHERE cargo_space_id=@slot AND status='1' AND locked='N' AND NULLIF(tray_code,'') IS NULL) OR EXISTS(SELECT 1 FROM dbo.bas_stock WHERE cargo_space_id=@slot) OR EXISTS(SELECT 1 FROM dbo.mydo_job j JOIN dbo.bas_cargo_space s ON s.cargo_space_id=j.cargo_space_id OR s.cargo_space_id=j.target_cargo_space_id WHERE s.warehouse_id=@warehouse AND s.group_coding_no=@lane AND j.job_id<>@job_id) THROW 51103,N'试点通道已有库存或在途任务,请稍后重试。',1; IF EXISTS(SELECT 1 FROM dbo.bas_cargo_space s WHERE s.warehouse_id=@warehouse AND s.group_coding_no=@lane AND (s.locked<>'N' OR s.status NOT IN('1','2'))) THROW 51104,N'试点通道正在作业或被锁定,请稍后重试。',1; IF @depth=1 AND EXISTS(SELECT 1 FROM dbo.bas_cargo_space s WHERE s.warehouse_id=@warehouse AND s.group_coding_no=@lane AND TRY_CONVERT(int,s.group_coding)=2 AND (s.status<>'1' OR NULLIF(s.tray_code,'') IS NOT NULL OR EXISTS(SELECT 1 FROM dbo.bas_stock x WHERE x.cargo_space_id=s.cargo_space_id))) THROW 51105,N'外侧尚有托盘,不能向通道内侧补货。',1; SELECT @rear=cargo_space_id FROM dbo.bas_cargo_space WHERE warehouse_id=@warehouse AND group_coding_no=@lane AND TRY_CONVERT(int,group_coding)=1; IF @depth<>2 OR NOT EXISTS(SELECT 1 FROM dbo.bas_cargo_space WHERE cargo_space_id=@rear AND status='2') RETURN; IF NOT EXISTS(SELECT 1 FROM dbo.mydo_job_detail WHERE job_id=@job_id) OR EXISTS(SELECT 1 FROM dbo.mydo_job_detail WHERE job_id=@job_id AND (NULLIF(spare4,'') IS NULL OR spare4<>@project)) OR (SELECT COUNT(DISTINCT spare4) FROM dbo.bas_stock WHERE cargo_space_id=@rear)<>1 OR EXISTS(SELECT 1 FROM dbo.bas_stock x JOIN dbo.bas_cargo_space s ON s.cargo_space_id=x.cargo_space_id WHERE x.cargo_space_id=@rear AND (NULLIF(x.spare4,'') IS NULL OR x.tray_code<>s.tray_code OR x.tray_code IS NULL OR ISNULL(x.out_quantity,0)<>0)) THROW 51106,N'托盘项目明细不一致或库存已分配,不能参与混放。',1; SELECT TOP(1) @resident=spare4 FROM dbo.bas_stock WHERE cargo_space_id=@rear; IF @resident=@project RETURN; IF @resident='999' OR NOT EXISTS(SELECT 1 FROM mixed_pilot.control WHERE id=1 AND enabled=1 AND all_projects_may_mix=1) OR NOT EXISTS(SELECT 1 FROM mixed_pilot.lane WHERE warehouse_id=@warehouse AND lane_code=@lane AND enabled=1 AND physical_fit_confirmed=1) THROW 51107,N'该通道未开放混放或尚未确认托盘适配。',1; IF (SELECT COUNT(*) FROM dbo.bas_cargo_space e WHERE e.warehouse_id=@warehouse AND e.the_floor=@floor AND e.this_cargo_area='E' AND e.status='1' AND e.locked='N' AND NULLIF(e.tray_code,'') IS NULL AND NOT EXISTS(SELECT 1 FROM dbo.bas_stock x WHERE x.cargo_space_id=e.cargo_space_id) AND NOT EXISTS(SELECT 1 FROM dbo.mydo_job x WHERE x.cargo_space_id=e.cargo_space_id OR x.target_cargo_space_id=e.cargo_space_id) AND NOT EXISTS(SELECT 1 FROM dbo.bas_cargo_space b WHERE b.warehouse_id=e.warehouse_id AND b.group_coding_no=e.group_coding_no AND TRY_CONVERT(int,b.group_coding)>TRY_CONVERT(int,e.group_coding) AND (b.status<>'1' OR b.locked<>'N' OR NULLIF(b.tray_code,'') IS NOT NULL OR EXISTS(SELECT 1 FROM dbo.bas_stock x WHERE x.cargo_space_id=b.cargo_space_id) OR EXISTS(SELECT 1 FROM dbo.mydo_job x WHERE x.cargo_space_id=b.cargo_space_id OR x.target_cargo_space_id=b.cargo_space_id)))) <(SELECT min_free_e_slots FROM mixed_pilot.control WHERE id=1) THROW 51108,N'同层可用移库空间不足,暂停新增混放。',1; UPDATE mixed_pilot.lane SET protected=1 WHERE warehouse_id=@warehouse AND lane_code=@lane; IF EXISTS(SELECT 1 FROM mixed_pilot.admission WHERE job_id=@job_id AND (cargo_space_id<>@slot OR tray_code<>@tray OR resident_project<>@resident OR guest_project<>@project)) THROW 51127,N'该任务已有不同的混放记录,请核对后重新创建任务。',1; IF NOT EXISTS(SELECT 1 FROM mixed_pilot.admission WHERE job_id=@job_id) INSERT mixed_pilot.admission(job_id,lane_code,cargo_space_id,tray_code,resident_project,guest_project) VALUES(@job_id,@lane,@slot,@tray,@resident,@project); END; GO CREATE PROCEDURE mixed_pilot.try_fallback @job_id varchar(255),@slot varchar(80) OUTPUT AS BEGIN SET NOCOUNT ON; SET @slot=NULL; IF NOT EXISTS(SELECT 1 FROM mixed_pilot.control WHERE id=1 AND enabled=1 AND all_projects_may_mix=1) RETURN; DECLARE @candidate varchar(80),@last_error nvarchar(2048); DECLARE candidates CURSOR LOCAL FAST_FORWARD FOR SELECT s.cargo_space_id FROM dbo.bas_cargo_space s JOIN mixed_pilot.lane l ON l.warehouse_id=s.warehouse_id AND l.lane_code=s.group_coding_no JOIN dbo.mydo_job j ON j.job_id=@job_id AND j.warehouse_id=s.warehouse_id WHERE l.enabled=1 AND l.physical_fit_confirmed=1 AND s.this_cargo_area='C' AND TRY_CONVERT(int,s.group_coding)=2 AND s.status='1' AND s.locked='N' AND NULLIF(s.tray_code,'') IS NULL AND EXISTS(SELECT 1 FROM dbo.bas_cargo_space r WHERE r.warehouse_id=s.warehouse_id AND r.group_coding_no=s.group_coding_no AND TRY_CONVERT(int,r.group_coding)=1 AND r.status='2') AND NOT EXISTS(SELECT 1 FROM dbo.bas_cargo_space busy WHERE busy.warehouse_id=s.warehouse_id AND busy.the_floor=s.the_floor AND busy.status='3') ORDER BY s.the_floor,s.group_coding_no; OPEN candidates; FETCH NEXT FROM candidates INTO @candidate; WHILE @@FETCH_STATUS=0 BEGIN BEGIN TRY EXEC mixed_pilot.check_inbound @job_id,@candidate; SET @slot=@candidate; END TRY BEGIN CATCH IF ERROR_NUMBER() NOT BETWEEN 51101 AND 51108 BEGIN CLOSE candidates; DEALLOCATE candidates; THROW; END; SET @last_error=ERROR_MESSAGE(); END CATCH; IF @slot IS NOT NULL BREAK; FETCH NEXT FROM candidates INTO @candidate; END; CLOSE candidates; DEALLOCATE candidates; IF @slot IS NULL AND @last_error IS NOT NULL THROW 51128,@last_error,1; END; GO CREATE PROCEDURE mixed_pilot.check_move @source varchar(255),@target varchar(255),@tray varchar(255) AS BEGIN SET NOCOUNT ON; DECLARE @floor int,@warehouse varchar(80),@src_lane varchar(80),@src_depth int,@dst_lane varchar(80),@dst_depth int,@dummy int; -- Lock both positions before the Legacy routine changes source/target or creates a task. SELECT @dummy=COUNT(*) FROM dbo.bas_cargo_space WITH(UPDLOCK,HOLDLOCK) WHERE cargo_space_id IN(@source,@target); SELECT @floor=the_floor,@warehouse=warehouse_id,@src_lane=group_coding_no,@src_depth=TRY_CONVERT(int,group_coding) FROM dbo.bas_cargo_space WHERE cargo_space_id=@source AND status='2' AND locked='N' AND tray_code=@tray; IF @floor IS NULL OR @source=@target OR NULLIF(@tray,'') IS NULL THROW 51111,N'移库起点、托盘或货位状态不一致,未创建移库任务。',1; IF EXISTS(SELECT 1 FROM dbo.mydo_job WITH(UPDLOCK,HOLDLOCK) WHERE tray_code=@tray OR cargo_space_id IN(@source,@target) OR target_cargo_space_id IN(@source,@target)) THROW 51112,N'移库起终点已有任务,未重复创建移库。',1; IF NOT EXISTS(SELECT 1 FROM dbo.bas_stock WITH(UPDLOCK,HOLDLOCK) WHERE cargo_space_id=@source AND tray_code=@tray) OR EXISTS(SELECT 1 FROM dbo.bas_stock WITH(UPDLOCK,HOLDLOCK) WHERE cargo_space_id=@source AND (tray_code<>@tray OR tray_code IS NULL OR ISNULL(out_quantity,0)<>0)) THROW 51113,N'移库源库存不一致或已分配,未创建移库任务。',1; SELECT @dst_lane=group_coding_no,@dst_depth=TRY_CONVERT(int,group_coding) FROM dbo.bas_cargo_space WHERE cargo_space_id=@target AND warehouse_id=@warehouse AND the_floor=@floor AND this_cargo_area='E' AND status='1' AND locked='N' AND NULLIF(tray_code,'') IS NULL; IF @dst_lane IS NULL OR @dst_depth IS NULL OR EXISTS(SELECT 1 FROM dbo.bas_stock WITH(UPDLOCK,HOLDLOCK) WHERE cargo_space_id=@target) THROW 51114,N'同层移库目标不可用,未创建移库任务。',1; SELECT @dummy=COUNT(*) FROM dbo.bas_cargo_space WITH(UPDLOCK,HOLDLOCK) WHERE warehouse_id=@warehouse AND group_coding_no IN(@src_lane,@dst_lane); IF EXISTS(SELECT 1 FROM dbo.bas_cargo_space b WITH(UPDLOCK,HOLDLOCK) WHERE b.warehouse_id=@warehouse AND ((b.group_coding_no=@src_lane AND TRY_CONVERT(int,b.group_coding)>@src_depth) OR (b.group_coding_no=@dst_lane AND TRY_CONVERT(int,b.group_coding)>@dst_depth)) AND (b.status<>'1' OR b.locked<>'N' OR NULLIF(b.tray_code,'') IS NOT NULL OR EXISTS(SELECT 1 FROM dbo.bas_stock x WITH(UPDLOCK,HOLDLOCK) WHERE x.cargo_space_id=b.cargo_space_id) OR EXISTS(SELECT 1 FROM dbo.mydo_job x WITH(UPDLOCK,HOLDLOCK) WHERE x.cargo_space_id=b.cargo_space_id OR x.target_cargo_space_id=b.cargo_space_id))) THROW 51115,N'移库路径外侧被占用,未创建移库任务。',1; END;