Corrections sur les jobs En retard
This commit is contained in:
@@ -7,6 +7,7 @@ import db from '../db/index.js';
|
||||
import { HttpError } from '../middleware/errorHandler.js';
|
||||
import { requireInvestisseur } from '../middleware/investisseurScope.js';
|
||||
import { generateSimul, generateSimulWithReinvestissements } from '../utils/schedule.js';
|
||||
import { recordHistory, detectChangements, detectTypeEvenement } from './investissements.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -417,7 +418,7 @@ router.post('/dossier', (req, res, next) => {
|
||||
|
||||
/* ── 2. Chercher l'investissement existant (clé naturelle) */
|
||||
const existing = db.prepare(`
|
||||
SELECT id FROM investissements
|
||||
SELECT * FROM investissements
|
||||
WHERE investisseur_id = ? AND nom_projet = ? AND date_souscription = ?
|
||||
LIMIT 1
|
||||
`).get(req.investisseur.id, inv.nom_projet, inv.date_souscription);
|
||||
@@ -499,6 +500,20 @@ router.post('/dossier', (req, res, next) => {
|
||||
} else {
|
||||
/* ────────────── SCÉNARIO UPDATE ──────────────────────── */
|
||||
investissementId = existing.id;
|
||||
|
||||
const nouveau = {
|
||||
plateforme_id: plateformeId,
|
||||
date_premiere_echeance: inv.date_premiere_echeance || null,
|
||||
date_cible: inv.date_cible || null,
|
||||
date_debut_simul: inv.date_debut_simul || null,
|
||||
montant_investi: Number(inv.montant_investi),
|
||||
taux_interet: inv.taux_interet ?? null,
|
||||
duree_mois: inv.duree_mois ?? null,
|
||||
type_remb: inv.type_remb || 'in_fine',
|
||||
freq_interets: inv.freq_interets || 'mensuel',
|
||||
statut: inv.statut || 'en_cours',
|
||||
};
|
||||
|
||||
db.prepare(`
|
||||
UPDATE investissements SET
|
||||
plateforme_id = ?, emetteur = ?,
|
||||
@@ -508,11 +523,10 @@ router.post('/dossier', (req, res, next) => {
|
||||
reference = ?, notes = ?
|
||||
WHERE id = ?
|
||||
`).run(
|
||||
plateformeId, inv.emetteur || null,
|
||||
inv.date_premiere_echeance || null, inv.date_cible || null, inv.date_debut_simul || null,
|
||||
Number(inv.montant_investi), inv.taux_interet ?? null, inv.duree_mois ?? null,
|
||||
inv.type_remb || 'in_fine', inv.freq_interets || 'mensuel',
|
||||
inv.statut || 'en_cours',
|
||||
nouveau.plateforme_id, inv.emetteur || null,
|
||||
nouveau.date_premiere_echeance, nouveau.date_cible, nouveau.date_debut_simul,
|
||||
nouveau.montant_investi, nouveau.taux_interet, nouveau.duree_mois,
|
||||
nouveau.type_remb, nouveau.freq_interets, nouveau.statut,
|
||||
inv.reference || null, inv.notes || null,
|
||||
investissementId,
|
||||
);
|
||||
@@ -565,15 +579,29 @@ router.post('/dossier', (req, res, next) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Entrée d'historique de la mise à jour
|
||||
db.prepare(`
|
||||
INSERT INTO investissement_historique (investissement_id, type_evenement, changements)
|
||||
VALUES (?, 'import', ?)
|
||||
`).run(investissementId, JSON.stringify([{
|
||||
champ: 'import', label: 'Mise à jour dossier',
|
||||
ancienne_valeur: null,
|
||||
nouvelle_valeur: `${dossier.exported_at || 'inconnu'} — ${rembInserted} remb. ajouté(s), ${reinvInserted} réinvest. ajouté(s)`,
|
||||
}]));
|
||||
// Entrée d'historique de la mise à jour — diff précis champ par champ
|
||||
// (même logique que l'édition manuelle, pour que la date_cible/date_premiere_echeance
|
||||
// etc. écrasées par ce ré-import restent traçables dans l'historique du prêt).
|
||||
const changements = detectChangements(existing, nouveau);
|
||||
const notesImport = `Import dossier (${dossier.exported_at || 'date export inconnue'}) — ` +
|
||||
`${rembInserted} remb. ajouté(s), ${reinvInserted} réinvest. ajouté(s)`;
|
||||
|
||||
if (changements.length > 0) {
|
||||
recordHistory(investissementId, {
|
||||
type_evenement: detectTypeEvenement(changements),
|
||||
changements,
|
||||
notes: notesImport,
|
||||
});
|
||||
} else {
|
||||
recordHistory(investissementId, {
|
||||
type_evenement: 'import',
|
||||
changements: [{
|
||||
champ: 'import', label: 'Mise à jour dossier',
|
||||
ancienne_valeur: null,
|
||||
nouvelle_valeur: notesImport,
|
||||
}],
|
||||
});
|
||||
}
|
||||
|
||||
action = 'updated';
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { generateSimul } from '../utils/schedule.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
const TRACKED_FIELDS = [
|
||||
export const TRACKED_FIELDS = [
|
||||
{ key: 'type_remb', label: 'Type de prêt' },
|
||||
{ key: 'taux_interet', label: 'Taux annuel (%)' },
|
||||
{ key: 'duree_mois', label: 'Durée (mois)' },
|
||||
@@ -20,7 +20,7 @@ const TRACKED_FIELDS = [
|
||||
{ key: 'plateforme_id', label: 'Plateforme' },
|
||||
];
|
||||
|
||||
function recordHistory(investissementId, { type_evenement, changements, notes }) {
|
||||
export function recordHistory(investissementId, { type_evenement, changements, notes }) {
|
||||
if (!changements || changements.length === 0) return;
|
||||
db.prepare(`
|
||||
INSERT INTO investissement_historique (investissement_id, type_evenement, changements, notes)
|
||||
@@ -28,7 +28,7 @@ function recordHistory(investissementId, { type_evenement, changements, notes })
|
||||
`).run(investissementId, type_evenement, JSON.stringify(changements), notes || null);
|
||||
}
|
||||
|
||||
function detectChangements(ancien, nouveau) {
|
||||
export function detectChangements(ancien, nouveau) {
|
||||
const diffs = [];
|
||||
for (const { key, label } of TRACKED_FIELDS) {
|
||||
const av = ancien[key] ?? null;
|
||||
@@ -42,7 +42,7 @@ function detectChangements(ancien, nouveau) {
|
||||
return diffs;
|
||||
}
|
||||
|
||||
function detectTypeEvenement(changements) {
|
||||
export function detectTypeEvenement(changements) {
|
||||
const champsRestructuration = ['type_remb', 'date_debut_simul'];
|
||||
if (changements.some(c => champsRestructuration.includes(c.champ))) return 'restructuration';
|
||||
return 'modification';
|
||||
@@ -180,7 +180,9 @@ router.post('/fix-differe-dates', (req, res, next) => {
|
||||
try {
|
||||
const rows = db.prepare(`
|
||||
SELECT i.id, i.nom_projet, i.date_souscription, i.duree_mois,
|
||||
i.date_premiere_echeance, i.date_cible
|
||||
i.date_premiere_echeance, i.date_cible,
|
||||
i.montant_investi, i.taux_interet, i.type_remb, i.freq_interets,
|
||||
i.date_debut_simul, i.echeance_fin_de_mois
|
||||
FROM investissements i
|
||||
JOIN investisseurs inv ON inv.id = i.investisseur_id AND inv.user_id = ?
|
||||
WHERE i.type_remb = 'differe'
|
||||
@@ -222,6 +224,45 @@ router.post('/fix-differe-dates', (req, res, next) => {
|
||||
|
||||
if (incoherent) {
|
||||
stmt.run(dateCalculee, dateCalculee, inv.id);
|
||||
|
||||
const changements = [];
|
||||
if (String(inv.date_premiere_echeance ?? null) !== String(dateCalculee)) {
|
||||
changements.push({
|
||||
champ: 'date_premiere_echeance',
|
||||
label: 'Date 1ère échéance',
|
||||
ancienne_valeur: inv.date_premiere_echeance,
|
||||
nouvelle_valeur: dateCalculee,
|
||||
});
|
||||
}
|
||||
if (String(inv.date_cible ?? null) !== String(dateCalculee)) {
|
||||
changements.push({
|
||||
champ: 'date_cible',
|
||||
label: 'Date cible',
|
||||
ancienne_valeur: inv.date_cible,
|
||||
nouvelle_valeur: dateCalculee,
|
||||
});
|
||||
}
|
||||
recordHistory(inv.id, {
|
||||
type_evenement: 'correction_auto_dates',
|
||||
changements,
|
||||
notes: 'Correction automatique (Nettoyage > Corriger les dates des prêts différés) : écart > 2 ans avec date_souscription + duree_mois',
|
||||
});
|
||||
|
||||
// Régénère l'échéancier de projection avec la date corrigée — sans ça,
|
||||
// simul_remboursements reste calé sur l'ancienne date aberrante.
|
||||
generateSimul(db, {
|
||||
id: inv.id,
|
||||
montant_investi: inv.montant_investi,
|
||||
taux_interet: inv.taux_interet,
|
||||
duree_mois: inv.duree_mois,
|
||||
type_remb: inv.type_remb,
|
||||
freq_interets: inv.freq_interets,
|
||||
date_premiere_echeance: dateCalculee,
|
||||
date_debut_simul: inv.date_debut_simul,
|
||||
date_souscription: inv.date_souscription,
|
||||
echeance_fin_de_mois: inv.echeance_fin_de_mois ?? 0,
|
||||
});
|
||||
|
||||
corriges.push({
|
||||
id: inv.id,
|
||||
nom_projet: inv.nom_projet,
|
||||
|
||||
Reference in New Issue
Block a user