RC projet: restaurer prime HT de reference et fiabiliser listeners modal impact

This commit is contained in:
Alexis Burnaz 2026-04-21 10:34:42 +02:00
parent 0b7d8b6eb3
commit 4927d22387
2 changed files with 329 additions and 15 deletions

View File

@ -11,6 +11,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
let modRCActRCC, modRCMar, modRCZone, modRCActCompl, modRCGarAdd;
let hasSavedGrilleData = false; // évite d'écraser une grille déjà enregistrée
let rcProjetGuard = null;
// Initialisation des tag pour select
var tagAnimauxVivants = false;
@ -57,10 +58,44 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
loadModulateurs();
// Appel des différentes fonctions d'initialisation
try {
setupEventListeners();
} catch (error) {
console.error('Erreur lors de setupEventListeners:', error);
}
try {
populateFormData();
} catch (error) {
console.error('Erreur lors de populateFormData:', error);
}
let impactListenersReady = false;
try {
setupTarifImpactListeners();
impactListenersReady = true;
} catch (error) {
console.error('Erreur lors de setupTarifImpactListeners:', error);
}
// Retry léger: certains contextes chargent des blocs dynamiques juste après init.
if (!impactListenersReady) {
setTimeout(() => {
try {
setupTarifImpactListeners();
} catch (error) {
console.error('Nouvel échec setupTarifImpactListeners (retry):', error);
}
}, 700);
}
updatePrimeReferenceRow();
setupRCSafeValidation();
updateSubmitButtonState('projetForm');
setTimeout(() => {
updatePrimeReferenceRow();
if (rcProjetGuard) rcProjetGuard.refresh();
}, 350);
}
let tarifOriginalData = null;
@ -92,6 +127,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
window.rc = rc;
window.projet = projet;
window.tarif = tarif;
updatePrimeReferenceRow();
return true;
} catch (error) {
console.warn('Impossible de recharger le contexte RC depuis la session:', error);
@ -112,6 +148,251 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
return Boolean(tarifOriginalData);
}
function parseValidationNumber(rawValue) {
if (window.RCValidationUtils && typeof window.RCValidationUtils.parseLooseNumber === 'function') {
return window.RCValidationUtils.parseLooseNumber(rawValue);
}
const normalized = String(rawValue ?? '')
.trim()
.replace(/\s/g, '')
.replace(/[€$£¥]/g, '')
.replace(',', '.');
const parsed = Number(normalized);
return Number.isFinite(parsed) ? parsed : NaN;
}
function formatReferenceAmount(value) {
const number = Number(value);
if (!Number.isFinite(number)) return '0,00 €';
return number.toLocaleString('fr-FR', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
}) + ' €';
}
function normalizeFranchiseChoice(rawChoice) {
const choice = String(rawChoice || '').trim().toLowerCase();
if (!choice) return null;
if (choice === '250' || choice.includes('250')) return '250';
if (choice === '400' || choice.includes('400')) return '400';
if (choice === 'mini300' || choice.includes('mini 300') || choice.includes('10%')) return 'mini300';
return null;
}
function resolveTarifSourceForReference() {
if (tarif && typeof tarif === 'object') return tarif;
if (rc?.["@expand"]?.tarifRC && typeof rc["@expand"].tarifRC === 'object') return rc["@expand"].tarifRC;
if (rc?.tarifRC && typeof rc.tarifRC === 'object') return rc.tarifRC;
return null;
}
function getPrimeReferenceState() {
const tarifSource = resolveTarifSourceForReference();
if (!tarifSource) {
return {
valid: false,
reason: 'Aucun tarif RC sélectionné n\'est rattaché à ce dossier.'
};
}
const franchiseKey = normalizeFranchiseChoice(tarifSource.franchiseChoisie);
if (!franchiseKey) {
return {
valid: false,
reason: 'Aucune franchise choisie n\'est disponible dans le tarif RC.'
};
}
const primeFieldByFranchise = {
'250': 'primeTotal_250',
'400': 'primeTotal_400',
'mini300': 'primeTotal_2000'
};
const primeField = primeFieldByFranchise[franchiseKey];
const primeValue = parseValidationNumber(tarifSource[primeField]);
if (!Number.isFinite(primeValue) || primeValue <= 0) {
return {
valid: false,
reason: 'La prime HT de référence du tarif choisi est invalide (0.00, vide ou incohérente).'
};
}
return {
valid: true,
franchiseKey,
primeValue
};
}
function updatePrimeReferenceRow() {
const primeInput = document.getElementById('primeRefHT');
const primeError = document.getElementById('primeRefHT-error');
if (!primeInput || !primeError) return;
const state = getPrimeReferenceState();
if (state.valid) {
primeInput.value = formatReferenceAmount(state.primeValue);
primeError.textContent = '';
primeError.style.display = 'none';
return;
}
primeInput.value = 'Non disponible';
primeError.textContent = state.reason;
primeError.style.display = 'block';
}
function setupRCSafeValidation() {
if (!window.RCValidationUtils || typeof window.RCValidationUtils.createGuard !== 'function') {
return;
}
rcProjetGuard = window.RCValidationUtils.createGuard({
summaryId: 'rcProjetBlockingSummary',
summaryTitle: 'Impossible d\'enregistrer ou de continuer car :',
blockTargets: ['#projetFormBtn', '#generateDeclinaison', '#generateProject']
});
rcProjetGuard.registerField('#CA', {
profile: 'numeric',
label: "Chiffre d'affaires",
min: 0,
positive: true,
requiredWhen: function () {
return document.querySelector('input[name="cotisation"]:checked')?.value === 'revisable';
}
});
rcProjetGuard.registerField('#cotisationIrreductible', {
profile: 'numeric',
label: 'Cotisation minimale irréductible',
min: 0
});
['#tauxRCCHT', '#tauxRCCTTC', '#tauxRCEHT', '#tauxRCETTC', '#tauxTotalHT', '#tauxTotalTTC'].forEach((selector) => {
rcProjetGuard.registerField(selector, {
profile: 'numeric',
label: 'Taux de cotisation',
min: 0,
decimals: 3,
activeWhen: function (field) {
return field && field.offsetParent !== null;
}
});
});
['#cotRCCHT', '#cotRCCTTC', '#cotRCEHT', '#cotRCETTC', '#cotPJHT', '#cotPJTTC', '#cotFraisHT', '#cotFraisTTC', '#cotTotalHT', '#cotTotalTTC'].forEach((selector) => {
rcProjetGuard.registerField(selector, {
profile: 'numeric',
label: 'Cotisation',
min: 0,
activeWhen: function (field) {
return field && field.offsetParent !== null;
}
});
});
rcProjetGuard.registerField('#nomAdditionnel', {
profile: 'text',
label: 'Nom assuré additionnel'
});
rcProjetGuard.registerField('#adresseAditionnel', {
profile: 'text',
label: 'Adresse assuré additionnel'
});
rcProjetGuard.registerField('#siretAdditionnel', {
profile: 'integer',
label: 'SIRET assuré additionnel',
min: 0
});
rcProjetGuard.registerField('#marqueVehicule', {
profile: 'text',
label: 'Marque véhicule'
});
rcProjetGuard.registerField('#genreVehicule', {
profile: 'text',
label: 'Genre véhicule'
});
rcProjetGuard.registerField('#typeVehicule', {
profile: 'text',
label: 'Type véhicule'
});
rcProjetGuard.registerField('#immatVehicule', {
profile: 'immat',
label: 'Immatriculation véhicule'
});
rcProjetGuard.registerField('#capitalVehicule', {
profile: 'numeric',
label: 'Capital véhicule',
min: 0,
positive: true
});
rcProjetGuard.observe('#selected-activities input[type="text"]', {
profile: 'numeric',
label: 'Capital à assurer activité',
min: 0,
positive: true,
required: true,
activeWhen: function (field) {
return field && field.offsetParent !== null;
}
});
rcProjetGuard.observe('#empTableAdditionnel input[name="nom"]', {
profile: 'text',
label: 'Nom assuré additionnel'
});
rcProjetGuard.observe('#empTableAdditionnel input[name="adresse"]', {
profile: 'text',
label: 'Adresse assuré additionnel'
});
rcProjetGuard.observe('#empTableAdditionnel input[name="siret"]', {
profile: 'integer',
label: 'SIRET assuré additionnel',
min: 0
});
rcProjetGuard.observe('#empTableVehicules input[name="marque"], #empTableVehicules input[name="genre"], #empTableVehicules input[name="type"]', {
profile: 'text',
label: 'Désignation véhicule'
});
rcProjetGuard.observe('#empTableVehicules input[name="immat"]', {
profile: 'immat',
label: 'Immatriculation véhicule'
});
rcProjetGuard.observe('#empTableVehicules input[name="capital"]', {
profile: 'numeric',
label: 'Capital véhicule',
min: 0,
positive: true
});
rcProjetGuard.observe('#tabAdvaloTerrestre input[type="text"], #tabAdvaloMultimodal input[type="text"], #tabAdvaloAerien input[type="text"]', {
profile: 'number_or_consulter',
label: 'Valeur ad valorem',
min: 0,
positive: true,
decimals: 3,
required: false
});
rcProjetGuard.registerExternal('prime-reference', function () {
const state = getPrimeReferenceState();
if (state.valid) {
return { valid: true };
}
return {
valid: false,
message: state.reason
};
});
rcProjetGuard.refresh();
}
async function loadModulateurs() {
try {
const response = await fetch('/rc/modulo/activiteRCC');
@ -676,6 +957,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
calcAddTaxe('cotRCEHT', 0.09, 'cotRCETTC');
calcCotIrreductible();
calcCotTotal();
if (rcProjetGuard) rcProjetGuard.refresh();
}
function captureRCEState() {
@ -2857,7 +3139,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
if (projet && projet.cotFraisTTC) { document.getElementById("cotFraisTTC").value = projet.cotFraisTTC };
// Populate tableau vehicule
if (!rc || !projet.designationVehicule || Object.keys(projet.designationVehicule).length === 0) {
if (!rc || !projet || !projet.designationVehicule || Object.keys(projet.designationVehicule).length === 0) {
console.log("Le JSON est vide, pas de véhicules à pré-remplir.");
} else {
for (let i = 0; i < projet.designationVehicule.length; i++) {
@ -2907,6 +3189,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
document.getElementById('divAdvaloMultimodal').style.display = "none";
};
}
updatePrimeReferenceRow();
if (rcProjetGuard) rcProjetGuard.refresh();
}
function populateGrAdvalo(jsonData, tableID) {
@ -3444,6 +3729,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
document.getElementById("cotTotalHT").value = (cotRCCHT + cotRCEHT + cotPJHT + cotFraisHT).toFixed(2);
document.getElementById("cotTotalTTC").value = (cotRCCTTC + cotRCETTC + cotPJTTC + cotFraisTTC).toFixed(2);
if (rcProjetGuard) rcProjetGuard.refresh();
}
function calcTauxTotal() {
@ -3454,6 +3740,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
document.getElementById("tauxTotalHT").value = (tauxRCCHT + tauxRCEHT).toFixed(3);
document.getElementById("tauxTotalTTC").value = (tauxRCCTTC + tauxRCETTC).toFixed(3);
if (rcProjetGuard) rcProjetGuard.refresh();
}
function calcCotFromTauxCA(idTaux, idCot) {
@ -3493,6 +3780,12 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
// Gérer la soumission du formulaire
async function handleSubmitForm(event) {
event.preventDefault();
updatePrimeReferenceRow();
if (rcProjetGuard && rcProjetGuard.refresh().length > 0) {
M.toast({ html: 'Corrigez les erreurs du formulaire avant de continuer.', classes: 'red' });
return;
}
// Étape 1: Créer d'abord un enregistrement dans projetRC
const grilleMultimodal = extractGrilleAdvalo('tabAdvaloMultimodal');
@ -3807,6 +4100,11 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
// Fonction exposée pour sauvegarder le projet sans générer le document
async function saveProjetRC() {
try {
updatePrimeReferenceRow();
if (rcProjetGuard && rcProjetGuard.refresh().length > 0) {
return { valid: false, message: 'Le formulaire contient encore des erreurs.' };
}
// Étape 1: Créer d'abord un enregistrement dans projetRC
const grilleMultimodal = extractGrilleAdvalo('tabAdvaloMultimodal');
const grilleTerrestre = extractGrilleAdvalo('tabAdvaloTerrestre');

View File

@ -1,4 +1,5 @@
<form id="projetForm">
<div id="rcProjetBlockingSummary" class="rc-blocking-summary"></div>
<!-- Historique de projet -->
<div class="row" id="historiqueDiv">
<div class="col s12">
@ -776,7 +777,8 @@
</div>
<div class="input-field">
<i class="material-icons prefix">trending_up</i>
<input id="CA" type="text" placeholder="100000">
<label class="rc-field-label" for="CA">Montant en euros</label>
<input id="CA" type="text">
<span class="helper-text">Chiffre d'affaires</span>
<span id="CA-error" class="helper-text red-text"></span>
</div>
@ -790,7 +792,8 @@
</div>
<div class="input-field">
<i class="material-icons prefix">euro_symbol</i>
<input id="cotisationIrreductible" type="text" placeholder="200">
<label class="rc-field-label" for="cotisationIrreductible">Montant en euros</label>
<input id="cotisationIrreductible" type="text">
<span class="helper-text">Cotisation minimale irréductible</span>
<span id="cotisationIrreductible-error" class="helper-text red-text"></span>
</div>
@ -820,7 +823,7 @@
<td><input type="text" name="genre" id="genreVehicule" placeholder="VP" /></td>
<td><input type="text" name="type" id="typeVehicule" placeholder="Non défini" /></td>
<td><input type="text" name="immat" id="immatVehicule" placeholder="AA-999-AA" /></td>
<td><input type="text" name="capital" id="capitalVehicule" placeholder="10 000 €" /></td>
<td><input type="text" name="capital" id="capitalVehicule" /></td>
<td><button class="btn" type="button" id="btnAddVehicule"><i class="material-icons">add</i></button></td>
</tr>
</table>
@ -914,42 +917,42 @@
<tr>
<td>RC Contractuelle</td>
<td>
<input type="text" name="cotRCCHT" id="cotRCCHT" placeholder="00.00" />
<input type="text" name="cotRCCHT" id="cotRCCHT" />
<span id="cotRCCHT-error" class="helper-text red-text"></span>
</td>
<td>
<input type="text" name="cotRCCTaux" id="cotRCCTaux" value="Sans taxe" disabled />
</td>
<td>
<input type="text" name="cotRCCTTC" id="cotRCCTTC" placeholder="00.00" />
<input type="text" name="cotRCCTTC" id="cotRCCTTC" />
<span id="cotRCCTTC-error" class="helper-text red-text"></span>
</td>
</tr>
<tr id="RCE2" name="RCE2" style="display : none;">
<td>Autres RC</td>
<td>
<input type="text" name="cotRCEHT" id="cotRCEHT" placeholder="00.00" />
<input type="text" name="cotRCEHT" id="cotRCEHT" />
<span id="cotRCEHT-error" class="helper-text red-text"></span>
</td>
<td>
<input type="text" name="cotRCETaux" id="cotRCETaux" value="9" disabled />
</td>
<td>
<input type="text" name="cotRCETTC" id="cotRCETTC" placeholder="00.00" />
<input type="text" name="cotRCETTC" id="cotRCETTC" />
<span id="cotRCETTC-error" class="helper-text red-text"></span>
</td>
</tr>
<tr id="PJ2" name="PJ2" style="display : none;">
<td>Protection Juridique</td>
<td>
<input type="text" name="cotPJHT" id="cotPJHT" placeholder="100.00" />
<input type="text" name="cotPJHT" id="cotPJHT" />
<span id="cotPJHT-error" class="helper-text red-text"></span>
</td>
<td>
<input type="text" name="cotPJTaux" id="cotPJTaux" value="13.4" disabled />
</td>
<td>
<input type="text" name="cotPJTTC" id="cotPJTTC" placeholder="113.40" />
<input type="text" name="cotPJTTC" id="cotPJTTC" />
<span id="cotPJTTC-error" class="helper-text red-text"></span>
</td>
</tr>
@ -966,17 +969,30 @@
<span id="cotFraisTTC-error" class="helper-text red-text"></span>
</td>
</tr>
<tr id="primeRefRow">
<td>Prime HT de référence (tarif choisi)</td>
<td>
<input type="text" name="primeRefHT" id="primeRefHT" readonly />
<span id="primeRefHT-error" class="helper-text red-text"></span>
</td>
<td>
<input type="text" name="primeRefTaxe" id="primeRefTaxe" value="Tarif choisi" disabled />
</td>
<td>
<input type="text" name="primeRefTTC" id="primeRefTTC" value="//" disabled />
</td>
</tr>
<tr>
<td>Total</td>
<td>
<input type="text" name="cotTotalHT" id="cotTotalHT" placeholder="0.00" />
<input type="text" name="cotTotalHT" id="cotTotalHT" />
<span id="cotTotalHT-error" class="helper-text red-text"></span>
</td>
<td>
<input type="text" name="cotTotalTaux" id="cotTotalTaux" value="//" disabled />
</td>
<td>
<input type="text" name="cotTotalTTC" id="cotTotalTTC" placeholder="0.00" />
<input type="text" name="cotTotalTTC" id="cotTotalTTC" />
<span id="cotTotalTTC-error" class="helper-text red-text"></span>
</td>
</tr>