#!/usr/bin/env php [ 'invoice_email', // TRU-77 (added 2026-08-16) 'wash_certificate_email', 'email', 'customer_number', ], 'invoices' => [ 'po_number', 'closed_at', 'customer_number', ], 'bookings' => [ 'id', 'customer_number', 'department', ], ]; function check_schema(): array { global $db; $report = [ 'ok' => true, 'missing' => [], 'tables_checked' => 0, 'columns_checked' => 0, 'timestamp' => date('c'), ]; if (!isset($db) || !is_object($db) || !method_exists($db, 'query')) { $report['ok'] = false; $report['error'] = 'no_db_connection'; return $report; } // First: run the schema bootstrap (additive, idempotent) so we // give the DB a chance to self-heal. if (class_exists(customer_invoice_email_schema_bootstrap::class)) { customer_invoice_email_schema_bootstrap::ensureSchema(); } foreach (SCHEMA_REQUIREMENTS as $table => $columns) { $report['tables_checked']++; // Confirm the table itself exists $tableSafe = str_replace('`', '', $table); $result = $db->query("SHOW TABLES LIKE '{$tableSafe}'"); if (!$result || (int)$result->num_rows === 0) { $report['ok'] = false; $report['missing'][] = "table `{$table}` does not exist"; continue; } foreach ($columns as $column) { $report['columns_checked']++; $colSafe = str_replace("'", '', $column); $r = $db->query("SHOW COLUMNS FROM `{$tableSafe}` LIKE '{$colSafe}'"); if (!$r || (int)$r->num_rows === 0) { $report['ok'] = false; $report['missing'][] = "{$table}.{$column}"; } } } return $report; } // CLI mode if (PHP_SAPI === 'cli') { $report = check_schema(); echo json_encode($report, JSON_PRETTY_PRINT) . "\n"; exit($report['ok'] ? 0 : 1); }