FixBug: Décalrage de date des prêts différés
This commit is contained in:
+50
-14
@@ -227,27 +227,45 @@ if (rembCols.includes('autres_taxes')) {
|
||||
}
|
||||
|
||||
// ── Migration : renommage date_debut → date_premiere_echeance, date_echeance → date_cible ──
|
||||
//
|
||||
// ATTENTION (bug corrigé le 12/07/2026) : le bloc de "correction de formule" ci-dessous
|
||||
// (SET date_cible = date_premiere_echeance + (duree_mois-1) mois, SANS clause IS NULL)
|
||||
// s'exécutait auparavant à CHAQUE démarrage du serveur, pour TOUS les investissements,
|
||||
// quel que soit type_remb. Combiné à la migration suivante (qui recopie date_cible dans
|
||||
// date_premiere_echeance pour les prêts différés), cela créait une boucle : à chaque
|
||||
// redémarrage, date_cible dérivait de +(duree_mois-1) mois supplémentaires, sans jamais
|
||||
// être tracé dans investissement_historique. C'est la cause des dates aberrantes (parfois
|
||||
// des siècles dans le futur) observées sur les prêts différés. La correction ne doit
|
||||
// s'exécuter qu'UNE SEULE FOIS, au moment réel du renommage de colonne — jamais après.
|
||||
{
|
||||
const cols = db.prepare('PRAGMA table_info(investissements)').all().map(c => c.name);
|
||||
const migrationEnCours = cols.includes('date_debut') || cols.includes('date_echeance');
|
||||
|
||||
if (cols.includes('date_debut')) {
|
||||
db.exec('ALTER TABLE investissements RENAME COLUMN date_debut TO date_premiere_echeance');
|
||||
}
|
||||
if (cols.includes('date_echeance')) {
|
||||
db.exec('ALTER TABLE investissements RENAME COLUMN date_echeance TO date_cible');
|
||||
}
|
||||
// Backfill date_premiere_echeance = souscription + 1 mois si vide
|
||||
// Backfill date_premiere_echeance = souscription + 1 mois si vide (idempotent : ne touche
|
||||
// jamais une valeur déjà renseignée)
|
||||
db.exec(`UPDATE investissements
|
||||
SET date_premiere_echeance = date(date_souscription, '+1 month')
|
||||
WHERE date_premiere_echeance IS NULL AND date_souscription IS NOT NULL`);
|
||||
// Backfill date_cible = date_premiere_echeance + (duree_mois - 1) mois si vide
|
||||
// Backfill date_cible = date_premiere_echeance + (duree_mois - 1) mois si vide (idempotent)
|
||||
// Formule cohérente avec la simulation : échéance 1 = date_premiere_echeance, dernière = +duree-1 mois
|
||||
db.exec(`UPDATE investissements
|
||||
SET date_cible = date(date_premiere_echeance, '+' || (duree_mois - 1) || ' months')
|
||||
WHERE date_cible IS NULL AND date_premiere_echeance IS NOT NULL AND duree_mois IS NOT NULL`);
|
||||
// Correction des date_cible déjà calculées avec l'ancienne formule (+duree_mois au lieu de +duree_mois-1)
|
||||
db.exec(`UPDATE investissements
|
||||
SET date_cible = date(date_premiere_echeance, '+' || (duree_mois - 1) || ' months')
|
||||
WHERE date_premiere_echeance IS NOT NULL AND duree_mois IS NOT NULL`);
|
||||
|
||||
// Correction ponctuelle des date_cible déjà calculées avec l'ancienne formule
|
||||
// (+duree_mois au lieu de +duree_mois-1) — ne s'exécute que le jour du renommage effectif
|
||||
// des colonnes (migrationEnCours), jamais à chaque démarrage.
|
||||
if (migrationEnCours) {
|
||||
db.exec(`UPDATE investissements
|
||||
SET date_cible = date(date_premiere_echeance, '+' || (duree_mois - 1) || ' months')
|
||||
WHERE date_premiere_echeance IS NOT NULL AND duree_mois IS NOT NULL`);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Migration : type_remb 'mensuel' → 'amortissable' + ajout freq_interets ──
|
||||
@@ -275,19 +293,37 @@ if (!rembCols2.includes('interets_nets')) {
|
||||
// ── Migration : prêts différés — date_premiere_echeance doit égaler date_cible ──
|
||||
// (versement unique à l'échéance : les deux dates sont identiques)
|
||||
{
|
||||
const needsFix = db.prepare(`
|
||||
SELECT COUNT(*) AS n FROM investissements
|
||||
const aCorriger = db.prepare(`
|
||||
SELECT id, nom_projet, date_premiere_echeance, date_cible
|
||||
FROM investissements
|
||||
WHERE type_remb = 'differe'
|
||||
AND date_cible IS NOT NULL
|
||||
AND (date_premiere_echeance IS NULL OR date_premiere_echeance != date_cible)
|
||||
`).get().n;
|
||||
`).all();
|
||||
|
||||
if (needsFix > 0) {
|
||||
db.exec(`
|
||||
UPDATE investissements
|
||||
SET date_premiere_echeance = date_cible
|
||||
WHERE type_remb = 'differe' AND date_cible IS NOT NULL
|
||||
if (aCorriger.length > 0) {
|
||||
const updateStmt = db.prepare(`
|
||||
UPDATE investissements SET date_premiere_echeance = date_cible WHERE id = ?
|
||||
`);
|
||||
const histStmt = db.prepare(`
|
||||
INSERT INTO investissement_historique (investissement_id, type_evenement, changements, notes)
|
||||
VALUES (?, 'correction_auto_echeancier', ?, ?)
|
||||
`);
|
||||
|
||||
for (const inv of aCorriger) {
|
||||
updateStmt.run(inv.id);
|
||||
histStmt.run(
|
||||
inv.id,
|
||||
JSON.stringify([{
|
||||
champ: 'date_premiere_echeance',
|
||||
label: 'Date 1ère échéance',
|
||||
ancienne_valeur: inv.date_premiere_echeance,
|
||||
nouvelle_valeur: inv.date_cible,
|
||||
}]),
|
||||
"Migration au démarrage : synchronisation avec date_cible (prêt différé — les deux dates doivent être identiques)",
|
||||
);
|
||||
}
|
||||
|
||||
// Régénère les simulations avec la nouvelle logique (date = startDate directement)
|
||||
const differeInvs = db.prepare(`
|
||||
SELECT id, montant_investi, taux_interet, duree_mois, type_remb, freq_interets,
|
||||
|
||||
Reference in New Issue
Block a user