From fdf62924668d49233bf128193d4c865f6475dfe7 Mon Sep 17 00:00:00 2001 From: Thanakorn S Date: Thu, 21 May 2026 15:21:36 +0700 Subject: [PATCH] =?UTF-8?q?add=20setup.php=20=E2=80=94=20one-shot=20produc?= =?UTF-8?q?tion=20database=20setup=20script?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Creates wms + wms2 databases and all 54 tables from scratch using CREATE TABLE IF NOT EXISTS. Reads credentials from app/config.php. Safe to re-run (idempotent). CLI-only guard prevents web access. Dynamic td_stock_ tables are excluded — the app creates them automatically on first warehouse use. Run: php setup.php Co-Authored-By: Claude Sonnet 4.6 --- setup.php | 1139 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1139 insertions(+) create mode 100644 setup.php diff --git a/setup.php b/setup.php new file mode 100644 index 0000000..6f29134 --- /dev/null +++ b/setup.php @@ -0,0 +1,1139 @@ + tables are created automatically by the app + * the first time a warehouse is used; they are NOT listed here. + */ + +if (PHP_SAPI !== 'cli') { + http_response_code(403); + exit('Run via CLI only: php setup.php'); +} + +// ── Load config ─────────────────────────────────────────────────────────────── +$config = __DIR__ . '/app/config.php'; +if (!file_exists($config)) { + exit("ERROR: app/config.php not found. Configure it before running setup.\n"); +} +require $config; + +$host = $db_server ?? 'localhost'; +$user = $db_user ?? 'root'; +$pass = $db_pass ?? ''; +$db1 = $db_database ?? 'wms'; +$db2 = $db_database2 ?? 'wms2'; + +// ── Helpers ─────────────────────────────────────────────────────────────────── +$ok_count = 0; +$skip_count = 0; +$err_count = 0; + +function info(string $msg): void { echo "\033[36m •\033[0m {$msg}\n"; } +function ok(string $msg): void { global $ok_count; $ok_count++; echo "\033[32m ✓\033[0m {$msg}\n"; } +function skip(string $msg): void { global $skip_count; $skip_count++; echo "\033[33m –\033[0m {$msg}\n"; } +function fail(string $msg): void { global $err_count; $err_count++; echo "\033[31m ✗\033[0m {$msg}\n"; } + +function run(PDO $pdo, string $sql, string $label): void { + try { + $pdo->exec($sql); + ok($label); + } catch (PDOException $e) { + if (str_contains($e->getMessage(), 'already exists')) { + skip($label . ' (already exists)'); + } else { + fail($label . ': ' . $e->getMessage()); + } + } +} + +// ── Connect (no DB selected) ────────────────────────────────────────────────── +echo "\n\033[1m=== mn3wms Production Setup ===\033[0m\n\n"; +echo "Host : {$host}\n"; +echo "DB1 : {$db1} (auth / identity)\n"; +echo "DB2 : {$db2} (business data)\n\n"; + +try { + $pdo = new PDO("mysql:host={$host};charset=utf8", $user, $pass); + $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + ok("Connected to MySQL as {$user}@{$host}"); +} catch (PDOException $e) { + fail("Cannot connect: " . $e->getMessage()); + exit(1); +} + +// ── Create databases ────────────────────────────────────────────────────────── +echo "\n--- Databases ---\n"; +run($pdo, "CREATE DATABASE IF NOT EXISTS `{$db1}` CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci", "Database `{$db1}`"); +run($pdo, "CREATE DATABASE IF NOT EXISTS `{$db2}` CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci", "Database `{$db2}`"); + +// ───────────────────────────────────────────────────────────────────────────── +// WMS (auth / identity) tables +// ───────────────────────────────────────────────────────────────────────────── +echo "\n--- {$db1} tables ---\n"; +$pdo->exec("USE `{$db1}`"); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `user` ( + `user_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `username` varchar(255) NOT NULL, + `password` varchar(255) NOT NULL, + `email` varchar(255) NOT NULL, + `status` varchar(40) NOT NULL DEFAULT 'not activated', + `name` tinytext NOT NULL, + `surname` tinytext NOT NULL, + `address` tinytext DEFAULT NULL, + `country` varchar(50) NOT NULL DEFAULT '', + `profile_picture` tinytext NOT NULL, + `default_company` int(11) DEFAULT 0, + `language` varchar(3) NOT NULL DEFAULT 'th', + `regis_date` timestamp NOT NULL DEFAULT current_timestamp(), + `license` enum('owner','user') NOT NULL DEFAULT 'owner', + `app_access` enum('all','wms','accounting') NOT NULL DEFAULT 'all', + `active` varchar(255) NOT NULL DEFAULT 'yes', + `phone` varchar(50) NOT NULL DEFAULT '', + `verify_token` varchar(64) DEFAULT NULL, + `verify_expires_at` datetime DEFAULT NULL, + `login_attempts` int(11) NOT NULL DEFAULT 0, + `locked_until` datetime DEFAULT NULL, + PRIMARY KEY (`user_id`), + UNIQUE KEY `username` (`username`), + UNIQUE KEY `email` (`email`), + KEY `idx_user_verify_token` (`verify_token`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'user'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `company_list` ( + `company_id` int(11) NOT NULL AUTO_INCREMENT, + `channel_name` varchar(100) NOT NULL DEFAULT '' COMMENT 'Unique slug used for login routing', + `company_name` varchar(255) NOT NULL DEFAULT '', + `company_name2` varchar(255) NOT NULL DEFAULT '' COMMENT 'Secondary / English name', + `company_logo` varchar(255) NOT NULL DEFAULT '', + `company_seal` varchar(255) NOT NULL DEFAULT '', + `branch` varchar(255) NOT NULL DEFAULT 'สำนักงานใหญ่', + `branch_no` varchar(50) NOT NULL DEFAULT '', + `fiscal_year` varchar(10) NOT NULL DEFAULT '', + `fx` varchar(10) NOT NULL DEFAULT 'thb', + `address` text NOT NULL DEFAULT '', + `address2` text NOT NULL DEFAULT '', + `tax_id` varchar(50) NOT NULL DEFAULT '', + `prompt_pay` varchar(50) NOT NULL DEFAULT '', + `entrepreneur` varchar(100) NOT NULL DEFAULT '', + `email` varchar(255) NOT NULL DEFAULT '', + `phone` varchar(50) NOT NULL DEFAULT '', + `fax` varchar(50) NOT NULL DEFAULT '', + `website` varchar(255) NOT NULL DEFAULT '', + `facebook_page` varchar(255) NOT NULL DEFAULT '', + `package` varchar(50) NOT NULL DEFAULT 'starter', + PRIMARY KEY (`company_id`), + UNIQUE KEY `channel_name` (`channel_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'company_list'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `company_map_user` ( + `map_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `role` varchar(15) NOT NULL DEFAULT 'user', + `app_access` varchar(15) NOT NULL DEFAULT 'wms', + `invite_token` varchar(64) DEFAULT NULL, + `created_at` datetime DEFAULT NULL, + PRIMARY KEY (`map_id`), + KEY `user_id` (`user_id`), + KEY `company_id` (`company_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'company_map_user'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `company_setting` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL, + `setting_key` varchar(64) NOT NULL, + `value` varchar(255) NOT NULL DEFAULT '', + `updated_at` datetime DEFAULT NULL, + `log` mediumtext DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `company_key` (`company_id`,`setting_key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'company_setting'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `company_smtp` ( + `smtp_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(10) unsigned NOT NULL, + `server` varchar(255) NOT NULL, + `port` varchar(10) NOT NULL DEFAULT '587', + `username` varchar(255) NOT NULL, + `password` text NOT NULL, + `from_name` varchar(255) NOT NULL DEFAULT '', + `from_email` varchar(255) NOT NULL DEFAULT '', + `encryption` enum('tls','ssl','none') NOT NULL DEFAULT 'tls', + `updated_at` datetime DEFAULT NULL, + PRIMARY KEY (`smtp_id`), + UNIQUE KEY `uq_company_smtp` (`company_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'company_smtp'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `company_usage` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL, + `day_date` date NOT NULL, + `daily_count` int(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + UNIQUE KEY `uq_company_day` (`company_id`,`day_date`), + KEY `idx_company_id` (`company_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'company_usage'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `schema_migrations` ( + `version` varchar(64) NOT NULL, + `applied_at` datetime NOT NULL DEFAULT current_timestamp(), + PRIMARY KEY (`version`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'schema_migrations'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `whitelist` ( + `list_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `cookie` varchar(32) NOT NULL, + `status` int(11) NOT NULL DEFAULT 1 COMMENT '0=block 1=wait 2=allow', + `ip` varchar(20) NOT NULL, + `dt` timestamp NOT NULL DEFAULT current_timestamp(), + PRIMARY KEY (`list_id`), + UNIQUE KEY `cookie` (`cookie`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'whitelist'); + +// ───────────────────────────────────────────────────────────────────────────── +// WMS2 (business data) tables +// ───────────────────────────────────────────────────────────────────────────── +echo "\n--- {$db2} tables ---\n"; +$pdo->exec("USE `{$db2}`"); + +// ── Master data ─────────────────────────────────────────────────────────────── +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_warehouse` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `warehouse_name` varchar(255) NOT NULL DEFAULT '', + `location` text NOT NULL DEFAULT '', + `manager` int(11) NOT NULL DEFAULT 0, + `description` text NOT NULL DEFAULT '', + `status` int(1) NOT NULL DEFAULT 1, + `log` mediumtext NOT NULL DEFAULT '{}', + PRIMARY KEY (`id`), + UNIQUE KEY `company_id_warehouse_name` (`company_id`,`warehouse_name`), + KEY `company_id` (`company_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'md_warehouse'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_storage` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `warehouse` varchar(255) NOT NULL DEFAULT '', + `zone` text NOT NULL DEFAULT '', + `aisle_from` varchar(255) NOT NULL DEFAULT '', + `aisle_to` varchar(255) NOT NULL DEFAULT '', + `rack_from` varchar(255) NOT NULL DEFAULT '', + `rack_to` varchar(255) NOT NULL DEFAULT '', + `description` text NOT NULL DEFAULT '', + `status` int(1) NOT NULL DEFAULT 1, + `log` mediumtext NOT NULL DEFAULT '{}', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'md_storage'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_rack` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL, + `td_stock_id` int(11) NOT NULL DEFAULT 0, + `warehouse` int(11) NOT NULL, + `storage_id` int(11) NOT NULL DEFAULT 0, + `zone` varchar(10) NOT NULL, + `aisle` varchar(10) NOT NULL, + `rack` varchar(10) NOT NULL, + `product_sku` varchar(50) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `uk_rack_location` (`company_id`,`warehouse`,`zone`,`aisle`,`rack`), + KEY `idx_storage` (`storage_id`), + KEY `idx_sku` (`company_id`,`product_sku`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'md_rack'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_rack_log` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(10) NOT NULL, + `md_rack_id` int(10) unsigned NOT NULL, + `user_id` int(10) unsigned DEFAULT NULL, + `dt` datetime NOT NULL DEFAULT current_timestamp(), + `login` datetime DEFAULT NULL, + `action` enum('occupy','release','transfer_in','transfer_out') NOT NULL, + `product_sku` varchar(100) DEFAULT NULL, + `td_stock_id` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `idx_rack` (`company_id`,`md_rack_id`), + KEY `idx_user` (`company_id`,`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'td_rack_log'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_product_category` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `category` varchar(255) NOT NULL DEFAULT '', + `slug` varchar(255) NOT NULL DEFAULT '', + `description` text NOT NULL DEFAULT '', + `status` int(1) NOT NULL DEFAULT 1, + `log` mediumtext NOT NULL DEFAULT '{}', + PRIMARY KEY (`id`), + UNIQUE KEY `company_id_product_id` (`company_id`,`category`), + KEY `company_id` (`company_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'md_product_category'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_product` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `product_name` varchar(255) NOT NULL DEFAULT '', + `sku` varchar(255) NOT NULL DEFAULT '', + `barcode` varchar(64) DEFAULT NULL, + `price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `cost_price` decimal(15,2) NOT NULL DEFAULT 0.00, + `tax_rate` decimal(5,2) NOT NULL DEFAULT 0.00, + `sales_account_code` varchar(20) DEFAULT NULL, + `purchase_account_code` varchar(20) DEFAULT NULL, + `uom` varchar(20) NOT NULL DEFAULT 'pcs', + `min_stock` decimal(18,4) NOT NULL DEFAULT 0.0000, + `reorder_point` decimal(18,4) NOT NULL DEFAULT 0.0000, + `category` int(11) NOT NULL DEFAULT 0, + `product_image` text NOT NULL DEFAULT '', + `description` text NOT NULL DEFAULT '', + `status` int(1) NOT NULL DEFAULT 1, + `log` mediumtext NOT NULL DEFAULT '{}', + PRIMARY KEY (`id`), + UNIQUE KEY `company_id_product_id` (`company_id`,`product_name`), + KEY `company_id` (`company_id`), + KEY `idx_product_barcode` (`company_id`,`barcode`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'md_product'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_lot` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(10) unsigned NOT NULL, + `product_sku` varchar(100) NOT NULL, + `lot_number` varchar(100) NOT NULL, + `expiry_date` date NOT NULL, + `description` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `company_id_product_sku_lot_number` (`company_id`,`product_sku`,`lot_number`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'md_lot'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_contact_type` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `contact_type` varchar(255) NOT NULL DEFAULT '', + `description` text NOT NULL DEFAULT '', + `status` int(1) NOT NULL DEFAULT 1, + `log` mediumtext NOT NULL DEFAULT '{}', + PRIMARY KEY (`id`), + UNIQUE KEY `company_id_product_id` (`company_id`,`contact_type`), + KEY `company_id` (`company_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'md_contact_type'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_contact` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `contact_name` varchar(255) NOT NULL, + `tax_id` varchar(255) NOT NULL, + `organization` varchar(255) NOT NULL, + `branch` varchar(255) NOT NULL, + `contact_type` int(11) unsigned NOT NULL, + `billing_address` text NOT NULL, + `shipping_location` varchar(255) NOT NULL, + `shipping_address` text NOT NULL, + `remark` text NOT NULL, + `contact_image` mediumtext NOT NULL, + `status` int(1) unsigned NOT NULL DEFAULT 1, + `log` mediumtext NOT NULL DEFAULT '{}', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'md_contact'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_barcode` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(10) unsigned NOT NULL, + `barcode_type` varchar(20) NOT NULL, + `barcode` varchar(320) NOT NULL, + `product_sku` varchar(100) DEFAULT NULL, + `lot_number` varchar(100) DEFAULT NULL, + `serial_number` varchar(100) DEFAULT NULL, + `warehouse_id` int(10) unsigned DEFAULT NULL, + `zone` varchar(100) DEFAULT NULL, + `aisle` varchar(100) DEFAULT NULL, + `rack` varchar(100) DEFAULT NULL, + `print_count` int(10) unsigned NOT NULL DEFAULT 0, + `last_printed_dt` datetime DEFAULT NULL, + `created_dt` datetime NOT NULL DEFAULT current_timestamp(), + `status` tinyint(4) NOT NULL DEFAULT 1, + PRIMARY KEY (`id`), + UNIQUE KEY `company_id_barcode` (`company_id`,`barcode`), + KEY `company_id_type` (`company_id`,`barcode_type`), + KEY `company_id_product_lot` (`company_id`,`product_sku`,`lot_number`), + KEY `company_id_location` (`company_id`,`warehouse_id`,`zone`,`aisle`,`rack`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'md_barcode'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_sku_barcode_label` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(10) unsigned NOT NULL, + `product_sku` varchar(100) NOT NULL, + `lot_number` varchar(100) NOT NULL, + `serial_number` varchar(100) NOT NULL, + `barcode` varchar(320) NOT NULL, + `created_dt` datetime NOT NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`), + UNIQUE KEY `company_id_barcode` (`company_id`,`barcode`), + KEY `company_id_product_lot` (`company_id`,`product_sku`,`lot_number`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'md_sku_barcode_label'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_lock_operation` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `operation_type` varchar(50) NOT NULL DEFAULT '', + `user_id` int(11) NOT NULL DEFAULT 0, + `locked_at` datetime NOT NULL, + `expires_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `op` (`company_id`,`operation_type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'md_lock_operation'); + +// ── Accounting master ───────────────────────────────────────────────────────── +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_department` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL, + `dept_code` varchar(20) NOT NULL, + `dept_name` varchar(255) NOT NULL, + `description` text DEFAULT NULL, + `status` tinyint(1) NOT NULL DEFAULT 1, + PRIMARY KEY (`id`), + UNIQUE KEY `uq_company_dept` (`company_id`,`dept_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'md_department'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_account` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL, + `account_code` varchar(20) NOT NULL, + `account_name` varchar(255) NOT NULL, + `account_type` enum('asset','liability','equity','revenue','expense') NOT NULL, + `account_category` varchar(50) NOT NULL DEFAULT '', + `parent_code` varchar(20) DEFAULT NULL, + `is_posting` tinyint(1) NOT NULL DEFAULT 1, + `status` tinyint(1) NOT NULL DEFAULT 1, + PRIMARY KEY (`id`), + UNIQUE KEY `uq_company_account` (`company_id`,`account_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'md_account'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_account_formula` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL, + `formula_name` varchar(100) NOT NULL, + `document_type` varchar(50) NOT NULL, + `description` text DEFAULT NULL, + `is_default` tinyint(1) NOT NULL DEFAULT 0, + `status` tinyint(1) NOT NULL DEFAULT 1, + `created_at` datetime NOT NULL DEFAULT current_timestamp(), + `updated_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `idx_company_doc` (`company_id`,`document_type`), + KEY `idx_status` (`company_id`,`status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'md_account_formula'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `md_account_formula_item` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL, + `formula_id` int(11) NOT NULL, + `drcr` enum('D','C') NOT NULL, + `account_code` varchar(20) NOT NULL, + `amount_key` enum('grand_total','total','tax','amount') NOT NULL, + `description` varchar(255) DEFAULT NULL, + `sort_order` int(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + KEY `idx_formula` (`company_id`,`formula_id`), + KEY `idx_account` (`company_id`,`account_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'md_account_formula_item'); + +// ── Stock (template + base) ─────────────────────────────────────────────────── +// td_stock_ tables are created automatically by the app on first use. +// This base table matches the template used by WarehouseManager::createStockTableForWarehouse(). +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_stock` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `ref_id` int(11) unsigned NOT NULL DEFAULT 0, + `company_id` int(11) NOT NULL DEFAULT 0, + `uuid` varchar(20) NOT NULL, + `type` varchar(20) NOT NULL, + `ref_warehouse` varchar(20) NOT NULL DEFAULT '', + `date` datetime DEFAULT NULL, + `product_sku` varchar(255) NOT NULL DEFAULT '0', + `lot_number` varchar(255) NOT NULL DEFAULT '', + `serial_number` varchar(255) NOT NULL DEFAULT '', + `source` varchar(255) NOT NULL DEFAULT '', + `source_id` int(11) NOT NULL DEFAULT 0, + `in` decimal(18,4) NOT NULL DEFAULT 0.0000, + `out` decimal(18,4) NOT NULL DEFAULT 0.0000, + `price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `zone` varchar(255) NOT NULL DEFAULT '', + `aisle` varchar(255) NOT NULL DEFAULT '', + `rack` varchar(255) NOT NULL DEFAULT '', + `contact_id` int(11) NOT NULL DEFAULT 0, + `description` text NOT NULL DEFAULT '', + `status` int(3) NOT NULL DEFAULT 0, + `log` mediumtext NOT NULL DEFAULT '{}', + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `product_id` (`product_sku`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_stock (base template)'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `warehouse_balance` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) unsigned NOT NULL DEFAULT 0, + `warehouse_id` int(11) unsigned NOT NULL DEFAULT 0, + `product_sku` varchar(255) NOT NULL DEFAULT '', + `month` varchar(10) NOT NULL, + `total_in` decimal(18,4) NOT NULL DEFAULT 0.0000, + `total_out` decimal(18,4) NOT NULL DEFAULT 0.0000, + PRIMARY KEY (`id`), + UNIQUE KEY `company_id_warehouse_id_product_sku_month` (`company_id`,`warehouse_id`,`product_sku`,`month`), + KEY `company_id` (`company_id`), + KEY `product_id` (`warehouse_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'warehouse_balance'); + +// ── Transactions ────────────────────────────────────────────────────────────── +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_gl` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `source_type` varchar(50) NOT NULL DEFAULT '', + `source_id` int(11) NOT NULL DEFAULT 0, + `reference` varchar(100) NOT NULL DEFAULT '', + `description` varchar(255) NOT NULL DEFAULT '', + `journal_date` date DEFAULT NULL, + `formula_id` int(11) NOT NULL DEFAULT 0, + `period` varchar(7) NOT NULL DEFAULT '', + `current_version` tinyint(4) NOT NULL DEFAULT 1, + `history` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '[]' CHECK (json_valid(`history`)), + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `period` (`period`), + KEY `formula_id` (`formula_id`), + KEY `source` (`company_id`,`source_type`,`source_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_gl'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_gl_item` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `gl_id` int(10) unsigned NOT NULL, + `account_code` varchar(20) NOT NULL DEFAULT '', + `department_id` int(11) NOT NULL DEFAULT 0, + `debit` decimal(18,4) NOT NULL DEFAULT 0.0000, + `credit` decimal(18,4) NOT NULL DEFAULT 0.0000, + `description` varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (`id`), + KEY `gl_id` (`gl_id`), + KEY `company_id` (`company_id`), + KEY `account_code` (`account_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_gl_item'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_batch_action` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `type` varchar(50) NOT NULL DEFAULT '', + `doc_type` varchar(50) NOT NULL DEFAULT '', + `total` int(11) NOT NULL DEFAULT 0, + `succeeded` int(11) NOT NULL DEFAULT 0, + `failed` int(11) NOT NULL DEFAULT 0, + `failed_ids` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '[]' CHECK (json_valid(`failed_ids`)), + `user_id` int(11) NOT NULL DEFAULT 0, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `type` (`type`), + KEY `doc_type` (`doc_type`), + KEY `user_id` (`user_id`), + KEY `created_at` (`created_at`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_batch_action'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_quotation` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `uuid` varchar(32) NOT NULL DEFAULT '', + `quotation_number` varchar(50) NOT NULL DEFAULT '', + `contact_id` int(11) NOT NULL DEFAULT 0, + `department_id` int(11) NOT NULL DEFAULT 0, + `quotation_date` date DEFAULT NULL, + `valid_until` date DEFAULT NULL, + `status` tinyint(1) NOT NULL DEFAULT 0, + `subtotal` decimal(18,4) NOT NULL DEFAULT 0.0000, + `discount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax` decimal(18,4) NOT NULL DEFAULT 0.0000, + `grand_total` decimal(18,4) NOT NULL DEFAULT 0.0000, + `notes` text NOT NULL DEFAULT '', + `log` mediumtext NOT NULL DEFAULT '{}', + `created_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `quotation_number` (`quotation_number`), + KEY `status` (`status`), + KEY `contact_id` (`contact_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'td_quotation'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_quotation_item` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `quotation_id` int(11) unsigned NOT NULL DEFAULT 0, + `item_id` int(11) unsigned NOT NULL DEFAULT 0, + `product_sku` varchar(100) NOT NULL DEFAULT '', + `product_name` varchar(255) NOT NULL DEFAULT '', + `quantity` decimal(18,4) NOT NULL DEFAULT 0.0000, + `unit_price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `total_price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_rate` decimal(5,2) NOT NULL DEFAULT 0.00, + `converted_qty` decimal(18,4) NOT NULL DEFAULT 0.0000, + PRIMARY KEY (`id`), + UNIQUE KEY `uq_qt_item` (`quotation_id`,`item_id`), + KEY `idx_quotation` (`company_id`,`quotation_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'td_quotation_item'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_order` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `uuid` varchar(32) NOT NULL DEFAULT '', + `source_id` int(11) NOT NULL DEFAULT 0, + `source` varchar(20) NOT NULL DEFAULT '', + `order_number` varchar(50) NOT NULL DEFAULT '', + `contact_id` int(11) NOT NULL DEFAULT 0, + `department_id` int(11) NOT NULL DEFAULT 0, + `order_date` date DEFAULT NULL, + `status` tinyint(1) NOT NULL DEFAULT 0, + `subtotal` decimal(18,4) NOT NULL DEFAULT 0.0000, + `discount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_adjustment` decimal(8,2) NOT NULL DEFAULT 0.00, + `shipping_fee` decimal(18,4) NOT NULL DEFAULT 0.0000, + `shipping_tracking_number` varchar(100) DEFAULT NULL, + `grand_total` decimal(18,4) NOT NULL DEFAULT 0.0000, + `notes` text NOT NULL DEFAULT '', + `log` mediumtext NOT NULL DEFAULT '{}', + `created_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `contact_id` (`contact_id`), + KEY `order_number` (`order_number`), + KEY `status` (`status`), + KEY `order_date` (`order_date`), + KEY `quotation_id` (`source_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_order'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_order_item` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `order_id` int(11) unsigned NOT NULL DEFAULT 0, + `item_id` int(11) unsigned NOT NULL DEFAULT 0, + `product_sku` varchar(100) NOT NULL DEFAULT '', + `product_name` varchar(255) NOT NULL DEFAULT '', + `quantity` decimal(18,4) NOT NULL DEFAULT 0.0000, + `unit_price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `total_price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_rate` decimal(5,2) NOT NULL DEFAULT 0.00, + `warehouse_id` int(11) NOT NULL DEFAULT 0, + `stock_out_id` int(11) NOT NULL DEFAULT 0, + `lot_number` varchar(100) NOT NULL DEFAULT '', + `invoiced_qty` decimal(18,4) NOT NULL DEFAULT 0.0000, + PRIMARY KEY (`id`), + UNIQUE KEY `uq_order_item` (`order_id`,`item_id`), + KEY `idx_order` (`company_id`,`order_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'td_order_item'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_invoice` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `uuid` varchar(32) NOT NULL DEFAULT '', + `source_id` int(11) NOT NULL DEFAULT 0, + `source` varchar(20) NOT NULL DEFAULT '', + `doc_type` varchar(20) NOT NULL DEFAULT 'invoice', + `invoice_number` varchar(50) NOT NULL DEFAULT '', + `ref_invoice_id` int(11) unsigned NOT NULL DEFAULT 0, + `order_id` int(11) unsigned NOT NULL DEFAULT 0, + `contact_id` int(11) NOT NULL DEFAULT 0, + `department_id` int(11) NOT NULL DEFAULT 0, + `issued_date` date DEFAULT NULL, + `due_date` date DEFAULT NULL, + `subtotal` decimal(18,4) NOT NULL DEFAULT 0.0000, + `discount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_adjustment` decimal(8,2) NOT NULL DEFAULT 0.00, + `shipping_fee` decimal(18,4) NOT NULL DEFAULT 0.0000, + `grand_total` decimal(18,4) NOT NULL DEFAULT 0.0000, + `formula_id` int(11) DEFAULT NULL, + `status` tinyint(1) NOT NULL DEFAULT 0, + `notes` text NOT NULL DEFAULT '', + `log` mediumtext NOT NULL DEFAULT '{}', + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `order_id` (`order_id`), + KEY `contact_id` (`contact_id`), + KEY `invoice_number` (`invoice_number`), + KEY `ref_invoice_id` (`ref_invoice_id`), + KEY `doc_type` (`doc_type`), + KEY `status` (`status`), + KEY `due_date` (`due_date`), + KEY `source_id` (`source_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_invoice'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_invoice_item` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `invoice_id` int(11) unsigned NOT NULL DEFAULT 0, + `item_id` int(11) unsigned NOT NULL DEFAULT 0, + `product_sku` varchar(100) NOT NULL DEFAULT '', + `product_name` varchar(255) NOT NULL DEFAULT '', + `quantity` decimal(18,4) NOT NULL DEFAULT 0.0000, + `unit_price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `total_price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_rate` decimal(5,2) NOT NULL DEFAULT 0.00, + PRIMARY KEY (`id`), + UNIQUE KEY `uq_invoice_item` (`invoice_id`,`item_id`), + KEY `idx_invoice` (`company_id`,`invoice_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'td_invoice_item'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_return` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `uuid` varchar(32) NOT NULL DEFAULT '', + `return_number` varchar(50) NOT NULL DEFAULT '', + `order_id` int(11) unsigned NOT NULL DEFAULT 0, + `invoice_id` int(11) unsigned NOT NULL DEFAULT 0, + `contact_id` int(11) NOT NULL DEFAULT 0, + `department_id` int(11) NOT NULL DEFAULT 0, + `return_date` date DEFAULT NULL, + `status` tinyint(1) NOT NULL DEFAULT 0, + `reason` text NOT NULL DEFAULT '', + `refund_amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_adjustment` decimal(8,2) NOT NULL DEFAULT 0.00, + `notes` text NOT NULL DEFAULT '', + `log` mediumtext NOT NULL DEFAULT '{}', + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `order_id` (`order_id`), + KEY `invoice_id` (`invoice_id`), + KEY `contact_id` (`contact_id`), + KEY `return_number` (`return_number`), + KEY `status` (`status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_return'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_return_item` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `return_id` int(11) unsigned NOT NULL DEFAULT 0, + `item_id` int(11) unsigned NOT NULL DEFAULT 0, + `product_sku` varchar(100) NOT NULL DEFAULT '', + `product_name` varchar(255) NOT NULL DEFAULT '', + `quantity` decimal(18,4) NOT NULL DEFAULT 0.0000, + `unit_price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `total_price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_rate` decimal(5,2) NOT NULL DEFAULT 0.00, + `warehouse_id` int(11) NOT NULL DEFAULT 0, + `stock_out_id` int(11) NOT NULL DEFAULT 0, + `stock_out_warehouse_id` int(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + UNIQUE KEY `uq_return_item` (`return_id`,`item_id`), + KEY `idx_return` (`company_id`,`return_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'td_return_item'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_purchase_request` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `uuid` varchar(32) NOT NULL DEFAULT '', + `request_number` varchar(50) NOT NULL DEFAULT '', + `contact_id` int(11) NOT NULL DEFAULT 0, + `department_id` int(11) NOT NULL DEFAULT 0, + `request_date` date DEFAULT NULL, + `required_date` date DEFAULT NULL, + `status` tinyint(1) NOT NULL DEFAULT 0, + `subtotal` decimal(18,4) NOT NULL DEFAULT 0.0000, + `discount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax` decimal(18,4) NOT NULL DEFAULT 0.0000, + `shipping_fee` decimal(18,4) NOT NULL DEFAULT 0.0000, + `grand_total` decimal(18,4) NOT NULL DEFAULT 0.0000, + `notes` text NOT NULL DEFAULT '', + `log` mediumtext NOT NULL DEFAULT '{}', + `created_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `request_number` (`request_number`), + KEY `status` (`status`), + KEY `contact_id` (`contact_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'td_purchase_request'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_purchase_request_item` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `request_id` int(11) unsigned NOT NULL DEFAULT 0, + `item_id` int(11) unsigned NOT NULL DEFAULT 0, + `product_sku` varchar(100) NOT NULL DEFAULT '', + `product_name` varchar(255) NOT NULL DEFAULT '', + `quantity` decimal(18,4) NOT NULL DEFAULT 0.0000, + `unit_price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `total_price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_rate` decimal(5,2) NOT NULL DEFAULT 0.00, + `converted_qty` decimal(18,4) NOT NULL DEFAULT 0.0000, + PRIMARY KEY (`id`), + UNIQUE KEY `uq_pr_item` (`request_id`,`item_id`), + KEY `idx_pr_item` (`company_id`,`request_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'td_purchase_request_item'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_purchase_order` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL, + `uuid` varchar(64) NOT NULL, + `source_id` int(11) NOT NULL DEFAULT 0, + `source` varchar(32) NOT NULL DEFAULT '', + `po_number` varchar(32) NOT NULL, + `contact_id` int(11) DEFAULT NULL, + `department_id` int(11) NOT NULL DEFAULT 0, + `po_date` date NOT NULL, + `expected_date` date DEFAULT NULL, + `closed_at` datetime DEFAULT NULL, + `warehouse_id` int(11) NOT NULL DEFAULT 0, + `status` tinyint(4) NOT NULL DEFAULT 0, + `subtotal` decimal(15,2) NOT NULL DEFAULT 0.00, + `discount` decimal(15,2) NOT NULL DEFAULT 0.00, + `tax` decimal(15,2) NOT NULL DEFAULT 0.00, + `tax_adjustment` decimal(8,2) NOT NULL DEFAULT 0.00, + `shipping_fee` decimal(15,2) NOT NULL DEFAULT 0.00, + `grand_total` decimal(15,2) NOT NULL DEFAULT 0.00, + `notes` text DEFAULT NULL, + `log` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`log`)), + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `idx_po_company` (`company_id`), + KEY `idx_po_status` (`company_id`,`status`), + KEY `idx_po_contact` (`company_id`,`contact_id`), + KEY `idx_po_date` (`company_id`,`po_date`), + KEY `idx_po_source` (`company_id`,`source`,`source_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'td_purchase_order'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_purchase_order_item` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `order_id` int(11) unsigned NOT NULL DEFAULT 0, + `item_id` int(11) unsigned NOT NULL DEFAULT 0, + `product_sku` varchar(100) NOT NULL DEFAULT '', + `product_name` varchar(255) NOT NULL DEFAULT '', + `quantity` decimal(18,4) NOT NULL DEFAULT 0.0000, + `unit_price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `total_price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_rate` decimal(5,2) NOT NULL DEFAULT 0.00, + `received_qty` decimal(18,4) NOT NULL DEFAULT 0.0000, + `stock_in_id` int(11) NOT NULL DEFAULT 0, + `invoiced_qty` decimal(18,4) NOT NULL DEFAULT 0.0000, + PRIMARY KEY (`id`), + UNIQUE KEY `uq_po_item` (`order_id`,`item_id`), + KEY `idx_order` (`company_id`,`order_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'td_purchase_order_item'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_supplier_return` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `uuid` varchar(32) NOT NULL DEFAULT '', + `return_number` varchar(32) NOT NULL DEFAULT '', + `po_id` int(11) unsigned NOT NULL DEFAULT 0, + `invoice_id` int(11) unsigned NOT NULL DEFAULT 0, + `contact_id` int(11) NOT NULL DEFAULT 0, + `department_id` int(11) NOT NULL DEFAULT 0, + `return_date` date NOT NULL, + `status` tinyint(1) NOT NULL DEFAULT 0, + `reason` text NOT NULL DEFAULT '', + `refund_amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_adjustment` decimal(8,2) NOT NULL DEFAULT 0.00, + `notes` text NOT NULL DEFAULT '', + `log` mediumtext NOT NULL DEFAULT '{}', + `shipping_tracking_number` varchar(100) NOT NULL DEFAULT '', + PRIMARY KEY (`id`), + KEY `idx_company_id` (`company_id`), + KEY `idx_po_id` (`po_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'td_supplier_return'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_supplier_return_item` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `return_id` int(11) unsigned NOT NULL DEFAULT 0, + `item_id` int(11) unsigned NOT NULL DEFAULT 0, + `product_sku` varchar(100) NOT NULL DEFAULT '', + `product_name` varchar(255) NOT NULL DEFAULT '', + `quantity` decimal(18,4) NOT NULL DEFAULT 0.0000, + `unit_price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `total_price` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `tax_rate` decimal(5,2) NOT NULL DEFAULT 0.00, + `warehouse_id` int(11) NOT NULL DEFAULT 0, + `stock_in_id` int(11) NOT NULL DEFAULT 0, + `zone` varchar(50) NOT NULL DEFAULT '', + `aisle` varchar(50) NOT NULL DEFAULT '', + `rack` varchar(50) NOT NULL DEFAULT '', + PRIMARY KEY (`id`), + UNIQUE KEY `uq_sr_item` (`return_id`,`item_id`), + KEY `idx_return` (`company_id`,`return_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +", 'td_supplier_return_item'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_receipt_billing` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `uuid` varchar(32) NOT NULL DEFAULT '', + `billing_number` varchar(50) NOT NULL DEFAULT '', + `contact_id` int(11) NOT NULL DEFAULT 0, + `billing_date` date DEFAULT NULL, + `amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `status` tinyint(1) NOT NULL DEFAULT 1, + `notes` text NOT NULL DEFAULT '', + `log` mediumtext NOT NULL DEFAULT '{}', + `created_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `contact_id` (`contact_id`), + KEY `billing_number` (`billing_number`), + KEY `status` (`status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_receipt_billing'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_receipt_billing_item` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `billing_id` int(11) unsigned NOT NULL DEFAULT 0, + `invoice_id` int(11) unsigned NOT NULL DEFAULT 0, + `doc_type` varchar(20) NOT NULL DEFAULT '', + `amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `billing_id` (`billing_id`), + KEY `invoice_id` (`invoice_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_receipt_billing_item'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_receipt` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `uuid` varchar(32) NOT NULL DEFAULT '', + `receipt_number` varchar(50) NOT NULL DEFAULT '', + `contact_id` int(11) NOT NULL DEFAULT 0, + `department_id` int(11) NOT NULL DEFAULT 0, + `receipt_billing_id` int(11) unsigned NOT NULL DEFAULT 0, + `receipt_date` date DEFAULT NULL, + `payment_method` varchar(50) NOT NULL DEFAULT '', + `amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `formula_id` int(11) DEFAULT NULL, + `status` tinyint(1) NOT NULL DEFAULT 1, + `notes` text NOT NULL DEFAULT '', + `log` mediumtext NOT NULL DEFAULT '{}', + `created_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `contact_id` (`contact_id`), + KEY `receipt_number` (`receipt_number`), + KEY `status` (`status`), + KEY `receipt_billing_id` (`receipt_billing_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_receipt'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_receipt_item` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `receipt_id` int(11) unsigned NOT NULL DEFAULT 0, + `invoice_id` int(11) unsigned NOT NULL DEFAULT 0, + `doc_type` varchar(20) NOT NULL DEFAULT '', + `department_id` int(11) NOT NULL DEFAULT 0, + `amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `receipt_id` (`receipt_id`), + KEY `invoice_id` (`invoice_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_receipt_item'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_payment_billing` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `uuid` varchar(32) NOT NULL DEFAULT '', + `billing_number` varchar(50) NOT NULL DEFAULT '', + `contact_id` int(11) NOT NULL DEFAULT 0, + `billing_date` date DEFAULT NULL, + `amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `status` tinyint(1) NOT NULL DEFAULT 1, + `notes` text NOT NULL DEFAULT '', + `log` mediumtext NOT NULL DEFAULT '{}', + `created_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `contact_id` (`contact_id`), + KEY `billing_number` (`billing_number`), + KEY `status` (`status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_payment_billing'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_payment_billing_item` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `billing_id` int(11) unsigned NOT NULL DEFAULT 0, + `invoice_id` int(11) unsigned NOT NULL DEFAULT 0, + `doc_type` varchar(20) NOT NULL DEFAULT '', + `amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `billing_id` (`billing_id`), + KEY `invoice_id` (`invoice_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_payment_billing_item'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_payment` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `uuid` varchar(32) NOT NULL DEFAULT '', + `payment_number` varchar(50) NOT NULL DEFAULT '', + `contact_id` int(11) NOT NULL DEFAULT 0, + `department_id` int(11) NOT NULL DEFAULT 0, + `payment_billing_id` int(11) unsigned NOT NULL DEFAULT 0, + `payment_date` date DEFAULT NULL, + `payment_method` varchar(50) NOT NULL DEFAULT '', + `amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + `formula_id` int(11) DEFAULT NULL, + `status` tinyint(1) NOT NULL DEFAULT 1, + `notes` text NOT NULL DEFAULT '', + `log` mediumtext NOT NULL DEFAULT '{}', + `created_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `contact_id` (`contact_id`), + KEY `payment_billing_id` (`payment_billing_id`), + KEY `payment_number` (`payment_number`), + KEY `status` (`status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_payment'); + +run($pdo, " +CREATE TABLE IF NOT EXISTS `td_payment_item` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(11) NOT NULL DEFAULT 0, + `payment_id` int(11) unsigned NOT NULL DEFAULT 0, + `invoice_id` int(11) unsigned NOT NULL DEFAULT 0, + `doc_type` varchar(20) NOT NULL DEFAULT '', + `department_id` int(11) NOT NULL DEFAULT 0, + `amount` decimal(18,4) NOT NULL DEFAULT 0.0000, + PRIMARY KEY (`id`), + KEY `company_id` (`company_id`), + KEY `payment_id` (`payment_id`), + KEY `invoice_id` (`invoice_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; +", 'td_payment_item'); + +// ── Summary ─────────────────────────────────────────────────────────────────── +$total = $ok_count + $skip_count + $err_count; +echo "\n\033[1m=== Done ===\033[0m\n"; +printf(" Created : %d\n", $ok_count); +printf(" Skipped : %d\n", $skip_count); +printf(" Errors : %d\n", $err_count); +echo PHP_EOL; + +if ($err_count > 0) { + echo "\033[31mSetup completed with errors. Review the output above.\033[0m\n\n"; + exit(1); +} + +echo "\033[32mSetup complete. Both databases are ready.\033[0m\n"; +echo "Next step: visit /login/index.php and register the first owner account.\n\n"; +exit(0);