Amélioration de la détection
This commit is contained in:
@@ -174,11 +174,18 @@ router.get('/comptes-courants', (req, res) => {
|
|||||||
res.json(rows);
|
res.json(rows);
|
||||||
});
|
});
|
||||||
|
|
||||||
// POST /api/investissements/fix-differe-dates
|
// POST /api/investissements/fix-differe-dates { seuilMois?: 3|6|12|18|24 }
|
||||||
// Corrige date_premiere_echeance et date_cible des prêts différés dont les dates
|
// Corrige date_premiere_echeance et date_cible des prêts différés dont les dates
|
||||||
// s'écartent de plus de 2 ans par rapport à date_souscription + duree_mois.
|
// s'écartent de plus de `seuilMois` mois par rapport à date_souscription + duree_mois.
|
||||||
|
const SEUILS_MOIS_VALIDES = [3, 6, 12, 18, 24];
|
||||||
|
const SEUIL_MOIS_DEFAUT = 24;
|
||||||
|
|
||||||
router.post('/fix-differe-dates', (req, res, next) => {
|
router.post('/fix-differe-dates', (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
|
const seuilMois = SEUILS_MOIS_VALIDES.includes(Number(req.body?.seuilMois))
|
||||||
|
? Number(req.body.seuilMois)
|
||||||
|
: SEUIL_MOIS_DEFAUT;
|
||||||
|
|
||||||
const rows = db.prepare(`
|
const rows = db.prepare(`
|
||||||
SELECT i.id, i.nom_projet, i.date_souscription, i.duree_mois,
|
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,
|
||||||
@@ -191,7 +198,9 @@ router.post('/fix-differe-dates', (req, res, next) => {
|
|||||||
AND i.duree_mois IS NOT NULL
|
AND i.duree_mois IS NOT NULL
|
||||||
`).all(req.user.id);
|
`).all(req.user.id);
|
||||||
|
|
||||||
const SEUIL_JOURS = 730; // 2 ans
|
// Approximation jours/mois (moyenne julienne) — cohérent avec l'ancien seuil fixe
|
||||||
|
// de 730 jours pour 24 mois (2 ans).
|
||||||
|
const SEUIL_JOURS = Math.round(seuilMois * 30.44);
|
||||||
|
|
||||||
function addMonths(dateStr, months) {
|
function addMonths(dateStr, months) {
|
||||||
const d = new Date(dateStr + 'T00:00:00Z');
|
const d = new Date(dateStr + 'T00:00:00Z');
|
||||||
@@ -246,7 +255,8 @@ router.post('/fix-differe-dates', (req, res, next) => {
|
|||||||
recordHistory(inv.id, {
|
recordHistory(inv.id, {
|
||||||
type_evenement: 'correction_auto_dates',
|
type_evenement: 'correction_auto_dates',
|
||||||
changements,
|
changements,
|
||||||
notes: 'Correction automatique (Nettoyage > Corriger les dates des prêts différés) : écart > 2 ans avec date_souscription + duree_mois',
|
notes: `Correction automatique (Nettoyage > Corriger les dates des prêts différés) : ` +
|
||||||
|
`écart > ${seuilMois} mois avec date_souscription + duree_mois`,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Régénère l'échéancier de projection avec la date corrigée — sans ça,
|
// Régénère l'échéancier de projection avec la date corrigée — sans ça,
|
||||||
@@ -282,7 +292,7 @@ router.post('/fix-differe-dates', (req, res, next) => {
|
|||||||
// sinon le prêt affiche un statut incohérent avec sa date jusqu'au lendemain.
|
// sinon le prêt affiche un statut incohérent avec sa date jusqu'au lendemain.
|
||||||
const statutsMisAJour = corriges.length > 0 ? checkStatutsRetard() : 0;
|
const statutsMisAJour = corriges.length > 0 ? checkStatutsRetard() : 0;
|
||||||
|
|
||||||
res.json({ updated: corriges.length, detail: corriges, statutsMisAJour });
|
res.json({ updated: corriges.length, detail: corriges, statutsMisAJour, seuilMois });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
next(err);
|
next(err);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export default function DataCleanupSection() {
|
|||||||
const [loadingReprocess, setLoadingReprocess] = useState(false);
|
const [loadingReprocess, setLoadingReprocess] = useState(false);
|
||||||
const [showDiffereModal, setShowDiffereModal] = useState(false);
|
const [showDiffereModal, setShowDiffereModal] = useState(false);
|
||||||
const [loadingDiffere, setLoadingDiffere] = useState(false);
|
const [loadingDiffere, setLoadingDiffere] = useState(false);
|
||||||
|
const [seuilMoisDiffere, setSeuilMoisDiffere] = useState(24);
|
||||||
const [showEcheancierModal, setShowEcheancierModal] = useState(false);
|
const [showEcheancierModal, setShowEcheancierModal] = useState(false);
|
||||||
const [loadingEcheancier, setLoadingEcheancier] = useState(false);
|
const [loadingEcheancier, setLoadingEcheancier] = useState(false);
|
||||||
const [showBackfillModal, setShowBackfillModal] = useState(false);
|
const [showBackfillModal, setShowBackfillModal] = useState(false);
|
||||||
@@ -56,7 +57,9 @@ export default function DataCleanupSection() {
|
|||||||
setErrorMsg(null);
|
setErrorMsg(null);
|
||||||
setSuccessMsg(null);
|
setSuccessMsg(null);
|
||||||
try {
|
try {
|
||||||
const { updated, detail, statutsMisAJour } = await api.post('/investissements/fix-differe-dates', {});
|
const { updated, detail, statutsMisAJour } = await api.post('/investissements/fix-differe-dates', {
|
||||||
|
seuilMois: seuilMoisDiffere,
|
||||||
|
});
|
||||||
if (updated === 0) {
|
if (updated === 0) {
|
||||||
setSuccessMsg('Aucune date incohérente détectée sur les prêts différés.');
|
setSuccessMsg('Aucune date incohérente détectée sur les prêts différés.');
|
||||||
} else {
|
} else {
|
||||||
@@ -163,8 +166,8 @@ export default function DataCleanupSection() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="text-muted" style={{ fontSize: 12 }}>
|
<div className="text-muted" style={{ fontSize: 12 }}>
|
||||||
Recalcule la date de 1ère échéance et la date cible à partir de la date de souscription
|
Recalcule la date de 1ère échéance et la date cible à partir de la date de souscription
|
||||||
et de la durée prévue. Seuls les prêts dont les dates s'écartent de plus de 2 ans
|
et de la durée prévue. Seuls les prêts dont les dates s'écartent de la valeur calculée
|
||||||
de la valeur calculée sont corrigés.
|
de plus qu'un seuil choisi (3 à 24 mois) sont corrigés.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
@@ -259,11 +262,28 @@ export default function DataCleanupSection() {
|
|||||||
border: '1px solid var(--border)' }}>
|
border: '1px solid var(--border)' }}>
|
||||||
date souscription + durée (mois)
|
date souscription + durée (mois)
|
||||||
</p>
|
</p>
|
||||||
<p style={{ margin: '0 0 20px', lineHeight: 1.6 }} className="text-muted">
|
<p style={{ margin: '0 0 12px', lineHeight: 1.6 }} className="text-muted">
|
||||||
La correction ne s'applique que si l'écart entre la date existante et la date calculée
|
La correction ne s'applique que si l'écart entre la date existante et la date calculée
|
||||||
dépasse <strong>2 ans</strong>. L'échéancier de projection (simulation de remboursement)
|
dépasse le seuil choisi ci-dessous. L'échéancier de projection (simulation de
|
||||||
est régénéré automatiquement avec la date corrigée.
|
remboursement) est régénéré automatiquement avec la date corrigée.
|
||||||
</p>
|
</p>
|
||||||
|
<div style={{ margin: '0 0 20px' }}>
|
||||||
|
<label style={{ display: 'block', fontSize: 'var(--fs-sm)', fontWeight: 500, marginBottom: 6 }}>
|
||||||
|
Seuil d'écart
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
value={seuilMoisDiffere}
|
||||||
|
onChange={e => setSeuilMoisDiffere(Number(e.target.value))}
|
||||||
|
disabled={loadingDiffere}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
>
|
||||||
|
<option value={3}>3 mois</option>
|
||||||
|
<option value={6}>6 mois</option>
|
||||||
|
<option value={12}>12 mois</option>
|
||||||
|
<option value={18}>18 mois</option>
|
||||||
|
<option value={24}>24 mois (défaut)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
|
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
|
||||||
<button onClick={() => setShowDiffereModal(false)} disabled={loadingDiffere}>Annuler</button>
|
<button onClick={() => setShowDiffereModal(false)} disabled={loadingDiffere}>Annuler</button>
|
||||||
<button className="primary" onClick={() => handleFixDiffereDates()} disabled={loadingDiffere}>
|
<button className="primary" onClick={() => handleFixDiffereDates()} disabled={loadingDiffere}>
|
||||||
|
|||||||
Reference in New Issue
Block a user