diff --git a/api/database.php b/api/database.php index a8cef9f..bd99926 100644 --- a/api/database.php +++ b/api/database.php @@ -187,6 +187,8 @@ function migrateDB(PDO $db): void { catch (PDOException $e) { if (strpos($e->getMessage(), 'duplicate column') === false) throw $e; } } + + // Empty barcode strings break UNIQUE (only one '' allowed); normalize to NULL. $db->exec("UPDATE products SET barcode = NULL WHERE barcode IS NOT NULL AND TRIM(barcode) = ''"); @@ -319,6 +321,27 @@ function migrateDB(PDO $db): void { $db->exec("CREATE INDEX IF NOT EXISTS idx_transactions_type_date ON transactions(type, created_at)"); $db->exec("CREATE INDEX IF NOT EXISTS idx_transactions_pid_type_undone ON transactions(product_id, type, undone)"); +// Custom locations table (v1.9.0) — dynamic inventory locations managed from Settings +$locTables = $db->query("SELECT name FROM sqlite_master WHERE type='table' AND name='locations'")->fetchAll(); +if (empty($locTables)) { + $db->exec(" + CREATE TABLE locations ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + key TEXT UNIQUE NOT NULL, + label TEXT NOT NULL, + icon TEXT DEFAULT '📦', + sort_order INTEGER DEFAULT 0, + is_builtin INTEGER DEFAULT 0 + ); + "); + $db->exec("INSERT INTO locations (key, label, icon, sort_order, is_builtin) VALUES + ('dispensa', 'Dispensa', '🗄️', 1, 1), + ('frigo', 'Frigo', '🧊', 2, 1), + ('freezer', 'Freezer', '❄️', 3, 1), + ('altro', 'Altro', '📦', 4, 1) + "); +} + // Internal shopping list table (v1.8.0) — used when SHOPPING_MODE=internal $shopTables = $db->query("SELECT name FROM sqlite_master WHERE type='table' AND name='shopping_list'")->fetchAll(); if (empty($shopTables)) {