path = "backend/src/db/index.js" with open(path, "r", encoding="utf-8") as f: content = f.read() anchor = """db.prepare(` UPDATE enveloppes_referentiel SET plafond_eur = 61200, updated_at = datetime('now') WHERE nom = 'PEL' AND plafond_eur IS NULL `).run(); export default db; """ assert content.count(anchor) == 1, f"anchor count={content.count(anchor)}" block = '''db.prepare(` UPDATE enveloppes_referentiel SET plafond_eur = 61200, updated_at = datetime('now') WHERE nom = 'PEL' AND plafond_eur IS NULL `).run(); // Extension du 29/09/26 (demande Olivier) : "je ne voudrais pas faire un nième référentiel [...] // il faut peut-être que cela soit des catégories supplémentaires même si ce n'a pas tout à fait // le même statut" — plutôt qu'un 3e référentiel séparé pour les actifs "physiques"/hors // enveloppe fiscale (immobilier direct, crypto, métaux précieux, objets de collection, // participations non cotées), ils sont intégrés au référentiel existant : quelques nouvelles // catégories (familles) dans categories_enveloppes, et des enveloppes rattachées, sur le même // principe que les enveloppes SCPI/OPCI/SCI détenues en direct déjà présentes (aucun support — // détention directe, pas de menu de supports ; aucun institution_id — catalogue seul, comme le // reste de ce référentiel). Les participations non cotées réutilisent la catégorie existante // "Financement participatif / private equity" plutôt que d'en créer une nouvelle (même famille // que le Crowdequity et les FCPI/FIP). Toujours exécuté (INSERT OR IGNORE, clés UNIQUE sur nom) // — s'ajoute sans écraser à un référentiel déjà seedé, comme le backfill CEL/PEL ci-dessus. { const insCatEnvExtra = db.prepare('INSERT OR IGNORE INTO categories_enveloppes (nom) VALUES (?)'); for (const nom of ['Immobilier physique', 'Actifs numériques', 'Métaux précieux', 'Objets de collection']) { insCatEnvExtra.run(nom); } const EXTRA_ENVELOPPES = [ { nom: 'Résidence principale', categories: ['Immobilier physique'], description: "Logement occupé à titre de résidence principale.", plafond_eur: null, regime_fiscal: "Plus-value de cession exonérée (résidence principale)", supports: [] }, { nom: 'Immobilier locatif (détention directe)', categories: ['Immobilier physique'], description: "Bien immobilier loué, détenu en direct (hors SCPI/SCI).", plafond_eur: null, regime_fiscal: "Revenus fonciers (micro-foncier ou réel) + plus-value immobilière (abattement selon durée de détention)", supports: [] }, { nom: 'Compte crypto (exchange)', categories: ['Actifs numériques'], description: "Cryptomonnaies détenues sur une plateforme d'échange centralisée.", plafond_eur: null, regime_fiscal: "Flat tax 30 % sur les plus-values de cession (particuliers), déclaration 2086", supports: [] }, { nom: 'Wallet crypto (auto-conservation)', categories: ['Actifs numériques'], description: "Cryptomonnaies en auto-conservation (wallet matériel ou logiciel).", plafond_eur: null, regime_fiscal: "Flat tax 30 % sur les plus-values de cession (particuliers), déclaration 2086", supports: [] }, { nom: 'Métaux précieux physiques', categories: ['Métaux précieux'], description: "Or, argent... détenus physiquement (lingots, pièces).", plafond_eur: null, regime_fiscal: "Taxe forfaitaire sur les métaux précieux (11 %), ou option pour le régime des plus-values sur biens meubles si justificatifs d'achat", supports: [] }, { nom: 'Objets de collection', categories: ['Objets de collection'], description: "Montres, art, antiquités...", plafond_eur: null, regime_fiscal: "Taxe forfaitaire sur les objets d'art/collection/antiquité (6 %), ou option pour le régime des plus-values sur biens meubles si justificatifs d'achat", supports: [] }, { nom: 'Participation directe non cotée (startups/PME)', categories: ['Financement participatif / private equity'], description: "Prise de participation directe au capital d'une société non cotée, hors plateforme crowdequity.", plafond_eur: null, regime_fiscal: "Flat tax 30 % sur les plus-values (ou barème) ; réduction d'IR à l'entrée possible sous conditions (IR-PME/Madelin)", supports: [] }, ]; const insEnvRefExtra = db.prepare('INSERT OR IGNORE INTO enveloppes_referentiel (nom, description, plafond_eur, regime_fiscal) VALUES (?, ?, ?, ?)'); const getEnvRefIdExtra = db.prepare('SELECT id FROM enveloppes_referentiel WHERE nom = ?'); const getCatEnvIdExtra = db.prepare('SELECT id FROM categories_enveloppes WHERE nom = ?'); const linkEnvCatExtra = db.prepare('INSERT OR IGNORE INTO referentiel_categories_enveloppes (enveloppe_id, categorie_id) VALUES (?, ?)'); db.transaction(() => { for (const { nom, description, plafond_eur, regime_fiscal, categories } of EXTRA_ENVELOPPES) { insEnvRefExtra.run(nom, description ?? null, plafond_eur ?? null, regime_fiscal ?? null); const env = getEnvRefIdExtra.get(nom); if (!env) continue; for (const catNom of categories) { const cat = getCatEnvIdExtra.get(catNom); if (cat) linkEnvCatExtra.run(env.id, cat.id); } } })(); } export default db; ''' content = content.replace(anchor, block, 1) with open(path, "w", encoding="utf-8") as f: f.write(content) print("Extension actifs directs inserted OK, new length:", len(content))