Files
crowdlending-app/_to_delete/extra_actifs_migration.py
2026-09-27 15:09:18 +02:00

72 lines
5.3 KiB
Python

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))