From bd992f2f943f2c6266a16ff343231254469b6136 Mon Sep 17 00:00:00 2001 From: le king fu Date: Sun, 19 Apr 2026 16:41:55 -0400 Subject: [PATCH] feat(categories): add v1 IPC seed, i18n keys, and migration v8 (#115) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Livraison 1 du milestone spec-refonte-seed-categories-ipc. Applies the new v1 IPC (Indice des prix à la consommation) taxonomy to freshly created profiles while leaving existing v2 profiles untouched until the migration wizard (upcoming issue #121) prompts them to move. - Migration v8 (additive only): - ALTER TABLE categories ADD COLUMN i18n_key TEXT - INSERT OR IGNORE user_preferences.categories_schema_version=v2 (existing profiles tagged as v2 for later migration) - consolidated_schema.sql rewritten with the full v1 seed and categories_schema_version='v1' default for brand-new profiles - src/data/categoryTaxonomyV1.json bundled as the TS-side source of truth (consumed by #116 categoryTaxonomyService next) - categoriesSeed.* i18n namespace (FR/EN) — 150 entries each - CategoryTree and CategoryCombobox fall back to the raw `name` when i18n_key is null (user-created categories stay literal) - CategoryTreeNode and CategoryRow gain the i18n_key field end-to-end Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitignore | 1 + CHANGELOG.fr.md | 3 + CHANGELOG.md | 3 + src-tauri/src/commands/profile_commands.rs | 11 +- .../src/database/consolidated_schema.sql | 479 ++++++++++++++++- src-tauri/src/lib.rs | 13 + src/components/categories/CategoryTree.tsx | 4 +- src/components/shared/CategoryCombobox.tsx | 17 +- src/data/categoryTaxonomyV1.json | 498 ++++++++++++++++++ src/i18n/locales/en.json | 228 ++++++++ src/i18n/locales/fr.json | 228 ++++++++ src/services/categoryService.ts | 1 + src/shared/types/index.ts | 8 + 13 files changed, 1483 insertions(+), 11 deletions(-) create mode 100644 src/data/categoryTaxonomyV1.json diff --git a/.gitignore b/.gitignore index 3758002..a98c5e9 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ target/ # User data data/ +!src/data/ *.db *.db-journal *.db-wal diff --git a/CHANGELOG.fr.md b/CHANGELOG.fr.md index 9864328..ca96de5 100644 --- a/CHANGELOG.fr.md +++ b/CHANGELOG.fr.md @@ -2,6 +2,9 @@ ## [Non publié] +### Ajouté +- **Seed de catégories IPC pour les nouveaux profils** : les nouveaux profils sont désormais créés avec la taxonomie v1 IPC (Indice des prix à la consommation) — une hiérarchie alignée sur les catégories de Statistique Canada. Les noms des catégories du seed sont traduits dynamiquement depuis la clé i18n `categoriesSeed.*` (FR/EN), donc affichés dans la langue de l'utilisateur. Les profils existants gardent l'ancien seed v2, marqués via une nouvelle préférence `categories_schema_version` (une page de migration ultérieure offrira le passage v2→v1). Côté interne : colonne `categories.i18n_key` (nullable) ajoutée par la migration v8 (strictement additive), `src/data/categoryTaxonomyV1.json` livré comme source de vérité côté TS, les renderers `CategoryTree` et `CategoryCombobox` utilisent `name` en repli quand aucune clé de traduction n'est présente (catégories créées par l'utilisateur) (#115) + ## [0.8.3] - 2026-04-19 ### Ajouté diff --git a/CHANGELOG.md b/CHANGELOG.md index 83e958b..c9cd94c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## [Unreleased] +### Added +- **IPC-aligned categories seed for new profiles**: brand-new profiles are now seeded with the v1 IPC (Indice des prix à la consommation) taxonomy — a structured hierarchy aligned with Statistics Canada consumer price index categories. Category labels are now translated dynamically from the `categoriesSeed.*` i18n namespace (FR/EN), so seed categories display in the user's current language. Existing profiles remain on the legacy v2 seed, marked via a new `categories_schema_version` user preference (a later migration wizard will offer the v2→v1 transition). Internally: nullable `categories.i18n_key` column added in migration v8 (additive only), `src/data/categoryTaxonomyV1.json` bundled as the TS-side source of truth, `CategoryTree` and `CategoryCombobox` renderers fall back to the raw `name` when no translation key is present (user-created rows) (#115) + ## [0.8.3] - 2026-04-19 ### Added diff --git a/src-tauri/src/commands/profile_commands.rs b/src-tauri/src/commands/profile_commands.rs index fb9a0de..e678435 100644 --- a/src-tauri/src/commands/profile_commands.rs +++ b/src-tauri/src/commands/profile_commands.rs @@ -114,10 +114,13 @@ pub fn delete_profile_db(app: tauri::AppHandle, db_filename: String) -> Result<( #[tauri::command] pub fn get_new_profile_init_sql() -> Result, String> { - Ok(vec![ - database::CONSOLIDATED_SCHEMA.to_string(), - database::SEED_CATEGORIES.to_string(), - ]) + // Brand-new profiles ship with the v1 IPC-aligned category taxonomy: the + // consolidated schema bakes the v1 seed (categories + keywords + the + // categories_schema_version='v1' preference) directly. The legacy v2 seed + // migration still runs first because tauri-plugin-sql applies every + // declared migration on `Database.load`; the consolidated script then + // deletes the v2 rows and re-inserts the v1 rows in the 1000+ id range. + Ok(vec![database::CONSOLIDATED_SCHEMA.to_string()]) } // Argon2id parameters for PIN hashing (same as export_import_commands.rs) diff --git a/src-tauri/src/database/consolidated_schema.sql b/src-tauri/src/database/consolidated_schema.sql index 227d3b7..cb593ec 100644 --- a/src-tauri/src/database/consolidated_schema.sql +++ b/src-tauri/src/database/consolidated_schema.sql @@ -1,6 +1,9 @@ -- Consolidated schema for new profile databases --- This file bakes in the base schema + all migrations (v3-v6) --- Used ONLY for initializing new profile databases (not for the default profile) +-- This file bakes in the base schema + all migrations (v3-v8) and pre-seeds +-- the v1 IPC-aligned category taxonomy so that brand-new profiles immediately +-- use the new standard. Existing profiles keep their v2 seed and are only +-- tagged via the migration (categories_schema_version = 'v2'). +-- Used ONLY for initializing new profile databases (not for the default profile). CREATE TABLE IF NOT EXISTS import_sources ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -39,6 +42,7 @@ CREATE TABLE IF NOT EXISTS categories ( is_active INTEGER NOT NULL DEFAULT 1, is_inputable INTEGER NOT NULL DEFAULT 1, sort_order INTEGER NOT NULL DEFAULT 0, + i18n_key TEXT, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (parent_id) REFERENCES categories(id) ON DELETE SET NULL ); @@ -177,8 +181,477 @@ CREATE INDEX IF NOT EXISTS idx_budget_entries_period ON budget_entries(year, mon CREATE INDEX IF NOT EXISTS idx_adjustment_entries_adjustment ON adjustment_entries(adjustment_id); CREATE INDEX IF NOT EXISTS idx_imported_files_source ON imported_files(source_id); --- Default preferences +-- Default preferences (new profiles ship with the v1 IPC taxonomy) INSERT OR IGNORE INTO user_preferences (key, value) VALUES ('language', 'fr'); INSERT OR IGNORE INTO user_preferences (key, value) VALUES ('theme', 'light'); INSERT OR IGNORE INTO user_preferences (key, value) VALUES ('currency', 'EUR'); INSERT OR IGNORE INTO user_preferences (key, value) VALUES ('date_format', 'DD/MM/YYYY'); +INSERT OR REPLACE INTO user_preferences (key, value) VALUES ('categories_schema_version', 'v1'); + +-- ============================================================================ +-- Seed v1 — IPC Statistique Canada-aligned, 3 levels, Canada/Québec +-- ---------------------------------------------------------------------------- +-- Reset any pre-existing category data (possible when tauri-plugin-sql runs +-- the historical v2 seed migration on this fresh DB before this script +-- executes). Keywords/categories are wiped and re-inserted with the v1 IDs +-- (1000+ range) so existing references in migrations v3-v7 stay inert. +-- ============================================================================ +DELETE FROM keywords; +UPDATE transactions SET category_id = NULL; +DELETE FROM categories; + +-- LEVEL 1 — Roots (9 IPC components + Revenus + Transferts) +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1000, 'Revenus', NULL, 'income', '#16a34a', 0, 1, 'categoriesSeed.revenus.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1100, 'Alimentation', NULL, 'expense', '#ea580c', 0, 2, 'categoriesSeed.alimentation.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1200, 'Logement', NULL, 'expense', '#dc2626', 0, 3, 'categoriesSeed.logement.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1300, 'Ménage & ameublement', NULL, 'expense', '#ca8a04', 0, 4, 'categoriesSeed.menage.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1400, 'Vêtements & chaussures', NULL, 'expense', '#d946ef', 0, 5, 'categoriesSeed.vetements.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1500, 'Transport', NULL, 'expense', '#2563eb', 0, 6, 'categoriesSeed.transport.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1600, 'Santé & soins personnels', NULL, 'expense', '#f43f5e', 0, 7, 'categoriesSeed.sante.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1700, 'Loisirs, formation & lecture', NULL, 'expense', '#8b5cf6', 0, 8, 'categoriesSeed.loisirs.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1800, 'Boissons, tabac & cannabis', NULL, 'expense', '#7c3aed', 0, 9, 'categoriesSeed.consommation.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1900, 'Finances & obligations', NULL, 'expense', '#6b7280', 0, 10, 'categoriesSeed.finances.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1950, 'Transferts & placements', NULL, 'transfer', '#0ea5e9', 0, 11, 'categoriesSeed.transferts.root'); + +-- 1000 — Revenus +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1010, 'Emploi', 1000, 'income', '#22c55e', 0, 1, 'categoriesSeed.revenus.emploi.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1011, 'Paie régulière', 1010, 'income', '#22c55e', 1, 1, 'categoriesSeed.revenus.emploi.paie'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1012, 'Primes & bonus', 1010, 'income', '#4ade80', 1, 2, 'categoriesSeed.revenus.emploi.primes'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1013, 'Travail autonome', 1010, 'income', '#86efac', 1, 3, 'categoriesSeed.revenus.emploi.autonome'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1020, 'Gouvernemental', 1000, 'income', '#16a34a', 0, 2, 'categoriesSeed.revenus.gouvernemental.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1021, 'Remboursement impôt', 1020, 'income', '#16a34a', 1, 1, 'categoriesSeed.revenus.gouvernemental.remboursementImpot'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1022, 'Allocations familiales', 1020, 'income', '#15803d', 1, 2, 'categoriesSeed.revenus.gouvernemental.allocations'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1023, 'Crédits TPS/TVQ', 1020, 'income', '#166534', 1, 3, 'categoriesSeed.revenus.gouvernemental.credits'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1024, 'Assurance-emploi / RQAP', 1020, 'income', '#14532d', 1, 4, 'categoriesSeed.revenus.gouvernemental.assuranceEmploi'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1030, 'Revenus de placement', 1000, 'income', '#10b981', 0, 3, 'categoriesSeed.revenus.placement.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1031, 'Intérêts & dividendes', 1030, 'income', '#10b981', 1, 1, 'categoriesSeed.revenus.placement.interets'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1032, 'Gains en capital', 1030, 'income', '#059669', 1, 2, 'categoriesSeed.revenus.placement.capital'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1033, 'Revenus locatifs', 1030, 'income', '#047857', 1, 3, 'categoriesSeed.revenus.placement.locatifs'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1090, 'Autres revenus', 1000, 'income', '#84cc16', 1, 9, 'categoriesSeed.revenus.autres'); + +-- 1100 — Alimentation +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1110, 'Épicerie & marché', 1100, 'expense', '#ea580c', 0, 1, 'categoriesSeed.alimentation.epicerie.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1111, 'Épicerie régulière', 1110, 'expense', '#ea580c', 1, 1, 'categoriesSeed.alimentation.epicerie.reguliere'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1112, 'Boucherie & poissonnerie', 1110, 'expense', '#c2410c', 1, 2, 'categoriesSeed.alimentation.epicerie.boucherie'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1113, 'Boulangerie & pâtisserie', 1110, 'expense', '#9a3412', 1, 3, 'categoriesSeed.alimentation.epicerie.boulangerie'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1114, 'Dépanneur', 1110, 'expense', '#7c2d12', 1, 4, 'categoriesSeed.alimentation.epicerie.depanneur'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1115, 'Marché & produits spécialisés', 1110, 'expense', '#fb923c', 1, 5, 'categoriesSeed.alimentation.epicerie.marche'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1120, 'Restauration', 1100, 'expense', '#f97316', 0, 2, 'categoriesSeed.alimentation.restauration.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1121, 'Restaurant', 1120, 'expense', '#f97316', 1, 1, 'categoriesSeed.alimentation.restauration.restaurant'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1122, 'Café & boulangerie rapide', 1120, 'expense', '#fb923c', 1, 2, 'categoriesSeed.alimentation.restauration.cafe'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1123, 'Restauration rapide', 1120, 'expense', '#fdba74', 1, 3, 'categoriesSeed.alimentation.restauration.fastfood'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1124, 'Livraison à domicile', 1120, 'expense', '#fed7aa', 1, 4, 'categoriesSeed.alimentation.restauration.livraison'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1125, 'Cantine & cafétéria', 1120, 'expense', '#ffedd5', 1, 5, 'categoriesSeed.alimentation.restauration.cantine'); + +-- 1200 — Logement +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1210, 'Habitation principale', 1200, 'expense', '#dc2626', 0, 1, 'categoriesSeed.logement.habitation.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1211, 'Loyer', 1210, 'expense', '#dc2626', 1, 1, 'categoriesSeed.logement.habitation.loyer'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1212, 'Hypothèque', 1210, 'expense', '#b91c1c', 1, 2, 'categoriesSeed.logement.habitation.hypotheque'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1213, 'Taxes municipales & scolaires', 1210, 'expense', '#991b1b', 1, 3, 'categoriesSeed.logement.habitation.taxes'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1214, 'Charges de copropriété', 1210, 'expense', '#7f1d1d', 1, 4, 'categoriesSeed.logement.habitation.copropriete'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1220, 'Services publics', 1200, 'expense', '#ef4444', 0, 2, 'categoriesSeed.logement.services.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1221, 'Électricité', 1220, 'expense', '#ef4444', 1, 1, 'categoriesSeed.logement.services.electricite'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1222, 'Gaz naturel', 1220, 'expense', '#f87171', 1, 2, 'categoriesSeed.logement.services.gaz'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1223, 'Chauffage (mazout, propane)', 1220, 'expense', '#fca5a5', 1, 3, 'categoriesSeed.logement.services.chauffage'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1224, 'Eau & égouts', 1220, 'expense', '#fecaca', 1, 4, 'categoriesSeed.logement.services.eau'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1230, 'Communications', 1200, 'expense', '#6366f1', 0, 3, 'categoriesSeed.logement.communications.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1231, 'Internet résidentiel', 1230, 'expense', '#6366f1', 1, 1, 'categoriesSeed.logement.communications.internet'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1232, 'Téléphonie mobile', 1230, 'expense', '#818cf8', 1, 2, 'categoriesSeed.logement.communications.mobile'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1233, 'Téléphonie résidentielle', 1230, 'expense', '#a5b4fc', 1, 3, 'categoriesSeed.logement.communications.residentielle'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1234, 'Câblodistribution & streaming TV', 1230, 'expense', '#c7d2fe', 1, 4, 'categoriesSeed.logement.communications.streamingTv'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1240, 'Entretien & réparations', 1200, 'expense', '#e11d48', 0, 4, 'categoriesSeed.logement.entretien.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1241, 'Entretien général', 1240, 'expense', '#e11d48', 1, 1, 'categoriesSeed.logement.entretien.general'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1242, 'Rénovations', 1240, 'expense', '#be123c', 1, 2, 'categoriesSeed.logement.entretien.renovations'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1243, 'Matériaux & outils', 1240, 'expense', '#9f1239', 1, 3, 'categoriesSeed.logement.entretien.materiaux'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1244, 'Aménagement paysager', 1240, 'expense', '#881337', 1, 4, 'categoriesSeed.logement.entretien.paysager'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1250, 'Assurance habitation', 1200, 'expense', '#14b8a6', 1, 5, 'categoriesSeed.logement.assurance'); + +-- 1300 — Ménage & ameublement +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1310, 'Ameublement', 1300, 'expense', '#ca8a04', 0, 1, 'categoriesSeed.menage.ameublement.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1311, 'Meubles', 1310, 'expense', '#ca8a04', 1, 1, 'categoriesSeed.menage.ameublement.meubles'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1312, 'Électroménagers', 1310, 'expense', '#a16207', 1, 2, 'categoriesSeed.menage.ameublement.electromenagers'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1313, 'Décoration', 1310, 'expense', '#854d0e', 1, 3, 'categoriesSeed.menage.ameublement.decoration'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1320, 'Fournitures ménagères', 1300, 'expense', '#eab308', 0, 2, 'categoriesSeed.menage.fournitures.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1321, 'Produits d''entretien', 1320, 'expense', '#eab308', 1, 1, 'categoriesSeed.menage.fournitures.entretien'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1322, 'Literie & linge de maison', 1320, 'expense', '#facc15', 1, 2, 'categoriesSeed.menage.fournitures.literie'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1323, 'Vaisselle & ustensiles', 1320, 'expense', '#fde047', 1, 3, 'categoriesSeed.menage.fournitures.vaisselle'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1330, 'Services domestiques', 1300, 'expense', '#fbbf24', 0, 3, 'categoriesSeed.menage.services.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1331, 'Ménage & nettoyage', 1330, 'expense', '#fbbf24', 1, 1, 'categoriesSeed.menage.services.nettoyage'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1332, 'Buanderie & pressing', 1330, 'expense', '#fcd34d', 1, 2, 'categoriesSeed.menage.services.buanderie'); + +-- 1400 — Vêtements & chaussures +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1410, 'Vêtements adultes', 1400, 'expense', '#d946ef', 1, 1, 'categoriesSeed.vetements.adultes'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1420, 'Vêtements enfants', 1400, 'expense', '#c026d3', 1, 2, 'categoriesSeed.vetements.enfants'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1430, 'Chaussures', 1400, 'expense', '#a21caf', 1, 3, 'categoriesSeed.vetements.chaussures'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1440, 'Accessoires & bijoux', 1400, 'expense', '#86198f', 1, 4, 'categoriesSeed.vetements.accessoires'); + +-- 1500 — Transport +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1510, 'Véhicule personnel', 1500, 'expense', '#2563eb', 0, 1, 'categoriesSeed.transport.vehicule.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1511, 'Achat / location véhicule', 1510, 'expense', '#2563eb', 1, 1, 'categoriesSeed.transport.vehicule.achat'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1512, 'Essence', 1510, 'expense', '#1d4ed8', 1, 2, 'categoriesSeed.transport.vehicule.essence'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1513, 'Entretien & réparations auto', 1510, 'expense', '#1e40af', 1, 3, 'categoriesSeed.transport.vehicule.entretien'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1514, 'Immatriculation & permis', 1510, 'expense', '#1e3a8a', 1, 4, 'categoriesSeed.transport.vehicule.immatriculation'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1515, 'Stationnement & péages', 1510, 'expense', '#3b82f6', 1, 5, 'categoriesSeed.transport.vehicule.stationnement'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1516, 'Assurance auto', 1510, 'expense', '#60a5fa', 1, 6, 'categoriesSeed.transport.vehicule.assurance'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1520, 'Transport public', 1500, 'expense', '#0ea5e9', 0, 2, 'categoriesSeed.transport.public.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1521, 'Autobus & métro', 1520, 'expense', '#0ea5e9', 1, 1, 'categoriesSeed.transport.public.autobus'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1522, 'Train de banlieue', 1520, 'expense', '#0284c7', 1, 2, 'categoriesSeed.transport.public.train'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1523, 'Taxi & covoiturage', 1520, 'expense', '#0369a1', 1, 3, 'categoriesSeed.transport.public.taxi'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1530, 'Voyages longue distance', 1500, 'expense', '#38bdf8', 0, 3, 'categoriesSeed.transport.voyages.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1531, 'Avion', 1530, 'expense', '#38bdf8', 1, 1, 'categoriesSeed.transport.voyages.avion'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1532, 'Train & autocar', 1530, 'expense', '#7dd3fc', 1, 2, 'categoriesSeed.transport.voyages.trainAutocar'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1533, 'Hébergement', 1530, 'expense', '#bae6fd', 1, 3, 'categoriesSeed.transport.voyages.hebergement'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1534, 'Location véhicule voyage', 1530, 'expense', '#e0f2fe', 1, 4, 'categoriesSeed.transport.voyages.location'); + +-- 1600 — Santé & soins personnels +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1610, 'Soins médicaux', 1600, 'expense', '#f43f5e', 0, 1, 'categoriesSeed.sante.medicaux.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1611, 'Pharmacie', 1610, 'expense', '#f43f5e', 1, 1, 'categoriesSeed.sante.medicaux.pharmacie'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1612, 'Consultations médicales', 1610, 'expense', '#e11d48', 1, 2, 'categoriesSeed.sante.medicaux.consultations'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1613, 'Dentiste & orthodontiste', 1610, 'expense', '#be123c', 1, 3, 'categoriesSeed.sante.medicaux.dentiste'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1614, 'Optométrie & lunettes', 1610, 'expense', '#9f1239', 1, 4, 'categoriesSeed.sante.medicaux.optometrie'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1615, 'Thérapies (physio, psycho, etc.)', 1610, 'expense', '#881337', 1, 5, 'categoriesSeed.sante.medicaux.therapies'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1616, 'Assurance santé complémentaire', 1610, 'expense', '#fb7185', 1, 6, 'categoriesSeed.sante.medicaux.assurance'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1620, 'Soins personnels', 1600, 'expense', '#fb7185', 0, 2, 'categoriesSeed.sante.personnels.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1621, 'Coiffure & esthétique', 1620, 'expense', '#fb7185', 1, 1, 'categoriesSeed.sante.personnels.coiffure'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1622, 'Produits de soins corporels', 1620, 'expense', '#fda4af', 1, 2, 'categoriesSeed.sante.personnels.soins'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1630, 'Assurance vie & invalidité', 1600, 'expense', '#14b8a6', 1, 3, 'categoriesSeed.sante.assuranceVie'); + +-- 1700 — Loisirs, formation & lecture +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1710, 'Divertissement', 1700, 'expense', '#8b5cf6', 0, 1, 'categoriesSeed.loisirs.divertissement.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1711, 'Cinéma & spectacles', 1710, 'expense', '#8b5cf6', 1, 1, 'categoriesSeed.loisirs.divertissement.cinema'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1712, 'Jeux vidéo & consoles', 1710, 'expense', '#a78bfa', 1, 2, 'categoriesSeed.loisirs.divertissement.jeux'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1713, 'Streaming vidéo', 1710, 'expense', '#c4b5fd', 1, 3, 'categoriesSeed.loisirs.divertissement.streamingVideo'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1714, 'Streaming musique & audio', 1710, 'expense', '#ddd6fe', 1, 4, 'categoriesSeed.loisirs.divertissement.streamingMusique'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1715, 'Jouets & passe-temps', 1710, 'expense', '#ede9fe', 1, 5, 'categoriesSeed.loisirs.divertissement.jouets'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1720, 'Sports & plein air', 1700, 'expense', '#22c55e', 0, 2, 'categoriesSeed.loisirs.sports.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1721, 'Abonnements sportifs', 1720, 'expense', '#22c55e', 1, 1, 'categoriesSeed.loisirs.sports.abonnements'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1722, 'Équipement sportif', 1720, 'expense', '#4ade80', 1, 2, 'categoriesSeed.loisirs.sports.equipement'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1723, 'Parcs & activités plein air', 1720, 'expense', '#86efac', 1, 3, 'categoriesSeed.loisirs.sports.parcs'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1730, 'Formation & éducation', 1700, 'expense', '#6366f1', 0, 3, 'categoriesSeed.loisirs.formation.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1731, 'Scolarité (frais)', 1730, 'expense', '#6366f1', 1, 1, 'categoriesSeed.loisirs.formation.scolarite'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1732, 'Matériel scolaire', 1730, 'expense', '#818cf8', 1, 2, 'categoriesSeed.loisirs.formation.materiel'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1733, 'Cours & certifications', 1730, 'expense', '#a5b4fc', 1, 3, 'categoriesSeed.loisirs.formation.cours'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1734, 'Abonnements professionnels', 1730, 'expense', '#c7d2fe', 1, 4, 'categoriesSeed.loisirs.formation.abonnements'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1740, 'Lecture & médias', 1700, 'expense', '#ec4899', 0, 4, 'categoriesSeed.loisirs.lecture.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1741, 'Livres', 1740, 'expense', '#ec4899', 1, 1, 'categoriesSeed.loisirs.lecture.livres'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1742, 'Journaux & magazines', 1740, 'expense', '#f472b6', 1, 2, 'categoriesSeed.loisirs.lecture.journaux'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1750, 'Animaux de compagnie', 1700, 'expense', '#a855f7', 0, 5, 'categoriesSeed.loisirs.animaux.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1751, 'Nourriture & accessoires animaux', 1750, 'expense', '#a855f7', 1, 1, 'categoriesSeed.loisirs.animaux.nourriture'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1752, 'Vétérinaire', 1750, 'expense', '#c084fc', 1, 2, 'categoriesSeed.loisirs.animaux.veterinaire'); + +-- 1800 — Boissons, tabac & cannabis +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1810, 'Alcool (SAQ, microbrasseries)', 1800, 'expense', '#7c3aed', 1, 1, 'categoriesSeed.consommation.alcool'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1820, 'Cannabis (SQDC)', 1800, 'expense', '#6d28d9', 1, 2, 'categoriesSeed.consommation.cannabis'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1830, 'Tabac', 1800, 'expense', '#5b21b6', 1, 3, 'categoriesSeed.consommation.tabac'); + +-- 1900 — Finances & obligations +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1910, 'Frais bancaires', 1900, 'expense', '#6b7280', 0, 1, 'categoriesSeed.finances.fraisBancaires.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1911, 'Frais de compte', 1910, 'expense', '#6b7280', 1, 1, 'categoriesSeed.finances.fraisBancaires.compte'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1912, 'Intérêts & frais de crédit', 1910, 'expense', '#9ca3af', 1, 2, 'categoriesSeed.finances.fraisBancaires.interets'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1913, 'Frais de change', 1910, 'expense', '#d1d5db', 1, 3, 'categoriesSeed.finances.fraisBancaires.change'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1920, 'Impôts & taxes', 1900, 'expense', '#dc2626', 0, 2, 'categoriesSeed.finances.impots.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1921, 'Impôt fédéral', 1920, 'expense', '#dc2626', 1, 1, 'categoriesSeed.finances.impots.federal'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1922, 'Impôt provincial', 1920, 'expense', '#b91c1c', 1, 2, 'categoriesSeed.finances.impots.provincial'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1923, 'Acomptes provisionnels', 1920, 'expense', '#991b1b', 1, 3, 'categoriesSeed.finances.impots.acomptes'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1930, 'Dons & cotisations', 1900, 'expense', '#ec4899', 0, 3, 'categoriesSeed.finances.dons.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1931, 'Dons de charité', 1930, 'expense', '#ec4899', 1, 1, 'categoriesSeed.finances.dons.charite'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1932, 'Cotisations professionnelles', 1930, 'expense', '#f472b6', 1, 2, 'categoriesSeed.finances.dons.professionnelles'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1933, 'Cotisations syndicales', 1930, 'expense', '#f9a8d4', 1, 3, 'categoriesSeed.finances.dons.syndicales'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1940, 'Cadeaux', 1900, 'expense', '#f43f5e', 1, 4, 'categoriesSeed.finances.cadeaux'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1945, 'Retrait cash', 1900, 'expense', '#57534e', 1, 5, 'categoriesSeed.finances.cash'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1946, 'Achats divers non catégorisés', 1900, 'expense', '#78716c', 1, 6, 'categoriesSeed.finances.divers'); + +-- 1950 — Transferts & placements +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1960, 'Épargne & placements', 1950, 'transfer', '#0ea5e9', 0, 1, 'categoriesSeed.transferts.epargne.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1961, 'REER / RRSP', 1960, 'transfer', '#0ea5e9', 1, 1, 'categoriesSeed.transferts.epargne.reer'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1962, 'CELI / TFSA', 1960, 'transfer', '#0284c7', 1, 2, 'categoriesSeed.transferts.epargne.celi'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1963, 'REEE / RESP', 1960, 'transfer', '#0369a1', 1, 3, 'categoriesSeed.transferts.epargne.reee'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1964, 'Compte non-enregistré', 1960, 'transfer', '#075985', 1, 4, 'categoriesSeed.transferts.epargne.nonEnregistre'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1965, 'Fonds d''urgence', 1960, 'transfer', '#0c4a6e', 1, 5, 'categoriesSeed.transferts.epargne.urgence'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1970, 'Remboursement de dette', 1950, 'transfer', '#7c3aed', 0, 2, 'categoriesSeed.transferts.dette.root'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1971, 'Paiement carte crédit', 1970, 'transfer', '#7c3aed', 1, 1, 'categoriesSeed.transferts.dette.carteCredit'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1972, 'Remboursement prêt étudiant', 1970, 'transfer', '#8b5cf6', 1, 2, 'categoriesSeed.transferts.dette.etudiant'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1973, 'Remboursement prêt perso', 1970, 'transfer', '#a78bfa', 1, 3, 'categoriesSeed.transferts.dette.personnel'); +INSERT INTO categories (id, name, parent_id, type, color, is_inputable, sort_order, i18n_key) VALUES (1980, 'Transferts internes', 1950, 'transfer', '#64748b', 1, 3, 'categoriesSeed.transferts.internes'); + +-- ============================================================================ +-- Keywords — Canadian suppliers (150+ entries) +-- ============================================================================ + +-- Alimentation > Épicerie régulière (1111) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('METRO', 1111, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('IGA', 1111, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('MAXI', 1111, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('SUPER C', 1111, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('LOBLAWS', 1111, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PROVIGO', 1111, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('ADONIS', 1111, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('WHOLE FOODS', 1111, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('AVRIL', 1111, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('RACHELLE-BERY', 1111, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('COSTCO', 1111, 50); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('WALMART', 1111, 50); + +-- Épicerie > Boucherie (1112) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BOUCHERIE', 1112, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('POISSONNERIE', 1112, 0); + +-- Épicerie > Boulangerie (1113) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BOULANGERIE', 1113, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PATISSERIE', 1113, 0); + +-- Épicerie > Dépanneur (1114) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('COUCHE-TARD', 1114, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('DEPANNEUR', 1114, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('7-ELEVEN', 1114, 0); + +-- Restauration > Restaurant (1121) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('RESTAURANT', 1121, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BRASSERIE', 1121, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BISTRO', 1121, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('SUSHI', 1121, 0); + +-- Restauration > Café (1122) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('STARBUCKS', 1122, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('TIM HORTONS', 1122, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('SECOND CUP', 1122, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('VAN HOUTTE', 1122, 0); + +-- Restauration > Fast food (1123) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('MCDONALD', 1123, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('SUBWAY', 1123, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('A&W', 1123, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BURGER KING', 1123, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('KFC', 1123, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('DOMINOS', 1123, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PIZZA HUT', 1123, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BELLE PROVINCE', 1123, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('ST-HUBERT', 1123, 0); + +-- Restauration > Livraison (1124) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('DOORDASH', 1124, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('DD/DOORDASH', 1124, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('UBER EATS', 1124, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('SKIPTHEDISHES', 1124, 0); + +-- Logement > Hypothèque (1212) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('MTG/HYP', 1212, 0); + +-- Logement > Taxes municipales (1213) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('M-ST-HILAIRE TX', 1213, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('TAXES MUNICIPALES', 1213, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('CSS PATRIOT', 1213, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('TAXE SCOLAIRE', 1213, 0); + +-- Électricité (1221) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('HYDRO-QUEBEC', 1221, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('HYDRO QUEBEC', 1221, 0); + +-- Gaz (1222) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('ENERGIR', 1222, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('GAZ METRO', 1222, 0); + +-- Internet (1231) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('VIDEOTRON', 1231, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BELL INTERNET', 1231, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('ORICOM', 1231, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('COGECO', 1231, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('EBOX', 1231, 0); + +-- Mobile (1232) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('FIZZ', 1232, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('KOODO', 1232, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PUBLIC MOBILE', 1232, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('VIRGIN', 1232, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BELL MOBILITE', 1232, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('TELUS MOBILE', 1232, 0); + +-- Entretien maison (1241) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('IKEA', 1241, 0); + +-- Matériaux & outils (1243) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('CANADIAN TIRE', 1243, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('CANAC', 1243, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('RONA', 1243, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('HOME DEPOT', 1243, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BMR', 1243, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PRINCESS AUTO', 1243, 0); + +-- Assurance habitation (1250) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BELAIR', 1250, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PRYSM', 1250, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('INTACT ASSURANCE', 1250, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('DESJARDINS ASSURANCE', 1250, 0); + +-- Meubles (1311) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('TANGUAY', 1311, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('LEON', 1311, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('STRUCTUBE', 1311, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BRICK', 1311, 0); + +-- Électroménagers (1312) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BEST BUY', 1312, 0); + +-- Décoration (1313) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BOUCLAIR', 1313, 0); + +-- Vêtements (1410) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('UNIQLO', 1410, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('WINNERS', 1410, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('SIMONS', 1410, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('MARKS', 1410, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('H&M', 1410, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('OLD NAVY', 1410, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('GAP', 1410, 0); + +-- Transport — Essence (1512) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('SHELL', 1512, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('ESSO', 1512, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('ULTRAMAR', 1512, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PETRO-CANADA', 1512, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PETRO CANADA', 1512, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('CREVIER', 1512, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('HARNOIS', 1512, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('COUCHE-TARD ESSENCE', 1512, 10); + +-- Permis / SAAQ (1514) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('SAAQ', 1514, 0); + +-- Transport public — autobus/métro (1521) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('STM', 1521, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('RTC', 1521, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('STL', 1521, 0); + +-- Train de banlieue (1522) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('GARE MONT-SAINT', 1522, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('GARE SAINT-HUBERT', 1522, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('GARE CENTRALE', 1522, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('EXO', 1522, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('REM', 1522, 0); + +-- Taxi / Uber (1523) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('UBER', 1523, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('LYFT', 1523, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('TAXI', 1523, 0); + +-- Avion (1531) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('AIR CANADA', 1531, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('WESTJET', 1531, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('AIR TRANSAT', 1531, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PORTER', 1531, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('AEROPORTS DE MONTREAL', 1531, 0); + +-- Hébergement (1533) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('AIRBNB', 1533, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('HILTON', 1533, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('MARRIOTT', 1533, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BOOKING.COM', 1533, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('NORWEGIAN CRUISE', 1533, 0); + +-- Pharmacie (1611) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('JEAN COUTU', 1611, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('FAMILIPRIX', 1611, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PHARMAPRIX', 1611, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PROXIM', 1611, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('UNIPRIX', 1611, 0); + +-- Thérapies (1615) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PHYSIOACTIF', 1615, 0); + +-- Cinéma & spectacles (1711) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('CINEPLEX', 1711, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('CINEMA DU PARC', 1711, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('TICKETMASTER', 1711, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('CLUB SODA', 1711, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('LEPOINTDEVENTE', 1711, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('EVENBRITE', 1711, 0); + +-- Jeux vidéo (1712) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('STEAMGAMES', 1712, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PLAYSTATION', 1712, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('NINTENDO', 1712, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('XBOX', 1712, 0); + +-- Streaming vidéo (1713) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('NETFLIX', 1713, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PRIMEVIDEO', 1713, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('DISNEY PLUS', 1713, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('CRAVE', 1713, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('APPLE TV', 1713, 0); + +-- Streaming musique (1714) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('SPOTIFY', 1714, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('APPLE MUSIC', 1714, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('YOUTUBE MUSIC', 1714, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('TIDAL', 1714, 0); + +-- Jouets & hobbies (1715) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('LEGO', 1715, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('TOYS R US', 1715, 0); + +-- Équipement sportif (1722) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('MOUNTAIN EQUIPMENT', 1722, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('LA CORDEE', 1722, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('DECATHLON', 1722, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('SPORTS EXPERTS', 1722, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('ATMOSPHERE', 1722, 0); + +-- Parcs & activités (1723) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('SEPAQ', 1723, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('BLOC SHOP', 1723, 0); + +-- Lecture (1741) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('RENAUD-BRAY', 1741, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('INDIGO', 1741, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('ARCHAMBAULT', 1741, 0); + +-- Animaux — nourriture (1751) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('MONDOU', 1751, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PET SMART', 1751, 0); + +-- Alcool (1810) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('SAQ', 1810, 0); + +-- Cannabis (1820) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('SQDC', 1820, 0); + +-- Frais bancaires (1911) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PROGRAMME PERFORMANCE', 1911, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('FRAIS MENSUELS', 1911, 0); + +-- Impôts (1921, 1922) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('GOUV. QUEBEC', 1922, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('REVENU QUEBEC', 1922, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('ARC IMPOT', 1921, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('CRA TAX', 1921, 0); + +-- Dons de charité (1931) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('OXFAM', 1931, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('CENTRAIDE', 1931, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('FPA', 1931, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('CROIX-ROUGE', 1931, 0); + +-- Cotisations professionnelles (1932) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('ORDRE DES COMPTABL', 1932, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('CPA CANADA', 1932, 0); + +-- Cadeaux (1940) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('DANS UN JARDIN', 1940, 0); + +-- Divers (1946) — catch-all marketplace +INSERT INTO keywords (keyword, category_id, priority) VALUES ('AMAZON', 1946, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('AMZN', 1946, 0); + +-- Placements (1964) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('WS INVESTMENTS', 1964, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('WEALTHSIMPLE', 1964, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PEAK INVESTMENT', 1964, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('DYNAMIC FUND', 1964, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('FIDELITY', 1964, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('AGF', 1964, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('QUESTRADE', 1964, 0); + +-- Paie (1011) +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PAY/PAY', 1011, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('DEPOT PAIE', 1011, 0); +INSERT INTO keywords (keyword, category_id, priority) VALUES ('PAYROLL', 1011, 0); diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 80cabec..290cb22 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -82,6 +82,19 @@ pub fn run() { UPDATE keywords SET category_id = 312 WHERE keyword = 'INS/ASS' AND category_id = 31;", kind: MigrationKind::Up, }, + // Migration v8 — additive: tag existing profiles with the v2 categories + // taxonomy and add a nullable i18n_key column on categories so the v1 + // IPC seed (applied only to brand-new profiles via consolidated_schema) + // can store translation keys. Existing v2 profiles are untouched: the + // column defaults to NULL (falling back to the category's `name`) and + // the preference is a no-op INSERT OR IGNORE so re-runs are safe. + Migration { + version: 8, + description: "add i18n_key to categories and categories_schema_version preference", + sql: "ALTER TABLE categories ADD COLUMN i18n_key TEXT; + INSERT OR IGNORE INTO user_preferences (key, value) VALUES ('categories_schema_version', 'v2');", + kind: MigrationKind::Up, + }, ]; tauri::Builder::default() diff --git a/src/components/categories/CategoryTree.tsx b/src/components/categories/CategoryTree.tsx index 68d4287..18bea05 100644 --- a/src/components/categories/CategoryTree.tsx +++ b/src/components/categories/CategoryTree.tsx @@ -129,7 +129,9 @@ function TreeRowContent({ className="w-3 h-3 rounded-full flex-shrink-0" style={{ backgroundColor: node.color ?? "#9ca3af" }} /> - {node.name} + + {node.i18n_key ? t(node.i18n_key, { defaultValue: node.name }) : node.name} + {node.keyword_count > 0 && ( diff --git a/src/components/shared/CategoryCombobox.tsx b/src/components/shared/CategoryCombobox.tsx index 3dfa347..a8ad312 100644 --- a/src/components/shared/CategoryCombobox.tsx +++ b/src/components/shared/CategoryCombobox.tsx @@ -1,4 +1,5 @@ import { useState, useRef, useEffect, useCallback, useId, useMemo } from "react"; +import { useTranslation } from "react-i18next"; import type { Category } from "../../shared/types"; interface CategoryComboboxProps { @@ -54,6 +55,7 @@ export default function CategoryCombobox({ onExtraSelect, activeExtra, }: CategoryComboboxProps) { + const { t } = useTranslation(); const [open, setOpen] = useState(false); const [query, setQuery] = useState(""); const [highlightIndex, setHighlightIndex] = useState(0); @@ -66,15 +68,24 @@ export default function CategoryCombobox({ const depths = useMemo(() => computeDepths(categories), [categories]); + // Resolve the display name for a category: seed rows carry an i18n_key that + // we translate with name as defaultValue; user-created rows just use name. + const displayName = useCallback( + (c: Category) => (c.i18n_key ? t(c.i18n_key, { defaultValue: c.name }) : c.name), + [t] + ); + const selectedCategory = categories.find((c) => c.id === value); const displayLabel = activeExtra != null ? extraOptions?.find((o) => o.value === activeExtra)?.label ?? "" - : selectedCategory?.name ?? ""; + : selectedCategory + ? displayName(selectedCategory) + : ""; const normalizedQuery = normalize(query); const filtered = query - ? categories.filter((c) => normalize(c.name).includes(normalizedQuery)) + ? categories.filter((c) => normalize(displayName(c)).includes(normalizedQuery)) : categories; const filteredExtras = extraOptions @@ -228,7 +239,7 @@ export default function CategoryCombobox({ style={depth > 0 ? { paddingLeft: `calc(${compact ? "0.5rem" : "0.75rem"} + ${depth * 1}rem)` } : undefined} > {indent} - {cat.name} + {displayName(cat)} ); })} diff --git a/src/data/categoryTaxonomyV1.json b/src/data/categoryTaxonomyV1.json new file mode 100644 index 0000000..13e143f --- /dev/null +++ b/src/data/categoryTaxonomyV1.json @@ -0,0 +1,498 @@ +{ + "version": "v1", + "description": "IPC Statistique Canada-aligned category taxonomy, 3 levels, Canada/Québec. Derived from src-tauri/src/database/consolidated_schema.sql — keep the two in sync when rolling a new seed version.", + "roots": [ + { + "id": 1000, + "name": "Revenus", + "i18n_key": "categoriesSeed.revenus.root", + "type": "income", + "color": "#16a34a", + "sort_order": 1, + "children": [ + { + "id": 1010, + "name": "Emploi", + "i18n_key": "categoriesSeed.revenus.emploi.root", + "type": "income", + "color": "#22c55e", + "sort_order": 1, + "children": [ + { "id": 1011, "name": "Paie régulière", "i18n_key": "categoriesSeed.revenus.emploi.paie", "type": "income", "color": "#22c55e", "sort_order": 1, "children": [] }, + { "id": 1012, "name": "Primes & bonus", "i18n_key": "categoriesSeed.revenus.emploi.primes", "type": "income", "color": "#4ade80", "sort_order": 2, "children": [] }, + { "id": 1013, "name": "Travail autonome", "i18n_key": "categoriesSeed.revenus.emploi.autonome", "type": "income", "color": "#86efac", "sort_order": 3, "children": [] } + ] + }, + { + "id": 1020, + "name": "Gouvernemental", + "i18n_key": "categoriesSeed.revenus.gouvernemental.root", + "type": "income", + "color": "#16a34a", + "sort_order": 2, + "children": [ + { "id": 1021, "name": "Remboursement impôt", "i18n_key": "categoriesSeed.revenus.gouvernemental.remboursementImpot", "type": "income", "color": "#16a34a", "sort_order": 1, "children": [] }, + { "id": 1022, "name": "Allocations familiales", "i18n_key": "categoriesSeed.revenus.gouvernemental.allocations", "type": "income", "color": "#15803d", "sort_order": 2, "children": [] }, + { "id": 1023, "name": "Crédits TPS/TVQ", "i18n_key": "categoriesSeed.revenus.gouvernemental.credits", "type": "income", "color": "#166534", "sort_order": 3, "children": [] }, + { "id": 1024, "name": "Assurance-emploi / RQAP", "i18n_key": "categoriesSeed.revenus.gouvernemental.assuranceEmploi", "type": "income", "color": "#14532d", "sort_order": 4, "children": [] } + ] + }, + { + "id": 1030, + "name": "Revenus de placement", + "i18n_key": "categoriesSeed.revenus.placement.root", + "type": "income", + "color": "#10b981", + "sort_order": 3, + "children": [ + { "id": 1031, "name": "Intérêts & dividendes", "i18n_key": "categoriesSeed.revenus.placement.interets", "type": "income", "color": "#10b981", "sort_order": 1, "children": [] }, + { "id": 1032, "name": "Gains en capital", "i18n_key": "categoriesSeed.revenus.placement.capital", "type": "income", "color": "#059669", "sort_order": 2, "children": [] }, + { "id": 1033, "name": "Revenus locatifs", "i18n_key": "categoriesSeed.revenus.placement.locatifs", "type": "income", "color": "#047857", "sort_order": 3, "children": [] } + ] + }, + { "id": 1090, "name": "Autres revenus", "i18n_key": "categoriesSeed.revenus.autres", "type": "income", "color": "#84cc16", "sort_order": 9, "children": [] } + ] + }, + { + "id": 1100, + "name": "Alimentation", + "i18n_key": "categoriesSeed.alimentation.root", + "type": "expense", + "color": "#ea580c", + "sort_order": 2, + "children": [ + { + "id": 1110, + "name": "Épicerie & marché", + "i18n_key": "categoriesSeed.alimentation.epicerie.root", + "type": "expense", + "color": "#ea580c", + "sort_order": 1, + "children": [ + { "id": 1111, "name": "Épicerie régulière", "i18n_key": "categoriesSeed.alimentation.epicerie.reguliere", "type": "expense", "color": "#ea580c", "sort_order": 1, "children": [] }, + { "id": 1112, "name": "Boucherie & poissonnerie", "i18n_key": "categoriesSeed.alimentation.epicerie.boucherie", "type": "expense", "color": "#c2410c", "sort_order": 2, "children": [] }, + { "id": 1113, "name": "Boulangerie & pâtisserie", "i18n_key": "categoriesSeed.alimentation.epicerie.boulangerie", "type": "expense", "color": "#9a3412", "sort_order": 3, "children": [] }, + { "id": 1114, "name": "Dépanneur", "i18n_key": "categoriesSeed.alimentation.epicerie.depanneur", "type": "expense", "color": "#7c2d12", "sort_order": 4, "children": [] }, + { "id": 1115, "name": "Marché & produits spécialisés", "i18n_key": "categoriesSeed.alimentation.epicerie.marche", "type": "expense", "color": "#fb923c", "sort_order": 5, "children": [] } + ] + }, + { + "id": 1120, + "name": "Restauration", + "i18n_key": "categoriesSeed.alimentation.restauration.root", + "type": "expense", + "color": "#f97316", + "sort_order": 2, + "children": [ + { "id": 1121, "name": "Restaurant", "i18n_key": "categoriesSeed.alimentation.restauration.restaurant", "type": "expense", "color": "#f97316", "sort_order": 1, "children": [] }, + { "id": 1122, "name": "Café & boulangerie rapide", "i18n_key": "categoriesSeed.alimentation.restauration.cafe", "type": "expense", "color": "#fb923c", "sort_order": 2, "children": [] }, + { "id": 1123, "name": "Restauration rapide", "i18n_key": "categoriesSeed.alimentation.restauration.fastfood", "type": "expense", "color": "#fdba74", "sort_order": 3, "children": [] }, + { "id": 1124, "name": "Livraison à domicile", "i18n_key": "categoriesSeed.alimentation.restauration.livraison", "type": "expense", "color": "#fed7aa", "sort_order": 4, "children": [] }, + { "id": 1125, "name": "Cantine & cafétéria", "i18n_key": "categoriesSeed.alimentation.restauration.cantine", "type": "expense", "color": "#ffedd5", "sort_order": 5, "children": [] } + ] + } + ] + }, + { + "id": 1200, + "name": "Logement", + "i18n_key": "categoriesSeed.logement.root", + "type": "expense", + "color": "#dc2626", + "sort_order": 3, + "children": [ + { + "id": 1210, + "name": "Habitation principale", + "i18n_key": "categoriesSeed.logement.habitation.root", + "type": "expense", + "color": "#dc2626", + "sort_order": 1, + "children": [ + { "id": 1211, "name": "Loyer", "i18n_key": "categoriesSeed.logement.habitation.loyer", "type": "expense", "color": "#dc2626", "sort_order": 1, "children": [] }, + { "id": 1212, "name": "Hypothèque", "i18n_key": "categoriesSeed.logement.habitation.hypotheque", "type": "expense", "color": "#b91c1c", "sort_order": 2, "children": [] }, + { "id": 1213, "name": "Taxes municipales & scolaires", "i18n_key": "categoriesSeed.logement.habitation.taxes", "type": "expense", "color": "#991b1b", "sort_order": 3, "children": [] }, + { "id": 1214, "name": "Charges de copropriété", "i18n_key": "categoriesSeed.logement.habitation.copropriete", "type": "expense", "color": "#7f1d1d", "sort_order": 4, "children": [] } + ] + }, + { + "id": 1220, + "name": "Services publics", + "i18n_key": "categoriesSeed.logement.services.root", + "type": "expense", + "color": "#ef4444", + "sort_order": 2, + "children": [ + { "id": 1221, "name": "Électricité", "i18n_key": "categoriesSeed.logement.services.electricite", "type": "expense", "color": "#ef4444", "sort_order": 1, "children": [] }, + { "id": 1222, "name": "Gaz naturel", "i18n_key": "categoriesSeed.logement.services.gaz", "type": "expense", "color": "#f87171", "sort_order": 2, "children": [] }, + { "id": 1223, "name": "Chauffage (mazout, propane)", "i18n_key": "categoriesSeed.logement.services.chauffage", "type": "expense", "color": "#fca5a5", "sort_order": 3, "children": [] }, + { "id": 1224, "name": "Eau & égouts", "i18n_key": "categoriesSeed.logement.services.eau", "type": "expense", "color": "#fecaca", "sort_order": 4, "children": [] } + ] + }, + { + "id": 1230, + "name": "Communications", + "i18n_key": "categoriesSeed.logement.communications.root", + "type": "expense", + "color": "#6366f1", + "sort_order": 3, + "children": [ + { "id": 1231, "name": "Internet résidentiel", "i18n_key": "categoriesSeed.logement.communications.internet", "type": "expense", "color": "#6366f1", "sort_order": 1, "children": [] }, + { "id": 1232, "name": "Téléphonie mobile", "i18n_key": "categoriesSeed.logement.communications.mobile", "type": "expense", "color": "#818cf8", "sort_order": 2, "children": [] }, + { "id": 1233, "name": "Téléphonie résidentielle", "i18n_key": "categoriesSeed.logement.communications.residentielle", "type": "expense", "color": "#a5b4fc", "sort_order": 3, "children": [] }, + { "id": 1234, "name": "Câblodistribution & streaming TV", "i18n_key": "categoriesSeed.logement.communications.streamingTv", "type": "expense", "color": "#c7d2fe", "sort_order": 4, "children": [] } + ] + }, + { + "id": 1240, + "name": "Entretien & réparations", + "i18n_key": "categoriesSeed.logement.entretien.root", + "type": "expense", + "color": "#e11d48", + "sort_order": 4, + "children": [ + { "id": 1241, "name": "Entretien général", "i18n_key": "categoriesSeed.logement.entretien.general", "type": "expense", "color": "#e11d48", "sort_order": 1, "children": [] }, + { "id": 1242, "name": "Rénovations", "i18n_key": "categoriesSeed.logement.entretien.renovations", "type": "expense", "color": "#be123c", "sort_order": 2, "children": [] }, + { "id": 1243, "name": "Matériaux & outils", "i18n_key": "categoriesSeed.logement.entretien.materiaux", "type": "expense", "color": "#9f1239", "sort_order": 3, "children": [] }, + { "id": 1244, "name": "Aménagement paysager", "i18n_key": "categoriesSeed.logement.entretien.paysager", "type": "expense", "color": "#881337", "sort_order": 4, "children": [] } + ] + }, + { "id": 1250, "name": "Assurance habitation", "i18n_key": "categoriesSeed.logement.assurance", "type": "expense", "color": "#14b8a6", "sort_order": 5, "children": [] } + ] + }, + { + "id": 1300, + "name": "Ménage & ameublement", + "i18n_key": "categoriesSeed.menage.root", + "type": "expense", + "color": "#ca8a04", + "sort_order": 4, + "children": [ + { + "id": 1310, + "name": "Ameublement", + "i18n_key": "categoriesSeed.menage.ameublement.root", + "type": "expense", + "color": "#ca8a04", + "sort_order": 1, + "children": [ + { "id": 1311, "name": "Meubles", "i18n_key": "categoriesSeed.menage.ameublement.meubles", "type": "expense", "color": "#ca8a04", "sort_order": 1, "children": [] }, + { "id": 1312, "name": "Électroménagers", "i18n_key": "categoriesSeed.menage.ameublement.electromenagers", "type": "expense", "color": "#a16207", "sort_order": 2, "children": [] }, + { "id": 1313, "name": "Décoration", "i18n_key": "categoriesSeed.menage.ameublement.decoration", "type": "expense", "color": "#854d0e", "sort_order": 3, "children": [] } + ] + }, + { + "id": 1320, + "name": "Fournitures ménagères", + "i18n_key": "categoriesSeed.menage.fournitures.root", + "type": "expense", + "color": "#eab308", + "sort_order": 2, + "children": [ + { "id": 1321, "name": "Produits d'entretien", "i18n_key": "categoriesSeed.menage.fournitures.entretien", "type": "expense", "color": "#eab308", "sort_order": 1, "children": [] }, + { "id": 1322, "name": "Literie & linge de maison", "i18n_key": "categoriesSeed.menage.fournitures.literie", "type": "expense", "color": "#facc15", "sort_order": 2, "children": [] }, + { "id": 1323, "name": "Vaisselle & ustensiles", "i18n_key": "categoriesSeed.menage.fournitures.vaisselle", "type": "expense", "color": "#fde047", "sort_order": 3, "children": [] } + ] + }, + { + "id": 1330, + "name": "Services domestiques", + "i18n_key": "categoriesSeed.menage.services.root", + "type": "expense", + "color": "#fbbf24", + "sort_order": 3, + "children": [ + { "id": 1331, "name": "Ménage & nettoyage", "i18n_key": "categoriesSeed.menage.services.nettoyage", "type": "expense", "color": "#fbbf24", "sort_order": 1, "children": [] }, + { "id": 1332, "name": "Buanderie & pressing", "i18n_key": "categoriesSeed.menage.services.buanderie", "type": "expense", "color": "#fcd34d", "sort_order": 2, "children": [] } + ] + } + ] + }, + { + "id": 1400, + "name": "Vêtements & chaussures", + "i18n_key": "categoriesSeed.vetements.root", + "type": "expense", + "color": "#d946ef", + "sort_order": 5, + "children": [ + { "id": 1410, "name": "Vêtements adultes", "i18n_key": "categoriesSeed.vetements.adultes", "type": "expense", "color": "#d946ef", "sort_order": 1, "children": [] }, + { "id": 1420, "name": "Vêtements enfants", "i18n_key": "categoriesSeed.vetements.enfants", "type": "expense", "color": "#c026d3", "sort_order": 2, "children": [] }, + { "id": 1430, "name": "Chaussures", "i18n_key": "categoriesSeed.vetements.chaussures", "type": "expense", "color": "#a21caf", "sort_order": 3, "children": [] }, + { "id": 1440, "name": "Accessoires & bijoux", "i18n_key": "categoriesSeed.vetements.accessoires", "type": "expense", "color": "#86198f", "sort_order": 4, "children": [] } + ] + }, + { + "id": 1500, + "name": "Transport", + "i18n_key": "categoriesSeed.transport.root", + "type": "expense", + "color": "#2563eb", + "sort_order": 6, + "children": [ + { + "id": 1510, + "name": "Véhicule personnel", + "i18n_key": "categoriesSeed.transport.vehicule.root", + "type": "expense", + "color": "#2563eb", + "sort_order": 1, + "children": [ + { "id": 1511, "name": "Achat / location véhicule", "i18n_key": "categoriesSeed.transport.vehicule.achat", "type": "expense", "color": "#2563eb", "sort_order": 1, "children": [] }, + { "id": 1512, "name": "Essence", "i18n_key": "categoriesSeed.transport.vehicule.essence", "type": "expense", "color": "#1d4ed8", "sort_order": 2, "children": [] }, + { "id": 1513, "name": "Entretien & réparations auto", "i18n_key": "categoriesSeed.transport.vehicule.entretien", "type": "expense", "color": "#1e40af", "sort_order": 3, "children": [] }, + { "id": 1514, "name": "Immatriculation & permis", "i18n_key": "categoriesSeed.transport.vehicule.immatriculation", "type": "expense", "color": "#1e3a8a", "sort_order": 4, "children": [] }, + { "id": 1515, "name": "Stationnement & péages", "i18n_key": "categoriesSeed.transport.vehicule.stationnement", "type": "expense", "color": "#3b82f6", "sort_order": 5, "children": [] }, + { "id": 1516, "name": "Assurance auto", "i18n_key": "categoriesSeed.transport.vehicule.assurance", "type": "expense", "color": "#60a5fa", "sort_order": 6, "children": [] } + ] + }, + { + "id": 1520, + "name": "Transport public", + "i18n_key": "categoriesSeed.transport.public.root", + "type": "expense", + "color": "#0ea5e9", + "sort_order": 2, + "children": [ + { "id": 1521, "name": "Autobus & métro", "i18n_key": "categoriesSeed.transport.public.autobus", "type": "expense", "color": "#0ea5e9", "sort_order": 1, "children": [] }, + { "id": 1522, "name": "Train de banlieue", "i18n_key": "categoriesSeed.transport.public.train", "type": "expense", "color": "#0284c7", "sort_order": 2, "children": [] }, + { "id": 1523, "name": "Taxi & covoiturage", "i18n_key": "categoriesSeed.transport.public.taxi", "type": "expense", "color": "#0369a1", "sort_order": 3, "children": [] } + ] + }, + { + "id": 1530, + "name": "Voyages longue distance", + "i18n_key": "categoriesSeed.transport.voyages.root", + "type": "expense", + "color": "#38bdf8", + "sort_order": 3, + "children": [ + { "id": 1531, "name": "Avion", "i18n_key": "categoriesSeed.transport.voyages.avion", "type": "expense", "color": "#38bdf8", "sort_order": 1, "children": [] }, + { "id": 1532, "name": "Train & autocar", "i18n_key": "categoriesSeed.transport.voyages.trainAutocar", "type": "expense", "color": "#7dd3fc", "sort_order": 2, "children": [] }, + { "id": 1533, "name": "Hébergement", "i18n_key": "categoriesSeed.transport.voyages.hebergement", "type": "expense", "color": "#bae6fd", "sort_order": 3, "children": [] }, + { "id": 1534, "name": "Location véhicule voyage", "i18n_key": "categoriesSeed.transport.voyages.location", "type": "expense", "color": "#e0f2fe", "sort_order": 4, "children": [] } + ] + } + ] + }, + { + "id": 1600, + "name": "Santé & soins personnels", + "i18n_key": "categoriesSeed.sante.root", + "type": "expense", + "color": "#f43f5e", + "sort_order": 7, + "children": [ + { + "id": 1610, + "name": "Soins médicaux", + "i18n_key": "categoriesSeed.sante.medicaux.root", + "type": "expense", + "color": "#f43f5e", + "sort_order": 1, + "children": [ + { "id": 1611, "name": "Pharmacie", "i18n_key": "categoriesSeed.sante.medicaux.pharmacie", "type": "expense", "color": "#f43f5e", "sort_order": 1, "children": [] }, + { "id": 1612, "name": "Consultations médicales", "i18n_key": "categoriesSeed.sante.medicaux.consultations", "type": "expense", "color": "#e11d48", "sort_order": 2, "children": [] }, + { "id": 1613, "name": "Dentiste & orthodontiste", "i18n_key": "categoriesSeed.sante.medicaux.dentiste", "type": "expense", "color": "#be123c", "sort_order": 3, "children": [] }, + { "id": 1614, "name": "Optométrie & lunettes", "i18n_key": "categoriesSeed.sante.medicaux.optometrie", "type": "expense", "color": "#9f1239", "sort_order": 4, "children": [] }, + { "id": 1615, "name": "Thérapies (physio, psycho, etc.)", "i18n_key": "categoriesSeed.sante.medicaux.therapies", "type": "expense", "color": "#881337", "sort_order": 5, "children": [] }, + { "id": 1616, "name": "Assurance santé complémentaire", "i18n_key": "categoriesSeed.sante.medicaux.assurance", "type": "expense", "color": "#fb7185", "sort_order": 6, "children": [] } + ] + }, + { + "id": 1620, + "name": "Soins personnels", + "i18n_key": "categoriesSeed.sante.personnels.root", + "type": "expense", + "color": "#fb7185", + "sort_order": 2, + "children": [ + { "id": 1621, "name": "Coiffure & esthétique", "i18n_key": "categoriesSeed.sante.personnels.coiffure", "type": "expense", "color": "#fb7185", "sort_order": 1, "children": [] }, + { "id": 1622, "name": "Produits de soins corporels", "i18n_key": "categoriesSeed.sante.personnels.soins", "type": "expense", "color": "#fda4af", "sort_order": 2, "children": [] } + ] + }, + { "id": 1630, "name": "Assurance vie & invalidité", "i18n_key": "categoriesSeed.sante.assuranceVie", "type": "expense", "color": "#14b8a6", "sort_order": 3, "children": [] } + ] + }, + { + "id": 1700, + "name": "Loisirs, formation & lecture", + "i18n_key": "categoriesSeed.loisirs.root", + "type": "expense", + "color": "#8b5cf6", + "sort_order": 8, + "children": [ + { + "id": 1710, + "name": "Divertissement", + "i18n_key": "categoriesSeed.loisirs.divertissement.root", + "type": "expense", + "color": "#8b5cf6", + "sort_order": 1, + "children": [ + { "id": 1711, "name": "Cinéma & spectacles", "i18n_key": "categoriesSeed.loisirs.divertissement.cinema", "type": "expense", "color": "#8b5cf6", "sort_order": 1, "children": [] }, + { "id": 1712, "name": "Jeux vidéo & consoles", "i18n_key": "categoriesSeed.loisirs.divertissement.jeux", "type": "expense", "color": "#a78bfa", "sort_order": 2, "children": [] }, + { "id": 1713, "name": "Streaming vidéo", "i18n_key": "categoriesSeed.loisirs.divertissement.streamingVideo", "type": "expense", "color": "#c4b5fd", "sort_order": 3, "children": [] }, + { "id": 1714, "name": "Streaming musique & audio", "i18n_key": "categoriesSeed.loisirs.divertissement.streamingMusique", "type": "expense", "color": "#ddd6fe", "sort_order": 4, "children": [] }, + { "id": 1715, "name": "Jouets & passe-temps", "i18n_key": "categoriesSeed.loisirs.divertissement.jouets", "type": "expense", "color": "#ede9fe", "sort_order": 5, "children": [] } + ] + }, + { + "id": 1720, + "name": "Sports & plein air", + "i18n_key": "categoriesSeed.loisirs.sports.root", + "type": "expense", + "color": "#22c55e", + "sort_order": 2, + "children": [ + { "id": 1721, "name": "Abonnements sportifs", "i18n_key": "categoriesSeed.loisirs.sports.abonnements", "type": "expense", "color": "#22c55e", "sort_order": 1, "children": [] }, + { "id": 1722, "name": "Équipement sportif", "i18n_key": "categoriesSeed.loisirs.sports.equipement", "type": "expense", "color": "#4ade80", "sort_order": 2, "children": [] }, + { "id": 1723, "name": "Parcs & activités plein air", "i18n_key": "categoriesSeed.loisirs.sports.parcs", "type": "expense", "color": "#86efac", "sort_order": 3, "children": [] } + ] + }, + { + "id": 1730, + "name": "Formation & éducation", + "i18n_key": "categoriesSeed.loisirs.formation.root", + "type": "expense", + "color": "#6366f1", + "sort_order": 3, + "children": [ + { "id": 1731, "name": "Scolarité (frais)", "i18n_key": "categoriesSeed.loisirs.formation.scolarite", "type": "expense", "color": "#6366f1", "sort_order": 1, "children": [] }, + { "id": 1732, "name": "Matériel scolaire", "i18n_key": "categoriesSeed.loisirs.formation.materiel", "type": "expense", "color": "#818cf8", "sort_order": 2, "children": [] }, + { "id": 1733, "name": "Cours & certifications", "i18n_key": "categoriesSeed.loisirs.formation.cours", "type": "expense", "color": "#a5b4fc", "sort_order": 3, "children": [] }, + { "id": 1734, "name": "Abonnements professionnels", "i18n_key": "categoriesSeed.loisirs.formation.abonnements", "type": "expense", "color": "#c7d2fe", "sort_order": 4, "children": [] } + ] + }, + { + "id": 1740, + "name": "Lecture & médias", + "i18n_key": "categoriesSeed.loisirs.lecture.root", + "type": "expense", + "color": "#ec4899", + "sort_order": 4, + "children": [ + { "id": 1741, "name": "Livres", "i18n_key": "categoriesSeed.loisirs.lecture.livres", "type": "expense", "color": "#ec4899", "sort_order": 1, "children": [] }, + { "id": 1742, "name": "Journaux & magazines", "i18n_key": "categoriesSeed.loisirs.lecture.journaux", "type": "expense", "color": "#f472b6", "sort_order": 2, "children": [] } + ] + }, + { + "id": 1750, + "name": "Animaux de compagnie", + "i18n_key": "categoriesSeed.loisirs.animaux.root", + "type": "expense", + "color": "#a855f7", + "sort_order": 5, + "children": [ + { "id": 1751, "name": "Nourriture & accessoires animaux", "i18n_key": "categoriesSeed.loisirs.animaux.nourriture", "type": "expense", "color": "#a855f7", "sort_order": 1, "children": [] }, + { "id": 1752, "name": "Vétérinaire", "i18n_key": "categoriesSeed.loisirs.animaux.veterinaire", "type": "expense", "color": "#c084fc", "sort_order": 2, "children": [] } + ] + } + ] + }, + { + "id": 1800, + "name": "Boissons, tabac & cannabis", + "i18n_key": "categoriesSeed.consommation.root", + "type": "expense", + "color": "#7c3aed", + "sort_order": 9, + "children": [ + { "id": 1810, "name": "Alcool (SAQ, microbrasseries)", "i18n_key": "categoriesSeed.consommation.alcool", "type": "expense", "color": "#7c3aed", "sort_order": 1, "children": [] }, + { "id": 1820, "name": "Cannabis (SQDC)", "i18n_key": "categoriesSeed.consommation.cannabis", "type": "expense", "color": "#6d28d9", "sort_order": 2, "children": [] }, + { "id": 1830, "name": "Tabac", "i18n_key": "categoriesSeed.consommation.tabac", "type": "expense", "color": "#5b21b6", "sort_order": 3, "children": [] } + ] + }, + { + "id": 1900, + "name": "Finances & obligations", + "i18n_key": "categoriesSeed.finances.root", + "type": "expense", + "color": "#6b7280", + "sort_order": 10, + "children": [ + { + "id": 1910, + "name": "Frais bancaires", + "i18n_key": "categoriesSeed.finances.fraisBancaires.root", + "type": "expense", + "color": "#6b7280", + "sort_order": 1, + "children": [ + { "id": 1911, "name": "Frais de compte", "i18n_key": "categoriesSeed.finances.fraisBancaires.compte", "type": "expense", "color": "#6b7280", "sort_order": 1, "children": [] }, + { "id": 1912, "name": "Intérêts & frais de crédit", "i18n_key": "categoriesSeed.finances.fraisBancaires.interets", "type": "expense", "color": "#9ca3af", "sort_order": 2, "children": [] }, + { "id": 1913, "name": "Frais de change", "i18n_key": "categoriesSeed.finances.fraisBancaires.change", "type": "expense", "color": "#d1d5db", "sort_order": 3, "children": [] } + ] + }, + { + "id": 1920, + "name": "Impôts & taxes", + "i18n_key": "categoriesSeed.finances.impots.root", + "type": "expense", + "color": "#dc2626", + "sort_order": 2, + "children": [ + { "id": 1921, "name": "Impôt fédéral", "i18n_key": "categoriesSeed.finances.impots.federal", "type": "expense", "color": "#dc2626", "sort_order": 1, "children": [] }, + { "id": 1922, "name": "Impôt provincial", "i18n_key": "categoriesSeed.finances.impots.provincial", "type": "expense", "color": "#b91c1c", "sort_order": 2, "children": [] }, + { "id": 1923, "name": "Acomptes provisionnels", "i18n_key": "categoriesSeed.finances.impots.acomptes", "type": "expense", "color": "#991b1b", "sort_order": 3, "children": [] } + ] + }, + { + "id": 1930, + "name": "Dons & cotisations", + "i18n_key": "categoriesSeed.finances.dons.root", + "type": "expense", + "color": "#ec4899", + "sort_order": 3, + "children": [ + { "id": 1931, "name": "Dons de charité", "i18n_key": "categoriesSeed.finances.dons.charite", "type": "expense", "color": "#ec4899", "sort_order": 1, "children": [] }, + { "id": 1932, "name": "Cotisations professionnelles", "i18n_key": "categoriesSeed.finances.dons.professionnelles", "type": "expense", "color": "#f472b6", "sort_order": 2, "children": [] }, + { "id": 1933, "name": "Cotisations syndicales", "i18n_key": "categoriesSeed.finances.dons.syndicales", "type": "expense", "color": "#f9a8d4", "sort_order": 3, "children": [] } + ] + }, + { "id": 1940, "name": "Cadeaux", "i18n_key": "categoriesSeed.finances.cadeaux", "type": "expense", "color": "#f43f5e", "sort_order": 4, "children": [] }, + { "id": 1945, "name": "Retrait cash", "i18n_key": "categoriesSeed.finances.cash", "type": "expense", "color": "#57534e", "sort_order": 5, "children": [] }, + { "id": 1946, "name": "Achats divers non catégorisés", "i18n_key": "categoriesSeed.finances.divers", "type": "expense", "color": "#78716c", "sort_order": 6, "children": [] } + ] + }, + { + "id": 1950, + "name": "Transferts & placements", + "i18n_key": "categoriesSeed.transferts.root", + "type": "transfer", + "color": "#0ea5e9", + "sort_order": 11, + "children": [ + { + "id": 1960, + "name": "Épargne & placements", + "i18n_key": "categoriesSeed.transferts.epargne.root", + "type": "transfer", + "color": "#0ea5e9", + "sort_order": 1, + "children": [ + { "id": 1961, "name": "REER / RRSP", "i18n_key": "categoriesSeed.transferts.epargne.reer", "type": "transfer", "color": "#0ea5e9", "sort_order": 1, "children": [] }, + { "id": 1962, "name": "CELI / TFSA", "i18n_key": "categoriesSeed.transferts.epargne.celi", "type": "transfer", "color": "#0284c7", "sort_order": 2, "children": [] }, + { "id": 1963, "name": "REEE / RESP", "i18n_key": "categoriesSeed.transferts.epargne.reee", "type": "transfer", "color": "#0369a1", "sort_order": 3, "children": [] }, + { "id": 1964, "name": "Compte non-enregistré", "i18n_key": "categoriesSeed.transferts.epargne.nonEnregistre", "type": "transfer", "color": "#075985", "sort_order": 4, "children": [] }, + { "id": 1965, "name": "Fonds d'urgence", "i18n_key": "categoriesSeed.transferts.epargne.urgence", "type": "transfer", "color": "#0c4a6e", "sort_order": 5, "children": [] } + ] + }, + { + "id": 1970, + "name": "Remboursement de dette", + "i18n_key": "categoriesSeed.transferts.dette.root", + "type": "transfer", + "color": "#7c3aed", + "sort_order": 2, + "children": [ + { "id": 1971, "name": "Paiement carte crédit", "i18n_key": "categoriesSeed.transferts.dette.carteCredit", "type": "transfer", "color": "#7c3aed", "sort_order": 1, "children": [] }, + { "id": 1972, "name": "Remboursement prêt étudiant", "i18n_key": "categoriesSeed.transferts.dette.etudiant", "type": "transfer", "color": "#8b5cf6", "sort_order": 2, "children": [] }, + { "id": 1973, "name": "Remboursement prêt perso", "i18n_key": "categoriesSeed.transferts.dette.personnel", "type": "transfer", "color": "#a78bfa", "sort_order": 3, "children": [] } + ] + }, + { "id": 1980, "name": "Transferts internes", "i18n_key": "categoriesSeed.transferts.internes", "type": "transfer", "color": "#64748b", "sort_order": 3, "children": [] } + ] + } + ] +} diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 5ddb2de..b286809 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -1002,5 +1002,233 @@ "body": "Your feedback will be sent to feedback.lacompagniemaximus.com so we can improve the app. This requires an internet connection and is an exception to the app's 100% local operation.", "accept": "I agree" } + }, + "categoriesSeed": { + "revenus": { + "root": "Income", + "emploi": { + "root": "Employment", + "paie": "Regular paycheque", + "primes": "Bonuses & premiums", + "autonome": "Self-employment" + }, + "gouvernemental": { + "root": "Government", + "remboursementImpot": "Tax refund", + "allocations": "Family allowances", + "credits": "GST/QST credits", + "assuranceEmploi": "Employment insurance / QPIP" + }, + "placement": { + "root": "Investment income", + "interets": "Interest & dividends", + "capital": "Capital gains", + "locatifs": "Rental income" + }, + "autres": "Other income" + }, + "alimentation": { + "root": "Food", + "epicerie": { + "root": "Groceries & markets", + "reguliere": "Regular groceries", + "boucherie": "Butcher & fishmonger", + "boulangerie": "Bakery & pastry", + "depanneur": "Convenience store", + "marche": "Markets & specialty food" + }, + "restauration": { + "root": "Dining out", + "restaurant": "Restaurant", + "cafe": "Coffee shop & quick bakery", + "fastfood": "Fast food", + "livraison": "Home delivery", + "cantine": "Cafeteria" + } + }, + "logement": { + "root": "Housing", + "habitation": { + "root": "Primary residence", + "loyer": "Rent", + "hypotheque": "Mortgage", + "taxes": "Municipal & school taxes", + "copropriete": "Condo fees" + }, + "services": { + "root": "Utilities", + "electricite": "Electricity", + "gaz": "Natural gas", + "chauffage": "Heating (oil, propane)", + "eau": "Water & sewer" + }, + "communications": { + "root": "Communications", + "internet": "Home internet", + "mobile": "Mobile phone", + "residentielle": "Landline phone", + "streamingTv": "Cable & TV streaming" + }, + "entretien": { + "root": "Maintenance & repairs", + "general": "General maintenance", + "renovations": "Renovations", + "materiaux": "Materials & tools", + "paysager": "Landscaping" + }, + "assurance": "Home insurance" + }, + "menage": { + "root": "Household & furnishings", + "ameublement": { + "root": "Furnishings", + "meubles": "Furniture", + "electromenagers": "Appliances", + "decoration": "Decoration" + }, + "fournitures": { + "root": "Household supplies", + "entretien": "Cleaning supplies", + "literie": "Bedding & linens", + "vaisselle": "Dishes & utensils" + }, + "services": { + "root": "Domestic services", + "nettoyage": "Cleaning services", + "buanderie": "Laundry & dry cleaning" + } + }, + "vetements": { + "root": "Clothing & footwear", + "adultes": "Adult clothing", + "enfants": "Children's clothing", + "chaussures": "Footwear", + "accessoires": "Accessories & jewelry" + }, + "transport": { + "root": "Transportation", + "vehicule": { + "root": "Personal vehicle", + "achat": "Vehicle purchase / lease", + "essence": "Gasoline", + "entretien": "Auto maintenance & repairs", + "immatriculation": "Registration & licence", + "stationnement": "Parking & tolls", + "assurance": "Auto insurance" + }, + "public": { + "root": "Public transit", + "autobus": "Bus & subway", + "train": "Commuter train", + "taxi": "Taxi & ride-sharing" + }, + "voyages": { + "root": "Long-distance travel", + "avion": "Air travel", + "trainAutocar": "Train & coach", + "hebergement": "Lodging", + "location": "Travel car rental" + } + }, + "sante": { + "root": "Health & personal care", + "medicaux": { + "root": "Medical care", + "pharmacie": "Pharmacy", + "consultations": "Medical consultations", + "dentiste": "Dentist & orthodontist", + "optometrie": "Optometry & eyewear", + "therapies": "Therapies (physio, psych, etc.)", + "assurance": "Supplemental health insurance" + }, + "personnels": { + "root": "Personal care", + "coiffure": "Haircare & esthetics", + "soins": "Personal care products" + }, + "assuranceVie": "Life & disability insurance" + }, + "loisirs": { + "root": "Leisure, education & reading", + "divertissement": { + "root": "Entertainment", + "cinema": "Cinema & shows", + "jeux": "Video games & consoles", + "streamingVideo": "Video streaming", + "streamingMusique": "Music & audio streaming", + "jouets": "Toys & hobbies" + }, + "sports": { + "root": "Sports & outdoors", + "abonnements": "Sports memberships", + "equipement": "Sports equipment", + "parcs": "Parks & outdoor activities" + }, + "formation": { + "root": "Education & training", + "scolarite": "Tuition fees", + "materiel": "School supplies", + "cours": "Courses & certifications", + "abonnements": "Professional subscriptions" + }, + "lecture": { + "root": "Reading & media", + "livres": "Books", + "journaux": "Newspapers & magazines" + }, + "animaux": { + "root": "Pets", + "nourriture": "Pet food & supplies", + "veterinaire": "Veterinarian" + } + }, + "consommation": { + "root": "Beverages, tobacco & cannabis", + "alcool": "Alcohol (SAQ, microbreweries)", + "cannabis": "Cannabis (SQDC)", + "tabac": "Tobacco" + }, + "finances": { + "root": "Finances & obligations", + "fraisBancaires": { + "root": "Bank fees", + "compte": "Account fees", + "interets": "Interest & credit fees", + "change": "Currency exchange fees" + }, + "impots": { + "root": "Taxes", + "federal": "Federal income tax", + "provincial": "Provincial income tax", + "acomptes": "Instalment payments" + }, + "dons": { + "root": "Donations & dues", + "charite": "Charitable donations", + "professionnelles": "Professional dues", + "syndicales": "Union dues" + }, + "cadeaux": "Gifts", + "cash": "Cash withdrawal", + "divers": "Miscellaneous uncategorized purchases" + }, + "transferts": { + "root": "Transfers & investments", + "epargne": { + "root": "Savings & investments", + "reer": "RRSP", + "celi": "TFSA", + "reee": "RESP", + "nonEnregistre": "Non-registered account", + "urgence": "Emergency fund" + }, + "dette": { + "root": "Debt repayment", + "carteCredit": "Credit card payment", + "etudiant": "Student loan repayment", + "personnel": "Personal loan repayment" + }, + "internes": "Internal transfers" + } } } diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 85bf55d..a543239 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -1002,5 +1002,233 @@ "body": "Votre feedback sera envoyé à feedback.lacompagniemaximus.com pour que nous puissions améliorer l'application. Cette opération nécessite une connexion Internet et constitue une exception au fonctionnement 100 % local de l'application.", "accept": "J'accepte" } + }, + "categoriesSeed": { + "revenus": { + "root": "Revenus", + "emploi": { + "root": "Emploi", + "paie": "Paie régulière", + "primes": "Primes & bonus", + "autonome": "Travail autonome" + }, + "gouvernemental": { + "root": "Gouvernemental", + "remboursementImpot": "Remboursement impôt", + "allocations": "Allocations familiales", + "credits": "Crédits TPS/TVQ", + "assuranceEmploi": "Assurance-emploi / RQAP" + }, + "placement": { + "root": "Revenus de placement", + "interets": "Intérêts & dividendes", + "capital": "Gains en capital", + "locatifs": "Revenus locatifs" + }, + "autres": "Autres revenus" + }, + "alimentation": { + "root": "Alimentation", + "epicerie": { + "root": "Épicerie & marché", + "reguliere": "Épicerie régulière", + "boucherie": "Boucherie & poissonnerie", + "boulangerie": "Boulangerie & pâtisserie", + "depanneur": "Dépanneur", + "marche": "Marché & produits spécialisés" + }, + "restauration": { + "root": "Restauration", + "restaurant": "Restaurant", + "cafe": "Café & boulangerie rapide", + "fastfood": "Restauration rapide", + "livraison": "Livraison à domicile", + "cantine": "Cantine & cafétéria" + } + }, + "logement": { + "root": "Logement", + "habitation": { + "root": "Habitation principale", + "loyer": "Loyer", + "hypotheque": "Hypothèque", + "taxes": "Taxes municipales & scolaires", + "copropriete": "Charges de copropriété" + }, + "services": { + "root": "Services publics", + "electricite": "Électricité", + "gaz": "Gaz naturel", + "chauffage": "Chauffage (mazout, propane)", + "eau": "Eau & égouts" + }, + "communications": { + "root": "Communications", + "internet": "Internet résidentiel", + "mobile": "Téléphonie mobile", + "residentielle": "Téléphonie résidentielle", + "streamingTv": "Câblodistribution & streaming TV" + }, + "entretien": { + "root": "Entretien & réparations", + "general": "Entretien général", + "renovations": "Rénovations", + "materiaux": "Matériaux & outils", + "paysager": "Aménagement paysager" + }, + "assurance": "Assurance habitation" + }, + "menage": { + "root": "Ménage & ameublement", + "ameublement": { + "root": "Ameublement", + "meubles": "Meubles", + "electromenagers": "Électroménagers", + "decoration": "Décoration" + }, + "fournitures": { + "root": "Fournitures ménagères", + "entretien": "Produits d'entretien", + "literie": "Literie & linge de maison", + "vaisselle": "Vaisselle & ustensiles" + }, + "services": { + "root": "Services domestiques", + "nettoyage": "Ménage & nettoyage", + "buanderie": "Buanderie & pressing" + } + }, + "vetements": { + "root": "Vêtements & chaussures", + "adultes": "Vêtements adultes", + "enfants": "Vêtements enfants", + "chaussures": "Chaussures", + "accessoires": "Accessoires & bijoux" + }, + "transport": { + "root": "Transport", + "vehicule": { + "root": "Véhicule personnel", + "achat": "Achat / location véhicule", + "essence": "Essence", + "entretien": "Entretien & réparations auto", + "immatriculation": "Immatriculation & permis", + "stationnement": "Stationnement & péages", + "assurance": "Assurance auto" + }, + "public": { + "root": "Transport public", + "autobus": "Autobus & métro", + "train": "Train de banlieue", + "taxi": "Taxi & covoiturage" + }, + "voyages": { + "root": "Voyages longue distance", + "avion": "Avion", + "trainAutocar": "Train & autocar", + "hebergement": "Hébergement", + "location": "Location véhicule voyage" + } + }, + "sante": { + "root": "Santé & soins personnels", + "medicaux": { + "root": "Soins médicaux", + "pharmacie": "Pharmacie", + "consultations": "Consultations médicales", + "dentiste": "Dentiste & orthodontiste", + "optometrie": "Optométrie & lunettes", + "therapies": "Thérapies (physio, psycho, etc.)", + "assurance": "Assurance santé complémentaire" + }, + "personnels": { + "root": "Soins personnels", + "coiffure": "Coiffure & esthétique", + "soins": "Produits de soins corporels" + }, + "assuranceVie": "Assurance vie & invalidité" + }, + "loisirs": { + "root": "Loisirs, formation & lecture", + "divertissement": { + "root": "Divertissement", + "cinema": "Cinéma & spectacles", + "jeux": "Jeux vidéo & consoles", + "streamingVideo": "Streaming vidéo", + "streamingMusique": "Streaming musique & audio", + "jouets": "Jouets & passe-temps" + }, + "sports": { + "root": "Sports & plein air", + "abonnements": "Abonnements sportifs", + "equipement": "Équipement sportif", + "parcs": "Parcs & activités plein air" + }, + "formation": { + "root": "Formation & éducation", + "scolarite": "Scolarité (frais)", + "materiel": "Matériel scolaire", + "cours": "Cours & certifications", + "abonnements": "Abonnements professionnels" + }, + "lecture": { + "root": "Lecture & médias", + "livres": "Livres", + "journaux": "Journaux & magazines" + }, + "animaux": { + "root": "Animaux de compagnie", + "nourriture": "Nourriture & accessoires animaux", + "veterinaire": "Vétérinaire" + } + }, + "consommation": { + "root": "Boissons, tabac & cannabis", + "alcool": "Alcool (SAQ, microbrasseries)", + "cannabis": "Cannabis (SQDC)", + "tabac": "Tabac" + }, + "finances": { + "root": "Finances & obligations", + "fraisBancaires": { + "root": "Frais bancaires", + "compte": "Frais de compte", + "interets": "Intérêts & frais de crédit", + "change": "Frais de change" + }, + "impots": { + "root": "Impôts & taxes", + "federal": "Impôt fédéral", + "provincial": "Impôt provincial", + "acomptes": "Acomptes provisionnels" + }, + "dons": { + "root": "Dons & cotisations", + "charite": "Dons de charité", + "professionnelles": "Cotisations professionnelles", + "syndicales": "Cotisations syndicales" + }, + "cadeaux": "Cadeaux", + "cash": "Retrait cash", + "divers": "Achats divers non catégorisés" + }, + "transferts": { + "root": "Transferts & placements", + "epargne": { + "root": "Épargne & placements", + "reer": "REER", + "celi": "CELI", + "reee": "REEE", + "nonEnregistre": "Compte non-enregistré", + "urgence": "Fonds d'urgence" + }, + "dette": { + "root": "Remboursement de dette", + "carteCredit": "Paiement carte crédit", + "etudiant": "Remboursement prêt étudiant", + "personnel": "Remboursement prêt perso" + }, + "internes": "Transferts internes" + } } } diff --git a/src/services/categoryService.ts b/src/services/categoryService.ts index f36837e..976bf2c 100644 --- a/src/services/categoryService.ts +++ b/src/services/categoryService.ts @@ -12,6 +12,7 @@ interface CategoryRow { is_inputable: boolean; sort_order: number; keyword_count: number; + i18n_key: string | null; } export async function getAllCategoriesWithCounts(): Promise { diff --git a/src/shared/types/index.ts b/src/shared/types/index.ts index 6e9b289..c9dc052 100644 --- a/src/shared/types/index.ts +++ b/src/shared/types/index.ts @@ -37,6 +37,13 @@ export interface Category { is_active: boolean; is_inputable: boolean; sort_order: number; + /** + * Translation key into `src/i18n/locales/*.json` under `categoriesSeed.*`. + * Populated by the v1 IPC-aligned seed; NULL for user-created categories + * and for v2 seed rows on existing profiles. Renderers must fall back to + * `name` when absent. + */ + i18n_key?: string | null; created_at: string; } @@ -489,6 +496,7 @@ export interface CategoryTreeNode { is_inputable: boolean; sort_order: number; keyword_count: number; + i18n_key: string | null; children: CategoryTreeNode[]; } -- 2.45.2