/* FT546WMS shadow V3.3 -> V3.4, SQL Server 2016 RTM compatible. Run only after stopping the WMS shadow-enabled JVM and waiting >120 seconds. Changes only alg.*. Never executes or alters a Legacy procedure. One transaction: any failure rolls back columns, procedure, state and manifest. */ SET NOCOUNT ON; SET XACT_ABORT ON; SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; IF DB_NAME() <> N'FT546-wms' THROW 51060, 'V3.4 upgrade refused: expected FT546-wms database', 1; IF SCHEMA_ID(N'alg') IS NULL OR OBJECT_ID(N'alg.shadow_package_manifest', N'U') IS NULL THROW 51061, 'V3.4 upgrade refused: shadow package manifest is missing', 1; DECLARE @expected TABLE (object_name sysname PRIMARY KEY, object_type char(2) NOT NULL); INSERT INTO @expected VALUES (N'shadow_package_manifest','U'),(N'warehouse_policy','U'),(N'project_policy','U'), (N'space_role','U'),(N'space_topology','U'),(N'inventory_item_snapshot','U'), (N'space_inventory_summary','U'),(N'lane_state','U'),(N'reservation','U'), (N'deep_workflow_lock','U'),(N'decision_log','U'),(N'shadow_snapshot_state','U'), (N'cargo_space_snapshot','U'),(N'active_job_snapshot','U'), (N'shadow_inbound_request_snapshot','U'),(N'shadow_outbound_request_snapshot','U'), (N'shadow_runtime_metric','U'),(N'shadow_instance_heartbeat','U'), (N'v_inventory_item','V'),(N'v_active_job','V'),(N'v_space_state','V'), (N'usp_rebuild_space_topology','P'),(N'usp_sync_inventory_snapshot','P'), (N'usp_compute_lane_semantic_fingerprint','P'),(N'usp_rebuild_lane_state','P'), (N'usp_refresh_dirty_lanes','P'),(N'usp_claim_shadow_instance','P'), (N'usp_refresh_shadow_snapshot','P'); DECLARE @columns TABLE ( table_name sysname, column_name sysname, type_name sysname, max_length smallint, precision_value tinyint, scale_value tinyint, PRIMARY KEY (table_name, column_name)); INSERT INTO @columns VALUES (N'cargo_space_snapshot',N'this_cargo_area',N'varchar',255,0,0), (N'shadow_inbound_request_snapshot',N'spare1',N'varchar',255,0,0), (N'shadow_inbound_request_snapshot',N'spare2',N'varchar',255,0,0), (N'shadow_inbound_request_snapshot',N'spare3',N'varchar',255,0,0), (N'shadow_inbound_request_snapshot',N'fault_flag',N'varchar',255,0,0), (N'shadow_inbound_request_snapshot',N'detail_count',N'int',4,10,0), (N'shadow_inbound_request_snapshot',N'field_group_count',N'int',4,10,0), (N'shadow_inbound_request_snapshot',N'product_scope_count',N'int',4,10,0), (N'shadow_inbound_request_snapshot',N'tray_job_count',N'int',4,10,0), (N'shadow_inbound_request_snapshot',N'legacy_scope_complete',N'int',4,10,0), (N'shadow_inbound_request_snapshot',N'predicate_version',N'int',4,10,0); BEGIN TRY BEGIN TRANSACTION; DECLARE @version varchar(40); SELECT @version = package_version FROM alg.shadow_package_manifest WITH (UPDLOCK, HOLDLOCK) WHERE package_id = 'FT546WMS_SHADOW_ONLY'; IF @version IS NULL OR @version NOT IN ('2026-09-07-33', '2026-09-07-34') OR (SELECT COUNT(*) FROM alg.shadow_package_manifest) <> 1 THROW 51062, 'V3.4 upgrade refused: exact shadow manifest does not match', 1; IF EXISTS ( SELECT 1 FROM sys.objects object LEFT JOIN @expected expected ON expected.object_name = object.name AND expected.object_type = object.type COLLATE DATABASE_DEFAULT WHERE object.schema_id = SCHEMA_ID(N'alg') AND object.is_ms_shipped = 0 AND object.parent_object_id = 0 AND expected.object_name IS NULL) THROW 51063, 'V3.4 upgrade refused: unknown object exists in alg schema', 1; IF EXISTS ( SELECT 1 FROM @expected expected LEFT JOIN sys.objects object ON object.schema_id = SCHEMA_ID(N'alg') AND object.name = expected.object_name AND object.type COLLATE DATABASE_DEFAULT = expected.object_type WHERE object.object_id IS NULL) THROW 51064, 'V3.4 upgrade refused: expected object is missing or has wrong type', 1; IF EXISTS (SELECT 1 FROM sys.triggers trigger_object JOIN sys.objects parent_object ON parent_object.object_id = trigger_object.parent_id WHERE parent_object.schema_id = SCHEMA_ID(N'alg')) THROW 51065, 'V3.4 upgrade refused: unexpected trigger on shadow table', 1; IF EXISTS (SELECT 1 FROM alg.shadow_instance_heartbeat WITH (UPDLOCK, HOLDLOCK) WHERE last_seen_at >= DATEADD(SECOND, -120, SYSUTCDATETIME()) OR claimed_at >= DATEADD(SECOND, -120, SYSUTCDATETIME())) THROW 51066, 'V3.4 upgrade refused: recent shadow heartbeat; stop WMS and wait over 120 seconds', 1; IF @version = '2026-09-07-34' BEGIN IF EXISTS ( SELECT 1 FROM @columns expected LEFT JOIN sys.columns column_info ON column_info.object_id = OBJECT_ID(N'alg.' + expected.table_name) AND column_info.name = expected.column_name WHERE column_info.column_id IS NULL OR TYPE_NAME(column_info.user_type_id) <> expected.type_name OR column_info.max_length <> expected.max_length OR column_info.precision <> expected.precision_value OR column_info.scale <> expected.scale_value OR column_info.is_nullable <> 1) THROW 51067, 'V3.4 upgrade refused: target columns are missing or incompatible', 1; DECLARE @installed_definition nvarchar(max) = OBJECT_DEFINITION(OBJECT_ID(N'alg.usp_refresh_shadow_snapshot', N'P')); IF @installed_definition IS NULL OR CHARINDEX(N'INBOUND_JOB_FIELDS_V1', @installed_definition) = 0 OR CHARINDEX(N'field_group_count', @installed_definition) = 0 OR CHARINDEX(N'this_cargo_area', @installed_definition) = 0 THROW 51071, 'V3.4 upgrade refused: refresh procedure is missing, unreadable or obsolete', 1; COMMIT TRANSACTION; PRINT 'V34_ALREADY_INSTALLED'; RETURN; END; IF EXISTS ( SELECT 1 FROM @columns expected JOIN sys.columns column_info ON column_info.object_id = OBJECT_ID(N'alg.' + expected.table_name) AND column_info.name = expected.column_name) THROW 51068, 'V3.4 upgrade refused: partial or foreign predicate columns already exist', 1; IF COL_LENGTH(N'alg.inventory_item_snapshot', N'spare1') IS NULL OR COL_LENGTH(N'alg.shadow_outbound_request_snapshot', N'predicate_version') IS NULL THROW 51070, 'V3.4 upgrade refused: V3.3 predicate columns are missing', 1; ALTER TABLE alg.cargo_space_snapshot ADD this_cargo_area varchar(255) NULL; ALTER TABLE alg.shadow_inbound_request_snapshot ADD spare1 varchar(255) NULL, spare2 varchar(255) NULL, spare3 varchar(255) NULL, fault_flag varchar(255) NULL, detail_count int NULL, field_group_count int NULL, product_scope_count int NULL, tray_job_count int NULL, legacy_scope_complete int NULL, predicate_version int NULL; DECLARE @refresh_sql nvarchar(max) = N'ALTER PROCEDURE alg.usp_refresh_shadow_snapshot @warehouse_id varchar(80), @snapshot_generation bigint, @instance_id varchar(80) AS BEGIN -- INBOUND_JOB_FIELDS_V1: task-derived inbound fields and conservative eligibility evidence. SET NOCOUNT ON; SET XACT_ABORT ON; IF NULLIF(LTRIM(RTRIM(@warehouse_id)), '''') IS NULL THROW 51006, ''warehouse_id is required'', 1; IF NULLIF(LTRIM(RTRIM(@instance_id)), '''') IS NULL THROW 51007, ''instance_id is required'', 1; IF @snapshot_generation <= 0 THROW 51008, ''snapshot_generation must be positive'', 1; DECLARE @pre_source_count bigint, @post_source_count bigint, @pre_source_signature varbinary(32), @post_source_signature varbinary(32), @source_payload nvarchar(max), @synchronized_at datetime2, @numeric_warehouse_id decimal(38,0), @current_generation bigint; IF LTRIM(RTRIM(@warehouse_id)) NOT LIKE ''%[^0-9]%'' SET @numeric_warehouse_id = TRY_CONVERT(decimal(38,0), LTRIM(RTRIM(@warehouse_id))); BEGIN TRY BEGIN TRANSACTION; SELECT @current_generation = state.snapshot_generation FROM alg.shadow_snapshot_state state WITH (UPDLOCK, HOLDLOCK) WHERE state.warehouse_id = @warehouse_id; IF @current_generation IS NOT NULL AND @snapshot_generation <= @current_generation THROW 51009, ''snapshot_generation must advance the published generation'', 1; SELECT @pre_source_count = (SELECT COUNT_BIG(*) FROM dbo.bas_cargo_space cargo WITH (NOLOCK)) + (SELECT COUNT_BIG(*) FROM dbo.bas_stock stock WITH (NOLOCK) JOIN dbo.bas_cargo_space cargo WITH (NOLOCK) ON cargo.cargo_space_id = stock.cargo_space_id WHERE cargo.warehouse_id = @warehouse_id) + (SELECT COUNT_BIG(*) FROM dbo.mydo_job job WITH (NOLOCK)) + (SELECT COUNT_BIG(*) FROM dbo.mydo_job_detail detail WITH (NOLOCK) JOIN dbo.mydo_job job WITH (NOLOCK) ON job.job_id = detail.job_id) + (SELECT COUNT_BIG(*) FROM dbo.out_stockout_detail outbound WITH (NOLOCK) JOIN dbo.out_stockout stockout WITH (NOLOCK) ON stockout.stockout_id = outbound.stockout_id WHERE ISNULL(outbound.quantity, 0) > ISNULL(outbound.allot_quantity, 0) AND (LTRIM(RTRIM(stockout.warehouse_id)) = LTRIM(RTRIM(@warehouse_id)) OR (@numeric_warehouse_id IS NOT NULL AND LTRIM(RTRIM(stockout.warehouse_id)) NOT LIKE ''%[^0-9]%'' AND TRY_CONVERT(decimal(38,0), LTRIM(RTRIM(stockout.warehouse_id))) = @numeric_warehouse_id))); SELECT @source_payload = ISNULL(CONVERT(nvarchar(max), ( SELECT cargo.cargo_space_id AS [@space_id], cargo.warehouse_id AS [@warehouse_id], cargo.group_coding_no AS [@lane_code], cargo.cargo_area_id AS [@cargo_area_id], cargo.roadway_id AS [@roadway_id], cargo.cargo_space_name AS [@display_name], cargo.the_platoon AS [@platoon], cargo.the_column AS [@column_no], cargo.the_floor AS [@floor_no], cargo.group_coding AS [@depth_raw], cargo.status AS [@space_status], cargo.locked AS [@locked], cargo.tray_code AS [@tray_code], cargo.this_cargo_area AS [@this_cargo_area] FROM dbo.bas_cargo_space cargo WITH (NOLOCK) ORDER BY cargo.cargo_space_id FOR XML PATH(''cargo''), ROOT(''cargo_spaces''), TYPE )), ''''); SET @source_payload = @source_payload + ''|STOCK|'' + ISNULL(CONVERT(nvarchar(max), ( SELECT stock.stock_id AS [@stock_id], stock.cargo_space_id AS [@space_id], stock.warehouse_id AS [@warehouse_id], stock.tray_code AS [@tray_code], stock.spare4 AS [@project_no], stock.product_id AS [@product_no], stock.lot_no AS [@lot_no], stock.in_date AS [@in_date], stock.quantity AS [@quantity], stock.out_quantity AS [@out_quantity], stock.spare1 AS [@spare1], stock.spare2 AS [@spare2], stock.spare3 AS [@spare3], stock.voltage AS [@voltage], stock.phase AS [@phase], (SELECT COUNT(*) FROM dbo.mydo_job trayJob WITH (NOLOCK) WHERE trayJob.tray_code = stock.tray_code) AS [@tray_job_count] FROM dbo.bas_stock stock WITH (NOLOCK) JOIN dbo.bas_cargo_space cargo WITH (NOLOCK) ON cargo.cargo_space_id = stock.cargo_space_id WHERE cargo.warehouse_id = @warehouse_id ORDER BY stock.stock_id FOR XML PATH(''stock''), ROOT(''stocks''), TYPE )), ''''); SET @source_payload = @source_payload + ''|JOB|'' + ISNULL(CONVERT(nvarchar(max), ( SELECT job.job_id AS [@job_id], job.status AS [@status], job.task_no AS [@task_no], job.tray_code AS [@tray_code], job.cargo_space_id AS [@source_space_id], job.target_cargo_space_id AS [@target_space_id], job.in_or_out AS [@in_or_out], job.create_time AS [@create_time], job.finish_time AS [@finish_time], job.warehouse_id AS [@warehouse_id], job.line_id AS [@line_id], job.fault_flag AS [@fault_flag] FROM dbo.mydo_job job WITH (NOLOCK) ORDER BY job.job_id FOR XML PATH(''job''), ROOT(''jobs''), TYPE )), ''''); SET @source_payload = @source_payload + ''|JOB_DETAIL|'' + ISNULL(CONVERT(nvarchar(max), ( SELECT detail.job_detail_id AS [@job_detail_id], detail.job_id AS [@job_id], detail.stock_id AS [@stock_id], detail.lot_no AS [@lot_no], detail.in_date AS [@in_date], detail.in_or_out_id AS [@request_id], detail.in_or_out_d_id AS [@request_detail_id], detail.product_id AS [@product_id], detail.stock_status AS [@stock_status], detail.in_quantity AS [@in_quantity], detail.stock_quantity AS [@stock_quantity], detail.out_quantity AS [@out_quantity], detail.pick_quantity AS [@pick_quantity], detail.stockin_detail_id AS [@stockin_detail_id], detail.spare1 AS [@spare1], detail.spare2 AS [@spare2], detail.spare3 AS [@spare3] FROM dbo.mydo_job_detail detail WITH (NOLOCK) JOIN dbo.mydo_job job WITH (NOLOCK) ON job.job_id = detail.job_id ORDER BY detail.job_detail_id FOR XML PATH(''job_detail''), ROOT(''job_details''), TYPE )), ''''); SET @source_payload = @source_payload + ''|OUTBOUND|'' + ISNULL(CONVERT(nvarchar(max), ( SELECT outbound.stockout_detail_id AS [@stockout_detail_id], outbound.warehouse_id AS [@warehouse_id], stockout.warehouse_id AS [@source_warehouse_id], outbound.spare4 AS [@project_no], outbound.spare1 AS [@spare1], outbound.spare2 AS [@spare2], outbound.spare3 AS [@spare3], outbound.fid AS [@voltage], outbound.unit AS [@phase], outbound.product_id AS [@product_id], outbound.lot_no AS [@lot_no], outbound.quantity AS [@quantity], outbound.assign_num AS [@assign_num], outbound.allot_quantity AS [@allot_quantity] FROM dbo.out_stockout_detail outbound WITH (NOLOCK) JOIN dbo.out_stockout stockout WITH (NOLOCK) ON stockout.stockout_id = outbound.stockout_id WHERE ISNULL(outbound.quantity, 0) > ISNULL(outbound.allot_quantity, 0) AND (LTRIM(RTRIM(stockout.warehouse_id)) = LTRIM(RTRIM(@warehouse_id)) OR (@numeric_warehouse_id IS NOT NULL AND LTRIM(RTRIM(stockout.warehouse_id)) NOT LIKE ''%[^0-9]%'' AND TRY_CONVERT(decimal(38,0), LTRIM(RTRIM(stockout.warehouse_id))) = @numeric_warehouse_id)) ORDER BY outbound.stockout_detail_id FOR XML PATH(''outbound''), ROOT(''outbound_requests''), TYPE )), ''''); SET @pre_source_signature = HASHBYTES(''SHA2_256'', CONVERT(varbinary(max), @source_payload)); DELETE FROM alg.cargo_space_snapshot WHERE warehouse_id = @warehouse_id; DELETE FROM alg.inventory_item_snapshot WHERE warehouse_id = @warehouse_id; DELETE FROM alg.active_job_snapshot WHERE warehouse_id = @warehouse_id; DELETE FROM alg.shadow_inbound_request_snapshot WHERE warehouse_id = @warehouse_id; DELETE FROM alg.shadow_outbound_request_snapshot WHERE warehouse_id = @warehouse_id; DELETE FROM alg.space_topology WHERE warehouse_id = @warehouse_id; DELETE FROM alg.space_inventory_summary WHERE warehouse_id = @warehouse_id; DELETE FROM alg.lane_state WHERE warehouse_id = @warehouse_id; SET @synchronized_at = SYSUTCDATETIME(); INSERT INTO alg.cargo_space_snapshot ( warehouse_id, space_id, lane_code, cargo_area_id, roadway_id, display_name, platoon, column_no, floor_no, depth_raw, space_status, locked, tray_code, snapshot_generation, synchronized_at, this_cargo_area) SELECT cargo.warehouse_id, cargo.cargo_space_id, cargo.group_coding_no, cargo.cargo_area_id, cargo.roadway_id, cargo.cargo_space_name, cargo.the_platoon, cargo.the_column, cargo.the_floor, cargo.group_coding, cargo.status, cargo.locked, cargo.tray_code, @snapshot_generation, @synchronized_at, cargo.this_cargo_area FROM dbo.bas_cargo_space cargo WITH (NOLOCK) WHERE cargo.warehouse_id = @warehouse_id; INSERT INTO alg.inventory_item_snapshot ( warehouse_id, stock_id, space_id, tray_code, project_no, product_no, lot_no, inbound_time_raw, inbound_at, quantity, out_quantity, snapshot_generation, synchronized_at, spare1, spare2, spare3, voltage, phase, tray_job_count) SELECT cargo.warehouse_id, stock.stock_id, stock.cargo_space_id, stock.tray_code, stock.spare4, stock.product_id, stock.lot_no, stock.in_date, TRY_CONVERT(datetime2, stock.in_date), stock.quantity, stock.out_quantity, @snapshot_generation, @synchronized_at, stock.spare1, stock.spare2, stock.spare3, stock.voltage, stock.phase, (SELECT COUNT(*) FROM dbo.mydo_job trayJob WITH (NOLOCK) WHERE trayJob.tray_code = stock.tray_code) FROM dbo.bas_stock stock WITH (NOLOCK) JOIN dbo.bas_cargo_space cargo WITH (NOLOCK) ON cargo.cargo_space_id = stock.cargo_space_id WHERE cargo.warehouse_id = @warehouse_id; INSERT INTO alg.active_job_snapshot ( warehouse_id, job_id, task_no, tray_code, source_space_id, target_space_id, status, in_or_out, create_time_raw, snapshot_generation, synchronized_at) SELECT job.warehouse_id, job.job_id, job.task_no, job.tray_code, NULLIF(LTRIM(RTRIM(job.cargo_space_id)), ''''), NULLIF(LTRIM(RTRIM(job.target_cargo_space_id)), ''''), job.status, job.in_or_out, job.create_time, @snapshot_generation, @synchronized_at FROM dbo.mydo_job job WITH (NOLOCK) WHERE job.warehouse_id = @warehouse_id AND (job.finish_time IS NULL OR LTRIM(RTRIM(job.finish_time)) = ''''); ;WITH inbound_detail_groups AS ( SELECT detail.job_id, detail.spare1, detail.spare2, detail.spare3 FROM dbo.mydo_job_detail detail WITH (NOLOCK) GROUP BY detail.job_id, detail.spare1, detail.spare2, detail.spare3 ), inbound_product_scopes AS ( SELECT detail.job_id, detail.product_id, detail.lot_no FROM dbo.mydo_job_detail detail WITH (NOLOCK) GROUP BY detail.job_id, detail.product_id, detail.lot_no ), inbound_details AS ( SELECT detail.job_id, COUNT(*) AS detail_count, MIN(detail.spare1) AS spare1, MIN(detail.spare2) AS spare2, MIN(detail.spare3) AS spare3, MIN(detail.product_id) AS product_id, MIN(detail.lot_no) AS lot_no, MAX(ISNULL(DATALENGTH(detail.spare1), 0)) AS spare1_bytes, MAX(ISNULL(DATALENGTH(detail.spare2), 0)) AS spare2_bytes, MAX(ISNULL(DATALENGTH(detail.spare3), 0)) AS spare3_bytes FROM dbo.mydo_job_detail detail WITH (NOLOCK) GROUP BY detail.job_id ), inbound_source AS ( SELECT job.task_no, job.tray_code, job.job_id AS request_id, job.warehouse_id AS raw_warehouse_id, job.line_id AS project_no, job.fault_flag, detail.product_id, detail.lot_no, detail.spare1, detail.spare2, detail.spare3, ISNULL(detail.detail_count, 0) AS detail_count, (SELECT COUNT(*) FROM inbound_detail_groups groups WHERE groups.job_id = job.job_id) AS field_group_count, (SELECT COUNT(*) FROM inbound_product_scopes scopes WHERE scopes.job_id = job.job_id) AS product_scope_count, (SELECT COUNT(*) FROM dbo.mydo_job trayJob WITH (NOLOCK) WHERE trayJob.tray_code = job.tray_code OR trayJob.task_no = job.task_no) AS tray_job_count, CASE WHEN EXISTS (SELECT 1 FROM dbo.bas_cargo_space scopeCargo WITH (NOLOCK) WHERE scopeCargo.warehouse_id IS NULL OR scopeCargo.warehouse_id <> @warehouse_id) THEN 0 ELSE 1 END AS legacy_scope_complete, CASE WHEN ISNULL(DATALENGTH(job.line_id), 0) <= 80 AND ISNULL(DATALENGTH(job.fault_flag), 0) <= 5 AND ISNULL(detail.spare1_bytes, 0) <= 80 AND ISNULL(detail.spare2_bytes, 0) <= 80 AND ISNULL(detail.spare3_bytes, 0) <= 80 THEN 1 ELSE 0 END AS predicate_version, ROW_NUMBER() OVER ( PARTITION BY job.task_no, job.tray_code ORDER BY job.job_id) AS source_rank FROM dbo.mydo_job job WITH (NOLOCK) LEFT JOIN inbound_details detail ON detail.job_id = job.job_id WHERE job.in_or_out < 20 AND (job.finish_time IS NULL OR LTRIM(RTRIM(job.finish_time)) = '''') AND (LTRIM(RTRIM(job.warehouse_id)) = LTRIM(RTRIM(@warehouse_id)) OR (@numeric_warehouse_id IS NOT NULL AND LTRIM(RTRIM(job.warehouse_id)) NOT LIKE ''%[^0-9]%'' AND TRY_CONVERT(decimal(38,0), LTRIM(RTRIM(job.warehouse_id))) = @numeric_warehouse_id)) ) INSERT INTO alg.shadow_inbound_request_snapshot ( warehouse_id, task_no, tray_no, request_id, raw_warehouse_id, project_no, product_id, lot_no, snapshot_generation, synchronized_at, spare1, spare2, spare3, fault_flag, detail_count, field_group_count, product_scope_count, tray_job_count, legacy_scope_complete, predicate_version) SELECT @warehouse_id, ISNULL(task_no, ''''), ISNULL(tray_code, ''''), request_id, raw_warehouse_id, project_no, product_id, lot_no, @snapshot_generation, @synchronized_at, spare1, spare2, spare3, fault_flag, detail_count, field_group_count, product_scope_count, tray_job_count, legacy_scope_complete, predicate_version FROM inbound_source WHERE source_rank = 1; INSERT INTO alg.shadow_outbound_request_snapshot ( warehouse_id, stockout_detail_id, raw_warehouse_id, project_no, product_id, requested_quantity, snapshot_generation, synchronized_at, allocated_quantity, spare1, spare2, spare3, voltage, phase, predicate_version) SELECT @warehouse_id, outbound.stockout_detail_id, outbound.warehouse_id, outbound.spare4, outbound.product_id, CONVERT(decimal(38,6), outbound.quantity), @snapshot_generation, @synchronized_at, CONVERT(decimal(38,6), outbound.allot_quantity), outbound.spare1, outbound.spare2, outbound.spare3, outbound.fid, outbound.unit, CASE WHEN ISNULL(DATALENGTH(outbound.product_id), 0) <= 80 AND ISNULL(DATALENGTH(outbound.spare1), 0) <= 80 AND ISNULL(DATALENGTH(outbound.spare2), 0) <= 80 AND ISNULL(DATALENGTH(outbound.spare3), 0) <= 80 AND ISNULL(DATALENGTH(outbound.spare4), 0) <= 80 AND ISNULL(DATALENGTH(outbound.fid), 0) <= 80 AND ISNULL(DATALENGTH(outbound.unit), 0) <= 80 THEN 1 ELSE 0 END FROM dbo.out_stockout_detail outbound WITH (NOLOCK) JOIN dbo.out_stockout stockout WITH (NOLOCK) ON stockout.stockout_id = outbound.stockout_id WHERE ISNULL(outbound.quantity, 0) > ISNULL(outbound.allot_quantity, 0) AND (LTRIM(RTRIM(stockout.warehouse_id)) = LTRIM(RTRIM(@warehouse_id)) OR (@numeric_warehouse_id IS NOT NULL AND LTRIM(RTRIM(stockout.warehouse_id)) NOT LIKE ''%[^0-9]%'' AND TRY_CONVERT(decimal(38,0), LTRIM(RTRIM(stockout.warehouse_id))) = @numeric_warehouse_id)); EXEC alg.usp_rebuild_space_topology @warehouse_id = @warehouse_id, @snapshot_generation = @snapshot_generation; EXEC alg.usp_sync_inventory_snapshot @warehouse_id = @warehouse_id, @snapshot_generation = @snapshot_generation; EXEC alg.usp_rebuild_lane_state @warehouse_id = @warehouse_id, @snapshot_generation = @snapshot_generation; SELECT @post_source_count = (SELECT COUNT_BIG(*) FROM dbo.bas_cargo_space cargo WITH (NOLOCK)) + (SELECT COUNT_BIG(*) FROM dbo.bas_stock stock WITH (NOLOCK) JOIN dbo.bas_cargo_space cargo WITH (NOLOCK) ON cargo.cargo_space_id = stock.cargo_space_id WHERE cargo.warehouse_id = @warehouse_id) + (SELECT COUNT_BIG(*) FROM dbo.mydo_job job WITH (NOLOCK)) + (SELECT COUNT_BIG(*) FROM dbo.mydo_job_detail detail WITH (NOLOCK) JOIN dbo.mydo_job job WITH (NOLOCK) ON job.job_id = detail.job_id) + (SELECT COUNT_BIG(*) FROM dbo.out_stockout_detail outbound WITH (NOLOCK) JOIN dbo.out_stockout stockout WITH (NOLOCK) ON stockout.stockout_id = outbound.stockout_id WHERE ISNULL(outbound.quantity, 0) > ISNULL(outbound.allot_quantity, 0) AND (LTRIM(RTRIM(stockout.warehouse_id)) = LTRIM(RTRIM(@warehouse_id)) OR (@numeric_warehouse_id IS NOT NULL AND LTRIM(RTRIM(stockout.warehouse_id)) NOT LIKE ''%[^0-9]%'' AND TRY_CONVERT(decimal(38,0), LTRIM(RTRIM(stockout.warehouse_id))) = @numeric_warehouse_id))); SELECT @source_payload = ISNULL(CONVERT(nvarchar(max), ( SELECT cargo.cargo_space_id AS [@space_id], cargo.warehouse_id AS [@warehouse_id], cargo.group_coding_no AS [@lane_code], cargo.cargo_area_id AS [@cargo_area_id], cargo.roadway_id AS [@roadway_id], cargo.cargo_space_name AS [@display_name], cargo.the_platoon AS [@platoon], cargo.the_column AS [@column_no], cargo.the_floor AS [@floor_no], cargo.group_coding AS [@depth_raw], cargo.status AS [@space_status], cargo.locked AS [@locked], cargo.tray_code AS [@tray_code], cargo.this_cargo_area AS [@this_cargo_area] FROM dbo.bas_cargo_space cargo WITH (NOLOCK) ORDER BY cargo.cargo_space_id FOR XML PATH(''cargo''), ROOT(''cargo_spaces''), TYPE )), ''''); SET @source_payload = @source_payload + ''|STOCK|'' + ISNULL(CONVERT(nvarchar(max), ( SELECT stock.stock_id AS [@stock_id], stock.cargo_space_id AS [@space_id], stock.warehouse_id AS [@warehouse_id], stock.tray_code AS [@tray_code], stock.spare4 AS [@project_no], stock.product_id AS [@product_no], stock.lot_no AS [@lot_no], stock.in_date AS [@in_date], stock.quantity AS [@quantity], stock.out_quantity AS [@out_quantity], stock.spare1 AS [@spare1], stock.spare2 AS [@spare2], stock.spare3 AS [@spare3], stock.voltage AS [@voltage], stock.phase AS [@phase], (SELECT COUNT(*) FROM dbo.mydo_job trayJob WITH (NOLOCK) WHERE trayJob.tray_code = stock.tray_code) AS [@tray_job_count] FROM dbo.bas_stock stock WITH (NOLOCK) JOIN dbo.bas_cargo_space cargo WITH (NOLOCK) ON cargo.cargo_space_id = stock.cargo_space_id WHERE cargo.warehouse_id = @warehouse_id ORDER BY stock.stock_id FOR XML PATH(''stock''), ROOT(''stocks''), TYPE )), ''''); SET @source_payload = @source_payload + ''|JOB|'' + ISNULL(CONVERT(nvarchar(max), ( SELECT job.job_id AS [@job_id], job.status AS [@status], job.task_no AS [@task_no], job.tray_code AS [@tray_code], job.cargo_space_id AS [@source_space_id], job.target_cargo_space_id AS [@target_space_id], job.in_or_out AS [@in_or_out], job.create_time AS [@create_time], job.finish_time AS [@finish_time], job.warehouse_id AS [@warehouse_id], job.line_id AS [@line_id], job.fault_flag AS [@fault_flag] FROM dbo.mydo_job job WITH (NOLOCK) ORDER BY job.job_id FOR XML PATH(''job''), ROOT(''jobs''), TYPE )), ''''); SET @source_payload = @source_payload + ''|JOB_DETAIL|'' + ISNULL(CONVERT(nvarchar(max), ( SELECT detail.job_detail_id AS [@job_detail_id], detail.job_id AS [@job_id], detail.stock_id AS [@stock_id], detail.lot_no AS [@lot_no], detail.in_date AS [@in_date], detail.in_or_out_id AS [@request_id], detail.in_or_out_d_id AS [@request_detail_id], detail.product_id AS [@product_id], detail.stock_status AS [@stock_status], detail.in_quantity AS [@in_quantity], detail.stock_quantity AS [@stock_quantity], detail.out_quantity AS [@out_quantity], detail.pick_quantity AS [@pick_quantity], detail.stockin_detail_id AS [@stockin_detail_id], detail.spare1 AS [@spare1], detail.spare2 AS [@spare2], detail.spare3 AS [@spare3] FROM dbo.mydo_job_detail detail WITH (NOLOCK) JOIN dbo.mydo_job job WITH (NOLOCK) ON job.job_id = detail.job_id ORDER BY detail.job_detail_id FOR XML PATH(''job_detail''), ROOT(''job_details''), TYPE )), ''''); SET @source_payload = @source_payload + ''|OUTBOUND|'' + ISNULL(CONVERT(nvarchar(max), ( SELECT outbound.stockout_detail_id AS [@stockout_detail_id], outbound.warehouse_id AS [@warehouse_id], stockout.warehouse_id AS [@source_warehouse_id], outbound.spare4 AS [@project_no], outbound.spare1 AS [@spare1], outbound.spare2 AS [@spare2], outbound.spare3 AS [@spare3], outbound.fid AS [@voltage], outbound.unit AS [@phase], outbound.product_id AS [@product_id], outbound.lot_no AS [@lot_no], outbound.quantity AS [@quantity], outbound.assign_num AS [@assign_num], outbound.allot_quantity AS [@allot_quantity] FROM dbo.out_stockout_detail outbound WITH (NOLOCK) JOIN dbo.out_stockout stockout WITH (NOLOCK) ON stockout.stockout_id = outbound.stockout_id WHERE ISNULL(outbound.quantity, 0) > ISNULL(outbound.allot_quantity, 0) AND (LTRIM(RTRIM(stockout.warehouse_id)) = LTRIM(RTRIM(@warehouse_id)) OR (@numeric_warehouse_id IS NOT NULL AND LTRIM(RTRIM(stockout.warehouse_id)) NOT LIKE ''%[^0-9]%'' AND TRY_CONVERT(decimal(38,0), LTRIM(RTRIM(stockout.warehouse_id))) = @numeric_warehouse_id)) ORDER BY outbound.stockout_detail_id FOR XML PATH(''outbound''), ROOT(''outbound_requests''), TYPE )), ''''); SET @post_source_signature = HASHBYTES(''SHA2_256'', CONVERT(varbinary(max), @source_payload)); IF @pre_source_count <> @post_source_count OR @pre_source_signature <> @post_source_signature THROW 51025, ''FT546 shadow refresh refused: source changed during refresh'', 1; MERGE alg.shadow_snapshot_state WITH (HOLDLOCK) AS target USING (SELECT @warehouse_id AS warehouse_id) AS source ON source.warehouse_id = target.warehouse_id WHEN MATCHED THEN UPDATE SET snapshot_generation = @snapshot_generation, snapshot_status = ''PUBLISHED'', synchronized_at = SYSUTCDATETIME(), source_signature = @post_source_signature, source_row_count = @post_source_count, instance_id = @instance_id, last_error = NULL WHEN NOT MATCHED THEN INSERT ( warehouse_id, snapshot_generation, snapshot_status, synchronized_at, source_signature, source_row_count, instance_id, last_error) VALUES ( @warehouse_id, @snapshot_generation, ''PUBLISHED'', SYSUTCDATETIME(), @post_source_signature, @post_source_count, @instance_id, NULL); COMMIT TRANSACTION; END TRY BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; THROW; END CATCH; END;'; EXEC sys.sp_executesql @refresh_sql; -- Keep the generation monotonic; old rows cannot become predicate-version-1 evidence. UPDATE alg.shadow_snapshot_state WITH (UPDLOCK, HOLDLOCK) SET snapshot_status = 'INITIALIZING', source_signature = NULL, synchronized_at = NULL, last_error = NULL; UPDATE alg.shadow_package_manifest SET package_version = '2026-09-07-34' WHERE package_id = 'FT546WMS_SHADOW_ONLY' AND package_version = '2026-09-07-33'; IF @@ROWCOUNT <> 1 THROW 51069, 'V3.4 upgrade refused: manifest changed during upgrade', 1; COMMIT TRANSACTION; PRINT 'V34_UPGRADE_OK'; END TRY BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; THROW; END CATCH; GO