-- MySQL 8.0. Run in the target database before upgrading, with application writes stopped. -- Every row in the final result is a BLOCKER: repair with business confirmation. -- This check works on legacy and upgraded schemas; inferred dimensions never use company 1. -- Canonical source: after edits run pwsh -NoProfile -File scripts/sync-company-integrity.ps1 -- Verify the self-contained migration with the same command plus -Check. -- BEGIN COMPANY INTEGRITY CORE DROP TEMPORARY TABLE IF EXISTS tmp_company_application_dimensions; CREATE TEMPORARY TABLE tmp_company_application_dimensions AS SELECT a.id, COUNT(ai.id) item_count, COUNT(DISTINCT m.organization_id) organization_count, MIN(m.organization_id) organization_id, COUNT(m.id) material_count FROM material_applications a LEFT JOIN application_items ai ON ai.application_id=a.id LEFT JOIN materials m ON m.id=ai.material_id GROUP BY a.id; DROP TEMPORARY TABLE IF EXISTS tmp_company_log_dimensions; CREATE TEMPORARY TABLE tmp_company_log_dimensions AS SELECT s.id, o.organization_id, o.warehouse_id, o.location_id FROM stock_logs s JOIN inbound_orders o ON s.related_order_type='inbound' AND s.related_order_id=o.id JOIN inbound_items i ON i.inbound_order_id=o.id AND i.material_id=s.material_id WHERE s.type='in' AND s.quantity=i.quantity UNION SELECT s.id, o.organization_id, o.warehouse_id, o.location_id FROM stock_logs s JOIN outbound_orders o ON s.related_order_type='outbound' AND s.related_order_id=o.id JOIN outbound_items i ON i.outbound_order_id=o.id AND i.material_id=s.material_id WHERE s.type='out' AND s.quantity=i.quantity UNION SELECT s.id, d.organization_id, b.warehouse_id, b.location_id FROM stock_logs s JOIN material_applications a ON s.related_order_type='application' AND s.related_order_id=a.id JOIN tmp_company_application_dimensions d ON d.id=a.id AND d.item_count>0 AND d.organization_count=1 AND d.material_count=d.item_count JOIN application_items i ON i.application_id=a.id AND i.material_id=s.material_id JOIN inventory_balances b ON b.organization_id=d.organization_id AND b.material_id=s.material_id JOIN warehouses w ON w.id=b.warehouse_id AND w.organization_id=d.organization_id JOIN warehouse_locations l ON l.id=b.location_id AND l.warehouse_id=w.id WHERE s.type='out' AND a.status='approved' AND s.quantity=i.quantity; DROP TEMPORARY TABLE IF EXISTS tmp_company_integrity_anomalies; CREATE TEMPORARY TABLE tmp_company_integrity_anomalies ( issue VARCHAR(100) NOT NULL, entity_id BIGINT NOT NULL, detail VARCHAR(500) NOT NULL ); INSERT INTO tmp_company_integrity_anomalies SELECT 'category_parent',c.id,'Parent category belongs to another company or is missing' FROM material_categories c LEFT JOIN material_categories p ON p.id=c.parent_id WHERE c.parent_id IS NOT NULL AND (p.id IS NULL OR p.organization_id<>c.organization_id); INSERT INTO tmp_company_integrity_anomalies SELECT 'material_category_unit_type',m.id,'Material category, base unit or type belongs to another company or is missing' FROM materials m LEFT JOIN material_categories c ON c.id=m.category_id LEFT JOIN units u ON u.id=m.base_unit_id LEFT JOIN material_types mt ON mt.id=m.material_type_id WHERE c.id IS NULL OR c.organization_id<>m.organization_id OR (m.base_unit_id IS NOT NULL AND (u.id IS NULL OR u.organization_id<>m.organization_id)) OR (m.material_type_id IS NOT NULL AND (mt.id IS NULL OR mt.organization_id<>m.organization_id)); INSERT INTO tmp_company_integrity_anomalies SELECT 'rule_category',r.id,'Code rule category belongs to another company or is missing' FROM code_rules r LEFT JOIN material_categories c ON c.id=r.category_id WHERE c.id IS NULL OR c.organization_id<>r.organization_id; INSERT INTO tmp_company_integrity_anomalies SELECT 'duplicate_default',user_id,'User has more than one default organization' FROM user_organizations WHERE is_default<>0 GROUP BY user_id HAVING COUNT(*)>1; INSERT INTO tmp_company_integrity_anomalies SELECT 'user_without_access',u.id,'User has no enabled company grant and no enabled super_admin role' FROM users u WHERE NOT EXISTS(SELECT 1 FROM user_organizations g JOIN organizations o ON o.id=g.organization_id AND o.status='active' WHERE g.user_id=u.id) AND NOT EXISTS(SELECT 1 FROM user_roles ur JOIN roles r ON r.id=ur.role_id AND r.code='super_admin' AND r.enabled=1 WHERE ur.user_id=u.id); INSERT INTO tmp_company_integrity_anomalies SELECT 'multiple_warehouses',organization_id,'Company has multiple warehouses (including inactive ones)' FROM warehouses GROUP BY organization_id HAVING COUNT(*)>1; INSERT INTO tmp_company_integrity_anomalies SELECT 'multiple_locations',warehouse_id,'Warehouse has multiple locations (including inactive ones)' FROM warehouse_locations GROUP BY warehouse_id HAVING COUNT(*)>1; INSERT INTO tmp_company_integrity_anomalies SELECT 'inventory_dimensions',b.id,'Inventory material, company, warehouse or location do not agree' FROM inventory_balances b LEFT JOIN materials m ON m.id=b.material_id LEFT JOIN warehouses w ON w.id=b.warehouse_id LEFT JOIN warehouse_locations l ON l.id=b.location_id LEFT JOIN organizations o ON o.id=b.organization_id WHERE o.id IS NULL OR m.id IS NULL OR w.id IS NULL OR l.id IS NULL OR m.organization_id<>b.organization_id OR w.organization_id<>b.organization_id OR l.warehouse_id<>b.warehouse_id; INSERT INTO tmp_company_integrity_anomalies SELECT 'warning_dimensions',r.id,'Warning material, company or warehouse do not agree' FROM stock_warning_rules r LEFT JOIN materials m ON m.id=r.material_id LEFT JOIN warehouses w ON w.id=r.warehouse_id WHERE m.id IS NULL OR w.id IS NULL OR m.organization_id<>r.organization_id OR w.organization_id<>r.organization_id; INSERT INTO tmp_company_integrity_anomalies SELECT 'inbound_dimensions',o.id,'Inbound company, warehouse, location, materials or actual inventory dimensions do not agree' FROM inbound_orders o LEFT JOIN warehouses w ON w.id=o.warehouse_id LEFT JOIN warehouse_locations l ON l.id=o.location_id WHERE w.id IS NULL OR l.id IS NULL OR w.organization_id<>o.organization_id OR l.warehouse_id<>o.warehouse_id OR NOT EXISTS(SELECT 1 FROM inbound_items i WHERE i.inbound_order_id=o.id) OR EXISTS(SELECT 1 FROM inbound_items i LEFT JOIN materials m ON m.id=i.material_id WHERE i.inbound_order_id=o.id AND (m.id IS NULL OR m.organization_id<>o.organization_id OR NOT EXISTS(SELECT 1 FROM inventory_balances b WHERE b.material_id=i.material_id AND b.organization_id=o.organization_id AND b.warehouse_id=o.warehouse_id AND b.location_id=o.location_id))); INSERT INTO tmp_company_integrity_anomalies SELECT 'outbound_dimensions',o.id,'Outbound company, warehouse, location, materials or actual inventory dimensions do not agree' FROM outbound_orders o LEFT JOIN warehouses w ON w.id=o.warehouse_id LEFT JOIN warehouse_locations l ON l.id=o.location_id WHERE w.id IS NULL OR l.id IS NULL OR w.organization_id<>o.organization_id OR l.warehouse_id<>o.warehouse_id OR NOT EXISTS(SELECT 1 FROM outbound_items i WHERE i.outbound_order_id=o.id) OR EXISTS(SELECT 1 FROM outbound_items i LEFT JOIN materials m ON m.id=i.material_id WHERE i.outbound_order_id=o.id AND (m.id IS NULL OR m.organization_id<>o.organization_id OR NOT EXISTS(SELECT 1 FROM inventory_balances b WHERE b.material_id=i.material_id AND b.organization_id=o.organization_id AND b.warehouse_id=o.warehouse_id AND b.location_id=o.location_id))); INSERT INTO tmp_company_integrity_anomalies SELECT 'application_dimensions',id,'Application has empty, missing or mixed-company material details' FROM tmp_company_application_dimensions WHERE item_count=0 OR organization_count<>1 OR material_count<>item_count; INSERT INTO tmp_company_integrity_anomalies SELECT 'unattributable_stock_log',s.id,'Log has no unique verified material/document/company/warehouse/location association' FROM stock_logs s LEFT JOIN tmp_company_log_dimensions d ON d.id=s.id LEFT JOIN materials m ON m.id=s.material_id LEFT JOIN warehouses w ON w.id=d.warehouse_id LEFT JOIN warehouse_locations l ON l.id=d.location_id GROUP BY s.id,m.id,m.organization_id HAVING COUNT(d.id)<>1 OR COUNT(m.id)=0 OR SUM(d.organization_id<>m.organization_id OR w.organization_id<>d.organization_id OR l.warehouse_id<>d.warehouse_id)>0; -- The same check file must work before the columns exist and after backfill. SET @company_check_sql = IF( (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='stock_logs' AND column_name IN ('organization_id','warehouse_id','location_id'))=3, 'INSERT INTO tmp_company_integrity_anomalies SELECT ''stored_stock_log_dimensions'',s.id,''Stored log dimensions differ from verified source document'' FROM stock_logs s LEFT JOIN tmp_company_log_dimensions d ON d.id=s.id WHERE d.id IS NULL OR s.organization_id IS NULL OR s.warehouse_id IS NULL OR s.location_id IS NULL OR s.organization_id<>d.organization_id OR s.warehouse_id<>d.warehouse_id OR s.location_id<>d.location_id', 'DO 0'); PREPARE company_check FROM @company_check_sql; EXECUTE company_check; DEALLOCATE PREPARE company_check; SET @company_check_sql = IF( (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='material_applications' AND column_name='organization_id')=1, 'INSERT INTO tmp_company_integrity_anomalies SELECT ''stored_application_dimensions'',a.id,''Stored application company differs from verified detail materials'' FROM material_applications a JOIN tmp_company_application_dimensions d ON d.id=a.id WHERE a.organization_id IS NULL OR a.organization_id<>d.organization_id', 'DO 0'); PREPARE company_check FROM @company_check_sql; EXECUTE company_check; DEALLOCATE PREPARE company_check; -- END COMPANY INTEGRITY CORE SELECT issue, entity_id, detail FROM tmp_company_integrity_anomalies ORDER BY issue,entity_id; -- Counts are also review evidence, even when zero or one per dimension. SELECT organization_id,COUNT(*) warehouse_count FROM warehouses GROUP BY organization_id; SELECT warehouse_id,COUNT(*) location_count FROM warehouse_locations GROUP BY warehouse_id;