diff --git a/ecole/public/css/global.css b/ecole/public/css/global.css index 1413772f..50f196b0 100644 --- a/ecole/public/css/global.css +++ b/ecole/public/css/global.css @@ -1,5 +1,8 @@ body { font-family: 'Roboto', sans-serif; + background-color: white; + color: black; + color-scheme: light; } h1, h2, h3, h4, h5, h6 { diff --git a/ecole/public/js/nav-parcours.js b/ecole/public/js/nav-parcours.js index bb6ed373..0deb1071 100644 --- a/ecole/public/js/nav-parcours.js +++ b/ecole/public/js/nav-parcours.js @@ -33,8 +33,16 @@ document.addEventListener('DOMContentLoaded', function() { let produit = parcours["@expand"].contrat.produit const produitObj = contrat?.["@expand"]?.enCours || null; - const tarif = produitObj?.["@expand"]?.tarif || null; - const projet = produitObj?.["@expand"]?.projet || null; + + // RC utilise tarifRC/projetRC, les autres produits utilisent tarif/projet + let tarif, projet; + if (produit === "rc") { + tarif = produitObj?.["@expand"]?.tarifRC || null; + projet = produitObj?.["@expand"]?.projetRC || null; + } else { + tarif = produitObj?.["@expand"]?.tarif || null; + projet = produitObj?.["@expand"]?.projet || null; + } let scriptSrc; // let newScriptModuloSrc; @@ -54,11 +62,21 @@ document.addEventListener('DOMContentLoaded', function() { scriptSrc = `/js/${submenu}-form.js`; } + // RC utilise tarifRC/projetRC, les autres produits utilisent tarif/projet + let tarifId, projetId; + if (produit === "rc") { + tarifId = contrat?.["@expand"]?.enCours?.["@expand"]?.tarifRC?.id || null; + projetId = contrat?.["@expand"]?.enCours?.["@expand"]?.projetRC?.id || null; + } else { + tarifId = contrat?.["@expand"]?.enCours?.["@expand"]?.tarif?.id || null; + projetId = contrat?.["@expand"]?.enCours?.["@expand"]?.projet?.id || null; + } + const etapes = { "client": contrat?.client || null, "intermediaire": contrat?.intermediaire || null, - "tarif": contrat?.["@expand"]?.enCours?.["@expand"]?.tarif?.id || null, - "projet": contrat?.["@expand"]?.enCours?.["@expand"]?.projet?.id || null, + "tarif": tarifId, + "projet": projetId, "contrat": null } @@ -79,7 +97,6 @@ document.addEventListener('DOMContentLoaded', function() { document.getElementById('step-' + key).classList.add('line') } } - showLoader(); // Charger le formulaire associé fetch(fetchUrl) @@ -89,6 +106,7 @@ document.addEventListener('DOMContentLoaded', function() { // Suppression de tout script précédemment chargé const oldScript = document.querySelector('script.dynamic-script'); + if (oldScript) { oldScript.remove(); } @@ -120,26 +138,26 @@ document.addEventListener('DOMContentLoaded', function() { inputChanged = true }) }) - hideLoader(); }) .catch(error => console.error('Error:', error)); - //A MODIFIER UNE FOIS QUE RC SERA ADAPTé AU PARCOURS - if (produit == "RC") { - if (Object.keys(contrat?.["@expand"]?.enCours).length > 1) { - document.getElementById('generateProject').disabled = false; - } + // Gestion des boutons de génération pour tous les produits + const hasClient = parcours["@expand"]?.contrat?.client != ''; + const hasIntermediaire = parcours["@expand"]?.contrat?.intermediaire != ''; + const hasProduit = produitObj != undefined; + + // Bouton génération déclinaison tarifaire + if (hasClient && hasIntermediaire && hasProduit && tarif != null) { + document.getElementById('generateDeclinaison').disabled = false; } else { - // Enable / disable bouton generate project - if (parcours["@expand"].contrat.client != '' && parcours["@expand"].contrat.intermediaire != '' && produitObj != undefined && projet != null) { - document.getElementById('generateProject').disabled = false; - } - - // Enable / disable bouton generate déclinaison - if (parcours["@expand"].contrat.client != '' && parcours["@expand"].contrat.intermediaire != '' && produitObj != undefined && tarif != null) { - document.getElementById('generateDeclinaison').disabled = false; - } - + document.getElementById('generateDeclinaison').disabled = true; + } + + // Bouton génération projet + if (hasClient && hasIntermediaire && hasProduit && projet != null) { + document.getElementById('generateProject').disabled = false; + } else { + document.getElementById('generateProject').disabled = true; } } @@ -157,9 +175,6 @@ document.addEventListener('DOMContentLoaded', function() { const parcours = JSON.parse(sessionStorage.getItem('parcours')); var produit = parcours["@expand"].contrat.produit - const btn = this // bouton "générer projet" - btn.disabled = true; // le desactiver le temps du téléchargement - var fileName switch (produit.toLowerCase()) { case 'fac': @@ -183,21 +198,26 @@ document.addEventListener('DOMContentLoaded', function() { link.download = fileName; link.click(); }) - .finally(() => { - btn.disabled = false; // réactiver le bouton a la fin du téléchargement - }) .catch(error => console.error('Error downloading file:', error)); }); // Fonction de génération de projet - document.getElementById('generateProject').addEventListener('click', function() { + document.getElementById('generateProject').addEventListener('click', async function() { const numParcours = getNumParcoursFromURL(); let filename; const parcours = JSON.parse(sessionStorage.getItem('parcours')); let produit = parcours["@expand"].contrat.produit - const btn = this // bouton "générer projet" - btn.disabled = true; // le desactiver le temps du téléchargement + // Sauvegarder les données du projet avant de générer le document (si RC) + if (produit.toLowerCase() === 'rc' && typeof window.saveProjetRC === 'function') { + console.log('Sauvegarde des données projet RC avant génération...'); + const saveResult = await window.saveProjetRC(); + if (!saveResult || !saveResult.valid) { + console.error('Échec de la sauvegarde du projet RC'); + M.toast({html: 'Erreur lors de la sauvegarde du projet. Veuillez réessayer.'}); + return; + } + } // Envoi de la requête POST au serveur pour générer le projet fetch(`/generate/${produit}/projet/${numParcours}`, { @@ -228,23 +248,17 @@ document.addEventListener('DOMContentLoaded', function() { window.URL.revokeObjectURL(url); // Nettoie l'URL objet a.remove(); // Supprime l'élément a du document }) - .finally(() => { - btn.disabled = false; // réactiver le bouton a la fin du téléchargement - }) .catch(error => console.error('Erreur lors de la génération du projet:', error)); }); - document.getElementById('generateDeclinaison').addEventListener('click', function() { + document.getElementById('generateDeclinaison').addEventListener('click', async function() { const numParcours = getNumParcoursFromURL(); let filename; const parcours = JSON.parse(sessionStorage.getItem('parcours')); let produit = parcours["@expand"].contrat.produit - const btn = this // bouton "générer déclinaison tarifaire" - btn.disabled = true; // le desactiver le temps du téléchargement - - // Envoi de la requête POST au serveur pour générer le projet + // Envoi de la requête POST au serveur pour générer la déclinaison tarifaire fetch(`/generate/${produit}/tarif/${numParcours}`, { method: 'POST', headers: { @@ -274,9 +288,6 @@ document.addEventListener('DOMContentLoaded', function() { window.URL.revokeObjectURL(url); // Nettoie l'URL objet a.remove(); // Supprime l'élément a du document }) - .finally(() => { - btn.disabled = false; // réactiver le bouton a la fin du téléchargement - }) .catch(error => console.error('Erreur lors de la génération du projet:', error)); }); @@ -323,4 +334,4 @@ document.addEventListener('DOMContentLoaded', function() { // Exécutez init et gérez les erreurs potentielles init().catch(error => console.error('Error initializing the form:', error)); -}); +}); \ No newline at end of file diff --git a/ecole/public/js/projet-form-rc.js b/ecole/public/js/projet-form-rc.js index cdaadaa7..37352452 100644 --- a/ecole/public/js/projet-form-rc.js +++ b/ecole/public/js/projet-form-rc.js @@ -7,7 +7,10 @@ function initSubmenuForm() { window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollution de l'espace global (function () { // Variables globales du module - let parcours, contrat, client, intermediaire; + let parcours, contrat, client, intermediaire, rc, projet, tarif; + + let modRCActRCC, modRCMar, modRCZone, modRCActCompl, modRCGarAdd; + let hasSavedGrilleData = false; // évite d'écraser une grille déjà enregistrée // Initialisation des tag pour select var tagAnimauxVivants = false; @@ -35,16 +38,1089 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio contrat = JSON.parse(sessionStorage.getItem('contrat')); client = contrat?.["@expand"]?.client || null; intermediaire = contrat?.["@expand"]?.intermediaire || null; - rc = contrat?.["@expand"]?.enCours || null; + + // Récupérer les données RC depuis la nouvelle structure (EXACTEMENT comme TPPC) + rc = contrat?.["@expand"]?.enCours || null; // RC principal + projet = rc?.["@expand"]?.projet || null; // Données projet (normalized by contratService) + tarif = rc?.["@expand"]?.tarif || null; // Données tarif (normalized by contratService) + + // Exposer ces variables globalement pour que rc-orchestrator puisse y accéder + window.rc = rc; + window.tarif = tarif; + window.projet = projet; console.log("Initialisation pour formulaire projet :", parcours); + console.log("📊 RC:", rc); + console.log("📊 Tarif:", tarif); + console.log("📊 Projet:", projet); + + loadModulateurs(); // Appel des différentes fonctions d'initialisation setupEventListeners(); populateFormData(); + setupTarifImpactListeners(); updateSubmitButtonState('projetForm'); } + let tarifOriginalData = null; + + async function loadModulateurs() { + try { + const response = await fetch('/rc/modulo/activiteRCC'); + const data = await response.json(); + if (data.valid) { + modRCActRCC = data.objRetourne; + } + const response2 = await fetch('/rc/modulo/marchandiseRC'); + const data2 = await response2.json(); + if (data2.valid) { + modRCMar = data2.objRetourne; + } + const response3 = await fetch('/rc/modulo/zoneRC'); + const data3 = await response3.json(); + if (data3.valid) { + modRCZone = data3.objRetourne; + } + const response4 = await fetch('/rc/modulo/activiteComplRC'); + const data4 = await response4.json(); + if (data4.valid) { + modRCActCompl = data4.objRetourne; + } + const response5 = await fetch('/rc/modulo/garAdditionelRC'); + const data5 = await response5.json(); + if (data5.valid) { + modRCGarAdd = data5.objRetourne; + } + } catch (error) { + console.error('Erreur lors du chargement des modulateurs:', error); + } + } + + function saveOriginalTarifData() { + if (!tarif || !tarif.id) return; + + const garantieRCCSelector = document.getElementById('garantieRCC-selector'); + let garantiesRCC = []; + if (garantieRCCSelector) { + garantiesRCC = Array.from(garantieRCCSelector.selectedOptions).map(opt => opt.value); + } else if (projet) { + if (projet.extRCCConfie) garantiesRCC.push('contenant-confie'); + if (projet.extRCCTPPC) garantiesRCC.push('tppc'); + if (projet.extRCCModifCalArrim) garantiesRCC.push('modif-calage-arrimage'); + if (projet.extRCCFerroutage) garantiesRCC.push('ferroutage'); + if (projet.extRCCFraisRecons) garantiesRCC.push('frais-reconstitution'); + if (projet.extRCCRegie) garantiesRCC.push('regie'); + if (projet.extRCCSansMontageDemontage) garantiesRCC.push('sans-montage-demontage'); + } + + const parseArray = (value) => { + if (Array.isArray(value)) return value; + if (typeof value === 'string') { + try { + return JSON.parse(value); + } catch { + return []; + } + } + return []; + }; + + tarifOriginalData = { + checkVoiturier: rc?.checkVoiturier || false, + checkLoueur: rc?.checkLoueur || false, + checkCommissionnaire: rc?.checkCommissionnaire || false, + checkDemenageur: rc?.checkDemenageur || false, + checkLogistique: rc?.checkLogistique || false, + checkAutocariste: rc?.checkAutocariste || false, + checkAutres: rc?.checkAutres || false, + capitalVoiturier: rc?.capitalVoiturier || 0, + capitalCommissionnaire: rc?.capitalCommissionnaire || 0, + capitalDemenageur: rc?.capitalDemenageur || 0, + capitalLogistique: rc?.capitalLogistique || 0, + capitalAutocariste: rc?.capitalAutocariste || 0, + capitalAutres: rc?.capitalAutres || 0, + marchandisesVoiturier: parseArray(rc?.marchandisesVoiturier), + marchandisesCommissionnaire: parseArray(rc?.marchandisesCommissionnaire), + marchandisesDemenageur: parseArray(rc?.marchandisesDemenageur), + marchandisesLogistique: parseArray(rc?.marchandisesLogistique), + marchandisesAutocariste: parseArray(rc?.marchandisesAutocariste), + marchandisesAutres: parseArray(rc?.marchandisesAutres), + activitesVoiturier: parseArray(rc?.activitesVoiturier), + activitesCommissionnaire: parseArray(rc?.activitesCommissionnaire), + activitesDemenageur: parseArray(rc?.activitesDemenageur), + activitesLogistique: parseArray(rc?.activitesLogistique), + zone1: rc?.zone1 || false, + zone2: rc?.zone2 || false, + zone3: rc?.zone3 || false, + zone4: rc?.zone4 || false, + zone5: rc?.zone5 || false, + zone6: rc?.zone6 || false, + typeCotisation: rc?.typeCotisation || 'revisable', + checkRCE: rc?.checkRCE || false, + garantiesRCC: garantiesRCC, + ca: rc?.chiffreAffaires || tarif?.ca || '', + pj: tarif?.checkPJ || false + }; + } + + function checkTarifImpact(fieldType, fieldValue) { + if (!tarif || !tarif.id || !tarifOriginalData) return false; + + switch(fieldType) { + case 'activity': + return checkActivityImpact(fieldValue); + case 'marchandise': + return checkMarchandiseImpact(fieldValue); + case 'zone': + return checkZoneImpact(fieldValue); + case 'activiteCompl': + return checkActiviteComplImpact(fieldValue); + case 'typeCotisation': + return fieldValue === 'forfaitaire' && tarifOriginalData.typeCotisation === 'forfaitaire'; + default: + return false; + } + } + + function checkActivityImpact(activityData) { + if (!modRCActRCC) return false; + + const activities = ['checkVoiturier', 'checkCommissionnaire', 'checkDemenageur', 'checkLogistique', 'checkAutocariste', 'checkAutres']; + for (let act of activities) { + if (activityData[act] !== tarifOriginalData[act]) return true; + const capitalKey = act.replace('check', 'capital'); + const originalCapital = parseFloat(tarifOriginalData[capitalKey]) || 0; + const currentCapital = parseFloat(activityData[capitalKey]) || 0; + if (Math.abs(originalCapital - currentCapital) > 0.01) return true; + } + return false; + } + + function checkMarchandiseImpact(marchandiseData) { + if (!modRCMar) return false; + + const normalizeArray = (arr) => { + if (!arr) return []; + const normalized = Array.isArray(arr) ? arr : (typeof arr === 'string' ? JSON.parse(arr) : []); + return normalized.map(item => String(item).trim()).sort(); + }; + + const marchandiseKeys = ['marchandisesVoiturier', 'marchandisesCommissionnaire', 'marchandisesDemenageur', + 'marchandisesLogistique', 'marchandisesAutocariste', 'marchandisesAutres']; + for (let key of marchandiseKeys) { + const original = normalizeArray(tarifOriginalData[key]); + const current = normalizeArray(marchandiseData[key]); + if (JSON.stringify(original) !== JSON.stringify(current)) return true; + } + return false; + } + + function checkZoneImpact(zoneData) { + if (!modRCZone) return false; + + function getMaxZoneCoefficient(zones) { + let maxRCC = 1; + let maxRCE = 1; + + const zoneLabels = [ + "France Métropolitaine et pays limitrophes", + "Union Européenne", + "Autres pays européens sauf Russie et Ukraine (y compris UK et Norvège)", + "Pays du Maghreb et Amérique du Nord ( USA / Canada / Mexique )", + "Amérique Centrale et Sud / Caraïbes, Asie et Océanie", + "Afrique Hors Maghreb / Proche Orient / Moyen Orient" + ]; + + for (let i = 1; i <= 6; i++) { + if (zones[`zone${i}`]) { + const zoneKey = zoneLabels[i - 1]; + if (modRCZone[zoneKey]) { + if (typeof modRCZone[zoneKey].modRCC === "number") { + maxRCC = Math.max(maxRCC, modRCZone[zoneKey].modRCC); + } + if (typeof modRCZone[zoneKey].modRCE === "number") { + maxRCE = Math.max(maxRCE, modRCZone[zoneKey].modRCE); + } + } + } + } + + return { maxRCC, maxRCE }; + } + + const originalMax = getMaxZoneCoefficient(tarifOriginalData); + const currentMax = getMaxZoneCoefficient(zoneData); + + return originalMax.maxRCC !== currentMax.maxRCC || originalMax.maxRCE !== currentMax.maxRCE; + } + + function checkActiviteComplImpact(activiteComplData) { + if (!modRCActCompl) return false; + + const activiteKeys = ['activitesVoiturier', 'activitesCommissionnaire', 'activitesDemenageur', 'activitesLogistique']; + for (let key of activiteKeys) { + const original = Array.isArray(tarifOriginalData[key]) ? tarifOriginalData[key] : (tarifOriginalData[key] ? JSON.parse(tarifOriginalData[key]) : []); + const current = Array.isArray(activiteComplData[key]) ? activiteComplData[key] : (activiteComplData[key] ? JSON.parse(activiteComplData[key]) : []); + if (JSON.stringify(original.sort()) !== JSON.stringify(current.sort())) return true; + } + return false; + } + + function getCurrentActiviteComplData() { + const activitesCompl = { + activitesVoiturier: getActivitesComplFromForm('actComplVoiturier/Loueur'), + activitesCommissionnaire: getActivitesComplFromForm('actComplCommissionnaire de Transport'), + activitesDemenageur: getActivitesComplFromForm('actComplDéménageur'), + activitesLogistique: getActivitesComplFromForm('actComplLogistique') + }; + return activitesCompl; + } + + function getActivitesComplFromForm(containerName) { + const container = document.querySelector(`[name="${containerName}"]`); + if (!container) return []; + const checkboxes = container.querySelectorAll('input[type="checkbox"]:checked'); + const activites = []; + checkboxes.forEach(cb => { + const text = cb.nextElementSibling ? cb.nextElementSibling.textContent.trim() : cb.value; + activites.push(text); + }); + return activites; + } + + let lastChangedField = null; + let lastChangedValue = null; + let isRestoringValue = false; + + function showTarifImpactModal(callback, fieldElement, originalValue) { + const modal = document.getElementById('modalModif'); + if (!modal) return; + + const instance = M.Modal.getInstance(modal); + + lastChangedField = fieldElement; + lastChangedValue = originalValue; + + const okBtn = document.getElementById('modif-OK'); + const noBtn = document.getElementById('modif-NO'); + + if (okBtn) { + okBtn.onclick = function() { + instance.close(); + if (callback) callback(true); + }; + } + + if (noBtn) { + noBtn.onclick = function() { + instance.close(); + isRestoringValue = true; + + if (lastChangedField && lastChangedValue !== null) { + if (lastChangedField.tagName === 'INPUT') { + lastChangedField.value = lastChangedValue; + } else if (lastChangedField.tagName === 'SELECT') { + if (lastChangedField.multiple && Array.isArray(lastChangedValue)) { + Array.from(lastChangedField.options).forEach(opt => { + opt.selected = lastChangedValue.includes(opt.value); + }); + } else { + lastChangedField.value = lastChangedValue; + } + M.FormSelect.init(lastChangedField); + + if (lastChangedField.id === 'activity-selector') { + handleActivitySelection(); + } + } else if (lastChangedField.type === 'checkbox' || lastChangedField.type === 'radio') { + lastChangedField.checked = lastChangedValue; + } + } + + setTimeout(() => { + isRestoringValue = false; + }, 100); + + if (callback) callback(false); + }; + } + + instance.open(); + } + + function setupTarifImpactListeners() { + if (!tarif || !tarif.id) return; + + setTimeout(() => { + saveOriginalTarifData(); + }, 500); + + const activitySelector = document.getElementById('activity-selector'); + if (activitySelector) { + activitySelector.addEventListener('change', function(e) { + if (isRestoringValue) return; + + setTimeout(() => { + if (!tarif || !tarif.id || !tarifOriginalData || isRestoringValue) return; + const currentData = getCurrentActivityData(); + if (checkTarifImpact('activity', currentData)) { + e.stopImmediatePropagation(); + e.preventDefault(); + const originalSelection = Array.from(this.options).filter(opt => { + const wasSelected = tarifOriginalData.checkVoiturier && (opt.value === 'voiturier' || opt.value === 'loueur') || + tarifOriginalData.checkCommissionnaire && opt.value === 'commissionnaire-multimodal' || + tarifOriginalData.checkDemenageur && (opt.value === 'demenageur-particulier' || opt.value === 'demenageur-entreprise' || opt.value === 'demenageur-interne') || + tarifOriginalData.checkLogistique && (opt.value === 'entrepositaire-depositaire' || opt.value === 'prestataire-logistique') || + tarifOriginalData.checkAutocariste && opt.value === 'autocariste' || + tarifOriginalData.checkAutres && opt.value === 'autres'; + return wasSelected; + }).map(opt => opt.value); + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, this, originalSelection); + return false; + } + }, 200); + }, true); + } + + const marchandiseSelector = document.getElementById('marchandise-selector'); + if (marchandiseSelector) { + let lastMarchandiseSelection = Array.from(marchandiseSelector.selectedOptions).map(opt => opt.value); + + marchandiseSelector.addEventListener('mousedown', function() { + if (!isRestoringValue) { + lastMarchandiseSelection = Array.from(this.selectedOptions).map(opt => opt.value); + } + }, true); + + marchandiseSelector.addEventListener('change', function(e) { + if (isRestoringValue) { + handleMarchandiseSelection(); + return; + } + + const originalSelection = lastMarchandiseSelection; + + setTimeout(() => { + if (!tarif || !tarif.id || !tarifOriginalData || isRestoringValue) return; + const currentData = getCurrentMarchandiseData(); + if (checkTarifImpact('marchandise', currentData)) { + e.stopImmediatePropagation(); + e.preventDefault(); + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, this, originalSelection); + } else { + lastMarchandiseSelection = Array.from(this.selectedOptions).map(opt => opt.value); + handleMarchandiseSelection(); + } + }, 200); + }, true); + } + + for (let i = 1; i <= 6; i++) { + const zoneCheckbox = document.getElementById(`zone${i}`); + if (zoneCheckbox) { + zoneCheckbox.addEventListener('change', function(e) { + if (isRestoringValue) return; + + const checkboxId = this.id; + const originalChecked = tarifOriginalData[checkboxId] || false; + + setTimeout(() => { + if (!tarif || !tarif.id || !tarifOriginalData || isRestoringValue) return; + const currentData = getCurrentZoneData(); + if (checkTarifImpact('zone', currentData)) { + e.stopImmediatePropagation(); + e.preventDefault(); + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, this, originalChecked); + } + }, 200); + }, true); + } + } + + const garantieRCCSelector = document.getElementById('garantieRCC-selector'); + if (garantieRCCSelector) { + garantieRCCSelector.addEventListener('change', function(e) { + if (isRestoringValue) return; + + setTimeout(() => { + if (!tarif || !tarif.id || !tarifOriginalData || isRestoringValue) return; + const currentData = getCurrentGarantieRCCData(); + if (checkGarantieRCCImpact(currentData)) { + e.stopImmediatePropagation(); + const originalSelection = Array.from(this.selectedOptions).map(opt => opt.value); + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, this, originalSelection); + } + }, 200); + }, true); + } + + const activiteComplContainers = [ + 'actComplVoiturier/Loueur', + 'actComplCommissionnaire de Transport', + 'actComplDéménageur', + 'actComplLogistique' + ]; + + activiteComplContainers.forEach(containerName => { + const container = document.querySelector(`[name="${containerName}"]`); + if (container) { + const checkboxes = container.querySelectorAll('input[type="checkbox"]'); + checkboxes.forEach(checkbox => { + checkbox.addEventListener('change', function(e) { + if (isRestoringValue) return; + + const originalChecked = !this.checked; + + setTimeout(() => { + if (!tarif || !tarif.id || !tarifOriginalData || isRestoringValue) return; + const currentData = getCurrentActiviteComplData(); + if (checkTarifImpact('activiteCompl', currentData)) { + e.stopImmediatePropagation(); + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, this, originalChecked); + } + }, 200); + }, true); + }); + } + }); + + const radioButtonsCot = document.getElementsByName('cotisation'); + for (let i = 0; i < radioButtonsCot.length; i++) { + radioButtonsCot[i].addEventListener('change', function(e) { + if (isRestoringValue) return; + + setTimeout(() => { + if (!tarif || !tarif.id || !tarifOriginalData || isRestoringValue) return; + const originalValue = tarifOriginalData.typeCotisation; + if (this.value !== originalValue) { + e.stopImmediatePropagation(); + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, this, originalValue); + } + }, 200); + }, true); + } + + const capitalFields = ['voiturier', 'loueur', 'commissionnaire-multimodal', 'demenageur-particulier', + 'demenageur-particulier-dommage', 'demenageur-particulier-advalorem', + 'demenageur-entreprise', 'demenageur-interne', 'entrepositaire-depositaire', + 'prestataire-logistique', 'autocariste', 'autres']; + + capitalFields.forEach(fieldId => { + const field = document.getElementById(fieldId); + if (field) { + let originalValue = field.value || field.dataset.defaultValue || ''; + field.addEventListener('input', function(e) { + if (isRestoringValue) return; + + setTimeout(() => { + if (!tarif || !tarif.id || !tarifOriginalData || isRestoringValue) return; + const currentData = getCurrentActivityData(); + if (checkTarifImpact('activity', currentData)) { + const currentValue = this.value; + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, this, originalValue); + } else { + originalValue = this.value; + } + }, 200); + }); + } + }); + + const observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + if (mutation.addedNodes.length) { + capitalFields.forEach(fieldId => { + const field = document.getElementById(fieldId); + if (field && !field.hasAttribute('data-tarif-listener')) { + field.setAttribute('data-tarif-listener', 'true'); + let originalValue = field.value || field.dataset.defaultValue || ''; + field.addEventListener('input', function(e) { + if (isRestoringValue) return; + + setTimeout(() => { + if (!tarif || !tarif.id || !tarifOriginalData || isRestoringValue) return; + const currentData = getCurrentActivityData(); + if (checkTarifImpact('activity', currentData)) { + const currentValue = this.value; + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, this, originalValue); + } else { + originalValue = this.value; + } + }, 200); + }); + } + }); + } + }); + }); + + observer.observe(document.body, { + childList: true, + subtree: true + }); + + const switchPJ = document.getElementById('switchPJ'); + if (switchPJ) { + switchPJ.addEventListener('change', function(e) { + if (isRestoringValue) return; + + const originalChecked = tarifOriginalData.pj || false; + + setTimeout(() => { + if (!tarif || !tarif.id || !tarifOriginalData || isRestoringValue) return; + if (this.checked !== originalChecked) { + e.stopImmediatePropagation(); + e.preventDefault(); + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, this, originalChecked); + } + }, 200); + }, true); + } + } + + function checkGarantieRCCImpact(garantieData) { + if (!modRCActCompl && !modRCGarAdd) return false; + + const garantiesImpactantes = ['contenant-confie', 'tppc']; + const originalGaranties = tarifOriginalData?.garantiesRCC || []; + const currentGaranties = garantieData || []; + + for (let garantie of garantiesImpactantes) { + const wasSelected = originalGaranties.includes(garantie); + const isSelected = currentGaranties.includes(garantie); + if (wasSelected !== isSelected) return true; + } + + return false; + } + + function getCurrentActivityData() { + const activitySelector = document.getElementById('activity-selector'); + const selectedActivities = Array.from(activitySelector.selectedOptions).map(opt => opt.value); + + return { + checkVoiturier: selectedActivities.includes('voiturier') || selectedActivities.includes('loueur'), + checkCommissionnaire: selectedActivities.includes('commissionnaire-multimodal'), + checkDemenageur: selectedActivities.includes('demenageur-particulier') || selectedActivities.includes('demenageur-entreprise') || selectedActivities.includes('demenageur-interne'), + checkLogistique: selectedActivities.includes('entrepositaire-depositaire') || selectedActivities.includes('prestataire-logistique'), + checkAutocariste: selectedActivities.includes('autocariste'), + checkAutres: selectedActivities.includes('autres'), + capitalVoiturier: document.getElementById("voiturier") ? parseFloat(document.getElementById("voiturier").value) || 0 : (document.getElementById("select-voiturier")?.dataset.defaultValue ? parseFloat(document.getElementById("select-voiturier").dataset.defaultValue) : 0), + capitalCommissionnaire: document.getElementById("commissionnaire-multimodal") ? parseFloat(document.getElementById("commissionnaire-multimodal").value) || 0 : (document.getElementById("select-commissionnaire-multimodal")?.dataset.defaultValue ? parseFloat(document.getElementById("select-commissionnaire-multimodal").dataset.defaultValue) : 0), + capitalDemenageur: document.getElementById("demenageur-particulier") ? parseFloat(document.getElementById("demenageur-particulier").value) || 0 : (document.getElementById("select-demenageur-particulier")?.dataset.defaultValue ? parseFloat(document.getElementById("select-demenageur-particulier").dataset.defaultValue) : 0), + capitalLogistique: document.getElementById("entrepositaire-depositaire") ? parseFloat(document.getElementById("entrepositaire-depositaire").value) || 0 : (document.getElementById("select-entrepositaire-depositaire")?.dataset.defaultValue ? parseFloat(document.getElementById("select-entrepositaire-depositaire").dataset.defaultValue) : 0) + }; + } + + function getCurrentMarchandiseData() { + const selectedMarchandises = getSelectedMarchandises(); + const marchandiseTexts = selectedMarchandises.map(val => { + const option = document.querySelector(`#marchandise-selector option[value="${val}"]`); + return option ? option.textContent.trim() : val; + }); + + return { + marchandisesVoiturier: marchandiseTexts, + marchandisesCommissionnaire: marchandiseTexts, + marchandisesDemenageur: marchandiseTexts, + marchandisesLogistique: marchandiseTexts, + marchandisesAutocariste: marchandiseTexts, + marchandisesAutres: marchandiseTexts + }; + } + + function getCurrentZoneData() { + const zone1 = document.getElementById("zone1"); + const zone2 = document.getElementById("zone2"); + return { + zone1: zone1 && (zone1.checked || zone1.disabled), + zone2: zone2 && (zone2.checked || zone2.disabled), + zone3: document.getElementById("zone3") && document.getElementById("zone3").checked, + zone4: document.getElementById("zone4") && document.getElementById("zone4").checked, + zone5: document.getElementById("zone5") && document.getElementById("zone5").checked, + zone6: document.getElementById("zone6") && document.getElementById("zone6").checked + }; + } + + function getCurrentGarantieRCCData() { + const selector = document.getElementById('garantieRCC-selector'); + return Array.from(selector.selectedOptions).map(opt => opt.value); + } + + function getSelectedMarchandises() { + const selector = document.getElementById('marchandise-selector'); + return Array.from(selector.selectedOptions).map(opt => opt.value); + } + + function prefillFromTarif() { + if (!tarif || !rc) { + console.log('⚠️ Pas de données tarif/rc pour pré-remplir'); + return; + } + + console.log('📝 Pré-remplissage depuis tarif...', { rc, tarif }); + + function parseArray(value) { + if (Array.isArray(value)) return value; + if (typeof value === 'string') { + try { + return JSON.parse(value); + } catch { + return []; + } + } + return []; + } + + const activitySelector = document.getElementById('activity-selector'); + const marchandiseSelector = document.getElementById('marchandise-selector'); + + // ===== ACTIVITÉS ===== + + // Voiturier + if (rc.checkVoiturier && !projet?.actVoiturier && activitySelector) { + console.log(' ✓ Sélection Voiturier, capital:', rc.capitalVoiturier); + const voiturierOption = activitySelector.querySelector('option[value="voiturier"]'); + if (voiturierOption) { + voiturierOption.selected = true; + if (rc.capitalVoiturier) { + voiturierOption.setAttribute('data-default-value', rc.capitalVoiturier); + } + } + } + + // Loueur (souvent coché avec Voiturier) + if (rc.checkVoiturier && !projet?.actLoueur && activitySelector) { + console.log(' ✓ Sélection Loueur (car Voiturier coché)'); + const loueurOption = activitySelector.querySelector('option[value="loueur"]'); + if (loueurOption) { + loueurOption.selected = true; + } + } + + // Commissionnaire → Commissionnaire multimodal + if (rc.checkCommissionnaire && !projet?.actMultimodal && activitySelector) { + console.log(' ✓ Sélection Commissionnaire multimodal, capital:', rc.capitalCommissionnaire); + const multimodalOption = activitySelector.querySelector('option[value="commissionnaire-multimodal"]'); + if (multimodalOption) { + multimodalOption.selected = true; + if (rc.capitalCommissionnaire) { + multimodalOption.setAttribute('data-default-value', rc.capitalCommissionnaire); + } + } + } + + // Déménageur → Déménageur d'entreprises (pas particuliers) + if (rc.checkDemenageur && !projet?.actDemEntr && activitySelector) { + console.log(' ✓ Sélection Déménageur d\'entreprises, capital:', rc.capitalDemenageur); + const demenageurOption = activitySelector.querySelector('option[value="demenageur-entreprise"]'); + if (demenageurOption) { + demenageurOption.selected = true; + if (rc.capitalDemenageur) { + demenageurOption.setAttribute('data-default-value', rc.capitalDemenageur); + } + } + } + + // Logistique → Prestataire logistique + if (rc.checkLogistique && !projet?.actPrestaLog && activitySelector) { + console.log(' ✓ Sélection Prestataire logistique, capital:', rc.capitalLogistique); + const logistiqueOption = activitySelector.querySelector('option[value="prestataire-logistique"]'); + if (logistiqueOption) { + logistiqueOption.selected = true; + if (rc.capitalLogistique) { + logistiqueOption.setAttribute('data-default-value', rc.capitalLogistique); + } + } + } + + // Autocariste + if (rc.checkAutocariste && activitySelector) { + console.log(' ✓ Sélection Autocariste, capital:', rc.capitalAutocariste); + const autocaristeOption = activitySelector.querySelector('option[value="autocariste"]'); + if (autocaristeOption) { + autocaristeOption.selected = true; + if (rc.capitalAutocariste) { + autocaristeOption.setAttribute('data-default-value', rc.capitalAutocariste); + } + } + } + + // Autres + if (rc.checkAutres && activitySelector) { + console.log(' ✓ Sélection Autres activités, capital:', rc.capitalAutres); + const autresOption = activitySelector.querySelector('option[value="autres"]'); + if (autresOption) { + autresOption.selected = true; + if (rc.capitalAutres) { + autresOption.setAttribute('data-default-value', rc.capitalAutres); + } + } + } + + // IMPORTANT : Trigger change event pour que Materialize mette à jour l'affichage + if (activitySelector) { + console.log(' 🔄 Trigger change event sur activity-selector'); + const changeEvent = new Event('change', { bubbles: true }); + activitySelector.dispatchEvent(changeEvent); + + // Réinitialiser Materialize FormSelect + setTimeout(() => { + if (window.M && window.M.FormSelect) { + window.M.FormSelect.init(activitySelector); + console.log(' ✅ Materialize FormSelect réinitialisé'); + } + }, 100); + } + + // ===== MARCHANDISES ===== + + if (marchandiseSelector) { + const allMarchandises = [ + ...(parseArray(rc.marchandisesVoiturier)), + ...(parseArray(rc.marchandisesCommissionnaire)), + ...(parseArray(rc.marchandisesDemenageur)), + ...(parseArray(rc.marchandisesLogistique)), + ...(parseArray(rc.marchandisesAutocariste)), + ...(parseArray(rc.marchandisesAutres)) + ]; + + const uniqueMarchandises = [...new Set(allMarchandises)]; + console.log(' 📦 Marchandises:', uniqueMarchandises); + + const marchandiseMapping = { + 'Marchandises ordinaires': 'ordinaire', + 'Marchandises ordinaires et assimilées, les marchandises dangereuses dans le respect de la réglementation': 'ordinaire', + 'Véhicules roulants': 'roulant', + 'Engins de chantier et engins agricoles': 'engins-chantier-agricole', + 'Engins de chantier': 'engins-chantier-agricole', + 'Véhicules roulants dans le cadre d\'une activité de déménagement': 'roulant-demenagement', + 'Mobiliers usagés – Objets et effets personnels en déménagement': 'mobilier-usages', + 'Mobiliers en déménagement': 'mobilier-usages', + 'Marchandises périssables sous température dirigée': 'perissable-temperature-dirigee', + 'Marchandises périssables': 'perissable-temperature-dirigee', + 'Animaux vivants': 'animaux-vivant', + 'Marchandises en citerne': 'citerne', + 'Transports de béton': 'beton', + 'Transport de béton': 'beton', + 'Transports exceptionnels': 'exceptionnels', + 'Marchandises en vrac transportées en benne': 'vrac', + 'Marchandises en benne': 'vrac' + }; + + uniqueMarchandises.forEach(marchText => { + const mappedValue = marchandiseMapping[marchText] || marchText.toLowerCase().replace(/\s+/g, '-'); + const option = marchandiseSelector.querySelector(`option[value="${mappedValue}"]`); + if (option && !option.selected) { + option.selected = true; + } else if (!option) { + // Recherche floue si mapping exact échoue + const options = marchandiseSelector.querySelectorAll('option'); + options.forEach(opt => { + if (opt.textContent.trim().includes(marchText) || marchText.includes(opt.textContent.trim().substring(0, 20))) { + if (!opt.selected) opt.selected = true; + } + }); + } + }); + + // Trigger change event pour Materialize + const changeEvent = new Event('change', { bubbles: true }); + marchandiseSelector.dispatchEvent(changeEvent); + + setTimeout(() => { + if (window.M && window.M.FormSelect) { + window.M.FormSelect.init(marchandiseSelector); + } + }, 100); + } + + // ===== ZONES GÉOGRAPHIQUES ===== + + if (rc.zone1 !== undefined && !projet?.zone1) { + const zone1El = document.getElementById("zone1"); + if (zone1El) { + zone1El.checked = rc.zone1; + console.log(' ✓ Zone 1:', rc.zone1); + } + } + if (rc.zone2 !== undefined && !projet?.zone2) { + const zone2El = document.getElementById("zone2"); + if (zone2El) { + zone2El.checked = rc.zone2; + console.log(' ✓ Zone 2:', rc.zone2); + } + } + if (rc.zone3 !== undefined && !projet?.zone3) { + const zone3El = document.getElementById("zone3"); + if (zone3El) { + zone3El.checked = rc.zone3; + console.log(' ✓ Zone 3:', rc.zone3); + } + } + if (rc.zone4 !== undefined && !projet?.zone4) { + const zone4El = document.getElementById("zone4"); + if (zone4El) { + zone4El.checked = rc.zone4; + console.log(' ✓ Zone 4:', rc.zone4); + } + } + if (rc.zone5 !== undefined && !projet?.zone5) { + const zone5El = document.getElementById("zone5"); + if (zone5El) { + zone5El.checked = rc.zone5; + console.log(' ✓ Zone 5:', rc.zone5); + } + } + if (rc.zone6 !== undefined && !projet?.zone6) { + const zone6El = document.getElementById("zone6"); + if (zone6El) { + zone6El.checked = rc.zone6; + console.log(' ✓ Zone 6:', rc.zone6); + } + } + + // ===== TYPE DE COTISATION ===== + + if (rc.typeCotisation && !projet?.typeCot) { + const radioCot = document.querySelector(`input[name="typeCot"][value="${rc.typeCotisation}"]`); + if (radioCot) { + radioCot.checked = true; + console.log(' ✓ Type cotisation:', rc.typeCotisation); + } + } + + // ===== CA ===== + + if (rc.chiffreAffaires && !projet?.ca) { + const caEl = document.getElementById("CA"); + if (caEl) { + caEl.value = rc.chiffreAffaires; + console.log(' ✓ CA:', rc.chiffreAffaires); + } + } + + // ===== RCE (INCLURE LES AUTRES RC) ===== + + const hasRCEFromRC = rc && rc.checkRCE; + const hasRCEFromTarif = tarif && tarif.checkRCE; + if (hasRCEFromRC || hasRCEFromTarif) { + console.log(' ✓ RCE activée (checkRCE)'); + const choixRCEEl = document.getElementById("choixRCE"); + if (choixRCEEl) { + choixRCEEl.checked = true; + const garantieRCEEl = document.getElementById('garantieRCE'); + if (garantieRCEEl) garantieRCEEl.style.display = 'block'; + const rce1El = document.getElementById('RCE1'); + if (rce1El) rce1El.style.display = ''; + const rce2El = document.getElementById('RCE2'); + if (rce2El) rce2El.style.display = ''; + } + } + + // ===== PROTECTION JURIDIQUE ===== + + if (tarif && tarif.checkPJ && !projet?.pj) { + console.log(' ✓ Protection Juridique activée'); + const switchPJEl = document.getElementById("switchPJ"); + if (switchPJEl) { + switchPJEl.checked = true; + + // Afficher la section PJ + const pj1El = document.getElementById('PJ1'); + if (pj1El) pj1El.style.display = ''; + const pj2El = document.getElementById('PJ2'); + if (pj2El) pj2El.style.display = ''; + + // Pré-remplir les cotisations PJ si disponibles + if (tarif.cotPJHT && !projet?.cotPJHT) { + const cotPJHTEl = document.getElementById('cotPJHT'); + if (cotPJHTEl) { + cotPJHTEl.value = tarif.cotPJHT; + console.log(' ├─ Cotisation PJ HT:', tarif.cotPJHT); + } + } + if (tarif.cotPJTTC && !projet?.cotPJTTC) { + const cotPJTTCEl = document.getElementById('cotPJTTC'); + if (cotPJTTCEl) { + cotPJTTCEl.value = tarif.cotPJTTC; + console.log(' └─ Cotisation PJ TTC:', tarif.cotPJTTC); + } + } + } + } + + // Appliquer les capitaux APRÈS trigger (les inputs sont créés dynamiquement) + setTimeout(() => { + console.log(' 💰 Application des capitaux sur les inputs créés...'); + + // Mapping des activités vers leurs capitaux + const capitalMapping = { + 'voiturier': rc.capitalVoiturier, + 'commissionnaire-multimodal': rc.capitalCommissionnaire, + 'demenageur-entreprise': rc.capitalDemenageur, + 'prestataire-logistique': rc.capitalLogistique, + 'autocariste': rc.capitalAutocariste, + 'autres': rc.capitalAutres + }; + + for (const [activity, capital] of Object.entries(capitalMapping)) { + if (capital) { + const input = document.getElementById(activity); + if (input && !input.value) { + input.value = capital; + console.log(` ├─ ${activity}: ${capital}`); + } + } + } + + console.log(' ✅ Capitaux appliqués'); + }, 300); + + // Autres champs (garanties RCC, etc.) + const garantieRCCSelector = document.getElementById('garantieRCC-selector'); + if (garantieRCCSelector && !projet) { + if (rc.extRCCModifCalArrim) { + const option = garantieRCCSelector.querySelector('option[value="modif-calage-arrimage"]'); + if (option) option.selected = true; + } + if (rc.extRCCFerroutage) { + const option = garantieRCCSelector.querySelector('option[value="ferroutage"]'); + if (option) option.selected = true; + } + if (rc.extRCCFraisRecons) { + const option = garantieRCCSelector.querySelector('option[value="frais-reconstitution"]'); + if (option) option.selected = true; + } + if (rc.extRCCConfie) { + const option = garantieRCCSelector.querySelector('option[value="confie"]'); + if (option) option.selected = true; + } + if (rc.extRCCTPPC) { + const option = garantieRCCSelector.querySelector('option[value="tppc"]'); + if (option) option.selected = true; + } + if (rc.extRCCRegie) { + const option = garantieRCCSelector.querySelector('option[value="regie"]'); + if (option) option.selected = true; + } + if (rc.extRCCSansMontageDemontage) { + const option = garantieRCCSelector.querySelector('option[value="sans-montage-demontage"]'); + if (option) option.selected = true; + } + } + + // ===== ACTIVITÉS COMPLÉMENTAIRES ===== + + const activitesVoiturier = parseArray(rc.activitesVoiturier); + if (activitesVoiturier.length > 0) { + const container = document.querySelector('[name="actComplVoiturier/Loueur"]'); + if (container) { + activitesVoiturier.forEach(activite => { + const checkboxes = container.querySelectorAll('input[type="checkbox"]'); + checkboxes.forEach(cb => { + const label = cb.nextElementSibling; + if (label && label.textContent.trim() === activite) { + cb.checked = true; + } + }); + }); + } + } + + const activitesCommissionnaire = parseArray(rc.activitesCommissionnaire); + if (activitesCommissionnaire.length > 0) { + const container = document.querySelector('[name="actComplCommissionnaire de Transport"]'); + if (container) { + activitesCommissionnaire.forEach(activite => { + const checkboxes = container.querySelectorAll('input[type="checkbox"]'); + checkboxes.forEach(cb => { + const label = cb.nextElementSibling; + if (label && label.textContent.trim() === activite) { + cb.checked = true; + } + }); + }); + } + } + + const activitesDemenageur = parseArray(rc.activitesDemenageur); + if (activitesDemenageur.length > 0) { + const container = document.querySelector('[name="actComplDéménageur"]'); + if (container) { + activitesDemenageur.forEach(activite => { + const checkboxes = container.querySelectorAll('input[type="checkbox"]'); + checkboxes.forEach(cb => { + const label = cb.nextElementSibling; + if (label && label.textContent.trim() === activite) { + cb.checked = true; + } + }); + }); + } + } + + const activitesLogistique = parseArray(rc.activitesLogistique); + if (activitesLogistique.length > 0) { + const container = document.querySelector('[name="actComplLogistique"]'); + if (container) { + activitesLogistique.forEach(activite => { + const checkboxes = container.querySelectorAll('input[type="checkbox"]'); + checkboxes.forEach(cb => { + const label = cb.nextElementSibling; + if (label && label.textContent.trim() === activite) { + cb.checked = true; + } + }); + }); + } + } + + if (activitySelector) { + activitySelector.dispatchEvent(new Event('change')); + } + if (marchandiseSelector) { + marchandiseSelector.dispatchEvent(new Event('change')); + } + } + // Configuration des écouteurs d'événements function setupEventListeners() { document.getElementById('projetFormBtn').addEventListener('click', handleSubmitForm); @@ -133,10 +1209,20 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio document.getElementById('cotPJHT').value = ''; document.getElementById('cotPJTTC').value = ''; } - calcCotTotal(); }); + function restoreZonesFromOriginal() { + const orig = tarifOriginalData || {}; + ['zone1','zone2','zone3','zone4','zone5','zone6'].forEach(z => { + const el = document.getElementById(z); + if (el) { + el.disabled = false; + el.checked = Boolean(orig[z]); + } + }); + } + document.getElementById('btnMondeEntier').addEventListener('click', function () { document.getElementById('zone1').checked = true; document.getElementById('zone1').disabled = true; @@ -147,6 +1233,20 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio document.getElementById('zone5').checked = true; document.getElementById('zone6').checked = true; + // Détection impact tarif : zones + if (tarif && tarif.id && tarifOriginalData) { + const currentData = getCurrentZoneData(); + if (checkTarifImpact('zone', currentData)) { + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, null, null); + // Revenir à l'état original visuel + restoreZonesFromOriginal(); + } + } + handleGrAdvalo(); }); @@ -160,6 +1260,20 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio document.getElementById('zone5').checked = false; document.getElementById('zone6').checked = false; + // Détection impact tarif : zones + if (tarif && tarif.id && tarifOriginalData) { + const currentData = getCurrentZoneData(); + if (checkTarifImpact('zone', currentData)) { + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, null, null); + // Revenir à l'état original visuel + restoreZonesFromOriginal(); + } + } + handleGrAdvalo(); }); @@ -207,6 +1321,18 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio document.getElementById('zone1').addEventListener('click', function () { handleGrAdvalo(); + + if (tarif && tarif.id && tarifOriginalData) { + const currentData = getCurrentZoneData(); + if (checkTarifImpact('zone', currentData)) { + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, null, null); + restoreZonesFromOriginal(); + } + } }); document.getElementById('zone2').addEventListener('click', function () { @@ -219,6 +1345,18 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio } handleGrAdvalo(); + + if (tarif && tarif.id && tarifOriginalData) { + const currentData = getCurrentZoneData(); + if (checkTarifImpact('zone', currentData)) { + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, null, null); + restoreZonesFromOriginal(); + } + } }); document.getElementById('zone3').addEventListener('click', function () { @@ -235,18 +1373,66 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio } handleGrAdvalo(); + + if (tarif && tarif.id && tarifOriginalData) { + const currentData = getCurrentZoneData(); + if (checkTarifImpact('zone', currentData)) { + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, null, null); + restoreZonesFromOriginal(); + } + } }); document.getElementById('zone4').addEventListener('click', function () { handleGrAdvalo(); + + if (tarif && tarif.id && tarifOriginalData) { + const currentData = getCurrentZoneData(); + if (checkTarifImpact('zone', currentData)) { + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, null, null); + restoreZonesFromOriginal(); + } + } }); document.getElementById('zone5').addEventListener('click', function () { handleGrAdvalo(); + + if (tarif && tarif.id && tarifOriginalData) { + const currentData = getCurrentZoneData(); + if (checkTarifImpact('zone', currentData)) { + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, null, null); + restoreZonesFromOriginal(); + } + } }); document.getElementById('zone6').addEventListener('click', function () { handleGrAdvalo(); + + if (tarif && tarif.id && tarifOriginalData) { + const currentData = getCurrentZoneData(); + if (checkTarifImpact('zone', currentData)) { + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, null, null); + restoreZonesFromOriginal(); + } + } }); var radioButtonsCot = document.getElementsByName('cotisation'); @@ -365,6 +1551,33 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio }); document.getElementById('CA').addEventListener('input', function () { + if (isRestoringValue) { + validateField('CA', true); + updateSubmitButtonState('projetForm'); + calcCotFromTauxCA('tauxRCCHT', 'cotRCCHT'); + calcAddTaxe('cotRCCHT', 0, 'cotRCCTTC'); + calcCotFromTauxCA('tauxRCEHT', 'cotRCEHT'); + calcAddTaxe('cotRCEHT', 0.09, 'cotRCETTC'); + calcCotIrreductible(); + calcCotTotal(); + return; + } + + if (tarif && tarif.id && tarifOriginalData) { + const currentValue = this.value.trim(); + const originalValue = tarifOriginalData.ca || ''; + + if (currentValue !== originalValue) { + const originalValueToRestore = originalValue; + showTarifImpactModal((confirmed) => { + if (confirmed) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=tarif`; + } + }, this, originalValueToRestore); + return; + } + } + validateField('CA', true); updateSubmitButtonState('projetForm'); calcCotFromTauxCA('tauxRCCHT', 'cotRCCHT'); @@ -536,14 +1749,13 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio tagDemenageur = true; } else { - if (!(currentSelection.includes(("demenageur-particulier" || "demenageur-particulier-dommage" || "demenageur-particulier-advalorem") && "demenageur-entreprise" && "demenageur-interne"))) { - document.getElementById('marchandise-selector').querySelector('option[value="roulant-demenagement"]').selected = false; - document.getElementById('marchandise-selector').querySelector('option[value="mobilier-usages"]').selected = false; - document.getElementById('marchandise-selector').querySelector('option[value="ordinaire"]').selected = true; - document.getElementById('marchandise-selector').dispatchEvent(new Event('change')); - - tagDemenageur = false; - } + // Aucune activité déménageur n'est sélectionnée + document.getElementById('marchandise-selector').querySelector('option[value="roulant-demenagement"]').selected = false; + document.getElementById('marchandise-selector').querySelector('option[value="mobilier-usages"]').selected = false; + document.getElementById('marchandise-selector').querySelector('option[value="ordinaire"]').selected = true; + document.getElementById('marchandise-selector').dispatchEvent(new Event('change')); + + tagDemenageur = false; } if (currentSelection.includes("garde-meubles")) { @@ -617,10 +1829,9 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio document.getElementById('selected-voiturier-error').style.display = "block"; } } else { - if (!(currentSelection.includes("entrepositaire-depositaire" && "prestataire-logistique" && "manutentionnaire-levageur"))) { - tagVoiturier = false; - document.getElementById('selected-voiturier-error').style.display = "none"; - } + // Aucune activité nécessitant voiturier n'est sélectionnée + tagVoiturier = false; + document.getElementById('selected-voiturier-error').style.display = "none"; } if (currentSelection.length == 1) { @@ -723,22 +1934,71 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio M.FormSelect.init(idSelect); } + // Pré-remplir depuis le tarif si disponible (même si projet existe, on complète avec les données du tarif) + if (tarif && tarif.id) { + setTimeout(() => { + prefillFromTarif(); + + // S'assurer que "Inclure les autres RC" est coché après prefillFromTarif + setTimeout(() => { + const hasRCEProjet = projet && (projet.autresRC || projet.extRCEBraDebra || projet.extRCEMontageDemontage); + const hasRCERC = rc && rc.checkRCE; + const hasRCETarif = tarif && tarif.checkRCE; + const hasRCE = hasRCEProjet || hasRCERC || hasRCETarif; + + if (hasRCE) { + const choixRCEEl = document.getElementById("choixRCE"); + if (choixRCEEl) { + choixRCEEl.checked = true; + const garantieRCEEl = document.getElementById('garantieRCE'); + if (garantieRCEEl) garantieRCEEl.style.display = 'block'; + const rce1El = document.getElementById('RCE1'); + if (rce1El) rce1El.style.display = ''; + const rce2El = document.getElementById('RCE2'); + if (rce2El) rce2El.style.display = ''; + } + } + }, 200); + }, 300); + } + + // S'assurer que "Inclure les autres RC" est coché si nécessaire (après le chargement de toutes les données projet) + setTimeout(() => { + const hasRCEProjet = projet && (projet.autresRC || projet.extRCEBraDebra || projet.extRCEMontageDemontage); + const hasRCERC = rc && rc.checkRCE; + const hasRCETarif = tarif && tarif.checkRCE; + const hasRCE = hasRCEProjet || hasRCERC || hasRCETarif; + + if (hasRCE) { + const choixRCEEl = document.getElementById("choixRCE"); + if (choixRCEEl && !choixRCEEl.checked) { + choixRCEEl.checked = true; + const garantieRCEEl = document.getElementById('garantieRCE'); + if (garantieRCEEl) garantieRCEEl.style.display = 'block'; + const rce1El = document.getElementById('RCE1'); + if (rce1El) rce1El.style.display = ''; + const rce2El = document.getElementById('RCE2'); + if (rce2El) rce2El.style.display = ''; + } + } + }, 600); + // Populate par défaut Voiturier / Loueur - if (!rc) { + if (!projet && !tarif) { document.getElementById('activity-selector').querySelector('option[value="voiturier"]').selected = true; document.getElementById('activity-selector').querySelector('option[value="loueur"]').selected = true; document.getElementById('activity-selector').dispatchEvent(new Event('change')); } // Populate assurés additionnel - if (!rc || !rc.assureAdditionnel || Object.keys(rc.assureAdditionnel).length === 0) { + if (!projet || !projet.assureAdditionnel || Object.keys(projet.assureAdditionnel).length === 0) { console.log("Le JSON est vide, pas d'assurés additionnels à pré-remplir."); } else { document.getElementById('additionel').checked = true; document.getElementById('checkAdditionnel').style.display = "block"; - for (let i = 0; i < rc.assureAdditionnel.length; i++) { - const row = rc.assureAdditionnel[i]; + for (let i = 0; i < projet.assureAdditionnel.length; i++) { + const row = projet.assureAdditionnel[i]; addRowAdditionnel(row.nom, row.adresse, row.siret); } } @@ -746,20 +2006,20 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio // Populate activite const activitySelector = document.getElementById('activity-selector'); - if (rc.actVoiturier) { + if (projet && projet.actVoiturier) { activitySelector.querySelector('option[value="voiturier"]').selected = true; - document.getElementById("select-voiturier").dataset.defaultValue = rc.valueActVoiturier; + document.getElementById("select-voiturier").dataset.defaultValue = projet.valueActVoiturier; }; - if (rc.actLoueur) { + if (projet && projet.actLoueur) { activitySelector.querySelector('option[value="loueur"]').selected = true; - document.getElementById("select-loueur").dataset.defaultValue = rc.valueActLoueur; + document.getElementById("select-loueur").dataset.defaultValue = projet.valueActLoueur; }; - if (rc.actMultimodal) { + if (projet && projet.actMultimodal) { tagMultimodal = true; activitySelector.querySelector('option[value="commissionnaire-multimodal"]').selected = true; - document.getElementById("select-commissionnaire-multimodal").dataset.defaultValue = rc.valueActMultimodal; + document.getElementById("select-commissionnaire-multimodal").dataset.defaultValue = projet.valueActMultimodal; document.getElementById("btnAdvaloMultimodal").style.display = 'block'; document.getElementById("btnAdvaloAerien").style.display = 'block'; document.getElementById("btnAdvaloTerrestre").style.display = 'block'; @@ -768,59 +2028,59 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio document.getElementById('divAdvaloMultimodal').style.display = "block"; }; - if (rc.actDouane) { + if (projet && projet.actDouane) { activitySelector.querySelector('option[value="représentant-douane"]').selected = true; - document.getElementById("select-représentant-douane").dataset.defaultValue = rc.valueActDouane; + document.getElementById("select-représentant-douane").dataset.defaultValue = projet.valueActDouane; }; - if (rc.actDemPar) { + if (projet && projet.actDemPar) { activitySelector.querySelector('option[value="demenageur-particulier"]').selected = true; - document.getElementById("select-demenageur-particulier").dataset.defaultValue = rc.valueActDemPar; + document.getElementById("select-demenageur-particulier").dataset.defaultValue = projet.valueActDemPar; } - if (rc.actDemParDom) { + if (projet && projet.actDemParDom) { activitySelector.querySelector('option[value="demenageur-particulier-dommage"]').selected = true; - document.getElementById("select-demenageur-particulier-dommage").dataset.defaultValue = rc.valueActDemParDom; + document.getElementById("select-demenageur-particulier-dommage").dataset.defaultValue = projet.valueActDemParDom; } - if (rc.actDemParAdv) { + if (projet && projet.actDemParAdv) { activitySelector.querySelector('option[value="demenageur-particulier-advalorem"]').selected = true; - document.getElementById("select-demenageur-particulier-advalorem").dataset.defaultValue = rc.valueActDemParAdv; + document.getElementById("select-demenageur-particulier-advalorem").dataset.defaultValue = projet.valueActDemParAdv; } - if (rc.actDemEntr) { + if (projet && projet.actDemEntr) { activitySelector.querySelector('option[value="demenageur-entreprise"]').selected = true; - document.getElementById("select-demenageur-entreprise").dataset.defaultValue = rc.valueActDemEntr; + document.getElementById("select-demenageur-entreprise").dataset.defaultValue = projet.valueActDemEntr; } - if (rc.actDemInterne) { + if (projet && projet.actDemInterne) { activitySelector.querySelector('option[value="demenageur-interne"]').selected = true; - document.getElementById("select-demenageur-interne").dataset.defaultValue = rc.valueActDemInterne; + document.getElementById("select-demenageur-interne").dataset.defaultValue = projet.valueActDemInterne; } - if (rc.actGardeMeuble) { + if (projet && projet.actGardeMeuble) { activitySelector.querySelector('option[value="garde-meubles"]').selected = true; - document.getElementById("select-garde-meubles").dataset.defaultValue = rc.valueActGardeMeuble; + document.getElementById("select-garde-meubles").dataset.defaultValue = projet.valueActGardeMeuble; } - if (rc.actEntDep) { + if (projet && projet.actEntDep) { activitySelector.querySelector('option[value="entrepositaire-depositaire"]').selected = true; - document.getElementById("select-entrepositaire-depositaire").dataset.defaultValue = rc.valueActEntDep; + document.getElementById("select-entrepositaire-depositaire").dataset.defaultValue = projet.valueActEntDep; } - if (rc.actPrestaLog) { + if (projet && projet.actPrestaLog) { activitySelector.querySelector('option[value="prestataire-logistique"]').selected = true; - document.getElementById("select-prestataire-logistique").dataset.defaultValue = rc.valueActPrestaLog; + document.getElementById("select-prestataire-logistique").dataset.defaultValue = projet.valueActPrestaLog; } - if (rc.actLevageur) { + if (projet && projet.actLevageur) { activitySelector.querySelector('option[value="manutentionnaire-levageur"]').selected = true; - document.getElementById("select-manutentionnaire-levageur").dataset.defaultValue = rc.valueActLevageur; + document.getElementById("select-manutentionnaire-levageur").dataset.defaultValue = projet.valueActLevageur; } - if (rc.actTransitaire) { + if (projet && projet.actTransitaire) { activitySelector.querySelector('option[value="transitaire"]').selected = true; - document.getElementById("select-transitaire").dataset.defaultValue = rc.valueActTransitaire; + document.getElementById("select-transitaire").dataset.defaultValue = projet.valueActTransitaire; } document.getElementById('activity-selector').dispatchEvent(new Event('change')); @@ -828,98 +2088,156 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio // Populate marchandises const marchandiseSelector = document.getElementById('marchandise-selector'); - if (rc.marOrdinaire) { marchandiseSelector.querySelector('option[value="ordinaire"]').selected = true; }; - if (rc.marRoulant) { marchandiseSelector.querySelector('option[value="roulant"]').selected = true; }; - if (rc.marEngins) { marchandiseSelector.querySelector('option[value="engins-chantier-agricole"]').selected = true; }; - if (rc.marRoulantDem) { marchandiseSelector.querySelector('option[value="roulant-demenagement"]').selected = true; }; - if (rc.marMobilerUsag) { marchandiseSelector.querySelector('option[value="mobilier-usages"]').selected = true; }; - if (rc.marPerissable) { marchandiseSelector.querySelector('option[value="perissable-temperature-dirigee"]').selected = true; }; - if (rc.marAnimaux) { + if (projet && projet.marOrdinaire) { marchandiseSelector.querySelector('option[value="ordinaire"]').selected = true; }; + if (projet && projet.marRoulant) { marchandiseSelector.querySelector('option[value="roulant"]').selected = true; }; + if (projet && projet.marEngins) { marchandiseSelector.querySelector('option[value="engins-chantier-agricole"]').selected = true; }; + if (projet && projet.marRoulantDem) { marchandiseSelector.querySelector('option[value="roulant-demenagement"]').selected = true; }; + if (projet && projet.marMobilerUsag) { marchandiseSelector.querySelector('option[value="mobilier-usages"]').selected = true; }; + if (projet && projet.marPerissable) { marchandiseSelector.querySelector('option[value="perissable-temperature-dirigee"]').selected = true; }; + if (projet && projet.marAnimaux) { tagAnimauxVivants = true; marchandiseSelector.querySelector('option[value="animaux-vivant"]').selected = true; }; - if (rc.marCiterne) { marchandiseSelector.querySelector('option[value="citerne"]').selected = true; }; - if (rc.marBeton) { marchandiseSelector.querySelector('option[value="beton"]').selected = true; }; - if (rc.marExceptionnels) { marchandiseSelector.querySelector('option[value="exceptionnels"]').selected = true; }; - if (rc.marVrac) { marchandiseSelector.querySelector('option[value="vrac"]').selected = true; }; + if (projet && projet.marCiterne) { marchandiseSelector.querySelector('option[value="citerne"]').selected = true; }; + if (projet && projet.marBeton) { marchandiseSelector.querySelector('option[value="beton"]').selected = true; }; + if (projet && projet.marExceptionnels) { marchandiseSelector.querySelector('option[value="exceptionnels"]').selected = true; }; + if (projet && projet.marVrac) { marchandiseSelector.querySelector('option[value="vrac"]').selected = true; }; document.getElementById('marchandise-selector').dispatchEvent(new Event('change')); - // Populate territorialité - if (rc.zone1) { document.getElementById("zone1").checked = true }; - if (rc.zone2) { - document.getElementById("zone2").checked = true; - document.getElementById("zone1").checked = true; - document.getElementById("zone1").disabled = true; - }; - if (rc.zone3) { - document.getElementById("zone3").checked = true; - document.getElementById("zone2").checked = true; - document.getElementById("zone2").disabled = true; - document.getElementById("zone1").checked = true; - document.getElementById("zone1").disabled = true; - }; - if (rc.zone4) { document.getElementById("zone4").checked = true }; - if (rc.zone5) { document.getElementById("zone5").checked = true }; - if (rc.zone6) { document.getElementById("zone6").checked = true }; + // Populate territorialité - depuis projet OU depuis rc (tarif) en fallback + const zonesSource = projet || rc; + if (zonesSource) { + if (zonesSource.zone1) { + document.getElementById("zone1").checked = true; + document.getElementById("zone1").disabled = false; + } + if (zonesSource.zone2) { + document.getElementById("zone2").checked = true; + document.getElementById("zone2").disabled = false; + if (!zonesSource.zone1) { + document.getElementById("zone1").checked = true; + document.getElementById("zone1").disabled = true; + } + } + if (zonesSource.zone3) { + document.getElementById("zone3").checked = true; + document.getElementById("zone3").disabled = false; + if (!zonesSource.zone2) { + document.getElementById("zone2").checked = true; + document.getElementById("zone2").disabled = true; + } + if (!zonesSource.zone1) { + document.getElementById("zone1").checked = true; + document.getElementById("zone1").disabled = true; + } + } + if (zonesSource.zone4) { + document.getElementById("zone4").checked = true; + document.getElementById("zone4").disabled = false; + } + if (zonesSource.zone5) { + document.getElementById("zone5").checked = true; + document.getElementById("zone5").disabled = false; + } + if (zonesSource.zone6) { + document.getElementById("zone6").checked = true; + document.getElementById("zone6").disabled = false; + } + } // Populate extensions de garantie RCC const garantieRCCSelector = document.getElementById('garantieRCC-selector'); - if (rc.extRCCModifCalArrim) { garantieRCCSelector.querySelector('option[value="modif-calage-arrimage"]').selected = true; }; - if (rc.extRCCFerroutage) { garantieRCCSelector.querySelector('option[value="ferroutage"]').selected = true; }; - if (rc.extRCCFraisRecons) { garantieRCCSelector.querySelector('option[value="frais-reconstitution"]').selected = true; }; - if (rc.extRCCConfie) { + if (projet && projet.extRCCModifCalArrim) { garantieRCCSelector.querySelector('option[value="modif-calage-arrimage"]').selected = true; }; + if (projet && projet.extRCCFerroutage) { garantieRCCSelector.querySelector('option[value="ferroutage"]').selected = true; }; + if (projet && projet.extRCCFraisRecons) { garantieRCCSelector.querySelector('option[value="frais-reconstitution"]').selected = true; }; + if (projet && projet.extRCCConfie) { garantieRCCSelector.querySelector('option[value="contenant-confie"]').selected = true; - if (rc.typeExtConfies == "ADVALOREM") { + if (projet.typeExtConfies == "ADVALOREM") { document.getElementById("AdValorem").checked = true; } else { document.getElementById("ValeurDeclaree").checked = true; } }; - if (rc.extRCCTPPC) { garantieRCCSelector.querySelector('option[value="tppc"]').selected = true; }; - if (rc.extRCCRegie) { garantieRCCSelector.querySelector('option[value="regie"]').selected = true; }; - if (rc.extRCCSansMontageDemontage) { garantieRCCSelector.querySelector('option[value="sans-montage-demontage"]').selected = true; }; + if (projet && projet.extRCCTPPC) { garantieRCCSelector.querySelector('option[value="tppc"]').selected = true; }; + if (projet && projet.extRCCRegie) { garantieRCCSelector.querySelector('option[value="regie"]').selected = true; }; + if (projet && projet.extRCCSansMontageDemontage) { garantieRCCSelector.querySelector('option[value="sans-montage-demontage"]').selected = true; }; document.getElementById('garantieRCC-selector').dispatchEvent(new Event('change')); - // Populate extensions de garantie RCC - if (rc.autresRC) { - document.getElementById("choixRCE").checked = true; - document.getElementById('garantieRCE').style.display = 'block'; - document.getElementById('RCE1').style.display = ''; - document.getElementById('RCE2').style.display = ''; - } + // Populate extensions de garantie RCE - DOIT être fait APRÈS le chargement des données projet + setTimeout(() => { + const hasRCEProjet = projet && (projet.autresRC || projet.extRCEBraDebra || projet.extRCEMontageDemontage); + const hasRCERC = rc && rc.checkRCE; + const hasRCETarif = tarif && tarif.checkRCE; + const hasRCE = hasRCEProjet || hasRCERC || hasRCETarif; + + if (hasRCE) { + const choixRCEEl = document.getElementById("choixRCE"); + if (choixRCEEl) { + choixRCEEl.checked = true; + const garantieRCEEl = document.getElementById('garantieRCE'); + if (garantieRCEEl) { + garantieRCEEl.style.display = 'block'; + } + const rce1El = document.getElementById('RCE1'); + if (rce1El) { + rce1El.style.display = ''; + } + const rce2El = document.getElementById('RCE2'); + if (rce2El) { + rce2El.style.display = ''; + } + } + } + }, 100); const garantieRCESelector = document.getElementById('garantieRCE-selector'); - - if (rc.extRCEBraDebra) { garantieRCESelector.querySelector('option[value="branchement-debranchement"]').selected = true; }; - if (rc.extRCEMontageDemontage) { garantieRCESelector.querySelector('option[value="montage-demontage"]').selected = true; }; - - document.getElementById('garantieRCE-selector').dispatchEvent(new Event('change')); + if (garantieRCESelector) { + if (projet && projet.extRCEBraDebra) { + const option = garantieRCESelector.querySelector('option[value="branchement-debranchement"]'); + if (option) option.selected = true; + } + if (projet && projet.extRCEMontageDemontage) { + const option = garantieRCESelector.querySelector('option[value="montage-demontage"]'); + if (option) option.selected = true; + } + garantieRCESelector.dispatchEvent(new Event('change')); + } // Populate temporalité - if (rc.tempo) { document.getElementById(rc.tempo).checked = true }; - if (rc.dateEffet) { document.getElementById("dateEffet").value = rc.dateEffet }; - if (rc.dateEcheance) { document.getElementById("dateEcheance").value = rc.dateEcheance }; + if (projet && projet.tempo) { document.getElementById(projet.tempo).checked = true }; + if (projet && projet.dateEffet) { document.getElementById("dateEffet").value = projet.dateEffet }; + if (projet && projet.dateEcheance) { document.getElementById("dateEcheance").value = projet.dateEcheance }; if (contrat.type == "TEMPORAIRE") { document.getElementById("rowDateFin").style.display = 'block'; } - if (rc.dateFin) { document.getElementById("dateFin").value = rc.dateFin }; + if (projet && projet.dateFin) { document.getElementById("dateFin").value = projet.dateFin }; - if (rc.programmeInternationale) { document.getElementById("programmeInternationale").checked = true; } - if (rc.participationResultat) { document.getElementById("participationResultat").checked = true; } + if (projet && projet.programmeInternationale) { document.getElementById("programmeInternationale").checked = true; } + if (projet && projet.participationResultat) { document.getElementById("participationResultat").checked = true; } - if (rc.pj) { + if (projet && projet.pj) { document.getElementById("switchPJ").checked = true; document.getElementById('PJ1').style.display = ''; document.getElementById('PJ2').style.display = ''; } - // Populate Cotisation - if (rc.typeCot) { document.getElementById(rc.typeCot).checked = true }; + // Populate Cotisation - charger depuis RC principal si existe + const typeCotFromRC = rc?.typeCotisation || projet?.typeCot; + if (typeCotFromRC) { + const radioCot = document.getElementById(typeCotFromRC); + if (radioCot) radioCot.checked = true; + } - if (rc.typeCot == "forfaitaire") { + // Populate CA depuis RC principal + const caFromRC = rc?.chiffreAffaires || projet?.ca; + if (caFromRC) { + document.getElementById("CA").value = caFromRC; + } + + if ((typeCotFromRC || projet?.typeCot) == "forfaitaire") { document.getElementById("checkVehicules").style.display = 'block'; document.getElementById("colTauxAjustement").style.display = 'none'; document.getElementById("colCotMini").style.display = 'none'; @@ -939,60 +2257,71 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio document.getElementById("colTypeCot").style.float = "left"; } - if (rc.ca) { document.getElementById("CA").value = rc.ca }; - if (rc.cotIrreductible) { document.getElementById("cotisationIrreductible").value = rc.cotIrreductible }; - if (rc.tauxRCCHT) { document.getElementById("tauxRCCHT").value = rc.tauxRCCHT }; - if (rc.tauxRCCTTC) { document.getElementById("tauxRCCTTC").value = rc.tauxRCCTTC }; - if (rc.tauxRCEHT) { document.getElementById("tauxRCEHT").value = rc.tauxRCEHT }; - if (rc.tauxRCETTC) { document.getElementById("tauxRCETTC").value = rc.tauxRCETTC }; - if (rc.tauxTotalHT) { document.getElementById("tauxTotalHT").value = rc.tauxTotalHT }; - if (rc.tauxTotalTTC) { document.getElementById("tauxTotalTTC").value = rc.tauxTotalTTC }; - if (rc.cotRCCHT) { document.getElementById("cotRCCHT").value = rc.cotRCCHT }; - if (rc.cotRCCTTC) { document.getElementById("cotRCCTTC").value = rc.cotRCCTTC }; - if (rc.cotRCEHT) { document.getElementById("cotRCEHT").value = rc.cotRCEHT }; - if (rc.cotRCETTC) { document.getElementById("cotRCETTC").value = rc.cotRCETTC }; - if (rc.cotPJHT) { document.getElementById("cotPJHT").value = rc.cotPJHT }; - if (rc.cotPJTTC) { document.getElementById("cotPJTTC").value = rc.cotPJTTC }; - if (rc.cotTotalHT) { document.getElementById("cotTotalHT").value = rc.cotTotalHT }; - if (rc.cotTotalTTC) { document.getElementById("cotTotalTTC").value = rc.cotTotalTTC }; - if (rc.cotFraisHT) { document.getElementById("cotFraisHT").value = rc.cotFraisHT }; - if (rc.cotFraisTTC) { document.getElementById("cotFraisTTC").value = rc.cotFraisTTC }; + if (projet && projet.ca) { document.getElementById("CA").value = projet.ca }; + if (projet && projet.cotIrreductible) { document.getElementById("cotisationIrreductible").value = projet.cotIrreductible }; + if (projet && projet.tauxRCCHT) { document.getElementById("tauxRCCHT").value = projet.tauxRCCHT }; + if (projet && projet.tauxRCCTTC) { document.getElementById("tauxRCCTTC").value = projet.tauxRCCTTC }; + if (projet && projet.tauxRCEHT) { document.getElementById("tauxRCEHT").value = projet.tauxRCEHT }; + if (projet && projet.tauxRCETTC) { document.getElementById("tauxRCETTC").value = projet.tauxRCETTC }; + if (projet && projet.tauxTotalHT) { document.getElementById("tauxTotalHT").value = projet.tauxTotalHT }; + if (projet && projet.tauxTotalTTC) { document.getElementById("tauxTotalTTC").value = projet.tauxTotalTTC }; + if (projet && projet.cotRCCHT) { document.getElementById("cotRCCHT").value = projet.cotRCCHT }; + if (projet && projet.cotRCCTTC) { document.getElementById("cotRCCTTC").value = projet.cotRCCTTC }; + if (projet && projet.cotRCEHT) { document.getElementById("cotRCEHT").value = projet.cotRCEHT }; + if (projet && projet.cotRCETTC) { document.getElementById("cotRCETTC").value = projet.cotRCETTC }; + if (projet && projet.cotPJHT) { document.getElementById("cotPJHT").value = projet.cotPJHT }; + if (projet && projet.cotPJTTC) { document.getElementById("cotPJTTC").value = projet.cotPJTTC }; + if (projet && projet.cotTotalHT) { document.getElementById("cotTotalHT").value = projet.cotTotalHT }; + if (projet && projet.cotTotalTTC) { document.getElementById("cotTotalTTC").value = projet.cotTotalTTC }; + if (projet && projet.cotFraisHT) { document.getElementById("cotFraisHT").value = projet.cotFraisHT }; + if (projet && projet.cotFraisTTC) { document.getElementById("cotFraisTTC").value = projet.cotFraisTTC }; // Populate tableau vehicule - if (!rc || !rc.designationVehicule || Object.keys(rc.designationVehicule).length === 0) { + if (!rc || !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 < rc.designationVehicule.length; i++) { - const row = rc.designationVehicule[i]; + for (let i = 0; i < projet.designationVehicule.length; i++) { + const row = projet.designationVehicule[i]; addRowVehicule(row.marque, row.genre, row.type, row.immat, row.capital); } } // Populate Grille Advalorem - if (rc.actMultimodal) { - if (rc.grilleAerien) { - populateGrAdvalo(rc.grilleAerien, "tabAdvaloAerien"); + hasSavedGrilleData = Boolean( + (projet?.grilleMultimodal && (Array.isArray(projet.grilleMultimodal) ? projet.grilleMultimodal.length : true)) || + (projet?.grilleTerrestre && (Array.isArray(projet.grilleTerrestre) ? projet.grilleTerrestre.length : true)) || + (projet?.grilleAerien && (Array.isArray(projet.grilleAerien) ? projet.grilleAerien.length : true)) + ); + + const isMultimodal = Boolean(projet?.actMultimodal || rc?.actMultimodal); + if (isMultimodal) { + if (projet?.grilleAerien) { + const grilleAerien = Array.isArray(projet.grilleAerien) ? projet.grilleAerien : (typeof projet.grilleAerien === 'string' ? JSON.parse(projet.grilleAerien) : []); + populateGrAdvalo(grilleAerien, "tabAdvaloAerien"); document.getElementById('divAdvaloAerien').style.display = "block"; document.getElementById('divAdvaloTerrestre').style.display = "none"; document.getElementById('divAdvaloMultimodal').style.display = "none"; }; - if (rc.grilleTerrestre) { - populateGrAdvalo(rc.grilleTerrestre, "tabAdvaloTerrestre"); + if (projet?.grilleTerrestre) { + const grilleTerrestre = Array.isArray(projet.grilleTerrestre) ? projet.grilleTerrestre : (typeof projet.grilleTerrestre === 'string' ? JSON.parse(projet.grilleTerrestre) : []); + populateGrAdvalo(grilleTerrestre, "tabAdvaloTerrestre"); document.getElementById('divAdvaloTerrestre').style.display = "block"; document.getElementById('divAdvaloAerien').style.display = "none"; document.getElementById('divAdvaloMultimodal').style.display = "none"; }; - if (rc.grilleMultimodal) { - populateGrAdvalo(rc.grilleMultimodal, "tabAdvaloMultimodal"); + if (projet?.grilleMultimodal) { + const grilleMultimodal = Array.isArray(projet.grilleMultimodal) ? projet.grilleMultimodal : (typeof projet.grilleMultimodal === 'string' ? JSON.parse(projet.grilleMultimodal) : []); + populateGrAdvalo(grilleMultimodal, "tabAdvaloMultimodal"); document.getElementById('divAdvaloMultimodal').style.display = "block"; document.getElementById('divAdvaloAerien').style.display = "none"; document.getElementById('divAdvaloTerrestre').style.display = "none"; }; } else { - if (rc.grilleTerrestre) { - populateGrAdvalo(rc.grilleTerrestre, "tabAdvaloTerrestre"); + if (projet?.grilleTerrestre) { + const grilleTerrestre = Array.isArray(projet.grilleTerrestre) ? projet.grilleTerrestre : (typeof projet.grilleTerrestre === 'string' ? JSON.parse(projet.grilleTerrestre) : []); + populateGrAdvalo(grilleTerrestre, "tabAdvaloTerrestre"); document.getElementById('divAdvaloTerrestre').style.display = "block"; document.getElementById('divAdvaloAerien').style.display = "none"; document.getElementById('divAdvaloMultimodal').style.display = "none"; @@ -1002,20 +2331,35 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio function populateGrAdvalo(jsonData, tableID) { var table = document.getElementById(tableID); + if (!table) { + console.warn('Table non trouvée:', tableID); + return; + } + + if (!jsonData || !Array.isArray(jsonData) || jsonData.length === 0) { + console.warn('Données grille vides ou invalides pour', tableID, ':', jsonData); + return; + } + + console.log('Remplissage de la grille', tableID, 'avec', jsonData.length, 'catégories'); for (var i = 0; i < jsonData.length; i++) { var category = jsonData[i].name; + if (!category) continue; for (var j = 1; j < table.rows.length; j++) { - var categoryName = table.rows[j].cells[0].innerText.trim(); + var categoryName = table.rows[j].cells[0] ? table.rows[j].cells[0].innerText.trim() : ''; if (categoryName === category) { var categoryRow = table.rows[j]; for (var k = 1; k <= 6; k++) { var zoneKey = "zone" + k; - var zoneInput = categoryRow.cells[k].querySelector("input[type='text']"); - zoneInput.value = jsonData[i][zoneKey]; + var zoneInput = categoryRow.cells[k] ? categoryRow.cells[k].querySelector("input[type='text']") : null; + if (zoneInput && jsonData[i][zoneKey]) { + zoneInput.value = jsonData[i][zoneKey]; + console.log('Rempli:', category, zoneKey, '=', jsonData[i][zoneKey]); + } } break; @@ -1078,10 +2422,10 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio for (let k = 1; k <= 8; k++) { const element = document.getElementById(`${mode}Cat${k}Zone${zone}`); const marPerissable = document.getElementById("perissable-temperature-dirigee-chip") || null; - const marEngins = document.getElementById("engins-chantier-agricole-chip" || null); - const marMobilier = document.getElementById("mobilier-usages-chip" || null); - const marRoulantDem = document.getElementById("roulant-demenagement-chip" || null); - const marRoulant = document.getElementById("roulant-chip" || null); + const marEngins = document.getElementById("engins-chantier-agricole-chip") || null; + const marMobilier = document.getElementById("mobilier-usages-chip") || null; + const marRoulantDem = document.getElementById("roulant-demenagement-chip") || null; + const marRoulant = document.getElementById("roulant-chip") || null; let value = "Nous consulter"; // Par défaut @@ -1108,6 +2452,10 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio value = categories[mode][`Cat${k}`][zone - 1]; } } + // Si une grille enregistrée existe déjà, ne pas écraser les valeurs pré-remplies + if (hasSavedGrilleData && element && element.value && element.value.trim() !== '') { + continue; + } element.value = value; } } @@ -1154,21 +2502,32 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio // Iterate over each selected option Array.from(select.options).forEach(option => { - if (option.selected && option.value && !document.getElementById(option.value + "-chip")) { - const activityName = option.textContent; - const activityDiv = document.createElement('div'); - activityDiv.classList.add('activity-input', 'row'); - activityDiv.style.marginBottom = '10px'; - activityDiv.innerHTML = ` -
- - -
-
- -
- `; - activityFormsContainer.appendChild(activityDiv); + if (option.selected && option.value) { + const existingChip = document.getElementById(option.value + "-chip"); + if (!existingChip) { + const activityName = option.textContent; + const activityDiv = document.createElement('div'); + activityDiv.classList.add('activity-input', 'row'); + activityDiv.style.marginBottom = '10px'; + activityDiv.innerHTML = ` +
+ + +
+
+ +
+ `; + activityFormsContainer.appendChild(activityDiv); + } + } else { + const existingChip = document.getElementById(option.value + "-chip"); + if (existingChip) { + const activityDiv = existingChip.closest('.activity-input'); + if (activityDiv) { + activityDiv.remove(); + } + } } }); } @@ -1229,22 +2588,33 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio const marchandiseFormsContainer = document.getElementById('selected-marchandises'); // Clear previous entries - marchandiseFormsContainer.innerHTML = ''; // Clear any existing entries + marchandiseFormsContainer.innerHTML = ''; - // Iterate over each selected option + // Iterate over each option Array.from(select.options).forEach(option => { if (option.selected && option.value) { - const marchandiseName = option.textContent; - const marchandiseDiv = document.createElement('div'); - marchandiseDiv.classList.add('marchandise-input', 'row'); - marchandiseDiv.style.display = 'flex'; - marchandiseDiv.style.alignItems = 'center'; - marchandiseDiv.style.justifyContent = 'start'; - marchandiseDiv.style.marginBottom = '10px'; - marchandiseDiv.innerHTML = ` - ${marchandiseName} - `; - marchandiseFormsContainer.appendChild(marchandiseDiv); + const existingChip = document.getElementById(`${option.value}-chip`); + if (!existingChip) { + const marchandiseName = option.textContent; + const marchandiseDiv = document.createElement('div'); + marchandiseDiv.classList.add('marchandise-input', 'row'); + marchandiseDiv.style.display = 'flex'; + marchandiseDiv.style.alignItems = 'center'; + marchandiseDiv.style.justifyContent = 'start'; + marchandiseDiv.style.marginBottom = '10px'; + marchandiseDiv.innerHTML = ` + ${marchandiseName} + `; + marchandiseFormsContainer.appendChild(marchandiseDiv); + } + } else { + const existingChip = document.getElementById(`${option.value}-chip`); + if (existingChip) { + const chipContainer = existingChip.closest('.marchandise-input'); + if (chipContainer) { + chipContainer.remove(); + } + } } }); } @@ -1382,19 +2752,81 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio function extractGrilleAdvalo(tableID) { var jsonData = []; var table = document.getElementById(tableID); - var zonesCount = table.rows[0].cells.length - 1; - - for (var i = 1; i < table.rows.length; i++) { - var category = table.rows[i].cells[0].innerText.trim(); - var categoryData = { "name": category }; - - for (var j = 1; j <= zonesCount; j++) { - var zoneKey = "zone" + j; - var zoneValue = table.rows[i].cells[j].querySelector("input[type='text']").value || "Nous consulter"; - categoryData[zoneKey] = zoneValue; + if (!table) { + return jsonData; + } + + var parentDiv = table.closest('div'); + var wasHidden = false; + var originalDisplay = ''; + var originalVisibility = ''; + var originalPosition = ''; + var originalLeft = ''; + + if (parentDiv) { + originalDisplay = parentDiv.style.display || ''; + originalVisibility = parentDiv.style.visibility || ''; + originalPosition = parentDiv.style.position || ''; + originalLeft = parentDiv.style.left || ''; + + if (parentDiv.style.display === 'none' || window.getComputedStyle(parentDiv).display === 'none') { + wasHidden = true; + parentDiv.style.display = 'block'; + parentDiv.style.visibility = 'hidden'; + parentDiv.style.position = 'absolute'; + parentDiv.style.left = '-9999px'; + } + } + + try { + if (!table.rows || table.rows.length < 2) { + return jsonData; + } + + var zonesCount = table.rows[0] ? table.rows[0].cells.length - 1 : 0; + if (zonesCount === 0) { + return jsonData; } - jsonData.push(categoryData); + for (var i = 1; i < table.rows.length; i++) { + var row = table.rows[i]; + if (!row || !row.cells || row.cells.length === 0) continue; + + var category = row.cells[0] ? (row.cells[0].innerText || row.cells[0].textContent || '').trim() : ''; + if (!category) continue; + + var categoryData = { "name": category }; + + for (var j = 1; j <= zonesCount && j < row.cells.length; j++) { + var zoneKey = "zone" + j; + var cell = row.cells[j]; + if (!cell) { + categoryData[zoneKey] = "Nous consulter"; + continue; + } + + var input = cell.querySelector("input[type='text']"); + if (input) { + var zoneValue = (input.value || '').trim(); + categoryData[zoneKey] = zoneValue || "Nous consulter"; + } else { + categoryData[zoneKey] = "Nous consulter"; + } + } + + if (Object.keys(categoryData).length > 1) { + jsonData.push(categoryData); + } + } + } catch (error) { + console.error('Erreur lors de l\'extraction de la grille Ad Valorem:', error); + } finally { + if (wasHidden && parentDiv) { + parentDiv.style.display = originalDisplay; + parentDiv.style.visibility = originalVisibility; + parentDiv.style.position = originalPosition; + parentDiv.style.left = originalLeft; + } } return jsonData; @@ -1482,46 +2914,48 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio async function handleSubmitForm(event) { event.preventDefault(); - // Création d'une nouvelle saisie dans la collection RC - const responseRC = await fetch(`/rc/create`, { - method: 'POST', - body: JSON.stringify({ + // Étape 1: Créer d'abord un enregistrement dans projetRC + const grilleMultimodal = extractGrilleAdvalo('tabAdvaloMultimodal'); + const grilleTerrestre = extractGrilleAdvalo('tabAdvaloTerrestre'); + const grilleAerien = extractGrilleAdvalo('tabAdvaloAerien'); + + const projetRCData = { // Tableaux "assureAdditionnel": extractAssureAdditionnel('empTableAdditionnel'), "designationVehicule": extractDesignationVehicule('empTableVehicules'), - "grilleMultimodal": extractGrilleAdvalo('tabAdvaloMultimodal'), - "grilleTerrestre": extractGrilleAdvalo('tabAdvaloTerrestre'), - "grilleAerien": extractGrilleAdvalo('tabAdvaloAerien'), + "grilleMultimodal": grilleMultimodal, + "grilleTerrestre": grilleTerrestre, + "grilleAerien": grilleAerien, - // Activitées + // Activitées - avec gestion "Nous consulter" "actVoiturier": document.getElementById("voiturier-chip") ? true : false, - "valueActVoiturier": document.getElementById("voiturier-chip") ? document.getElementById("voiturier").value : false, + "valueActVoiturier": document.getElementById("voiturier-chip") ? getValueOrConsulter("voiturier") : false, "actLoueur": document.getElementById("loueur-chip") ? true : false, - "valueActLoueur": document.getElementById("loueur-chip") ? document.getElementById("loueur").value : false, + "valueActLoueur": document.getElementById("loueur-chip") ? getValueOrConsulter("loueur") : false, "actMultimodal": document.getElementById("commissionnaire-multimodal-chip") ? true : false, - "valueActMultimodal": document.getElementById("commissionnaire-multimodal-chip") ? document.getElementById("commissionnaire-multimodal").value : false, + "valueActMultimodal": document.getElementById("commissionnaire-multimodal-chip") ? getValueOrConsulter("commissionnaire-multimodal") : false, "actDouane": document.getElementById("représentant-douane-chip") ? true : false, - "valueActDouane": document.getElementById("représentant-douane-chip") ? document.getElementById("représentant-douane").value : false, + "valueActDouane": document.getElementById("représentant-douane-chip") ? getValueOrConsulter("représentant-douane") : false, "actDemPar": document.getElementById("demenageur-particulier-chip") ? true : false, - "valueActDemPar": document.getElementById("demenageur-particulier-chip") ? document.getElementById("demenageur-particulier").value : false, + "valueActDemPar": document.getElementById("demenageur-particulier-chip") ? getValueOrConsulter("demenageur-particulier") : false, "actDemParDom": document.getElementById("demenageur-particulier-dommage-chip") ? true : false, - "valueActDemParDom": document.getElementById("demenageur-particulier-dommage-chip") ? document.getElementById("demenageur-particulier-dommage").value : false, + "valueActDemParDom": document.getElementById("demenageur-particulier-dommage-chip") ? getValueOrConsulter("demenageur-particulier-dommage") : false, "actDemParAdv": document.getElementById("demenageur-particulier-advalorem-chip") ? true : false, - "valueActDemParAdv": document.getElementById("demenageur-particulier-advalorem-chip") ? document.getElementById("demenageur-particulier-advalorem").value : false, + "valueActDemParAdv": document.getElementById("demenageur-particulier-advalorem-chip") ? getValueOrConsulter("demenageur-particulier-advalorem") : false, "actDemEntr": document.getElementById("demenageur-entreprise-chip") ? true : false, - "valueActDemEntr": document.getElementById("demenageur-entreprise-chip") ? document.getElementById("demenageur-entreprise").value : false, + "valueActDemEntr": document.getElementById("demenageur-entreprise-chip") ? getValueOrConsulter("demenageur-entreprise") : false, "actDemInterne": document.getElementById("demenageur-interne-chip") ? true : false, - "valueActDemInterne": document.getElementById("demenageur-interne-chip") ? document.getElementById("demenageur-interne").value : false, + "valueActDemInterne": document.getElementById("demenageur-interne-chip") ? getValueOrConsulter("demenageur-interne") : false, "actGardeMeuble": document.getElementById("garde-meubles-chip") ? true : false, - "valueActGardeMeuble": document.getElementById("garde-meubles-chip") ? document.getElementById("garde-meubles").value : false, + "valueActGardeMeuble": document.getElementById("garde-meubles-chip") ? getValueOrConsulter("garde-meubles") : false, "actEntDep": document.getElementById("entrepositaire-depositaire-chip") ? true : false, - "valueActEntDep": document.getElementById("entrepositaire-depositaire-chip") ? document.getElementById("entrepositaire-depositaire").value : false, + "valueActEntDep": document.getElementById("entrepositaire-depositaire-chip") ? getValueOrConsulter("entrepositaire-depositaire") : false, "actPrestaLog": document.getElementById("prestataire-logistique-chip") ? true : false, - "valueActPrestaLog": document.getElementById("prestataire-logistique-chip") ? document.getElementById("prestataire-logistique").value : false, + "valueActPrestaLog": document.getElementById("prestataire-logistique-chip") ? getValueOrConsulter("prestataire-logistique") : false, "actLevageur": document.getElementById("manutentionnaire-levageur-chip") ? true : false, - "valueActLevageur": document.getElementById("manutentionnaire-levageur-chip") ? document.getElementById("manutentionnaire-levageur").value : false, + "valueActLevageur": document.getElementById("manutentionnaire-levageur-chip") ? getValueOrConsulter("manutentionnaire-levageur") : false, "actTransitaire": document.getElementById("transitaire-chip") ? true : false, - "valueActTransitaire": document.getElementById("transitaire-chip") ? document.getElementById("transitaire").value : false, + "valueActTransitaire": document.getElementById("transitaire-chip") ? getValueOrConsulter("transitaire") : false, //Marchandises "marOrdinaire": document.getElementById("ordinaire-chip") ? true : false, @@ -1536,13 +2970,13 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio "marExceptionnels": document.getElementById("exceptionnels-chip") ? true : false, "marVrac": document.getElementById("vrac-chip") ? true : false, - // Territorialités - "zone1": document.getElementById("zone1").checked ? true : false, - "zone2": document.getElementById("zone2").checked ? true : false, - "zone3": document.getElementById("zone3").checked ? true : false, - "zone4": document.getElementById("zone4").checked ? true : false, - "zone5": document.getElementById("zone5").checked ? true : false, - "zone6": document.getElementById("zone6").checked ? true : false, + // Territorialités - vérifier checked même si disabled + "zone1": document.getElementById("zone1") && (document.getElementById("zone1").checked || document.getElementById("zone1").disabled) ? true : false, + "zone2": document.getElementById("zone2") && (document.getElementById("zone2").checked || document.getElementById("zone2").disabled) ? true : false, + "zone3": document.getElementById("zone3") && document.getElementById("zone3").checked ? true : false, + "zone4": document.getElementById("zone4") && document.getElementById("zone4").checked ? true : false, + "zone5": document.getElementById("zone5") && document.getElementById("zone5").checked ? true : false, + "zone6": document.getElementById("zone6") && document.getElementById("zone6").checked ? true : false, // Extensions de garantie RCC "extRCCModifCalArrim": document.getElementById("modif-calage-arrimage-chip") ? true : false, @@ -1559,6 +2993,12 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio "extRCEBraDebra": document.getElementById("branchement-debranchement-chip") ? true : false, "extRCEMontageDemontage": document.getElementById("montage-demontage-chip") ? true : false, + // Activités complémentaires + "activitesVoiturier": JSON.stringify(getActivitesComplFromForm('actComplVoiturier/Loueur')), + "activitesCommissionnaire": JSON.stringify(getActivitesComplFromForm('actComplCommissionnaire de Transport')), + "activitesDemenageur": JSON.stringify(getActivitesComplFromForm('actComplDéménageur')), + "activitesLogistique": JSON.stringify(getActivitesComplFromForm('actComplLogistique')), + // Temporalités "tempo": extractTempo(), "dateEffet": document.getElementById("dateEffet").value, @@ -1568,39 +3008,108 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio "programmeInternationale": document.getElementById("programmeInternationale").checked ? true : false, "participationResultat": document.getElementById("participationResultat").checked ? true : false, - // Cotisations + // Cotisations - avec gestion "Nous consulter" "typeCot": extractTypeCot(), - "ca": document.getElementById("CA").value, - "cotIrreductible": document.getElementById("cotisationIrreductible").value, - "tauxRCCHT": document.getElementById("tauxRCCHT").value, - "tauxRCCTTC": document.getElementById("tauxRCCTTC").value, - "tauxRCEHT": document.getElementById("tauxRCEHT").value, - "tauxRCETTC": document.getElementById("tauxRCETTC").value, - "tauxTotalHT": document.getElementById("tauxTotalHT").value, - "tauxTotalTTC": document.getElementById("tauxTotalTTC").value, - "cotRCCHT": document.getElementById("cotRCCHT").value, - "cotRCCTTC": document.getElementById("cotRCCTTC").value, - "cotRCEHT": document.getElementById("cotRCEHT").value, - "cotRCETTC": document.getElementById("cotRCETTC").value, - "cotPJHT": document.getElementById("cotPJHT").value, - "cotPJTTC": document.getElementById("cotPJTTC").value, - "cotTotalHT": document.getElementById("cotTotalHT").value, - "cotTotalTTC": document.getElementById("cotTotalTTC").value, - "cotFraisHT": document.getElementById("cotFraisHT").value, - "cotFraisTTC": document.getElementById("cotFraisTTC").value + "ca": getValueOrConsulter("CA"), + "cotIrreductible": getValueOrConsulter("cotisationIrreductible"), + "tauxRCCHT": getValueOrConsulter("tauxRCCHT"), + "tauxRCCTTC": getValueOrConsulter("tauxRCCTTC"), + "tauxRCEHT": getValueOrConsulter("tauxRCEHT"), + "tauxRCETTC": getValueOrConsulter("tauxRCETTC"), + "tauxTotalHT": getValueOrConsulter("tauxTotalHT"), + "tauxTotalTTC": getValueOrConsulter("tauxTotalTTC"), + "cotRCCHT": getValueOrConsulter("cotRCCHT"), + "cotRCCTTC": getValueOrConsulter("cotRCCTTC"), + "cotRCEHT": getValueOrConsulter("cotRCEHT"), + "cotRCETTC": getValueOrConsulter("cotRCETTC"), + "cotPJHT": getValueOrConsulter("cotPJHT"), + "cotPJTTC": getValueOrConsulter("cotPJTTC"), + "cotTotalHT": getValueOrConsulter("cotTotalHT"), + "cotTotalTTC": getValueOrConsulter("cotTotalTTC"), + "cotFraisHT": getValueOrConsulter("cotFraisHT"), + "cotFraisTTC": getValueOrConsulter("cotFraisTTC") + }; - // Vous pouvez ajouter d'autres données pour la saisie dans la collection RC ici + // Créer ou mettre à jour l'enregistrement projetRC + let idProjetRC; + if (projet && projet.id) { + // Mettre à jour l'enregistrement projetRC existant + const responseProjetRC = await fetch(`/rc/projet/update/${projet.id}`, { + method: 'POST', + body: JSON.stringify(projetRCData), + headers: { + 'Content-Type': 'application/json', + }, + }); + const dataProjetRC = await responseProjetRC.json(); + if (dataProjetRC.valid) { + idProjetRC = dataProjetRC.projetRc.id; + } else { + console.log('Échec lors de la mise à jour de l\'enregistrement ProjetRC :', dataProjetRC.message); + return; + } + } else { + // Créer un nouvel enregistrement projetRC + const responseProjetRC = await fetch(`/rc/projet/create`, { + method: 'POST', + body: JSON.stringify(projetRCData), + headers: { + 'Content-Type': 'application/json', + }, + }); + const dataProjetRC = await responseProjetRC.json(); + if (dataProjetRC.valid) { + idProjetRC = dataProjetRC.projetRc.id; + } else { + console.log('Échec lors de la création de l\'enregistrement ProjetRC :', dataProjetRC.message); + return; + } + } + + if (idProjetRC) { + + // Étape 2: Créer ou mettre à jour l'enregistrement RC principal + let idRC; + if (rc && rc.id) { + // Mettre à jour l'enregistrement RC existant avec la nouvelle référence projetRC + const responseRC = await fetch(`/rc/update/${rc.id}`, { + method: 'POST', + body: JSON.stringify({ + projetRC: idProjetRC }), headers: { 'Content-Type': 'application/json', }, }); const dataRC = await responseRC.json(); - if (dataRC.valid) { - const idRC = dataRC.rc.id; + idRC = dataRC.rc.id; + } else { + console.log('Échec lors de la mise à jour de l\'enregistrement RC :', dataRC.message); + return; + } + } else { + // Créer un nouvel enregistrement RC + const responseRC = await fetch(`/rc/create`, { + method: 'POST', + body: JSON.stringify({ + projetRC: idProjetRC, + typeCotisation: extractTypeCot() + }), + headers: { + 'Content-Type': 'application/json', + }, + }); + const dataRC = await responseRC.json(); + if (dataRC.valid) { + idRC = dataRC.rc.id; + } else { + console.log('Échec lors de la création de l\'enregistrement RC :', dataRC.message); + return; + } + } - // Mettre à jour le champ "enCours" dans le contrat avec l'ID de la nouvelle saisie RC + // Étape 3: Mettre à jour le champ "rc" dans le contrat avec l'ID de la saisie RC const responseContratEnCours = await fetch(`/contrat/update/${contrat.produit}/${contrat.id}/${idRC}`, { method: 'POST', headers: { @@ -1666,47 +3175,264 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio 'Content-Type': 'application/json', }, }) - .then(response => { - if (!response.ok) { - throw new Error('Erreur réseau ou serveur'); - } + .then(response => { + if (!response.ok) { + throw new Error('Erreur réseau ou serveur'); + } - const disposition = response.headers.get('content-disposition'); - filename = disposition.split(';')[1].trim().split('=')[1]; + const disposition = response.headers.get('content-disposition'); + filename = disposition.split(';')[1].trim().split('=')[1]; - return response.blob(); // On attend une réponse sous forme de blob pour un fichier - }) - .then(blob => { - // Crée un URL pour le blob - const url = window.URL.createObjectURL(blob); - // Crée un élément a temporaire pour simuler un clic pour téléchargement - const a = document.createElement('a'); - a.href = url; - a.download = filename; // Nomme le fichier téléchargé - document.body.appendChild(a); // Ajoute l'élément au document - a.click(); // Simule un clic sur l'élément pour déclencher le téléchargement - window.URL.revokeObjectURL(url); // Nettoie l'URL objet - a.remove(); // Supprime l'élément a du document + return response.blob(); // On attend une réponse sous forme de blob pour un fichier + }) + .then(blob => { + // Crée un URL pour le blob + const url = window.URL.createObjectURL(blob); + // Crée un élément a temporaire pour simuler un clic pour téléchargement + const a = document.createElement('a'); + a.href = url; + a.download = filename; // Nomme le fichier téléchargé + document.body.appendChild(a); // Ajoute l'élément au document + a.click(); // Simule un clic sur l'élément pour déclencher le téléchargement + window.URL.revokeObjectURL(url); // Nettoie l'URL objet + a.remove(); // Supprime l'élément a du document - window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=projet`; - }) - .catch(error => console.error('Erreur lors de la génération du projet:', error)); + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=projet`; + }) + .catch(error => console.error('Erreur lors de la génération du projet 111:', error)); /// TODO FIN Génération fichier à l'enregistrement A RETIRER QUAND MODE CONTRAT /////////////////////////////////////////////////////////////////////////////////////////////////////// // TODO NE PAS OUBLIER LE HREF QUI EST DANS LE GEN ACTUELLEMENT // window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=projet`; } else { - console.log('Echec lors de la mise à jour de l\'historique du contrat :', dataHistoriqueUpdate.message); + console.log('Échec lors de la mise à jour de l\'historique du contrat :', dataHistoriqueUpdate.message); } } else { - console.log('Echec lors de la mise à jour du champ "enCours" dans le contrat :', dataContratEnCours.message); + console.log('Échec lors de la mise à jour du champ "rc" dans le contrat :', dataContratEnCours.message); } } else { - console.log('Echec lors de la création de la saisie dans la collection RC :', dataRC.message); + console.log('Échec lors de la création de l\'enregistrement ProjetRC :', dataProjetRC.message); } } - // Exposer init globalement pour y accéder depuis l'extérieur + // Fonction helper pour récupérer valeur ou "Nous consulter" + function getValueOrConsulter(id) { + const element = document.getElementById(id); + if (!element) return 'Nous consulter'; + const value = element.value?.trim(); + return value || 'Nous consulter'; + } + + // Fonction exposée pour sauvegarder le projet sans générer le document + async function saveProjetRC() { + try { + // Étape 1: Créer d'abord un enregistrement dans projetRC + const grilleMultimodal = extractGrilleAdvalo('tabAdvaloMultimodal'); + const grilleTerrestre = extractGrilleAdvalo('tabAdvaloTerrestre'); + const grilleAerien = extractGrilleAdvalo('tabAdvaloAerien'); + + const projetRCData = { + // Tableaux + "assureAdditionnel": extractAssureAdditionnel('empTableAdditionnel'), + "designationVehicule": extractDesignationVehicule('empTableVehicules'), + "grilleMultimodal": grilleMultimodal, + "grilleTerrestre": grilleTerrestre, + "grilleAerien": grilleAerien, + + // Activitées + "actVoiturier": document.getElementById("voiturier-chip") ? true : false, + "valueActVoiturier": document.getElementById("voiturier-chip") ? getValueOrConsulter("voiturier") : false, + "actLoueur": document.getElementById("loueur-chip") ? true : false, + "valueActLoueur": document.getElementById("loueur-chip") ? document.getElementById("loueur").value : false, + "actMultimodal": document.getElementById("commissionnaire-multimodal-chip") ? true : false, + "valueActMultimodal": document.getElementById("commissionnaire-multimodal-chip") ? document.getElementById("commissionnaire-multimodal").value : false, + "actDouane": document.getElementById("représentant-douane-chip") ? true : false, + "valueActDouane": document.getElementById("représentant-douane-chip") ? document.getElementById("représentant-douane").value : false, + "actDemPar": document.getElementById("demenageur-particulier-chip") ? true : false, + "valueActDemPar": document.getElementById("demenageur-particulier-chip") ? document.getElementById("demenageur-particulier").value : false, + "actDemParDom": document.getElementById("demenageur-particulier-dommage-chip") ? true : false, + "valueActDemParDom": document.getElementById("demenageur-particulier-dommage-chip") ? document.getElementById("demenageur-particulier-dommage").value : false, + "actDemParAdv": document.getElementById("demenageur-particulier-advalorem-chip") ? true : false, + "valueActDemParAdv": document.getElementById("demenageur-particulier-advalorem-chip") ? document.getElementById("demenageur-particulier-advalorem").value : false, + "actDemEntr": document.getElementById("demenageur-entreprise-chip") ? true : false, + "valueActDemEntr": document.getElementById("demenageur-entreprise-chip") ? document.getElementById("demenageur-entreprise").value : false, + "actDemInterne": document.getElementById("demenageur-interne-chip") ? true : false, + "valueActDemInterne": document.getElementById("demenageur-interne-chip") ? document.getElementById("demenageur-interne").value : false, + "actGardeMeuble": document.getElementById("garde-meubles-chip") ? true : false, + "valueActGardeMeuble": document.getElementById("garde-meubles-chip") ? document.getElementById("garde-meubles").value : false, + "actEntDep": document.getElementById("entrepositaire-depositaire-chip") ? true : false, + "valueActEntDep": document.getElementById("entrepositaire-depositaire-chip") ? document.getElementById("entrepositaire-depositaire").value : false, + "actPrestaLog": document.getElementById("prestataire-logistique-chip") ? true : false, + "valueActPrestaLog": document.getElementById("prestataire-logistique-chip") ? document.getElementById("prestataire-logistique").value : false, + "actLevageur": document.getElementById("manutentionnaire-levageur-chip") ? true : false, + "valueActLevageur": document.getElementById("manutentionnaire-levageur-chip") ? document.getElementById("manutentionnaire-levageur").value : false, + "actTransitaire": document.getElementById("transitaire-chip") ? true : false, + "valueActTransitaire": document.getElementById("transitaire-chip") ? document.getElementById("transitaire").value : false, + + //Marchandises + "marOrdinaire": document.getElementById("ordinaire-chip") ? true : false, + "marRoulant": document.getElementById("roulant-chip") ? true : false, + "marEngins": document.getElementById("engins-chantier-agricole-chip") ? true : false, + "marRoulantDem": document.getElementById("roulant-demenagement-chip") ? true : false, + "marMobilerUsag": document.getElementById("mobilier-usages-chip") ? true : false, + "marPerissable": document.getElementById("perissable-temperature-dirigee-chip") ? true : false, + "marAnimaux": document.getElementById("animaux-vivant-chip") ? true : false, + "marCiterne": document.getElementById("citerne-chip") ? true : false, + "marBeton": document.getElementById("beton-chip") ? true : false, + "marExceptionnels": document.getElementById("exceptionnels-chip") ? true : false, + "marVrac": document.getElementById("vrac-chip") ? true : false, + + // Territorialités - vérifier checked même si disabled + "zone1": document.getElementById("zone1") && (document.getElementById("zone1").checked || document.getElementById("zone1").disabled) ? true : false, + "zone2": document.getElementById("zone2") && (document.getElementById("zone2").checked || document.getElementById("zone2").disabled) ? true : false, + "zone3": document.getElementById("zone3") && document.getElementById("zone3").checked ? true : false, + "zone4": document.getElementById("zone4") && document.getElementById("zone4").checked ? true : false, + "zone5": document.getElementById("zone5") && document.getElementById("zone5").checked ? true : false, + "zone6": document.getElementById("zone6") && document.getElementById("zone6").checked ? true : false, + + // Extensions de garantie RCC + "extRCCModifCalArrim": document.getElementById("modif-calage-arrimage-chip") ? true : false, + "extRCCFerroutage": document.getElementById("ferroutage-chip") ? true : false, + "extRCCFraisRecons": document.getElementById("frais-reconstitution-chip") ? true : false, + "extRCCConfie": document.getElementById("contenant-confie-chip") ? true : false, + "typeExtConfies": document.getElementById("contenant-confie-chip") ? (document.getElementById('ValeurDeclaree').checked ? "VALEUR DECLAREE" : "ADVALOREM") : "", + "extRCCTPPC": document.getElementById("tppc-chip") ? true : false, + "extRCCRegie": document.getElementById("regie-chip") ? true : false, + "extRCCSansMontageDemontage": document.getElementById("sans-montage-demontage-chip") ? true : false, + + // Extensions de garantie RCE + "autresRC": document.getElementById("choixRCE").checked ? true : false, + "extRCEBraDebra": document.getElementById("branchement-debranchement-chip") ? true : false, + "extRCEMontageDemontage": document.getElementById("montage-demontage-chip") ? true : false, + + // Activités complémentaires + "activitesVoiturier": JSON.stringify(getActivitesComplFromForm('actComplVoiturier/Loueur')), + "activitesCommissionnaire": JSON.stringify(getActivitesComplFromForm('actComplCommissionnaire de Transport')), + "activitesDemenageur": JSON.stringify(getActivitesComplFromForm('actComplDéménageur')), + "activitesLogistique": JSON.stringify(getActivitesComplFromForm('actComplLogistique')), + + // Temporalités + "tempo": extractTempo(), + "dateEffet": document.getElementById("dateEffet").value, + "dateEcheance": document.getElementById("dateEcheance").value, + "dateFin": document.getElementById("dateFin").value, + "pj": document.getElementById("switchPJ").checked ? true : false, + "programmeInternationale": document.getElementById("programmeInternationale").checked ? true : false, + "participationResultat": document.getElementById("participationResultat").checked ? true : false, + + // Cotisations - avec gestion "Nous consulter" + "typeCot": extractTypeCot(), + "ca": getValueOrConsulter("CA"), + "cotIrreductible": getValueOrConsulter("cotisationIrreductible"), + "tauxRCCHT": getValueOrConsulter("tauxRCCHT"), + "tauxRCCTTC": getValueOrConsulter("tauxRCCTTC"), + "tauxRCEHT": getValueOrConsulter("tauxRCEHT"), + "tauxRCETTC": getValueOrConsulter("tauxRCETTC"), + "tauxTotalHT": getValueOrConsulter("tauxTotalHT"), + "tauxTotalTTC": getValueOrConsulter("tauxTotalTTC"), + "cotRCCHT": getValueOrConsulter("cotRCCHT"), + "cotRCCTTC": getValueOrConsulter("cotRCCTTC"), + "cotRCEHT": getValueOrConsulter("cotRCEHT"), + "cotRCETTC": getValueOrConsulter("cotRCETTC"), + "cotPJHT": getValueOrConsulter("cotPJHT"), + "cotPJTTC": getValueOrConsulter("cotPJTTC"), + "cotTotalHT": getValueOrConsulter("cotTotalHT"), + "cotTotalTTC": getValueOrConsulter("cotTotalTTC"), + "cotFraisHT": getValueOrConsulter("cotFraisHT"), + "cotFraisTTC": getValueOrConsulter("cotFraisTTC") + }; + + // Créer ou mettre à jour l'enregistrement projetRC + let idProjetRC; + if (projet && projet.id) { + // Mettre à jour l'enregistrement projetRC existant + const responseProjetRC = await fetch(`/rc/projet/update/${projet.id}`, { + method: 'POST', + body: JSON.stringify(projetRCData), + headers: { + 'Content-Type': 'application/json', + }, + }); + const dataProjetRC = await responseProjetRC.json(); + if (dataProjetRC.valid) { + idProjetRC = dataProjetRC.projetRc.id; + } else { + console.log('Échec lors de la mise à jour de l\'enregistrement ProjetRC :', dataProjetRC.message); + return { valid: false, message: 'Échec mise à jour ProjetRC' }; + } + } else { + // Créer un nouvel enregistrement projetRC + const responseProjetRC = await fetch(`/rc/projet/create`, { + method: 'POST', + body: JSON.stringify(projetRCData), + headers: { + 'Content-Type': 'application/json', + }, + }); + const dataProjetRC = await responseProjetRC.json(); + if (dataProjetRC.valid) { + idProjetRC = dataProjetRC.projetRc.id; + } else { + console.log('Échec lors de la création de l\'enregistrement ProjetRC :', dataProjetRC.message); + return { valid: false, message: 'Échec création ProjetRC' }; + } + } + + if (idProjetRC) { + + // Étape 2: Créer ou mettre à jour l'enregistrement RC principal + let idRC; + + if (rc && rc.id) { + // Mettre à jour l'enregistrement RC existant + const responseRC = await fetch(`/rc/update/${rc.id}`, { + method: 'POST', + body: JSON.stringify({ projetRC: idProjetRC }), + headers: { 'Content-Type': 'application/json' }, + }); + const dataRC = await responseRC.json(); + if (dataRC.valid) { + idRC = dataRC.rc.id; + } else { + return { valid: false, message: 'Échec mise à jour RC' }; + } + } else { + // Créer un nouvel enregistrement RC + const responseRC = await fetch(`/rc/create`, { + method: 'POST', + body: JSON.stringify({ + projetRC: idProjetRC, + typeCotisation: extractTypeCot() + }), + headers: { 'Content-Type': 'application/json' }, + }); + const dataRC = await responseRC.json(); + if (dataRC.valid) { + idRC = dataRC.rc.id; + } else { + return { valid: false, message: 'Échec création RC' }; + } + } + + // Étape 3: Mettre à jour le contrat + const responseContrat = await fetch(`/contrat/update/${contrat.produit}/${contrat.id}/${idRC}`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }); + const dataContrat = await responseContrat.json(); + + return { valid: dataContrat.valid, idRC, idProjetRC }; + } else { + return { valid: false, message: 'Échec création ProjetRC' }; + } + } catch (error) { + console.error('Erreur lors de la sauvegarde:', error); + return { valid: false, message: error.message }; + } + } + + // Exposer les fonctions globalement pour y accéder depuis l'extérieur window.initSubmenuForm = init; + window.saveProjetRC = saveProjetRC; })(); \ No newline at end of file diff --git a/ecole/public/js/rc-data-manager.js b/ecole/public/js/rc-data-manager.js new file mode 100644 index 00000000..283e2f54 --- /dev/null +++ b/ecole/public/js/rc-data-manager.js @@ -0,0 +1,647 @@ +/** + * ═══════════════════════════════════════════════════════════════════════════ + * RC DATA MANAGER + * ═══════════════════════════════════════════════════════════════════════════ + * + * Ce module gère la collecte, la sauvegarde et le pré-remplissage des données + * RC entre les formulaires Tarif et Projet. + * + * @requires rc-sync-utils.js + * @author AXA Transport Team + * @version 2.0.0 + * @since 2026-02-17 + */ + +(function(window) { + 'use strict'; + + const { toNumber, getValue, setValue, getElementByIdFlexible } = window.RCSync; + + // ═══════════════════════════════════════════════════════════════════════ + // MAPPING DES CHAMPS TARIF ↔ PROJET + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Mapping complet des champs entre Tarif et Projet. + * Permet la synchronisation bidirectionnelle. + * + * Structure: { tarifFieldId: projetFieldId } + */ + const FIELD_MAPPING = { + // Informations générales + 'CA': 'CA', + 'chiffreAffaire': 'CA', + 'nbVehicules': 'nombreVehicules', + 'nbrVehicule': 'nombreVehicules', + + // Type de cotisation + 'cotisation': 'typeCot', + + // Activités RCC - Voiturier + 'checkVoiturier': 'actVoiturier', + 'capitalVoiturier': 'valueActVoiturier', + + // Activités RCC - Commissionnaire (Multimodal) + 'checkCommissionnaire': 'actMultimodal', + 'capitalCommissionnaire': 'valueActMultimodal', + + // Activités RCC - Déménageur + 'checkDemenageur': 'actDemEntr', + 'capitalDemenageur': 'valueActDemEntr', + + // Activités RCC - Logistique + 'checkLogistique': 'actPrestaLog', + 'capitalLogistique': 'valueActPrestaLog', + + // RCE + 'checkRCE': 'autresRC', + + // Zones géographiques + 'zone1': 'zone1', + 'zone2': 'zone2', + 'zone3': 'zone3', + 'zone4': 'zone4', + 'zone5': 'zone5', + 'zone6': 'zone6', + + // Protection Juridique + 'checkPJ': 'pj', + + // Garanties additionnelles - Engagements complémentaires + 'checkDomImmat': 'extRCCConfie', // Simplifié + 'checkContConf': 'extRCCConfie', + 'checkTPPC': 'extRCCTPPC', + + // Extensions RCC + 'checkStationLavage': 'extRCCModifCalArrim', + + // Extensions RCE + // (géré séparément car structure différente) + + // Sinistralité + 'sinistre': 'nbSinistres3ans' + }; + + // ═══════════════════════════════════════════════════════════════════════ + // COLLECTE DES DONNÉES COMPLÈTES + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Collecte toutes les données du formulaire Tarif RC. + * Cette fonction est exhaustive et capture TOUS les champs nécessaires. + * + * @returns {Object} Objet contenant toutes les données du tarif + * + * @example + * const tarifData = collectAllTarifData(); + * console.log(tarifData.ca, tarifData.zones, tarifData.marchandises); + */ + function collectAllTarifData() { + // Références flexibles aux éléments + const getEl = getElementByIdFlexible; + + const data = { + // ═══ INFORMATIONS GÉNÉRALES ═══ + typeCotisation: document.querySelector('input[name="cotisation"]:checked')?.value || null, + ca: toNumber(getValue('CA') || getValue('chiffreAffaire')), + nombreVehicules: Math.max(0, Math.round(toNumber(getValue('nbVehicules') || getValue('nbrVehicule')))), + + // ═══ ACTIVITÉS RCC ═══ + activites: { + voiturier: { + checked: getValue('checkVoiturier') || false, + capital: toNumber(getValue('capitalVoiturier')), + pourcentage: toNumber(getValue('pourcent_voiturier') || getValue('pourcentVoiturier/Loueur')), + isSet: Boolean(getValue('pourcent_voiturier')?.trim()) + }, + commissionnaire: { + checked: getValue('checkCommissionnaire') || false, + capital: toNumber(getValue('capitalCommissionnaire')), + pourcentage: toNumber(getValue('pourcent_commissionnaire')), + isSet: Boolean(getValue('pourcent_commissionnaire')?.trim()) + }, + demenageur: { + checked: getValue('checkDemenageur') || false, + capital: toNumber(getValue('capitalDemenageur')), + pourcentage: toNumber(getValue('pourcent_demenageur')), + isSet: Boolean(getValue('pourcent_demenageur')?.trim()) + }, + logistique: { + checked: getValue('checkLogistique') || false, + capital: toNumber(getValue('capitalLogistique')), + pourcentage: toNumber(getValue('pourcent_logistique')), + isSet: Boolean(getValue('pourcent_logistique')?.trim()) + }, + autocariste: { + checked: getValue('checkAutocariste') || false, + capital: toNumber(getValue('capitalAutocariste')), + pourcentage: toNumber(getValue('pourcent_autocariste')), + isSet: Boolean(getValue('pourcent_autocariste')?.trim()) + }, + autres: { + checked: getValue('checkAutres') || false, + capital: toNumber(getValue('capitalAutres')), + pourcentage: toNumber(getValue('pourcent_autres')), + isSet: Boolean(getValue('pourcent_autres')?.trim()) + } + }, + + // ═══ RCE ═══ + rce: { + checked: getValue('checkRCE') || false + }, + + // ═══ ACTIVITÉS COMPLÉMENTAIRES (JSON) ═══ + activitesComplementaires: { + voiturier: collectActivitesComplJSON('voiturier'), + commissionnaire: collectActivitesComplJSON('commissionnaire'), + demenageur: collectActivitesComplJSON('demenageur'), + logistique: collectActivitesComplJSON('logistique') + }, + + // ═══ MARCHANDISES (JSON) ═══ + marchandises: { + voiturier: collectMarchandisesJSON('voiturier'), + commissionnaire: collectMarchandisesJSON('commissionnaire'), + demenageur: collectMarchandisesJSON('demenageur'), + logistique: collectMarchandisesJSON('logistique'), + autocariste: collectMarchandisesJSON('autocariste'), + autres: collectMarchandisesJSON('autres') + }, + + // ═══ ZONES GÉOGRAPHIQUES ═══ + zones: { + zone1: getValue('zone1') || false, + zone2: getValue('zone2') || false, + zone3: getValue('zone3') || false, + zone4: getValue('zone4') || false, + zone5: getValue('zone5') || false, + zone6: getValue('zone6') || false + }, + + // ═══ ENGAGEMENTS COMPLÉMENTAIRES ═══ + engagementsComplementaires: { + domicileImmatriculation: { + checked: getValue('checkDomImmat') || false, + capital: toNumber(getValue('inputDomImmat')) + }, + contenantConfie: { + checked: getValue('checkContConf') || false, + capital: toNumber(getValue('inputContConf')) + }, + differenceInventaire: { + checked: getValue('checkDiffInv') || false, + capital: toNumber(getValue('inputDiffInv')) + } + }, + + // ═══ GARANTIES ADDITIONNELLES ═══ + garantiesAdditionnelles: { + stationLavage: getValue('checkStationLavage') || false, + garageInterne: getValue('checkGarageInterne') || false, + cse: getValue('checkCSE') || false, + tppc: { + checked: getValue('checkTPPC') || false, + capital: toNumber(getValue('selTPPCcapital')), + vehicules: Math.max(0, Math.round(toNumber(getValue('selTPPCveh')))) + }, + pj: getValue('checkPJ') || false + }, + + // ═══ SINISTRALITÉ ═══ + sinistralite: { + nombre3ans: toNumber(getValue('sinistre')), + montant3ans: 0 // TODO: ajouter si champ existe + }, + + // ═══ RÉSULTATS DE CALCUL ═══ + resultats: { + // Franchise 250 + fr250: { + primeRCC: toNumber(getEl('rccFr250')?.textContent), + primeRCE: toNumber(getEl('rceFr250')?.textContent), + primePJ: toNumber(getEl('pjFr250')?.textContent), + primeTotal: toNumber(getEl('priceFr250')?.textContent), + tauxRCC: toNumber(getEl('tauxRccFr250')?.textContent), + tauxRCE: toNumber(getEl('tauxRceFr250')?.textContent), + tauxGlobal: toNumber(getEl('tauxGlobalFr250')?.textContent) + }, + // Franchise 400 + fr400: { + primeRCC: toNumber(getEl('rccFr400')?.textContent), + primeRCE: toNumber(getEl('rceFr400')?.textContent), + primePJ: toNumber(getEl('pjFr400')?.textContent), + primeTotal: toNumber(getEl('priceFr400')?.textContent), + tauxRCC: toNumber(getEl('tauxRccFr400')?.textContent), + tauxRCE: toNumber(getEl('tauxRceFr400')?.textContent), + tauxGlobal: toNumber(getEl('tauxGlobalFr400')?.textContent) + }, + // Franchise 2000 + fr2000: { + primeRCC: toNumber(getEl('rccFr2000')?.textContent), + primeRCE: toNumber(getEl('rceFr2000')?.textContent), + primePJ: toNumber(getEl('pjFr2000')?.textContent), + primeTotal: toNumber(getEl('priceFr2000')?.textContent), + tauxRCC: toNumber(getEl('tauxRccFr2000')?.textContent), + tauxRCE: toNumber(getEl('tauxRceFr2000')?.textContent), + tauxGlobal: toNumber(getEl('tauxGlobalFr2000')?.textContent) + }, + franchiseChoisie: window.franchiseChoisie || null, + tarifCommercial: toNumber(getValue('tarifCom')) + }, + + // ═══ COMMENTAIRE ═══ + commentaire: getValue('commentaire') || '' + }; + + console.log('📊 Données Tarif collectées:', data); + return data; + } + + /** + * Fonction helper pour collecter les activités complémentaires depuis le formulaire. + * + * @param {string} typeActivite - Type d'activité ('voiturier', 'commissionnaire', etc.) + * @returns {string} JSON array des activités cochées + * @private + */ + function collectActivitesComplJSON(typeActivite) { + let name; + switch(typeActivite.toLowerCase()) { + case 'voiturier': + name = 'actComplVoiturier/Loueur'; + break; + case 'commissionnaire': + name = 'actComplCommissionnaire de Transport'; + break; + case 'demenageur': + name = 'actComplDéménageur'; + break; + case 'logistique': + name = 'actComplLogistique'; + break; + default: + return JSON.stringify([]); + } + + const checkboxes = document.querySelectorAll(`[name="${name}"] input[type="checkbox"]:checked`); + const activites = []; + checkboxes.forEach(cb => { + const text = cb.nextElementSibling ? cb.nextElementSibling.textContent.trim() : cb.value; + activites.push(text); + }); + return JSON.stringify(activites); + } + + /** + * Fonction helper pour collecter les marchandises depuis le formulaire. + * + * @param {string} typeActivite - Type d'activité + * @returns {string} JSON array des marchandises cochées + * @private + */ + function collectMarchandisesJSON(typeActivite) { + let name; + switch(typeActivite.toLowerCase()) { + case 'voiturier': + name = 'marVoiturier/Loueur'; + break; + case 'commissionnaire': + name = 'marCommissionnaire de Transport'; + break; + case 'demenageur': + name = 'marDéménageur'; + break; + case 'logistique': + name = 'marLogistique'; + break; + case 'autocariste': + name = 'marAutocariste'; + break; + case 'autres': + name = 'marAutres activites'; + break; + default: + return JSON.stringify([]); + } + + const checkboxes = document.querySelectorAll(`[name="${name}"] input[type="checkbox"]:checked`); + const marchandises = []; + checkboxes.forEach(cb => { + const text = cb.nextElementSibling ? cb.nextElementSibling.textContent.trim() : cb.value; + marchandises.push(text); + }); + return JSON.stringify(marchandises); + } + + // ═══════════════════════════════════════════════════════════════════════ + // PRÉ-REMPLISSAGE TARIF → PROJET + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Pré-remplit le formulaire Projet avec les données du Tarif. + * Cette fonction est appelée quand l'utilisateur passe du Tarif au Projet. + * + * @param {Object} tarifData - Données complètes du tarif (de collectAllTarifData) + * + * @example + * const tarifData = collectAllTarifData(); + * prefillProjetFromTarif(tarifData); + */ + function prefillProjetFromTarif(tarifData) { + if (!tarifData) { + console.warn('Pas de données tarif à pré-remplir'); + return; + } + + console.log('📝 Pré-remplissage Projet depuis Tarif...'); + + try { + // ═══ INFORMATIONS GÉNÉRALES ═══ + + // CA + if (tarifData.ca) { + setValue('CA', tarifData.ca); + console.log(' ✓ CA:', tarifData.ca); + } + + // Type de cotisation + if (tarifData.typeCotisation) { + const radio = document.querySelector(`input[name="typeCot"][value="${tarifData.typeCotisation}"]`); + if (radio) { + radio.checked = true; + console.log(' ✓ Type cotisation:', tarifData.typeCotisation); + } + } + + // Nombre de véhicules + if (tarifData.nombreVehicules) { + setValue('nombreVehicules', tarifData.nombreVehicules); + console.log(' ✓ Véhicules:', tarifData.nombreVehicules); + } + + // ═══ ACTIVITÉS ═══ + + const activitySelector = document.getElementById('activity-selector'); + if (activitySelector && tarifData.activites) { + const activitesToAdd = []; + + if (tarifData.activites.voiturier?.checked) { + activitesToAdd.push('Voiturier/Loueur'); + } + if (tarifData.activites.commissionnaire?.checked) { + activitesToAdd.push('Commissionnaire de Transport'); + } + if (tarifData.activites.demenageur?.checked) { + activitesToAdd.push('Déménageur d\'entreprises'); + } + if (tarifData.activites.logistique?.checked) { + activitesToAdd.push('Prestataire logistique'); + } + if (tarifData.activites.autocariste?.checked) { + activitesToAdd.push('Autocariste'); + } + if (tarifData.activites.autres?.checked) { + activitesToAdd.push('Autres activités'); + } + + // Sélectionner les options dans le select + Array.from(activitySelector.options).forEach(option => { + if (activitesToAdd.includes(option.value)) { + option.selected = true; + } + }); + + // Trigger change pour créer les chips Materialize + const event = new Event('change', { bubbles: true }); + activitySelector.dispatchEvent(event); + + console.log(' ✓ Activités:', activitesToAdd.length); + } + + // ═══ MARCHANDISES ═══ + + const marchandiseSelector = document.getElementById('marchandise-selector'); + if (marchandiseSelector && tarifData.marchandises) { + const marchandisesToSelect = []; + + // Parser les marchandises de chaque type + ['voiturier', 'commissionnaire', 'demenageur', 'logistique', 'autocariste', 'autres'].forEach(type => { + const marchArray = tarifData.marchandises[type]; + if (Array.isArray(marchArray)) { + marchArray.forEach(m => marchandisesToSelect.push(m)); + } + }); + + // Sélectionner dans le select + Array.from(marchandiseSelector.options).forEach(option => { + if (marchandisesToSelect.includes(option.text) || marchandisesToSelect.includes(option.value)) { + option.selected = true; + } + }); + + const event = new Event('change', { bubbles: true }); + marchandiseSelector.dispatchEvent(event); + + console.log(' ✓ Marchandises:', marchandisesToSelect.length); + } + + // ═══ ZONES GÉOGRAPHIQUES ═══ + + if (tarifData.zones) { + let zonesCount = 0; + Object.keys(tarifData.zones).forEach(zoneKey => { + const checkbox = document.getElementById(zoneKey); + if (checkbox && tarifData.zones[zoneKey]) { + checkbox.checked = true; + zonesCount++; + } + }); + console.log(' ✓ Zones:', zonesCount); + } + + // ═══ PROTECTION JURIDIQUE ═══ + + if (tarifData.garantiesAdditionnelles?.pj) { + const switchPJ = document.getElementById('switchPJ'); + if (switchPJ) { + switchPJ.checked = true; + console.log(' ✓ PJ activée'); + + // Afficher la section PJ + const pjSection = document.getElementById('pj-section'); + if (pjSection) pjSection.style.display = 'block'; + } + } + + // ═══ RCE ═══ + + if (tarifData.rce?.checked) { + const choixRCE = document.getElementById('choixRCE'); + if (choixRCE) { + choixRCE.checked = true; + console.log(' ✓ RCE activée'); + + // Afficher la section RCE + const rceSection = document.getElementById('section-rce'); + if (rceSection) rceSection.style.display = 'block'; + } + } + + // ═══ TPPC ═══ + + if (tarifData.garantiesAdditionnelles?.tppc?.checked) { + const checkTPPC = document.getElementById('checkTPPC'); + if (checkTPPC) { + checkTPPC.checked = true; + + if (tarifData.garantiesAdditionnelles.tppc.capital) { + setValue('capitalTPPC', tarifData.garantiesAdditionnelles.tppc.capital); + } + if (tarifData.garantiesAdditionnelles.tppc.vehicules) { + setValue('vehiculesTPPC', tarifData.garantiesAdditionnelles.tppc.vehicules); + } + + console.log(' ✓ TPPC'); + } + } + + // ═══ ENGAGEMENTS COMPLÉMENTAIRES ═══ + + const engagements = tarifData.engagementsComplementaires; + if (engagements) { + if (engagements.domicileImmatriculation?.checked) { + setValue('checkDomImmat', true); + console.log(' ✓ Domicile immatriculation'); + } + if (engagements.contenantConfie?.checked) { + setValue('checkContConf', true); + console.log(' ✓ Contenant confié'); + } + } + + // ═══ SINISTRALITÉ ═══ + + if (tarifData.sinistralite) { + if (tarifData.sinistralite.nombre3ans) { + setValue('nbSinistres3ans', tarifData.sinistralite.nombre3ans); + } + if (tarifData.sinistralite.montant3ans) { + setValue('montantSinistres3ans', tarifData.sinistralite.montant3ans); + } + console.log(' ✓ Sinistralité'); + } + + // ═══ RÉSULTATS TARIFAIRES ═══ + + if (tarifData.resultats) { + const res = tarifData.resultats; + + // Taux + if (res.tauxRCCHT) setValue('tauxRCCHT', res.tauxRCCHT); + if (res.tauxRCCTTC) setValue('tauxRCCTTC', res.tauxRCCTTC); + if (res.tauxRCEHT) setValue('tauxRCEHT', res.tauxRCEHT); + if (res.tauxRCETTC) setValue('tauxRCETTC', res.tauxRCETTC); + if (res.tauxTotalHT) setValue('tauxTotalHT', res.tauxTotalHT); + if (res.tauxTotalTTC) setValue('tauxTotalTTC', res.tauxTotalTTC); + + // Cotisations + if (res.cotRCCHT) setValue('cotRCCHT', res.cotRCCHT); + if (res.cotRCCTTC) setValue('cotRCCTTC', res.cotRCCTTC); + if (res.cotRCEHT) setValue('cotRCEHT', res.cotRCEHT); + if (res.cotRCETTC) setValue('cotRCETTC', res.cotRCETTC); + if (res.cotPJHT) setValue('cotPJHT', res.cotPJHT); + if (res.cotPJTTC) setValue('cotPJTTC', res.cotPJTTC); + if (res.cotTotalHT) setValue('cotTotalHT', res.cotTotalHT); + if (res.cotTotalTTC) setValue('cotTotalTTC', res.cotTotalTTC); + + console.log(' ✓ Résultats tarifaires'); + } + + // Forcer la mise à jour des éléments Materialize + if (window.M && window.M.FormSelect) { + const selects = document.querySelectorAll('select'); + window.M.FormSelect.init(selects); + } + if (window.M && window.M.updateTextFields) { + window.M.updateTextFields(); + } + + console.log('✅ Pré-remplissage Projet terminé'); + + } catch (error) { + console.error('❌ Erreur lors du pré-remplissage Projet:', error); + } + } + + // ═══════════════════════════════════════════════════════════════════════ + // PRÉ-REMPLISSAGE PROJET → TARIF + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Pré-remplit le formulaire Tarif avec les données du Projet. + * Cette fonction est appelée quand l'utilisateur passe du Projet au Tarif. + * + * @param {Object} projetData - Données complètes du projet + * + * @example + * prefillTarifFromProjet(projetData); + */ + function prefillTarifFromProjet(projetData) { + if (!projetData) { + console.warn('Pas de données projet à pré-remplir'); + return; + } + + console.log('📝 Pré-remplissage Tarif depuis Projet...'); + + try { + // CA + if (projetData.ca) { + setValue('CA', projetData.ca); + } + + // Type de cotisation + if (projetData.typeCot) { + const radio = document.querySelector(`input[name="cotisation"][value="${projetData.typeCot}"]`); + if (radio) radio.checked = true; + } + + // Zones géographiques + ['zone1', 'zone2', 'zone3', 'zone4', 'zone5', 'zone6'].forEach(zone => { + if (projetData[zone]) { + setValue(zone, true); + } + }); + + // PJ + if (projetData.pj) { + setValue('checkPJ', true); + } + + // RCE + if (projetData.autresRC) { + setValue('checkRCE', true); + } + + console.log('✅ Pré-remplissage Tarif terminé'); + + } catch (error) { + console.error('❌ Erreur lors du pré-remplissage Tarif:', error); + } + } + + // ═══════════════════════════════════════════════════════════════════════ + // EXPORT PUBLIC + // ═══════════════════════════════════════════════════════════════════════ + + window.RCDataManager = { + collectAllTarifData, + prefillProjetFromTarif, + prefillTarifFromProjet, + FIELD_MAPPING + }; + + console.log('✅ RC Data Manager loaded'); + +})(window); diff --git a/ecole/public/js/rc-orchestrator.js b/ecole/public/js/rc-orchestrator.js new file mode 100644 index 00000000..43d54242 --- /dev/null +++ b/ecole/public/js/rc-orchestrator.js @@ -0,0 +1,388 @@ +/** + * ═══════════════════════════════════════════════════════════════════════════ + * RC SYNC ORCHESTRATOR + * ═══════════════════════════════════════════════════════════════════════════ + * + * Ce module orchestre la synchronisation entre Tarif RC et Projet RC. + * Il s'intègre avec les formulaires existants sans les modifier. + * + * @requires rc-sync-utils.js + * @requires rc-data-manager.js + * @author AXA Transport Team + * @version 2.0.0 + * @since 2026-02-17 + */ + +(function(window) { + 'use strict'; + + // Attendre que les dépendances soient chargées + if (!window.RCSync || !window.RCDataManager) { + console.error('❌ Dépendances RC Sync manquantes'); + return; + } + + const { isChangeImpactingTarif, showReturnToTarifModal } = window.RCSync; + const { collectAllTarifData, prefillProjetFromTarif, prefillTarifFromProjet } = window.RCDataManager; + + // ═══════════════════════════════════════════════════════════════════════ + // CONFIGURATION + // ═══════════════════════════════════════════════════════════════════════ + + const SESSION_STORAGE_KEYS = { + TARIF_DATA: 'rc_tarif_validated_data', + PROJET_DATA: 'rc_projet_data', + TARIF_ORIGINAL: 'rc_tarif_original_for_comparison' + }; + + // ═══════════════════════════════════════════════════════════════════════ + // DÉTECTION DE LA PAGE ACTIVE + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Détecte la page active (tarif ou projet) depuis l'URL. + * + * @returns {'tarif'|'projet'|null} Page active ou null + */ + function detectActivePage() { + const params = new URLSearchParams(window.location.search); + const submenu = params.get('submenu'); + + if (submenu === 'tarif' || submenu === 'tarifrc') { + return 'tarif'; + } else if (submenu === 'projet' || submenu === 'projetrc') { + return 'projet'; + } + + return null; + } + + // ═══════════════════════════════════════════════════════════════════════ + // GESTION SESSIONSTORAGE + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Sauvegarde les données du tarif validé dans sessionStorage. + * + * @param {Object} tarifData - Données complètes du tarif + */ + function saveTarifDataToSession(tarifData) { + try { + sessionStorage.setItem(SESSION_STORAGE_KEYS.TARIF_DATA, JSON.stringify(tarifData)); + sessionStorage.setItem(SESSION_STORAGE_KEYS.TARIF_ORIGINAL, JSON.stringify(tarifData)); + console.log('✅ Données tarif sauvegardées en session'); + } catch (error) { + console.error('❌ Erreur sauvegarde session:', error); + } + } + + /** + * Récupère les données du tarif depuis sessionStorage. + * + * @returns {Object|null} Données du tarif ou null + */ + function getTarifDataFromSession() { + try { + const data = sessionStorage.getItem(SESSION_STORAGE_KEYS.TARIF_DATA); + return data ? JSON.parse(data) : null; + } catch (error) { + console.error('❌ Erreur lecture session:', error); + return null; + } + } + + /** + * Récupère les données originales du tarif pour comparaison. + * + * @returns {Object|null} Données originales du tarif + */ + function getTarifOriginalDataFromSession() { + try { + const data = sessionStorage.getItem(SESSION_STORAGE_KEYS.TARIF_ORIGINAL); + return data ? JSON.parse(data) : null; + } catch (error) { + return null; + } + } + + // ═══════════════════════════════════════════════════════════════════════ + // HOOK: APRÈS VALIDATION TARIF + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Hook appelé après la validation du tarif commercial. + * Collecte toutes les données et les sauvegarde en session. + * + * Cette fonction doit être appelée juste avant la redirection vers le projet. + */ + function onTarifValidated() { + console.log('🎯 Hook: Tarif validé, collecte des données...'); + + try { + // Collecter toutes les données du tarif + const tarifData = collectAllTarifData(); + + // Sauvegarder en session pour le pré-remplissage projet + saveTarifDataToSession(tarifData); + + console.log('✅ Données tarif prêtes pour le projet'); + } catch (error) { + console.error('❌ Erreur hook tarif validé:', error); + } + } + + // ═══════════════════════════════════════════════════════════════════════ + // INITIALISATION PAGE PROJET + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Initialise le formulaire projet au chargement. + * Configure UNIQUEMENT la détection des changements impactants. + * Le pré-remplissage est géré par prefillFromTarif() existant dans projet-form-RC.js + */ + function initProjetPage() { + console.log('🚀 Initialisation RC Orchestrator pour page Projet...'); + + // Les données rc/tarif/projet sont DÉJÀ chargées depuis la base + // par le code existant dans projet-form-RC.js + // On configure juste la détection des changements + + setTimeout(() => { + setupProjetChangeDetection(); + }, 1000); // Attendre que prefillFromTarif() ait fini + } + + /** + * Configure la détection des changements impactants dans le projet. + * Affiche un modal si l'utilisateur modifie un champ qui impacte le tarif. + * Utilise les variables globales rc/tarif depuis projet-form-RC.js + */ + function setupProjetChangeDetection() { + // Les données originales sont dans les variables globales window.tarif et window.rc + // définies par projet-form-RC.js + const tarifOriginal = window.tarif; + const rcOriginal = window.rc; + + if (!tarifOriginal && !rcOriginal) { + console.log('ℹ️ Pas de tarif/rc, pas de détection'); + return; + } + + console.log('👁️ Configuration détection changements...'); + console.log('📋 Données originales:', { tarif: tarifOriginal, rc: rcOriginal }); + + // Liste COMPLÈTE des éléments à surveiller (tous les champs impactants) + const elementsToWatch = [ + // CA et infos générales + 'CA', 'chiffreAffaire', 'nombreVehicules', 'nbrVehicule', + + // Zones géographiques + 'zone1', 'zone2', 'zone3', 'zone4', 'zone5', 'zone6', + + // Protection Juridique + 'switchPJ', 'checkPJ', + + // RCE + 'choixRCE', 'checkRCE', + + // TPPC + 'checkTPPC', 'capitalTPPC', 'vehiculesTPPC', + + // Engagements complémentaires + 'checkDomImmat', 'checkContConf', 'checkDiffInv', + + // Garanties additionnelles + 'checkStationLavage', 'checkGarageInterne', 'checkCSE', + + // Sinistralité + 'nbSinistres3ans', 'montantSinistres3ans', + + // Autres + 'programmeInternationale', 'participationResultat' + ]; + + // Ajouter des listeners sur tous les éléments surveillés + elementsToWatch.forEach(elementId => { + const element = document.getElementById(elementId); + if (!element) return; + + const eventType = element.type === 'checkbox' ? 'change' : 'blur'; + + element.addEventListener(eventType, function(e) { + const fieldName = this.id; + const newValue = this.type === 'checkbox' ? this.checked : this.value; + + console.log(`🔍 Changement détecté: ${fieldName} = ${newValue}`); + + // Vérifier si c'est un champ impactant + if (isFieldImpactingTarif(fieldName)) { + console.warn(`⚠️ "${fieldName}" impacte le tarif !`); + showReturnToTarifModal(fieldName); + } else { + console.log(`ℹ️ "${fieldName}" n'impacte pas le tarif`); + } + }); + }); + + // Surveiller les radio buttons (type de cotisation) + const radioTypeCot = document.querySelectorAll('input[name="typeCot"]'); + radioTypeCot.forEach(radio => { + radio.addEventListener('change', function() { + console.log(`🔍 Changement type cotisation: ${this.value}`); + console.warn(`⚠️ Type de cotisation impacte le tarif !`); + showReturnToTarifModal('Type de cotisation'); + }); + }); + + // Surveiller le select activités + const activitySelector = document.getElementById('activity-selector'); + if (activitySelector) { + activitySelector.addEventListener('change', function() { + const selectedValues = Array.from(this.selectedOptions).map(opt => opt.value); + console.log(`🔍 Changement activités:`, selectedValues); + console.warn(`⚠️ Activités impactent le tarif !`); + showReturnToTarifModal('Activités'); + }); + } + + // Surveiller le select marchandises + const marchandiseSelector = document.getElementById('marchandise-selector'); + if (marchandiseSelector) { + marchandiseSelector.addEventListener('change', function() { + const selectedValues = Array.from(this.selectedOptions).map(opt => opt.value); + console.log(`🔍 Changement marchandises:`, selectedValues); + console.warn(`⚠️ Marchandises impactent le tarif !`); + showReturnToTarifModal('Marchandises'); + }); + } + + // Surveiller les boutons d'action sur les zones (Monde entier / Reset) + ['btnMondeEntier', 'btnReset'].forEach(btnId => { + const btn = document.getElementById(btnId); + if (!btn) return; + btn.addEventListener('click', () => { + console.log(`🔍 Changement zones via ${btnId}`); + console.warn('⚠️ Zones géographiques impactent le tarif !'); + showReturnToTarifModal('Zones géographiques'); + }); + }); + + console.log('✅ Détection changements configurée sur tous les champs impactants'); + } + + // ═══════════════════════════════════════════════════════════════════════ + // INITIALISATION PAGE TARIF + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Initialise le formulaire tarif au chargement. + * Pré-remplit depuis le projet si l'utilisateur vient du projet. + */ + function initTarifPage() { + console.log('🚀 Initialisation page Tarif...'); + + // Vérifier si on vient du projet + const projetData = JSON.parse(sessionStorage.getItem(SESSION_STORAGE_KEYS.PROJET_DATA) || 'null'); + + if (projetData && !getTarifDataFromSession()) { + // On a des données projet mais pas de tarif validé + // = L'utilisateur a commencé par le projet + console.log('📥 Pré-remplissage depuis projet...'); + + setTimeout(() => { + prefillTarifFromProjet(projetData); + }, 500); + } + } + + // ═══════════════════════════════════════════════════════════════════════ + // INTERCEPTION DES FONCTIONS EXISTANTES + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Intercepte la fonction de validation du tarif commercial existante. + * Ajoute notre hook avant la redirection. + */ + function interceptTarifValidation() { + // Attendre que la fonction window.saveTarifRC soit disponible + const checkInterval = setInterval(() => { + if (window.saveTarifRC) { + clearInterval(checkInterval); + + // Sauvegarder la fonction originale + const originalSaveTarifRC = window.saveTarifRC; + + // Remplacer par notre version wrappée + window.saveTarifRC = async function(...args) { + console.log('🎯 Interception saveTarifRC...'); + + // Appeler la fonction originale + const result = await originalSaveTarifRC.apply(this, args); + + // Si succès, appeler notre hook + if (result && result.valid) { + onTarifValidated(); + } + + return result; + }; + + console.log('✅ saveTarifRC intercepté'); + } + }, 100); + + // Timeout après 5 secondes + setTimeout(() => clearInterval(checkInterval), 5000); + } + + // ═══════════════════════════════════════════════════════════════════════ + // DÉMARRAGE AUTOMATIQUE + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Initialise l'orchestrateur au chargement de la page. + */ + function init() { + console.log('🎼 RC Sync Orchestrator: Démarrage...'); + + const activePage = detectActivePage(); + console.log(`📄 Page active détectée: ${activePage || 'aucune'}`); + + if (activePage === 'tarif') { + interceptTarifValidation(); + + // Attendre que le formulaire soit initialisé + setTimeout(() => { + initTarifPage(); + }, 1000); + + } else if (activePage === 'projet') { + // Attendre que le formulaire soit initialisé + setTimeout(() => { + initProjetPage(); + }, 1000); + } + } + + // Démarrage au chargement du DOM + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } + + // ═══════════════════════════════════════════════════════════════════════ + // EXPORT PUBLIC + // ═══════════════════════════════════════════════════════════════════════ + + window.RCOrchestrator = { + onTarifValidated, + initProjetPage, + initTarifPage, + saveTarifDataToSession, + getTarifDataFromSession + }; + + console.log('✅ RC Sync Orchestrator loaded'); + +})(window); diff --git a/ecole/public/js/rc-sync-utils.js b/ecole/public/js/rc-sync-utils.js new file mode 100644 index 00000000..0939ba32 --- /dev/null +++ b/ecole/public/js/rc-sync-utils.js @@ -0,0 +1,464 @@ +/** + * ═══════════════════════════════════════════════════════════════════════════ + * RC SYNCHRONIZATION UTILITIES + * ═══════════════════════════════════════════════════════════════════════════ + * + * Ce module contient toutes les fonctions utilitaires pour la synchronisation + * bidirectionnelle entre les formulaires Tarif RC et Projet RC. + * + * @author AXA Transport Team + * @version 2.0.0 + * @since 2026-02-17 + */ + +(function(window) { + 'use strict'; + + // ═══════════════════════════════════════════════════════════════════════ + // CONSTANTES + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Liste exhaustive des champs qui impactent le calcul du tarif. + * Si l'un de ces champs est modifié dans le projet, un modal + * demandera à l'utilisateur de retourner au tarif. + * + * @constant {Array} + */ + const TARIF_IMPACTING_FIELDS = [ + // Chiffre d'affaires et type de contrat + 'ca', 'chiffreAffaires', 'CA', + 'typeCotisation', 'cotisation', + 'nombreVehicules', 'nbVehicules', + + // Activités RCC + 'checkVoiturier', 'capitalVoiturier', 'actVoiturier', + 'checkCommissionnaire', 'capitalCommissionnaire', 'actMultimodal', + 'checkDemenageur', 'capitalDemenageur', + 'checkLogistique', 'capitalLogistique', + 'checkAutocariste', 'capitalAutocariste', + 'checkAutres', 'capitalAutres', + + // RCE + 'checkRCE', 'autresRC', + + // Activités complémentaires + 'actComplVoiturier', 'actComplCommissionnaire', 'actComplDemenageur', 'actComplLogistique', + 'activitesVoiturier', 'activitesCommissionnaire', 'activitesDemenageur', 'activitesLogistique', + + // Marchandises + 'marchandisesVoiturier', 'marchandisesCommissionnaire', 'marchandisesDemenageur', + 'marchandisesLogistique', 'marchandisesAutocariste', 'marchandisesAutres', + 'marOrdinaire', 'marRoulant', 'marEngins', 'marRoulantDem', 'marMobilerUsag', + 'marPerissable', 'marAnimaux', 'marCiterne', 'marBeton', 'marExceptionnels', 'marVrac', + + // Zones géographiques + 'zone1', 'zone2', 'zone3', 'zone4', 'zone5', 'zone6', + + // Extensions de garantie RCC + 'extRCCModifCalArrim', 'extRCCFerroutage', 'extRCCFraisRecons', + 'extRCCConfie', 'typeExtConfies', 'extRCCTPPC', 'extRCCRegie', 'extRCCSansMontageDemontage', + 'checkDomImmat', 'capitalDomImmat', 'checkContConf', 'capitalContConf', + 'checkDiffInv', 'capitalDiffInv', 'checkTPPC', 'capitalTPPC', 'vehiculesTPPC', + + // Extensions de garantie RCE + 'extRCEBraDebra', 'extRCEMontageDemontage', + + // Garanties additionnelles + 'checkStationLavage', 'checkGarageInterne', 'checkCSE', 'checkPJ', 'pj', + + // Sinistralité + 'sinistre', 'nbSinistres3ans', 'montantSinistres3ans' + ]; + + // ═══════════════════════════════════════════════════════════════════════ + // HELPERS - MANIPULATION DE VALEURS + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Convertit une valeur en nombre en gérant les formats français et internationaux. + * Gère les espaces, virgules, points, et valeurs nulles/undefined. + * + * @param {string|number|null|undefined} x - Valeur à convertir + * @returns {number} Nombre converti ou 0 si impossible + * + * @example + * toNumber("1 234,56") // 1234.56 + * toNumber("1.234,56") // 1234.56 + * toNumber("1,234.56") // 1234.56 + * toNumber(null) // 0 + */ + function toNumber(x) { + if (x == null) return 0; + + let value = String(x).trim(); + if (!value) return 0; + + value = value + .replace(/\s/g, '') + .replace(/[^\d.,-]/g, ''); + + if (!value) return 0; + + const isNegative = value.startsWith('-'); + value = value.replace(/-/g, ''); + if (isNegative && value) { + value = '-' + value; + } + + const hasComma = value.includes(','); + const hasDot = value.includes('.'); + + if (hasComma) { + value = value.replace(/\./g, '').replace(/,/g, '.'); + } else if (hasDot) { + const dotMatches = value.match(/\./g); + const dotCount = dotMatches ? dotMatches.length : 0; + if (dotCount > 1) { + const parts = value.split('.'); + const lastSegment = parts[parts.length - 1]; + if (lastSegment.length === 3) { + value = parts.join(''); + } else { + value = parts.slice(0, -1).join('') + '.' + lastSegment; + } + } + } + + const parsed = Number(value); + return Number.isFinite(parsed) ? parsed : 0; + } + + /** + * Récupère la valeur d'un élément par son ID de manière flexible. + * Gère les différents types d'éléments (input, select, textarea, etc.) + * et les cas où l'ID contient des caractères spéciaux. + * + * @param {string} id - ID de l'élément + * @returns {HTMLElement|null} Élément trouvé ou null + * + * @example + * const element = getElementByIdFlexible("my-element"); + */ + function getElementByIdFlexible(id) { + if (!id) return null; + const direct = document.getElementById(id); + if (direct) return direct; + try { + return document.querySelector(`[id="${id.replace(/"/g, '\\"')}"]`); + } catch (err) { + return null; + } + } + + /** + * Récupère la valeur d'un champ de formulaire de manière sécurisée. + * Gère les inputs, selects, textareas, checkboxes, et contenus textuels. + * + * @param {string} elementId - ID de l'élément + * @returns {string|number|boolean|null} Valeur du champ + * + * @example + * getValue("ca") // "100000" + * getValue("checkPJ") // true + */ + function getValue(elementId) { + const element = getElementByIdFlexible(elementId); + if (!element) return null; + + if (element.type === 'checkbox') { + return element.checked; + } else if (element.type === 'radio') { + const checked = document.querySelector(`input[name="${element.name}"]:checked`); + return checked ? checked.value : null; + } else if (element.tagName === 'SELECT') { + return element.value; + } else if (element.value !== undefined) { + return element.value; + } else { + return element.textContent || element.innerText || null; + } + } + + /** + * Définit la valeur d'un champ de formulaire. + * Gère automatiquement le type de champ et met à jour l'interface. + * + * @param {string} elementId - ID de l'élément + * @param {any} value - Valeur à définir + * + * @example + * setValue("ca", 100000); + * setValue("checkPJ", true); + */ + function setValue(elementId, value) { + const element = getElementByIdFlexible(elementId); + if (!element) { + console.warn(`Élément non trouvé: ${elementId}`); + return; + } + + if (element.type === 'checkbox') { + element.checked = Boolean(value); + } else if (element.type === 'radio') { + const radio = document.querySelector(`input[name="${element.name}"][value="${value}"]`); + if (radio) radio.checked = true; + } else if (element.tagName === 'SELECT') { + element.value = value; + // Réinitialiser Materialize select si présent + if (window.M && window.M.FormSelect) { + const instance = window.M.FormSelect.getInstance(element); + if (instance) instance.destroy(); + window.M.FormSelect.init(element); + } + } else if (element.value !== undefined) { + element.value = value; + } else { + element.textContent = value; + } + } + + // ═══════════════════════════════════════════════════════════════════════ + // COMPARAISON DE DONNÉES + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Compare deux tableaux pour vérifier leur égalité. + * Effectue une comparaison profonde élément par élément. + * + * @param {Array} arr1 - Premier tableau + * @param {Array} arr2 - Deuxième tableau + * @returns {boolean} true si les tableaux sont égaux + * + * @example + * arraysEqual([1,2,3], [1,2,3]) // true + * arraysEqual([1,2], [1,2,3]) // false + */ + function arraysEqual(arr1, arr2) { + if (!Array.isArray(arr1) || !Array.isArray(arr2)) return false; + if (arr1.length !== arr2.length) return false; + + const sorted1 = [...arr1].sort(); + const sorted2 = [...arr2].sort(); + + return sorted1.every((val, idx) => val === sorted2[idx]); + } + + /** + * Compare deux valeurs en tenant compte de leur type. + * Gère les tableaux, objets, null, undefined, et valeurs primitives. + * + * @param {any} value1 - Première valeur + * @param {any} value2 - Deuxième valeur + * @returns {boolean} true si les valeurs sont égales + * + * @example + * valuesEqual([1,2], [2,1]) // true (ordre indépendant) + * valuesEqual(null, undefined) // true + * valuesEqual(100, "100") // true (conversion automatique) + */ + function valuesEqual(value1, value2) { + // Normaliser null et undefined + if (value1 == null && value2 == null) return true; + if (value1 == null || value2 == null) return false; + + // Comparer les tableaux + if (Array.isArray(value1) && Array.isArray(value2)) { + return arraysEqual(value1, value2); + } + + // Comparer les objets + if (typeof value1 === 'object' && typeof value2 === 'object') { + return JSON.stringify(value1) === JSON.stringify(value2); + } + + // Comparer les nombres (avec conversion) + if (!isNaN(value1) && !isNaN(value2)) { + return toNumber(value1) === toNumber(value2); + } + + // Comparaison standard + return value1 === value2; + } + + // ═══════════════════════════════════════════════════════════════════════ + // DÉTECTION DE CHANGEMENTS IMPACTANTS + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Vérifie si un champ donné impacte le calcul du tarif. + * Se base sur la liste TARIF_IMPACTING_FIELDS. + * + * @param {string} fieldName - Nom du champ + * @returns {boolean} true si le champ impacte le tarif + * + * @example + * isFieldImpactingTarif("ca") // true + * isFieldImpactingTarif("dateEffet") // false + */ + function isFieldImpactingTarif(fieldName) { + return TARIF_IMPACTING_FIELDS.some(field => + fieldName.includes(field) || field.includes(fieldName) + ); + } + + /** + * Vérifie si un changement de valeur impacte le tarif. + * Compare la nouvelle valeur avec les données originales du tarif. + * + * @param {string} fieldName - Nom du champ modifié + * @param {any} newValue - Nouvelle valeur + * @param {Object} tarifOriginalData - Données originales du tarif + * @returns {boolean} true si le changement impacte le tarif + * + * @example + * const impacted = isChangeImpactingTarif("ca", 200000, tarifData); + * if (impacted) showReturnToTarifModal(); + */ + function isChangeImpactingTarif(fieldName, newValue, tarifOriginalData) { + // Vérifier si le champ est dans la liste des champs impactants + if (!isFieldImpactingTarif(fieldName)) { + return false; + } + + // Si pas de données originales, pas d'impact possible + if (!tarifOriginalData) { + return false; + } + + // Récupérer la valeur originale + const originalValue = tarifOriginalData[fieldName]; + + // Comparer les valeurs + return !valuesEqual(newValue, originalValue); + } + + // ═══════════════════════════════════════════════════════════════════════ + // MODAL DE RETOUR AU TARIF + // ═══════════════════════════════════════════════════════════════════════ + + /** + * Affiche le modal demandant à l'utilisateur de retourner au tarif. + * Ce modal s'affiche quand une modification dans le projet impacte + * le calcul du tarif. + * + * @param {string} [fieldName] - Nom du champ modifié (optionnel, pour info) + * + * @example + * showReturnToTarifModal("ca"); + */ + function showReturnToTarifModal(fieldName) { + const modalId = 'modalRetourTarif'; + let modal = document.getElementById(modalId); + + // Créer le modal s'il n'existe pas + if (!modal) { + modal = createReturnToTarifModal(); + document.body.appendChild(modal); + } + + // Mettre à jour le message si un champ est spécifié + if (fieldName) { + const messageEl = modal.querySelector('#modalRetourTarifMessage'); + if (messageEl) { + messageEl.innerHTML = ` + Vous avez modifié "${fieldName}" qui impacte le calcul du tarif. +

+ Vous devez retourner sur le formulaire Tarif pour recalculer et valider le nouveau tarif. + `; + } + } + + // Ouvrir le modal + if (window.M && window.M.Modal) { + const instance = window.M.Modal.getInstance(modal) || window.M.Modal.init(modal); + instance.open(); + } + } + + /** + * Crée l'élément DOM du modal de retour au tarif. + * + * @returns {HTMLElement} Élément modal créé + * @private + */ + function createReturnToTarifModal() { + const modal = document.createElement('div'); + modal.id = 'modalRetourTarif'; + modal.className = 'modal'; + + modal.innerHTML = ` + + + `; + + return modal; + } + + /** + * Navigate vers l'onglet Tarif depuis le Projet. + * + * @example + * navigateToTarif(); + */ + function navigateToTarif() { + // Fermer le modal + const modal = document.getElementById('modalRetourTarif'); + if (modal && window.M) { + const instance = window.M.Modal.getInstance(modal); + if (instance) instance.close(); + } + + // Naviguer vers le tarif + const numParcours = new URLSearchParams(window.location.search).get('numParcours'); + if (numParcours) { + window.location.href = `/navParcours?numParcours=${numParcours}&submenu=tarif`; + } + } + + // ═══════════════════════════════════════════════════════════════════════ + // EXPORT PUBLIC + // ═══════════════════════════════════════════════════════════════════════ + + /** + * API publique du module RC Sync. + * Toutes les fonctions exportées ici sont accessibles via window.RCSync. + */ + window.RCSync = { + // Helpers + toNumber, + getValue, + setValue, + getElementByIdFlexible, + + // Comparaison + arraysEqual, + valuesEqual, + + // Détection changements + isFieldImpactingTarif, + isChangeImpactingTarif, + + // Modal + showReturnToTarifModal, + navigateToTarif, + + // Constantes + TARIF_IMPACTING_FIELDS + }; + + console.log('✅ RC Sync Utils loaded'); + +})(window); diff --git a/ecole/public/js/tarif-form-rc.js b/ecole/public/js/tarif-form-rc.js new file mode 100644 index 00000000..aa29160e --- /dev/null +++ b/ecole/public/js/tarif-form-rc.js @@ -0,0 +1,3376 @@ +function initSubmenuForm() { + // Accéder aux informations stockées du parcours + const parcours = JSON.parse(sessionStorage.getItem('parcours')); +} + +function toNumber(x) { + if (x == null) return 0; + + let value = String(x).trim(); + if (!value) return 0; + + value = value + .replace(/\s/g, '') + .replace(/[^\d.,-]/g, ''); + + if (!value) return 0; + + const isNegative = value.startsWith('-'); + value = value.replace(/-/g, ''); + if (isNegative && value) { + value = '-' + value; + } + + const hasComma = value.includes(','); + const hasDot = value.includes('.'); + + if (hasComma) { + value = value.replace(/\./g, '').replace(/,/g, '.'); + } else if (hasDot) { + const dotMatches = value.match(/\./g); + const dotCount = dotMatches ? dotMatches.length : 0; + if (dotCount > 1) { + const parts = value.split('.'); + const lastSegment = parts[parts.length - 1]; + if (lastSegment.length === 3) { + value = parts.join(''); + } else { + value = parts.slice(0, -1).join('') + '.' + lastSegment; + } + } + } + + const parsed = Number(value); + return Number.isFinite(parsed) ? parsed : 0; +} + +// Fonction pour formater un nombre avec X décimales max (sans décimales si entier) +function formatNumber(num, decimals = 2) { + if (!num || isNaN(num)) return '0.' + '0'.repeat(decimals); + const factor = Math.pow(10, decimals); + const rounded = Math.round(num * factor) / factor; + // Si c'est un nombre entier, ne pas afficher les décimales + if (Number.isInteger(rounded)) { + return rounded.toString(); + } + return rounded.toFixed(decimals); +} + +function getElementByIdFlexible(id) { + if (!id) return null; + const direct = document.getElementById(id); + if (direct) return direct; + try { + return document.querySelector(`[id="${id.replace(/"/g, '\\"')}"]`); + } catch (err) { + return null; + } +} + +// Exposer initSubmenuForm globalement pour y accéder depuis l'extérieur +window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollution de l'espace global +(function () { + // Variables globales du module + let parcours, contrat, client, intermediaire, rc, projet, tarif; + + //Variables modulos et liste + let modRCCA, modRCActRCC, modRCActRCE, modRCActCompl, modRCMar, modRCZone, modRCEngagCompl, modRCGarAdd, modRCSinistre, modRCFranchise, modRCPrimeMini + + // ═══════════════════════════════════════════════════════════════ + // FONCTIONS HELPERS + // ═══════════════════════════════════════════════════════════════ + + // Fonction helper : trouver la tranche la plus proche + function findClosestTranche(val, tranches) { + if (val <= tranches[0]) return tranches[0]; + if (val >= tranches[tranches.length - 1]) return tranches[tranches.length - 1]; + + for (let i = 0; i < tranches.length - 1; i++) { + if (val >= tranches[i] && val < tranches[i + 1]) { + return tranches[i]; + } + } + return tranches[tranches.length - 1]; + } + + // Fonction pour afficher un avertissement visuel de dépassement % + function showPercentageWarning(excess) { + let warningDiv = document.getElementById('percentageWarning'); + if (!warningDiv) { + warningDiv = document.createElement('div'); + warningDiv.id = 'percentageWarning'; + warningDiv.style.cssText = ` + position: fixed; + top: 20px; + right: 20px; + background: #f44336; + color: white; + padding: 15px 25px; + border-radius: 5px; + box-shadow: 0 4px 6px rgba(0,0,0,0.3); + z-index: 9999; + font-weight: bold; + `; + document.body.appendChild(warningDiv); + } + + warningDiv.innerHTML = `Plafonnement à 100% (vous dépassiez de ${excess.toFixed(1)}%)`; + warningDiv.style.display = 'block'; + + setTimeout(() => { + warningDiv.style.display = 'none'; + }, 3000); + } + + // Fonction pour masquer toutes les primes (quand % invalide) + function hideAllPrimes() { + const primeElements = [ + 'primeChapActRCC', 'primeChapActRCE', + 'primeChapActComplRCC', 'primeChapActComplRCE', + 'primeChapMarchRCC', 'primeChapMarchRCE', + 'primeChapZonesRCC', 'primeChapZonesRCE', + 'primeEngValue', 'primeChapGarAddRCC', 'primeChapGarAddRCE', + 'priceFr250', 'priceFr400', 'priceFr2000' + ]; + + primeElements.forEach(id => { + const el = document.getElementById(id); + if (el) { + el.innerHTML = ' % invalide (> 100%)'; + } + }); + } + + // Fonction pour mettre à jour l'indicateur visuel du total des pourcentages + function updatePercentageIndicator(total) { + const indicator = document.getElementById('pourcentageTotal'); + if (!indicator) return; + + const displayTotal = total.toFixed(1); + indicator.textContent = `Total : ${displayTotal}%`; + + if (total > 100) { + indicator.style.background = '#f44336'; + indicator.style.color = 'white'; + indicator.style.border = '3px solid #c62828'; + } else if (total === 100 || Math.abs(total - 100) < 0.1) { + indicator.style.background = '#4caf50'; + indicator.style.color = 'white'; + indicator.style.border = '3px solid #2e7d32'; + } else if (total >= 95) { + indicator.style.background = '#ff9800'; + indicator.style.color = 'white'; + indicator.style.border = '3px solid #ef6c00'; + } else { + indicator.style.background = 'white'; + indicator.style.color = 'darkblue'; + indicator.style.border = '2px solid darkblue'; + } + } + + // ═══════════════════════════════════════════════════════════════ + + // Initialisation du formulaire et des données + function init() { + // Materialize init select + var select = document.querySelectorAll('select'); + M.FormSelect.init(select); + + // Materialize init Modal + var modals = document.querySelectorAll('.modal'); + M.Modal.init(modals); + + // Initialiser les modals spécifiques + window.modalAnimauxVivants = M.Modal.getInstance(document.getElementById('modalAnimauxVivants')); + window.modalTransportBeton = M.Modal.getInstance(document.getElementById('modalTransportBeton')); + window.modalAutocaristeRCE = M.Modal.getInstance(document.getElementById('modalAutocaristeRCE')); + window.modalTarifCom = M.Modal.getInstance(document.getElementById('modalTarifCom')); + + // Accéder aux informations stockées du parcours + parcours = JSON.parse(sessionStorage.getItem('parcours')); + contrat = JSON.parse(sessionStorage.getItem('contrat')); + client = contrat?.["@expand"]?.client || null; + intermediaire = contrat?.["@expand"]?.intermediaire || null; + + // Récupérer les données RC depuis la nouvelle structure (EXACTEMENT comme TPPC) + rc = contrat?.["@expand"]?.enCours || null; // RC principal + projet = rc?.["@expand"]?.projetRC || null; // Données projetRC + tarif = rc?.["@expand"]?.tarifRC || null; // Données tarifRC + + console.log("Initialisation pour formulaire tarif :", parcours); + + constantsJSON().then(() => { + //TODO à virer après les tests + console.log("--- Initialisation modulateur RC ---" + , "\nCA : ", modRCCA + , "\nactRCC : ", modRCActRCC + , "\nactRCE : ", modRCActRCE + , "\nactCompl : ", modRCActCompl + , "\nmar : ", modRCMar + , "\nengagComple : ", modRCEngagCompl + , "\nfranchise : ", modRCFranchise + , "\ngarAdd : ", modRCGarAdd + , "\nprimeMini : ", modRCPrimeMini + , "\nzone : ", modRCZone + , "\nantecedantSinistre: ", modRCSinistre + ); + + // Appel des différentes fonctions d'initialisation + setupEventListeners(); + setupTarifetteButtons(); + populateFormData(); + updatePercentageIndicator(100); // Initialiser à 100% + calcGlobal(); + }) + } + + // Configuration des listeners d'événements + function setupEventListeners() { + // Empêcher la soumission du formulaire avec la touche Enter + const form = document.getElementById('projetForm'); + if (form) { + form.addEventListener('keydown', function(e) { + // Si Enter est pressée et que ce n'est pas sur un bouton submit + if (e.key === 'Enter' && e.target.type !== 'submit' && e.target.tagName !== 'BUTTON') { + // Si c'est un input de pourcentage, on passe au suivant + if (e.target.classList.contains('input-pourcent')) { + e.preventDefault(); + // Déclencher l'événement input pour forcer le calcul + e.target.dispatchEvent(new Event('input', { bubbles: true })); + // Passer au champ suivant + const inputs = Array.from(document.querySelectorAll('.input-pourcent')).filter(inp => inp.offsetParent !== null); + const currentIndex = inputs.indexOf(e.target); + if (currentIndex >= 0 && currentIndex < inputs.length - 1) { + inputs[currentIndex + 1].focus(); + inputs[currentIndex + 1].select(); + } + } else { + // Pour les autres inputs, empêcher le submit mais permettre la navigation + e.preventDefault(); + } + } + }); + } + + document.getElementById('loadHistoriqueBtn').addEventListener('click', function () { + handleLoadHistoriqueBtn(); + }); + + resetInputs(); + + var radioButtonsCot = document.getElementsByName('cotisation'); + for (var i = 0; i < radioButtonsCot.length; i++) { + radioButtonsCot[i].addEventListener('change', function () { + if (this.value == "forfaitaire") { + document.getElementById("rowNbrVehicule").style.display = "block"; + document.getElementById("labelVoiturier").style.display = "block"; + document.getElementById("labelCommissionnaire").style.display = "none"; + document.getElementById("labelDemenageur").style.display = "block"; + document.getElementById("labelLogistique").style.display = "none"; + document.getElementById("labelAutocariste").style.display = "block"; + document.getElementById("labelAutres").style.display = "none"; + + document.getElementById("nbrVehicule").value = null; + + // Lancement du calcul forfaitaire + calcForfaitaire(); + } else if (this.value == "revisable") { + document.getElementById("rowNbrVehicule").style.display = "none"; + document.getElementById("labelVoiturier").style.display = "block"; + document.getElementById("labelCommissionnaire").style.display = "block"; + document.getElementById("labelDemenageur").style.display = "block"; + document.getElementById("labelLogistique").style.display = "block"; + document.getElementById("labelAutocariste").style.display = "none"; + document.getElementById("labelAutres").style.display = "block"; + + // Lancement du calcul revisable + calcRevisable(); + } + }); + }; + + document.getElementById('chiffreAffaire').addEventListener('input', function () { + const cot = document.querySelector('input[name="cotisation"]:checked')?.value; + + if (document.getElementById('chiffreAffaire').value.trim() == '') { + document.getElementById("modCA").style.display = "none"; + } else { + // Masquer modCA en forfaitaire car il n'est pas utilisé + if (cot === 'forfaitaire') { + document.getElementById("modCA").style.display = "none"; + } else { + document.getElementById("modCA").style.display = "block"; + } + } + + calcGlobal(); + // Validation conditionnelle : CA obligatoire seulement en revisable + if (typeof validateField === 'function') { + if (cot === 'revisable') { + validateField('chiffreAffaire', true); + } else { + // En forfaitaire, CA optionnel + validateField('chiffreAffaire', false); + } + } + if (document.getElementById('projetForm')) { + updateSubmitButtonState('projetForm'); + } + }); + + document.getElementById('nbrVehicule').addEventListener('input', function () { + // Validation : forcer entre 1 et 2 véhicules (comme ancienne plateforme) + let nbVeh = parseInt(this.value); + if (nbVeh < 1) { + this.value = 1; + } else if (nbVeh > 2) { + this.value = 2; + } else if (isNaN(nbVeh)) { + this.value = 1; + } + + calcGlobal(); + validateField('nbrVehicule', true); + if (document.getElementById('projetForm')) { + updateSubmitButtonState('projetForm'); + } + }); + + document.getElementById('sinistre').addEventListener('input', function () { + if (document.getElementById('sinistre').value.trim() == '') { + document.getElementById("modSinistre").style.display = "none"; + } else { + document.getElementById("modSinistre").style.display = "block"; + } + }); + + document.getElementById('checkRCE').addEventListener('click', function () { + var RCE = document.querySelectorAll('[name="RCE"]'); + + if (document.getElementById('checkRCE').checked == true) { + for (var i = 0; i < RCE.length; i++) { + RCE[i].style.display = "block"; + } + } else { + for (var i = 0; i < RCE.length; i++) { + RCE[i].style.display = "none"; + } + } + + calcGlobal(); + }); + + // Ajouter des styles dynamiques pour améliorer le feedback visuel + const style = document.createElement('style'); + style.textContent = ` + .input-pourcent:focus { + border-color: #1976d2 !important; + box-shadow: 0 0 8px rgba(25, 118, 210, 0.5) !important; + outline: none; + transform: scale(1.05); + transition: all 0.2s ease; + } + .input-pourcent:hover { + border-color: #5c6bc0 !important; + transition: all 0.2s ease; + } + .input-pourcent.set { + background-color: #e8f5e9 !important; + border-color: #4caf50 !important; + } + `; + document.head.appendChild(style); + + // Ajout d'un écouteur d'événement à chaque champ pourcentage + document.querySelectorAll('.input-pourcent').forEach(input => { + // Sélectionner automatiquement le contenu au focus pour faciliter la saisie + input.addEventListener('focus', function() { + this.select(); + }); + + // Validation automatique lors de la perte de focus (clic ailleurs) + input.addEventListener('blur', function() { + // Déclencher le recalcul si la valeur a changé + if (this.value !== this.defaultValue) { + this.dispatchEvent(new Event('input', { bubbles: true })); + } + }); + + input.addEventListener('input', function() { + // Récupérer l'ID de l'input modifié pour accéder à son isSet + const isSetInputId = 'isSet' + input.id.replace('pourcent', ''); + const isSetInput = document.getElementById(isSetInputId); + + // Mettre à jour isSet correspondant à true si l'input a une valeur + if (input.value != '') { + isSetInput.value = 'true'; + input.classList.add('set'); // Changer le fond + } else { + isSetInput.value = 'false'; // Réinitialiser isSet si l'input est vide + input.classList.remove('set'); // Remettre le fond d'origine + } + + // Réinitialiser les inputs non set à vide avant de recalculer + document.querySelectorAll('.input-pourcent').forEach(p => { + const correspondingIsSetInput = document.getElementById('isSet' + p.id.replace('pourcent', '')); + if (correspondingIsSetInput.value == 'false') { + p.value = ''; // Réinitialiser la valeur + } + }); + + // Calcul de la somme des pourcentages des champs actuellement modifiés + let totalPourcent = 0; + document.querySelectorAll('.input-pourcent').forEach(pourcentInput => { + if (pourcentInput.value != '' && pourcentInput.offsetParent != null) { + totalPourcent += toNumber(pourcentInput.value); + } + }); + + // PLAFONNEMENT STRICT À 100% + if (totalPourcent > 100) { + const excess = totalPourcent - 100; + + // Plafonnement : empêcher de dépasser + // Réduire la valeur qui vient d'être modifiée + const currentInputVal = toNumber(input.value); + const maxPossible = currentInputVal - excess; + + if (maxPossible >= 0) { + // Plafonner la valeur actuelle + input.value = maxPossible.toFixed(2); + totalPourcent = 100; + } else { + // La valeur est trop grande, la limiter au restant + const otherTotal = totalPourcent - currentInputVal; + input.value = (100 - otherTotal).toFixed(2); + totalPourcent = 100; + } + + // Afficher message d'avertissement visuel + showPercentageWarning(excess); + + // Masquer les primes pour montrer que c'est invalide + const allInputs = document.querySelectorAll('.input-pourcent'); + let finalTotal = 0; + allInputs.forEach(p => { + if (p.offsetParent != null) { + finalTotal += toNumber(p.value); + } + }); + + if (finalTotal > 100.01) { // Tolérance de 0.01 pour les arrondis + // BLOQUER les calculs - afficher erreur + hideAllPrimes(); + return; + } + } + + // Calcul de la différence à répartir + const remainingPourcent = 100 - totalPourcent; + + // Répartition de la différence sur les champs restants non marqués isSet + const nonModifiedInputs = Array.from(document.querySelectorAll('.input-pourcent')).filter(p => { + const correspondingIsSetInput = document.getElementById('isSet' + p.id.replace('pourcent', '')); + return p.value == '' && correspondingIsSetInput.value == 'false' && p.offsetParent != null; + }); + + // Vérifier si nous avons des inputs non modifiés pour répartir le pourcentage restant + if (remainingPourcent > 0 && nonModifiedInputs.length > 0) { + const pourcentToAdd = remainingPourcent / nonModifiedInputs.length; + + nonModifiedInputs.forEach(p => { + p.value = pourcentToAdd.toFixed(2); + }); + } else if (remainingPourcent > 0 && nonModifiedInputs.length === 0) { + // Tous les champs sont remplis mais total < 100 + // Trouver le dernier champ non-set et lui ajouter le restant + const allInputs = Array.from(document.querySelectorAll('.input-pourcent')).filter(p => p.offsetParent != null); + const lastNonSet = allInputs.filter(p => { + const correspondingIsSetInput = document.getElementById('isSet' + p.id.replace('pourcent', '')); + return correspondingIsSetInput.value == 'false'; + }).pop(); + + if (lastNonSet) { + const currentVal = toNumber(lastNonSet.value); + lastNonSet.value = (currentVal + remainingPourcent).toFixed(2); + } + } + + // Mettre à jour l'indicateur visuel du total + updatePercentageIndicator(totalPourcent); + + calcGlobal(); + }); + }); + + // Bouton reset de l'équilibrage pourcentage + document.getElementById('resetPourcent').addEventListener('click', function() { + resetInputs(); + updatePercentageIndicator(100); // Après reset = 100% + calcGlobal(); + }); + + document.getElementById('checkVoiturier').addEventListener('click', function () { + var actVoiturier = document.querySelectorAll('[name="actVoiturier/Loueur"]'); + var actComplVoiturier = document.querySelectorAll('[name="actComplVoiturier/Loueur"]'); + var marVoiturier = document.querySelectorAll('[name="marVoiturier/Loueur"]'); + + if (document.getElementById('checkVoiturier').checked == true) { + for (var i = 0; i < actVoiturier.length; i++) { + actVoiturier[i].style.display = "block"; + actComplVoiturier[i].style.display = "block"; + marVoiturier[i].style.display = "block"; + } + } else { + for (var i = 0; i < actVoiturier.length; i++) { + actVoiturier[i].style.display = "none"; + actComplVoiturier[i].style.display = "none"; + marVoiturier[i].style.display = "none"; + } + } + + // Reset de l'équilibrage pourcentage + resetInputs(); + updatePercentageIndicator(100); + calcGlobal(); + }); + + document.getElementById('checkCommissionnaire').addEventListener('click', function () { + var actCommissionnaire = document.querySelectorAll('[name="actCommissionnaire de Transport"]'); + var actComplCommissionnaire = document.querySelectorAll('[name="actComplCommissionnaire de Transport"]'); + var marCommissionnaire = document.querySelectorAll('[name="marCommissionnaire de Transport"]'); + + if (document.getElementById('checkCommissionnaire').checked == true) { + for (var i = 0; i < actCommissionnaire.length; i++) { + actCommissionnaire[i].style.display = "block"; + actComplCommissionnaire[i].style.display = "block"; + marCommissionnaire[i].style.display = "block"; + } + } else { + for (var i = 0; i < actCommissionnaire.length; i++) { + actCommissionnaire[i].style.display = "none"; + actComplCommissionnaire[i].style.display = "none"; + marCommissionnaire[i].style.display = "none"; + } + } + + // Reset de l'équilibrage pourcentage + resetInputs(); + updatePercentageIndicator(100); + calcGlobal(); + }); + + document.getElementById('checkDemenageur').addEventListener('click', function () { + var actDemenageur = document.querySelectorAll('[name="actDéménageur"]'); + var actComplDemenageur = document.querySelectorAll('[name="actComplDéménageur"]'); + var marDemenageur = document.querySelectorAll('[name="marDéménageur"]'); + + if (document.getElementById('checkDemenageur').checked == true) { + for (var i = 0; i < actDemenageur.length; i++) { + actDemenageur[i].style.display = "block"; + actComplDemenageur[i].style.display = "block"; + marDemenageur[i].style.display = "block"; + } + } else { + for (var i = 0; i < actDemenageur.length; i++) { + actDemenageur[i].style.display = "none"; + actComplDemenageur[i].style.display = "none"; + marDemenageur[i].style.display = "none"; + } + } + + // Reset de l'équilibrage pourcentage + resetInputs(); + updatePercentageIndicator(100); + calcGlobal(); + }); + + document.getElementById('checkLogistique').addEventListener('click', function () { + var actLogistique = document.querySelectorAll('[name="actLogistique"]'); + var actComplLogistique = document.querySelectorAll('[name="actComplLogistique"]'); + var marLogistique = document.querySelectorAll('[name="marLogistique"]'); + + if (document.getElementById('checkLogistique').checked == true) { + for (var i = 0; i < actLogistique.length; i++) { + actLogistique[i].style.display = "block"; + actComplLogistique[i].style.display = "block"; + marLogistique[i].style.display = "block"; + } + } else { + for (var i = 0; i < actLogistique.length; i++) { + actLogistique[i].style.display = "none"; + actComplLogistique[i].style.display = "none"; + marLogistique[i].style.display = "none"; + } + } + + // Reset de l'équilibrage pourcentage + resetInputs(); + updatePercentageIndicator(100); + calcGlobal(); + }); + + document.getElementById('checkAutocariste').addEventListener('click', function () { + var actAutocariste = document.querySelectorAll('[name="actAutocariste"]'); + var marAutocariste = document.querySelectorAll('[name="marAutocariste"]'); + + if (document.getElementById('checkAutocariste').checked == true) { + for (var i = 0; i < actAutocariste.length; i++) { + actAutocariste[i].style.display = "block"; + marAutocariste[i].style.display = "block"; + } + } else { + for (var i = 0; i < actAutocariste.length; i++) { + actAutocariste[i].style.display = "none"; + marAutocariste[i].style.display = "none"; + } + } + + // Reset de l'équilibrage pourcentage + resetInputs(); + updatePercentageIndicator(100); + calcGlobal(); + }); + + document.getElementById('checkAutres').addEventListener('click', function () { + var actAutres = document.querySelectorAll('[name="actAutres activites"]'); + var marAutres = document.querySelectorAll('[name="marAutres activites"]'); + + if (document.getElementById('checkAutres').checked == true) { + for (var i = 0; i < actAutres.length; i++) { + actAutres[i].style.display = "block"; + marAutres[i].style.display = "block"; + } + } else { + for (var i = 0; i < actAutres.length; i++) { + actAutres[i].style.display = "none"; + marAutres[i].style.display = "none"; + } + } + + // Reset de l'équilibrage pourcentage + resetInputs(); + updatePercentageIndicator(100); + calcGlobal(); + }); + + // Event listeners pour les inputs capital (au lieu de selects) + const capitalInputs = [ + 'selectActVoiturier/Loueur', + 'selectActCommissionnaire de Transport', + 'selectActDéménageur', + 'selectActLogistique', + 'selectActAutocariste', + 'selectActAutres activites' + ]; + + capitalInputs.forEach(name => { + const el = document.getElementsByName(name)[0]; + if (el) { + el.addEventListener('input', function() { + calcGlobal(); + }); + } + }); + + const checkboxesActComplVoiturier = document.querySelectorAll('div[name="actComplVoiturier/Loueur"] input[type="checkbox"]'); + checkboxesActComplVoiturier.forEach(checkbox => { + checkbox.addEventListener('change', function () { + calcGlobal(); + }); + }); + + const checkboxesActCompltComDeTransport = document.querySelectorAll('div[name="actComplCommissionnaire de Transport"] input[type="checkbox"]'); + checkboxesActCompltComDeTransport.forEach(checkbox => { + checkbox.addEventListener('change', function () { + calcGlobal(); + }); + }); + + const checkboxesActComplDem = document.querySelectorAll('div[name="actComplDéménageur"] input[type="checkbox"]'); + checkboxesActComplDem.forEach(checkbox => { + checkbox.addEventListener('change', function () { + calcGlobal(); + }); + }); + + const checkboxesActComplLogistique = document.querySelectorAll('div[name="actComplLogistique"] input[type="checkbox"]'); + checkboxesActComplLogistique.forEach(checkbox => { + checkbox.addEventListener('change', function () { + calcGlobal(); + }); + }); + + const checkboxesMarVoiturier = document.querySelectorAll('div[name="marVoiturier/Loueur"] input[type="checkbox"]'); + checkboxesMarVoiturier.forEach(checkbox => { + checkbox.addEventListener('change', function () { + calcGlobal(); + }); + }); + + const checkboxesMarComDeTransport = document.querySelectorAll('div[name="marCommissionnaire de Transport"] input[type="checkbox"]'); + checkboxesMarComDeTransport.forEach(checkbox => { + checkbox.addEventListener('change', function () { + calcGlobal(); + }); + }); + + const checkboxesMarDem = document.querySelectorAll('div[name="marDéménageur"] input[type="checkbox"]'); + checkboxesMarDem.forEach(checkbox => { + checkbox.addEventListener('change', function () { + calcGlobal(); + }); + }); + + const checkboxesMarLogistique = document.querySelectorAll('div[name="marLogistique"] input[type="checkbox"]'); + checkboxesMarLogistique.forEach(checkbox => { + checkbox.addEventListener('change', function () { + calcGlobal(); + }); + }); + + const checkboxesMarAutres = document.querySelectorAll('div[name="marAutres activites"] input[type="checkbox"]'); + checkboxesMarAutres.forEach(checkbox => { + checkbox.addEventListener('change', function () { + calcGlobal(); + }); + }); + + document.getElementById('btnMondeEntier').addEventListener('click', function () { + document.getElementById('zone1').checked = true; + document.getElementById('zone1').disabled = true; + document.getElementById('zone2').checked = true; + document.getElementById('zone2').disabled = true; + document.getElementById('zone3').checked = true; + document.getElementById('zone4').checked = true; + document.getElementById('zone5').checked = true; + document.getElementById('zone6').checked = true; + }); + + document.getElementById('btnReset').addEventListener('click', function () { + document.getElementById('zone1').checked = false; + document.getElementById('zone1').disabled = false; + document.getElementById('zone2').checked = false; + document.getElementById('zone2').disabled = false; + document.getElementById('zone3').checked = false; + document.getElementById('zone4').checked = false; + document.getElementById('zone5').checked = false; + document.getElementById('zone6').checked = false; + }); + + document.getElementById('btnZone1').addEventListener('click', function () { + const elem = document.getElementById('modalZone1'); + const instance = M.Modal.getInstance(elem); + instance.open(); + }); + + document.getElementById('btnZone2').addEventListener('click', function () { + const elem = document.getElementById('modalZone2'); + const instance = M.Modal.getInstance(elem); + instance.open(); + }); + + document.getElementById('btnZone3').addEventListener('click', function () { + const elem = document.getElementById('modalZone3'); + const instance = M.Modal.getInstance(elem); + instance.open(); + }); + + document.getElementById('btnZone4').addEventListener('click', function () { + const elem = document.getElementById('modalZone4'); + const instance = M.Modal.getInstance(elem); + instance.open(); + }); + + document.getElementById('btnZone5').addEventListener('click', function () { + const elem = document.getElementById('modalZone5'); + const instance = M.Modal.getInstance(elem); + instance.open(); + }); + + document.getElementById('btnZone6').addEventListener('click', function () { + const elem = document.getElementById('modalZone6'); + const instance = M.Modal.getInstance(elem); + instance.open(); + }); + + document.getElementById('btnZone7').addEventListener('click', function () { + const elem = document.getElementById('modalZoneExclus'); + const instance = M.Modal.getInstance(elem); + instance.open(); + }); + + document.getElementById('zone2').addEventListener('click', function () { + if (document.getElementById('zone2').checked == true) { + document.getElementById('zone1').checked = true; + document.getElementById('zone1').disabled = true; + } else if (document.getElementById('zone2').checked == false) { + document.getElementById('zone1').checked = true; + document.getElementById('zone1').disabled = false; + } + }); + + document.getElementById('zone3').addEventListener('click', function () { + if (document.getElementById('zone3').checked == true) { + document.getElementById('zone2').checked = true; + document.getElementById('zone1').checked = true; + document.getElementById('zone2').disabled = true; + document.getElementById('zone1').disabled = true; + } else if (document.getElementById('zone3').checked == false) { + document.getElementById('zone1').checked = true; + document.getElementById('zone1').disabled = true; + document.getElementById('zone2').checked = true; + document.getElementById('zone2').disabled = false; + } + }); + + // === Brancher toutes les cases zones sur calcGlobal === + document.querySelectorAll('input[id^="zone"]').forEach(cb => { + cb.addEventListener('change', calcGlobal); + }); + + // Dommages immatériels + document.getElementById('checkDomImmat').addEventListener('click', function () { + document.getElementById('selectDomImmat').style.display = this.checked ? "block" : "none"; + calcGlobal(); + }); + const inputDomImmat = document.getElementById('inputDomImmat'); + if (inputDomImmat) inputDomImmat.addEventListener('input', calcGlobal); + + // Contenants confiés + document.getElementById('checkContConf').addEventListener('click', function () { + document.getElementById('selectContConf').style.display = this.checked ? "block" : "none"; + calcGlobal(); + }); + const inputContConf = document.getElementById('inputContConf'); + if (inputContConf) inputContConf.addEventListener('input', calcGlobal); + + // Différence inventaire + document.getElementById('checkDiffInv').addEventListener('click', function () { + document.getElementById('selectDiffInv').style.display = this.checked ? "block" : "none"; + calcGlobal(); + }); + const inputDiffInv = document.getElementById('inputDiffInv'); + if (inputDiffInv) inputDiffInv.addEventListener('input', calcGlobal); + + // TPPC show/hide + recalc + const checkTPPC = document.getElementById('checkTPPC'); + const selectTPPC = document.getElementById('selectTPPC'); + + + + if (checkTPPC && selectTPPC) { + checkTPPC.addEventListener('click', function () { + console.log('TPPC checkbox clicked:', this.checked); + selectTPPC.style.display = this.checked ? "block" : "none"; + + if (!this.checked) { + // reset des valeurs si décoché + const cap = document.getElementById('selTPPCcapital'); + const veh = document.getElementById('selTPPCveh'); + if (cap) cap.value = ""; + if (veh) veh.value = ""; + } + + calcGlobal(); + }); + } else { + console.error('TPPC elements not found!', { checkTPPC, selectTPPC }); + } + + const inputTPPCcap = document.getElementById('selTPPCcapital'); + const inputTPPCveh = document.getElementById('selTPPCveh'); + if (inputTPPCcap) { + inputTPPCcap.addEventListener('input', calcGlobal); + console.log('TPPC capital input listener attached'); + } + if (inputTPPCveh) { + inputTPPCveh.addEventListener('input', calcGlobal); + console.log('TPPC véhicules input listener attached'); + } + + // Protection juridique + document.getElementById('checkPJ').addEventListener('click', calcGlobal); + + // RCE + document.getElementById('checkStationLavage').addEventListener('click', calcGlobal); + document.getElementById('checkGarageInterne').addEventListener('click', calcGlobal); + document.getElementById('checkCSE').addEventListener('click', calcGlobal); + // Dès que l’utilisateur tape ou modifie le champ sinistre, on recalcule + const elSin = document.getElementById('sinistre'); + if (elSin) { + elSin.addEventListener('input', () => { + console.log('[event] valeur sinistre modifiée =', elSin.value); + calcGlobal(); + }); + elSin.addEventListener('change', () => { + console.log('[event] valeur sinistre validée =', elSin.value); + calcGlobal(); + }); + } + + document.querySelectorAll('.franchise-card .btn').forEach(btn => { + btn.addEventListener('click', () => { + const selectedFr = btn.getAttribute('name'); // "250", "400", "mini300" + window.franchiseChoisie = selectedFr; + console.log('[tarifette] franchise choisie =', selectedFr); + document.querySelectorAll('.franchise-card').forEach(c => c.classList.remove('selected')); + btn.closest('.franchise-card').classList.add('selected'); + }); + }); + + // Event listeners pour les modals d'alerte + setupMarchandiseAlerts(); + setupActiviteAlerts(); + + // Event listener pour le bouton Valider du modal tarif commercial + document.getElementById('comm-OK').addEventListener('click', handleValidateTarifCom); + + // Le bouton Annuler ferme automatiquement le modal grâce à la classe "modal-close" + } + + // Peupler le formulaire avec les données + function populateFormData() { + //Poupulate select historique + if (!contrat.historique) { + document.getElementById('historiqueDiv').style.display = "none"; + } else { + document.getElementById('historiqueDiv').style.display = "block"; + + const idSelect = document.getElementById('idSelect'); + + contrat.historique.forEach(function (item) { + var option = document.createElement('option'); + option.value = item.id; + option.textContent = item.type + " " + item.produit + " - " + item.date + " - " + item.heure; + + if (item.nom != undefined && item.prenom != undefined) { + option.textContent += " - " + item.nom + " " + item.prenom; + } + + idSelect.appendChild(option); + }); + + M.FormSelect.init(idSelect); + } + + // ===== PRÉ-REMPLIR LE FORMULAIRE AVEC LES DONNÉES RC DE LA BASE ===== + if (!rc) { + console.log('Aucune donnée RC à pré-remplir'); + return; + } + + console.log('🔄 Pré-remplissage du formulaire tarif avec les données RC:', rc); + + // Type de cotisation + if (rc.typeCotisation) { + const radioBtn = document.getElementById(rc.typeCotisation); + if (radioBtn) { + radioBtn.checked = true; + radioBtn.dispatchEvent(new Event('change')); + } + } + + // Chiffre d'affaires et nombre de véhicules + const caField = getElementByIdFlexible('CA') || getElementByIdFlexible('chiffreAffaire'); + if (rc.chiffreAffaires && caField) caField.value = rc.chiffreAffaires; + + const nbVehiculeField = getElementByIdFlexible('nbVehicules') || getElementByIdFlexible('nbrVehicule'); + if (rc.nombreVehicules && nbVehiculeField) nbVehiculeField.value = rc.nombreVehicules; + + // Sinistralité (depuis tarifRC) + if (tarif && tarif.sinistre) { + document.getElementById('sinistre').value = tarif.sinistre; + } + + // Checkbox RCE + if (rc.checkRCE !== undefined) { + document.getElementById('checkRCE').checked = rc.checkRCE; + document.getElementById('checkRCE').dispatchEvent(new Event('click')); + } + + // Activité Voiturier/Loueur + if (rc.checkVoiturier !== undefined) { + const checkVoiturierEl = getElementByIdFlexible('checkVoiturier'); + if (checkVoiturierEl) { + checkVoiturierEl.checked = rc.checkVoiturier; + const capitalVoiturierEl = getElementByIdFlexible('capitalVoiturier') || document.querySelector('input[name="selectActVoiturier/Loueur"]'); + if (rc.capitalVoiturier && capitalVoiturierEl) capitalVoiturierEl.value = rc.capitalVoiturier; + checkVoiturierEl.dispatchEvent(new Event('click')); + } + } + + // Activité Commissionnaire + if (rc.checkCommissionnaire !== undefined) { + const checkCommissionnaireEl = getElementByIdFlexible('checkCommissionnaire'); + if (checkCommissionnaireEl) { + checkCommissionnaireEl.checked = rc.checkCommissionnaire; + const capitalCommissionnaireEl = getElementByIdFlexible('capitalCommissionnaire') || document.querySelector('input[name="selectActCommissionnaire de Transport"]') || document.querySelector('input[name="selectActCommissionnaireDeTransport"]'); + if (rc.capitalCommissionnaire && capitalCommissionnaireEl) capitalCommissionnaireEl.value = rc.capitalCommissionnaire; + checkCommissionnaireEl.dispatchEvent(new Event('click')); + } + } + + // Activité Déménageur + if (rc.checkDemenageur !== undefined) { + const checkDemenageurEl = getElementByIdFlexible('checkDemenageur'); + if (checkDemenageurEl) { + checkDemenageurEl.checked = rc.checkDemenageur; + const capitalDemenageurEl = getElementByIdFlexible('capitalDemenageur') || document.querySelector('input[name="selectActDéménageur"]') || document.querySelector('input[name="selectActDemenageur"]'); + if (rc.capitalDemenageur && capitalDemenageurEl) capitalDemenageurEl.value = rc.capitalDemenageur; + checkDemenageurEl.dispatchEvent(new Event('click')); + } + } + + // Activité Logistique + if (rc.checkLogistique !== undefined) { + const checkLogistiqueEl = getElementByIdFlexible('checkLogistique'); + if (checkLogistiqueEl) { + checkLogistiqueEl.checked = rc.checkLogistique; + const capitalLogistiqueEl = getElementByIdFlexible('capitalLogistique') || document.querySelector('input[name="selectActLogistique"]'); + if (rc.capitalLogistique && capitalLogistiqueEl) capitalLogistiqueEl.value = rc.capitalLogistique; + checkLogistiqueEl.dispatchEvent(new Event('click')); + } + } + + // Activité Autocariste + if (rc.checkAutocariste !== undefined) { + const checkAutocaristeEl = getElementByIdFlexible('checkAutocariste'); + if (checkAutocaristeEl) { + checkAutocaristeEl.checked = rc.checkAutocariste; + const capitalAutocaristeEl = getElementByIdFlexible('capitalAutocariste') || document.querySelector('input[name="selectActAutocariste"]'); + if (rc.capitalAutocariste && capitalAutocaristeEl) capitalAutocaristeEl.value = rc.capitalAutocariste; + checkAutocaristeEl.dispatchEvent(new Event('click')); + } + } + + // Activité Autres + if (rc.checkAutres !== undefined) { + const checkAutresEl = getElementByIdFlexible('checkAutres'); + if (checkAutresEl) { + checkAutresEl.checked = rc.checkAutres; + const capitalAutresEl = getElementByIdFlexible('capitalAutres') || document.querySelector('input[name="selectActAutres activites"]') || document.querySelector('input[name="selectActAutresActivites"]'); + if (rc.capitalAutres && capitalAutresEl) capitalAutresEl.value = rc.capitalAutres; + checkAutresEl.dispatchEvent(new Event('click')); + } + } + + // Zones géographiques + if (rc.zone1) document.getElementById('zone1').checked = rc.zone1; + if (rc.zone2) document.getElementById('zone2').checked = rc.zone2; + if (rc.zone3) document.getElementById('zone3').checked = rc.zone3; + if (rc.zone4) document.getElementById('zone4').checked = rc.zone4; + if (rc.zone5) document.getElementById('zone5').checked = rc.zone5; + if (rc.zone6) document.getElementById('zone6').checked = rc.zone6; + + // Pré-remplir les activités complémentaires (JSON) pour TOUTES les activités + const activitiesTypes = [ + { field: 'actComplVoiturier', name: 'actComplVoiturier/Loueur' }, + { field: 'actComplCommissionnaire', name: 'actComplCommissionnaire de Transport' }, + { field: 'actComplDemenageur', name: 'actComplDéménageur' }, + { field: 'actComplLogistique', name: 'actComplLogistique' } + ]; + + console.log('🔄 Pré-remplissage des activités complémentaires...'); + activitiesTypes.forEach(({ field, name }) => { + // D'abord DÉCOCHER toutes les checkboxes de cette activité + const allCheckboxes = document.querySelectorAll(`[name="${name}"] input[type="checkbox"]`); + allCheckboxes.forEach(cb => cb.checked = false); + + if (rc[field]) { + try { + // PocketBase parse automatiquement les champs JSON, donc rc[field] est déjà un array + const activites = Array.isArray(rc[field]) ? rc[field] : JSON.parse(rc[field]); + console.log(` ✓ ${field}:`, activites); + activites.forEach(actText => { + // Chercher la checkbox dont le span adjacent contient ce texte + allCheckboxes.forEach(cb => { + const label = cb.nextElementSibling?.textContent.trim(); + if (label === actText) { + cb.checked = true; + console.log(` ✓ Coché: ${actText}`); + } + }); + }); + } catch (e) { console.error(`❌ Erreur parsing ${field}:`, e); } + } + }); + + // Pré-remplir les marchandises (JSON) pour TOUTES les activités + const marchandisesTypes = [ + { field: 'marchandisesVoiturier', name: 'marVoiturier/Loueur' }, + { field: 'marchandisesCommissionnaire', name: 'marCommissionnaire de Transport' }, + { field: 'marchandisesDemenageur', name: 'marDéménageur' }, + { field: 'marchandisesLogistique', name: 'marLogistique' }, + { field: 'marchandisesAutocariste', name: 'marAutocariste' }, + { field: 'marchandisesAutres', name: 'marAutres activites' } + ]; + + console.log('🔄 Pré-remplissage des marchandises...'); + marchandisesTypes.forEach(({ field, name }) => { + // D'abord DÉCOCHER toutes les checkboxes de cette marchandise + const allCheckboxes = document.querySelectorAll(`[name="${name}"] input[type="checkbox"]`); + allCheckboxes.forEach(cb => cb.checked = false); + + if (rc[field]) { + try { + // PocketBase parse automatiquement les champs JSON, donc rc[field] est déjà un array + const marchandises = Array.isArray(rc[field]) ? rc[field] : JSON.parse(rc[field]); + console.log(` ✓ ${field}:`, marchandises); + marchandises.forEach(marText => { + // Chercher la checkbox dont le span adjacent contient ce texte + allCheckboxes.forEach(cb => { + const label = cb.nextElementSibling?.textContent.trim(); + if (label === marText) { + cb.checked = true; + console.log(` ✓ Coché: ${marText}`); + } + }); + }); + } catch (e) { console.error(`❌ Erreur parsing ${field}:`, e); } + } + }); + + // Pré-remplir les pourcentages (depuis tarifRC) + // Préférer l'objet tarif si présent, sinon retomber sur l'expansion RC + const tarifSource = tarif || rc?.["@expand"]?.tarifRC || rc?.tarifRC || rc || null; + // Fallback ultime : données de session (hook RC orchestrator) si tout est vide + let sessionTarifData = null; + try { + const stored = sessionStorage.getItem('rc_tarif_validated_data'); + sessionTarifData = stored ? JSON.parse(stored) : null; + } catch (e) { + sessionTarifData = null; + } + if (tarifSource || sessionTarifData) { + const pctVoiturierEl = getElementByIdFlexible('pourcent_voiturier') || getElementByIdFlexible('pourcentVoiturier/Loueur'); + if (tarifSource?.pourcentageVoiturier && pctVoiturierEl) pctVoiturierEl.value = tarifSource.pourcentageVoiturier; + + const pctCommissionnaireEl = getElementByIdFlexible('pourcent_commissionnaire') || getElementByIdFlexible('pourcentCommissionnaire de Transport') || getElementByIdFlexible('pourcentCommissionnaireDeTransport'); + if (tarifSource?.pourcentageCommissionnaire && pctCommissionnaireEl) pctCommissionnaireEl.value = tarifSource.pourcentageCommissionnaire; + + const pctDemenageurEl = getElementByIdFlexible('pourcent_demenageur') || getElementByIdFlexible('pourcentDéménageur') || getElementByIdFlexible('pourcentDemenageur'); + if (tarifSource?.pourcentageDemenageur && pctDemenageurEl) pctDemenageurEl.value = tarifSource.pourcentageDemenageur; + + const pctLogistiqueEl = getElementByIdFlexible('pourcent_logistique') || getElementByIdFlexible('pourcentLogistique'); + if (tarifSource?.pourcentageLogistique && pctLogistiqueEl) pctLogistiqueEl.value = tarifSource.pourcentageLogistique; + + const pctAutocaristeEl = getElementByIdFlexible('pourcent_autocariste') || getElementByIdFlexible('pourcentAutocariste'); + if (tarifSource?.pourcentageAutocariste && pctAutocaristeEl) pctAutocaristeEl.value = tarifSource.pourcentageAutocariste; + + const pctAutresEl = getElementByIdFlexible('pourcent_autres') || getElementByIdFlexible('pourcentAutres activites') || getElementByIdFlexible('pourcentAutresActivites'); + if (tarifSource?.pourcentageAutres && pctAutresEl) pctAutresEl.value = tarifSource.pourcentageAutres; + + // ===== ENGAGEMENTS COMPLÉMENTAIRES (depuis tarifRC) ===== + // Dommages immatériels + const engagementSrc = tarifSource || sessionTarifData?.engagementsComplementaires; + if (tarifSource?.checkDomImmat || engagementSrc?.domicileImmatriculation?.checked) { + document.getElementById('checkDomImmat').checked = true; + document.getElementById('selectDomImmat').style.display = 'block'; + const cap = tarifSource?.capitalDomImmat ?? engagementSrc?.domicileImmatriculation?.capital; + if (cap) { + document.getElementById('inputDomImmat').value = cap; + } + } + + // Contenants confiés + if (tarifSource?.checkContConf || engagementSrc?.contenantConfie?.checked) { + document.getElementById('checkContConf').checked = true; + document.getElementById('selectContConf').style.display = 'block'; + const cap = tarifSource?.capitalContConf ?? engagementSrc?.contenantConfie?.capital; + if (cap) { + document.getElementById('inputContConf').value = cap; + } + } + + // Différence inventaire + if (tarifSource?.checkDiffInv || engagementSrc?.differenceInventaire?.checked) { + document.getElementById('checkDiffInv').checked = true; + document.getElementById('selectDiffInv').style.display = 'block'; + const cap = tarifSource?.capitalDiffInv ?? engagementSrc?.differenceInventaire?.capital; + if (cap) { + document.getElementById('inputDiffInv').value = cap; + } + } + + // ===== GARANTIES ADDITIONNELLES (depuis tarifRC) ===== + // TPPC + const garantiesSrc = tarifSource || sessionTarifData?.garantiesAdditionnelles; + if (tarifSource?.checkTPPC || garantiesSrc?.tppc?.checked) { + document.getElementById('checkTPPC').checked = true; + document.getElementById('selectTPPC').style.display = 'block'; + const cap = tarifSource?.capitalTPPC ?? garantiesSrc?.tppc?.capital; + if (cap) { + document.getElementById('selTPPCcapital').value = cap; + } + const veh = tarifSource?.vehiculesTPPC ?? garantiesSrc?.tppc?.vehicules; + if (veh) { + document.getElementById('selTPPCveh').value = veh; + } + } + + // Protection juridique + if (tarifSource?.checkPJ || garantiesSrc?.pj) { + document.getElementById('checkPJ').checked = true; + } + + // RCE - Station lavage + if (tarifSource?.checkStationLavage || garantiesSrc?.stationLavage) { + document.getElementById('checkStationLavage').checked = true; + } + + // RCE - Garage interne + if (tarifSource?.checkGarageInterne || garantiesSrc?.garageInterne) { + document.getElementById('checkGarageInterne').checked = true; + } + + // RCE - CSE + if (tarifSource?.checkCSE || garantiesSrc?.cse) { + document.getElementById('checkCSE').checked = true; + } + + // ===== FRANCHISE CHOISIE ===== + if (tarifSource?.franchiseChoisie) { + window.franchiseChoisie = tarifSource.franchiseChoisie; + // Mettre en surbrillance la carte sélectionnée + const selectedButton = document.querySelector(`.franchise-card button[name="${tarifSource.franchiseChoisie}"]`); + if (selectedButton) { + selectedButton.closest('.franchise-card').classList.add('selected'); + } + } + } + + console.log('✅ Formulaire tarif pré-rempli avec succès'); + + // Recalculer après pré-remplissage + setTimeout(() => { + calcGlobal(); + }, 500); + } + + function calcModCA(caRaw){ + const ca = Number(String(caRaw || '').replace(/\s/g,'').replace(',','.')) || 0; + const thresholds = Object.keys(modRCCA).map(n => Number(n)).sort((a,b)=>a-b); + for (const t of thresholds) if (ca < t) return modRCCA[t]; + return modRCCA[thresholds.at(-1)] ?? 1; + } + + function calcModMarchandises(data, activityName, type, cot) { + let m = 1; + + // On cible le bloc correspondant à l'activité + const container = document.querySelector(`[name="mar${activityName}"]`); + if (!container) return 1; + + // On récupère toutes les cases à cocher de ce bloc + const checkboxes = container.querySelectorAll('input[type="checkbox"]'); + + checkboxes.forEach(cb => { + if (cb.checked) { + // Le libellé affiché est dans le juste après l'input + const label = cb.nextElementSibling?.innerText.trim(); + + // On simplifie le libellé pour matcher les clés du JSON + let key = null; + if (label.includes("ordinaires")) key = "Marchandises ordinaires"; + else if (label.includes("Véhicules roulants")) key = "Véhicules roulants"; + else if (label.includes("Engins de chantier")) key = "Engins de chantier"; + else if (label.includes("Mobiliers")) key = "Mobiliers en déménagement"; + else if (label.includes("périssables")) key = "Marchandises périssables"; + else if (label.includes("citerne")) key = "Marchandises en citerne"; + else if (label.includes("Animaux")) key = "Animaux vivants"; + else if (label.includes("benne")) key = "Marchandises en benne"; + else if (label.includes("béton")) key = "Transport de béton"; + + if (key) { + const v = data?.[cot]?.[activityName]?.[key]?.[`mod${type}`]; + if (typeof v === "number") { + m *= v; + } else { + console.warn(`Pas de mod trouvé pour activité=${activityName}, clé=${key}, type=${type}, cot=${cot}`); + } + } else { + console.warn(`Libellé non reconnu: "${label}"`); + } + } + }); + + return m; + } + + function getZoneMods(data) { + let mRCC = 1; + let mRCE = 1; + + // On parcourt toutes les cases à cocher de zones + for (let i = 1; i <= 6; i++) { + const cb = document.getElementById(`zone${i}`); + if (cb && cb.checked) { + // Récupérer le libellé affiché + const label = document.getElementById(`zone${i}-text`).innerText.trim(); + + // Trouver la clé correspondante dans le JSON + let key = null; + if (label.includes("France Métropolitaine")) key = "France Métropolitaine et pays limitrophes"; + else if (label.includes("Union Européenne")) key = "Union Européenne"; + else if (label.includes("Autres pays européens")) key = "Autres pays européens sauf Russie et Ukraine (y compris UK et Norvège)"; + else if (label.includes("Maghreb") || label.includes("Amérique du Nord")) key = "Pays du Maghreb et Amérique du Nord ( USA / Canada / Mexique )"; + else if (label.includes("Amérique Centrale") || label.includes("Asie") || label.includes("Océanie")) key = "Amérique Centrale et Sud / Caraïbes, Asie et Océanie"; + else if (label.includes("Afrique") || label.includes("Moyen Orient")) key = "Afrique Hors Maghreb / Proche Orient / Moyen Orient"; + + if (key && data[key]) { + const zone = data[key]; + if (typeof zone.modRCC === "number") mRCC = Math.max(mRCC, zone.modRCC); + if (typeof zone.modRCE === "number") mRCE = Math.max(mRCE, zone.modRCE); + } + } + } + + return { mRCC, mRCE }; +} + + function calcModActCompl(data, activityName, type, cot) { + let m = 1; + const current = getSelectedActivities().find(a => a.typeActivite === activityName); + if (!current) return 1; + const table = data?.[cot]?.[activityName] || {}; + (current.listActComplChecked||[]).forEach(name => { + const v = table[name]?.[`mod${type}`]; + if (typeof v === "number") m *= v; + }); + return m; + } + + function calcEngagCompl(data, primeRCC) { + let prime = primeRCC; + let surPrime = 0; + let modDommImmat = 1; + let infos = []; + + function writeToCard(inputId, message) { + const inputEl = document.getElementById(inputId); + if (!inputEl) return; + + const cardContent = inputEl.closest('.card-content'); + if (!cardContent) return; + + // Supprime l’ancien wrapper pour cet input + cardContent.querySelectorAll(`div.chip[data-for="${inputId}"]`).forEach(el => el.remove()); + + if (!message) return; + + // Wrapper + const wrapper = document.createElement("div"); + wrapper.classList.add("chip"); // uniquement "chip" + wrapper.dataset.for = inputId; + + // Message + const p = document.createElement("p"); + p.dataset.for = inputId; + p.classList.add("helper-text", "red-text"); + p.style.display = "block"; // override helper-text { display: none; } + p.textContent = message; + + wrapper.appendChild(p); + cardContent.appendChild(wrapper); + } + + + + + + + + // === Contenants confiés === + const checkContConf = document.getElementById('checkContConf'); + const inputContConf = document.getElementById('inputContConf'); + if (checkContConf?.checked) { + const val = toNumber(inputContConf?.value); + if (val > 0) { + const tranches = Object.keys(data.modRCC["Contenants confiés"]).map(Number).sort((a,b)=>a-b); + const tranche = findClosestTranche(val, tranches); + const add = data.modRCC["Contenants confiés"][tranche]; + if (typeof add === "number") { + surPrime += add; + const msg = `Prime RCC : +${add.toLocaleString('fr-FR',{style:'currency',currency:'EUR'})}`; + //infos.push(msg); pour ajouter le message dans la div "Prime RCC" + writeToCard('inputContConf', msg); + } + } + } else { + writeToCard('inputContConf', null); // supprime si décoché + } + + // === Différence inventaire === + const checkDiffInv = document.getElementById('checkDiffInv'); + const inputDiffInv = document.getElementById('inputDiffInv'); + if (checkDiffInv?.checked) { + const val = toNumber(inputDiffInv?.value); + if (val > 0) { + const tranches = Object.keys(data.modRCC["Différence inventaire"]).map(Number).sort((a,b)=>a-b); + const tranche = findClosestTranche(val, tranches); + const add = data.modRCC["Différence inventaire"][tranche]; + if (typeof add === "number") { + surPrime += add; + const msg = `Prime RCC : +${add.toLocaleString('fr-FR',{style:'currency',currency:'EUR'})}`; + //infos.push(msg); pour ajouter le message dans la div "Prime RCC" + writeToCard('inputDiffInv', msg); + } + } + } else { + writeToCard('inputDiffInv', null); + } + + // === Dommages immatériels === + const checkDomImmat = document.getElementById('checkDomImmat'); + const inputDomImmat = document.getElementById('inputDomImmat'); + if (checkDomImmat?.checked) { + const val = toNumber(inputDomImmat?.value); + if (val > 0) { + const tranches = Object.keys(data.modRCC["Dommages immatériels"]).map(Number).sort((a,b)=>a-b); + const tranche = findClosestTranche(val, tranches); + const mod = data.modRCC["Dommages immatériels"][tranche]; + if (typeof mod === "number") { + modDommImmat = mod; + const msg = `Mod Taux RCC : ×${mod}`; + //infos.push(msg); pour ajouter le message dans la div "Prime RCC" + writeToCard('inputDomImmat', msg); + } + } + } else { + writeToCard('inputDomImmat', null); + } + + // === Totaux === + prime += surPrime; + prime *= modDommImmat; + + return { prime, surPrime, infos }; + } + + // Fonction helper : trouver la tranche la plus proche + function findClosestTranche(val, tranches) { + if (val <= tranches[0]) return tranches[0]; + if (val >= tranches[tranches.length - 1]) return tranches[tranches.length - 1]; + + for (let i = 0; i < tranches.length - 1; i++) { + if (val >= tranches[i] && val < tranches[i + 1]) { + // Prendre la tranche inférieure ou égale + return tranches[i]; + } + } + return tranches[tranches.length - 1]; + } + + // Fonction pour afficher un avertissement visuel de dépassement % + function showPercentageWarning(excess) { + // Créer ou récupérer le div d'avertissement + let warningDiv = document.getElementById('percentageWarning'); + if (!warningDiv) { + warningDiv = document.createElement('div'); + warningDiv.id = 'percentageWarning'; + warningDiv.style.cssText = ` + position: fixed; + top: 20px; + right: 20px; + background: #f44336; + color: white; + padding: 15px 25px; + border-radius: 5px; + box-shadow: 0 4px 6px rgba(0,0,0,0.3); + z-index: 9999; + font-weight: bold; + animation: slideIn 0.3s ease; + `; + document.body.appendChild(warningDiv); + } + + warningDiv.innerHTML = `Vous dépassez 100% (vous dépassiez de ${excess.toFixed(1)}%)`; + warningDiv.style.display = 'block'; + + // Masquer après 3 secondes + setTimeout(() => { + warningDiv.style.display = 'none'; + }, 3000); + } + + // Fonction pour masquer toutes les primes (quand % invalide) + function hideAllPrimes() { + const primeElements = [ + 'primeChapActRCC', 'primeChapActRCE', + 'primeChapActComplRCC', 'primeChapActComplRCE', + 'primeChapMarchRCC', 'primeChapMarchRCE', + 'primeChapZonesRCC', 'primeChapZonesRCE', + 'primeEngValue', 'primeChapGarAddRCC', 'primeChapGarAddRCE', + 'priceFr250', 'priceFr400', 'priceFr2000' + ]; + + primeElements.forEach(id => { + const el = document.getElementById(id); + if (el) { + el.innerHTML = ' % invalide (> 100%)'; + } + }); + } + + // Fonction pour afficher toutes les primes (quand % valide) + function showAllPrimes() { + } + + // Fonction pour mettre à jour l'indicateur visuel du total des pourcentages + function updatePercentageIndicator(total) { + const indicator = document.getElementById('pourcentageTotal'); + if (!indicator) return; + + const displayTotal = total.toFixed(1); + indicator.textContent = `Total : ${displayTotal}%`; + + // Changer la couleur selon le total + if (total > 100) { + // ROUGE : Dépassement - INVALIDE + indicator.style.background = '#f44336'; + indicator.style.color = 'white'; + indicator.style.border = '3px solid #c62828'; + indicator.style.animation = 'pulse 1s infinite'; + } else if (total === 100 || Math.abs(total - 100) < 0.1) { + // VERT : Parfait - 100% + indicator.style.background = '#4caf50'; + indicator.style.color = 'white'; + indicator.style.border = '3px solid #2e7d32'; + indicator.style.animation = 'none'; + } else if (total >= 95) { + // ORANGE : Proche de 100% + indicator.style.background = '#ff9800'; + indicator.style.color = 'white'; + indicator.style.border = '3px solid #ef6c00'; + indicator.style.animation = 'none'; + } else { + // BLEU : En cours de saisie + indicator.style.background = 'white'; + indicator.style.color = 'darkblue'; + indicator.style.border = '2px solid darkblue'; + indicator.style.animation = 'none'; + } + } + + function calcGarAdd(data, primeRCC, primeRCE) { + let primeRCCres = Number(primeRCC) || 0; + let primeRCEres = Number(primeRCE) || 0; + let surPrimeRCE = 0; + const infosRCC = []; + const infosRCE = []; + + function writeToCard(inputId, message) { + const inputEl = document.getElementById(inputId); + if (!inputEl) return; + + const cardContent = inputEl.closest('.card-content'); + if (!cardContent) return; + + // Supprime l’ancien wrapper pour cet input + cardContent.querySelectorAll(`div.chip[data-for="${inputId}"]`).forEach(el => el.remove()); + + if (!message) return; + + // Wrapper + const wrapper = document.createElement("div"); + wrapper.classList.add("chip"); + wrapper.dataset.for = inputId; + + // Style : occupe sa propre ligne mais largeur adaptée au contenu + wrapper.style.display = "table"; // se comporte comme un bloc centré sur son contenu + wrapper.style.margin = "8px auto"; // centre horizontalement + + // Message + const p = document.createElement("p"); + p.dataset.for = inputId; + p.classList.add("helper-text", "red-text"); + p.style.display = "block"; // override helper-text { display: none; } + p.textContent = message; + + wrapper.appendChild(p); + cardContent.appendChild(wrapper); + } + + + + + + + // === Station de lavage (RCE forfait) === + const checkStation = document.getElementById('checkStationLavage'); + if (checkStation?.checked) { + const add = data.modRCE["Station de lavage"]; + if (typeof add === "number") { + surPrimeRCE += add; + const msg = `Prime RCE : +${add.toLocaleString('fr-FR', { style:'currency', currency:'EUR' })}`; + //infosRCE.push(msg); + writeToCard('checkStationLavage', msg); + } + } else { + writeToCard('checkStationLavage', null); + } + + // === Garage interne (RCE forfait) === + const checkGarage = document.getElementById('checkGarageInterne'); + if (checkGarage?.checked) { + const add = data.modRCE["Garage interne"]; + if (typeof add === "number") { + surPrimeRCE += add; + const msg = `Prime RCE : +${add.toLocaleString('fr-FR', { style:'currency', currency:'EUR' })}`; + //infosRCE.push(msg); + writeToCard('checkGarageInterne', msg); + } + } else { + writeToCard('checkGarageInterne', null); + } + + // === Comité Social et Economique (RCE forfait) === + const checkCSE = document.getElementById('checkCSE'); + if (checkCSE?.checked) { + const add = data.modRCE["Comité Social et Economique"]; + if (typeof add === "number") { + surPrimeRCE += add; + const msg = `Prime RCE : +${add.toLocaleString('fr-FR', { style:'currency', currency:'EUR' })}`; + //infosRCE.push(msg); + writeToCard('checkCSE', msg); + } + } else { + writeToCard('checkCSE', null); + } + + // === Addition des garanties RCE === + primeRCEres += surPrimeRCE; + + return { primeRCC: primeRCCres, primeRCE: primeRCEres, surPrimeRCE, infosRCC, infosRCE }; + } + + + + function calcSinistre(data, primeRCC, primeRCE) { + console.log('[calcSinistre] start', { primeRCC, primeRCE }); + + let primeRCCres = Number(primeRCC) || 0; + let primeRCEres = Number(primeRCE) || 0; + let mod = 1; + + const elSin = document.getElementById('sinistre'); + const elCA = document.getElementById('chiffreAffaire'); + const chip = document.getElementById('modSinistre'); + + if (!elSin || !elCA) { + console.warn('[calcSinistre] Missing #sinistre or #chiffreAffaire'); + } else { + const sinistreVal = toNumber(elSin.value); + const CA = toNumber(elCA.value); + + console.log('[calcSinistre] inputs', { sinistreVal, CA }); + + if (CA > 0 && sinistreVal >= 0) { + const ratio = sinistreVal / CA; + let key = 0.4; + if (ratio <= 0.4) key = 0.4; + else if (ratio <= 0.7) key = 0.7; + else key = 1; + + mod = data[key]; + console.log('[calcSinistre] ratio=', ratio.toFixed(3), 'key=', key, 'mod=', mod); + } else { + console.log('[calcSinistre] CA <= 0 or sinistre < 0 -> mod=1'); + } + } + + // Apply modulation to both RCC and RCE + primeRCCres *= mod; + primeRCEres *= mod; + + if (chip) { + chip.style.display = 'block'; + chip.innerHTML = 'Modulation sinistre :
x ' + mod.toLocaleString('fr-FR', { minimumFractionDigits: 2 }); + } else { + console.warn('[calcSinistre] #modSinistre not found'); + } + + console.log('[calcSinistre] result', { primeRCC: primeRCCres, primeRCE: primeRCEres, mod }); + return { primeRCC: primeRCCres, primeRCE: primeRCEres, mod }; + } + + + // --- Fonctions utilitaires --- + + function getMaxMiniRCC(activites, cot) { + let maxMini = 0; + activites.forEach(act => { + // Récupérer l'input/select pour cette activité + const inputEl = document.querySelector(`input[name="selectAct${act}"], select[name="selectAct${act}"]`); + if (!inputEl) return; + + const capitalSaisi = toNumber(inputEl.value); + if (capitalSaisi <= 0) return; + + // Déterminer le type de cotisation + const cotType = cot === 'revisable' ? 'revisable' : 'forfaitaire'; + + // Trouver la tranche la plus proche + const grilleAct = modRCPrimeMini?.[cotType]?.[act]; + if (grilleAct) { + const tranches = Object.keys(grilleAct).map(Number).sort((a,b)=>a-b); + const tranche = findClosestTranche(capitalSaisi, tranches); + const miniData = grilleAct[tranche]; + + if (miniData && typeof miniData.miniRCC === 'number') { + maxMini = Math.max(maxMini, miniData.miniRCC); + } + } + }); + return maxMini; + } + + function getMaxMiniRCE(activites, cot) { + let maxMini = 0; + activites.forEach(act => { + // Récupérer l'input/select pour cette activité + const inputEl = document.querySelector(`input[name="selectAct${act}"], select[name="selectAct${act}"]`); + if (!inputEl) return; + + const capitalSaisi = toNumber(inputEl.value); + if (capitalSaisi <= 0) return; + + // Déterminer le type de cotisation + const cotType = cot === 'revisable' ? 'revisable' : 'forfaitaire'; + + // Trouver la tranche la plus proche + const grilleAct = modRCPrimeMini?.[cotType]?.[act]; + if (grilleAct) { + const tranches = Object.keys(grilleAct).map(Number).sort((a,b)=>a-b); + const tranche = findClosestTranche(capitalSaisi, tranches); + const miniData = grilleAct[tranche]; + + if (miniData && typeof miniData.miniRCE === 'number') { + maxMini = Math.max(maxMini, miniData.miniRCE); + } + } + }); + return maxMini; + } + + + function calcTarifRCC({ + CA, + primeRCCbase, + primeRCEbase, + capitalTPPC, + nbVehicules, + coefTPPC, + franchiseCoef, + primeMini + }) { + // --- Prime RCC avec franchise --- + let primeFranchiseRCC = Number(primeRCCbase) * Number(franchiseCoef.modRCC || 1); + let primeFranchiseRCE = Number(primeRCEbase) * Number(franchiseCoef.modRCE || 1); + + // --- Ajout TPPC APRÈS franchise --- + const primeTPPC = capitalTPPC * nbVehicules * coefTPPC; + primeFranchiseRCC = primeFranchiseRCC + primeTPPC; + + // --- Calcul taux AVANT minima --- + let tauxRCC = CA > 0 ? (primeFranchiseRCC * 100 / CA).toFixed(2) : "0.00"; + let tauxRCE = CA > 0 ? (primeFranchiseRCE * 100 / CA).toFixed(2) : "0.00"; + + // --- Application des minima --- + let isMiniRCC = false; + let isMiniRCE = false; + + if (primeFranchiseRCC < primeMini[0]) { + tauxRCC = (primeFranchiseRCC * 100 / CA).toFixed(2); // Garder le taux avant mini + primeFranchiseRCC = primeMini[0]; + isMiniRCC = true; + } + + if (primeFranchiseRCE < primeMini[1]) { + tauxRCE = (primeFranchiseRCE * 100 / CA).toFixed(2); // Garder le taux avant mini + primeFranchiseRCE = primeMini[1]; + isMiniRCE = true; + } + + // --- Recalculer taux si PAS mini --- + if (!isMiniRCC && CA > 0) { + tauxRCC = (primeFranchiseRCC * 100 / CA).toFixed(2); + } + if (!isMiniRCE && CA > 0) { + tauxRCE = (primeFranchiseRCE * 100 / CA).toFixed(2); + } + + // --- Prime totale --- + const primeTotale = primeFranchiseRCC + primeFranchiseRCE; + + // --- Taux global --- + const tauxGlobal = CA > 0 ? ((primeTotale * 100 / CA).toFixed(2)) : "0.00"; + + return { + primeRCC: primeFranchiseRCC.toString(), + tauxRCC, + primeRCE: primeFranchiseRCE.toString(), + tauxRCE, + primeTotale: primeTotale.toString(), + tauxGlobal, + isMiniRCC, + isMiniRCE + }; + } + + + function calcTarifettes(primePJ, CA, activites, capitalTPPC, nbVehicules, coefTPPC, primeRCCbase, primeRCEbase) { + const cards = [ + { key: "250", priceId: "priceFr250", rccId: "rccFr250", rceId: "rceFr250", pjId: "pjFr250", txRccId: "tauxRccFr250", txRceId: "tauxRceFr250", txGlobId: "tauxGlobalFr250" }, + { key: "400", priceId: "priceFr400", rccId: "rccFr400", rceId: "rceFr400", pjId: "pjFr400", txRccId: "tauxRccFr400", txRceId: "tauxRceFr400", txGlobId: "tauxGlobalFr400" }, + { key: "10% avec mini 300 € et maxi 2000", priceId: "priceFr2000", rccId: "rccFr2000", rceId: "rceFr2000", pjId: "pjFr2000", txRccId: "tauxRccFr2000", txRceId: "tauxRceFr2000", txGlobId: "tauxGlobalFr2000" }, + ]; + + // Déterminer le type de cotisation + const cot = document.querySelector('input[name="cotisation"]:checked')?.value || 'revisable'; + const checkRCE = document.getElementById('checkRCE')?.checked || false; + const checkPJ = document.getElementById('checkPJ')?.checked || false; + + const primeMini = [ + getMaxMiniRCC(activites, cot), + getMaxMiniRCE(activites, cot) + ]; + + cards.forEach(card => { + const mods = modRCFranchise[card.key] || { modRCC: 1, modRCE: 1 }; + + const result = calcTarifRCC({ + CA, + primeRCCbase, + primeRCEbase, + capitalTPPC, + nbVehicules, + coefTPPC, + franchiseCoef: mods, + primeMini + }); + + // Calculer la PJ en fonction de la prime totale RCC+RCE + let primePJcalc = 0; + if (checkPJ) { + const primeTotaleAvantPJ = Number(result.primeRCC) + (checkRCE ? Number(result.primeRCE) : 0); + primePJcalc = calcPJ(primeTotaleAvantPJ); + } + + // Prime totale finale avec PJ + const primeTotaleFinale = Number(result.primeRCC) + (checkRCE ? Number(result.primeRCE) : 0) + primePJcalc; + const tauxGlobalFinal = CA > 0 ? formatNumber((Number(result.primeRCC) + (checkRCE ? Number(result.primeRCE) : 0)) * 100 / CA, 2) : "0.000"; + + // Récupérer les éléments du DOM + const elPrice = document.getElementById(card.priceId); + const elRCC = document.getElementById(card.rccId); + const elRCE = document.getElementById(card.rceId); + const elPJ = document.getElementById(card.pjId); + const elTxRCC = document.getElementById(card.txRccId); + const elTxRCE = document.getElementById(card.txRceId); + const elTxGlob = document.getElementById(card.txGlobId); + + // Récupérer les lignes parent pour masquer/afficher + const rowRCE = elRCE?.closest('p'); + const rowTxRCE = elTxRCE?.closest('p'); + const rowPJ = elPJ?.closest('p'); + const rowTxGlob = elTxGlob?.closest('p'); + + // Afficher le prix total + if (elPrice) elPrice.innerText = formatNumber(primeTotaleFinale, 2) + ' €'; + + // Afficher Prime RCC (toujours visible) + if (elRCC) { + elRCC.innerText = formatNumber(result.primeRCC, 2) + " €" + (result.isMiniRCC ? " (Mini)" : ""); + } + + // Afficher Prime RCE uniquement si cochée ET > 0 + if (rowRCE) { + if (checkRCE && result.primeRCE > 0) { + rowRCE.style.display = 'block'; + if (elRCE) { + elRCE.innerText = formatNumber(result.primeRCE, 2) + " €" + (result.isMiniRCE ? " (Mini)" : ""); + } + } else { + rowRCE.style.display = 'none'; + } + } + + // Afficher Prime PJ uniquement si cochée ET > 0 + if (rowPJ) { + if (checkPJ && primePJcalc > 0) { + rowPJ.style.display = 'block'; + if (elPJ) { + elPJ.innerText = formatNumber(primePJcalc, 2) + " €"; + } + } else { + rowPJ.style.display = 'none'; + } + } + + // En forfaitaire, ne pas afficher les taux (uniquement des primes fixes) + if (cot === 'forfaitaire') { + // Masquer tous les taux en forfaitaire + if (elTxRCC?.closest('p')) elTxRCC.closest('p').style.display = 'none'; + if (rowTxRCE) rowTxRCE.style.display = 'none'; + if (rowTxGlob) rowTxGlob.style.display = 'none'; + } else { + // En revisable, afficher les taux + if (elTxRCC?.closest('p')) { + elTxRCC.closest('p').style.display = 'block'; + elTxRCC.innerText = formatNumber(result.tauxRCC, 2) + " %"; + } + + if (rowTxRCE) { + if (checkRCE && result.primeRCE > 0) { + rowTxRCE.style.display = 'block'; + if (elTxRCE) { + elTxRCE.innerText = formatNumber(result.tauxRCE, 2) + " %"; + } + } else { + rowTxRCE.style.display = 'none'; + } + } + + if (rowTxGlob && CA > 0) { + rowTxGlob.style.display = 'block'; + if (elTxGlob) { + elTxGlob.innerText = tauxGlobalFinal + " %"; + } + } + } + }); + } + + // Fonction pour calculer la PJ selon la prime totale + function calcPJ(primeTotale) { + let primePJ = 0; + const tablePJ = modRCGarAdd?.modRCC?.["Protection juridique"]; + if (!tablePJ) return 0; + + // Parcourir les tranches de PJ et prendre la plus grande tranche inférieure à la prime totale + const tranches = Object.keys(tablePJ).map(Number).sort((a, b) => a - b); + for (const tranche of tranches) { + if (primeTotale >= tranche) { + primePJ = tablePJ[tranche]; + } else { + break; + } + } + return primePJ; + } + + + + function calcGlobal() { + // Vérification des pourcentages AVANT calcul + const allPourcentInputs = Array.from(document.querySelectorAll('.input-pourcent')).filter(p => p.offsetParent != null); + let totalPourcentCheck = 0; + allPourcentInputs.forEach(p => { + totalPourcentCheck += toNumber(p.value); + }); + + if (totalPourcentCheck > 100.01) { + // Total > 100% : BLOQUER tous les calculs + hideAllPrimes(); + return; + } + + const cot = document.querySelector('input[name="cotisation"]:checked')?.value; + let result = (cot === 'revisable') ? calcRevisable() : calcForfaitaire(); + + if (result) { + const capitalTPPCsaisi = toNumber(document.getElementById("selTPPCcapital")?.value); + const nbVehicules = toNumber(document.getElementById("selTPPCveh")?.value); + + // Trouver la tranche TPPC la plus proche + let capitalTPPC = 0; + let coefTPPC = 0; + if (capitalTPPCsaisi > 0 && modRCGarAdd?.modRCC?.["TPPC"]) { + const tranches = Object.keys(modRCGarAdd.modRCC.TPPC).map(Number).sort((a,b)=>a-b); + capitalTPPC = findClosestTranche(capitalTPPCsaisi, tranches); + coefTPPC = modRCGarAdd.modRCC.TPPC[capitalTPPC] || 0; + } + + calcTarifettes(result.primePJ, result.CA, result.activites, capitalTPPC, nbVehicules, coefTPPC, result.primeRCCbase, result.primeRCEbase); + } + } + + function calcRevisable() { + // ========= Variables centrales (déclarées au début) ========= + const capitalTPPCEl = document.getElementById("capital_TPPC"); + const vehiculeTPPCEl = document.getElementById("vehicule_TPPC"); + const coefTPPCEl = document.getElementById("garantie_prime_TPPC"); + + const capitalTPPC = toNumber(capitalTPPCEl?.value); + const nbVehicules = toNumber(vehiculeTPPCEl?.value); + const coefTPPC = toNumber(coefTPPCEl?.value) || 0.01; + let primeBaseRCC = 0; + let tauxBaseRCC = 0.000; + let primeRCC = 0; + let tauxRCC = 0.000; + let primeBaseRCE = 0; + let tauxBaseRCE = 0.000; + let primeRCE = 0; + let tauxRCE = 0.000; + let primePJ = 0; + let primeGlobal = 0; + let tauxGlobal = 0; + + // Tableaux de travail par activité + let primeBaseRCCparAct = []; + let primeBaseRCEparAct = []; + + // ========= Étape CA ========= + const modCA = calcModCA(document.getElementById('chiffreAffaire').value); + document.getElementById('modCA').innerHTML = + 'Mod. CA test :
x ' + modCA.toLocaleString('fr-FR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); + + // ========= Étape Activités (taux base) ========= + tauxBaseRCC = get_taux_base_RCC(modRCActRCC, "revisable"); + if (document.getElementById('checkRCE').checked === true) { + tauxBaseRCE = get_taux_base_RCE(modRCActRCE, "revisable"); + } + + const CA = toNumber(document.getElementById("chiffreAffaire").value); + + // ========= Calcul primes de base RCC ========= + for (let i = 0; i < tauxBaseRCC.length; i++) { + const pourcentInput = toNumber(document.getElementById("pourcent" + tauxBaseRCC[i].typeActivite)?.value); + const primeBase = (tauxBaseRCC[i].tauxBase / 100 * pourcentInput / 100 * CA); + primeBaseRCCparAct.push({ + typeActivite: tauxBaseRCC[i].typeActivite, + primeBase: primeBase + }); + } + + // ========= Calcul primes de base RCE si coché ========= + if (document.getElementById('checkRCE').checked) { + for (let i = 0; i < tauxBaseRCE.length; i++) { + const pourcentInput = toNumber(document.getElementById("pourcent" + tauxBaseRCE[i].typeActivite)?.value); + const primeBase = (tauxBaseRCE[i].tauxBase / 100 * pourcentInput / 100 * CA); + primeBaseRCEparAct.push({ + typeActivite: tauxBaseRCE[i].typeActivite, + primeBase: primeBase + }); + } + } + + // Sommes des primes de base (SANS mod CA) + primeBaseRCC = primeBaseRCCparAct.reduce((total, item) => total + item.primeBase, 0); + primeBaseRCE = primeBaseRCEparAct.reduce((total, item) => total + item.primeBase, 0); + + // UI (affichage sans mod CA) + document.getElementById('primeChapActRCC').innerHTML = + 'Prime de base RCC : ' + primeBaseRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + ''; + + document.getElementById('primeChapActRCE').innerHTML = + 'Prime de base RCE : ' + primeBaseRCE.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + ''; + + // ========= Étape Activités complémentaires ========= + for (let i = 0; i < primeBaseRCCparAct.length; i++) { + primeBaseRCCparAct[i].primeBase *= calcModActCompl(modRCActCompl, primeBaseRCCparAct[i].typeActivite, "RCC", "revisable"); + } + + if (document.getElementById('checkRCE').checked) { + for (let i = 0; i < primeBaseRCEparAct.length; i++) { + primeBaseRCEparAct[i].primeBase *= calcModActCompl( + modRCActCompl, + primeBaseRCEparAct[i].typeActivite, + "RCE", + "revisable" + ); + } + } + + // Re-sommes (toujours sans mod CA) + primeBaseRCC = primeBaseRCCparAct.reduce((total, item) => total + item.primeBase, 0); + primeBaseRCE = primeBaseRCEparAct.reduce((total, item) => total + item.primeBase, 0); + + document.getElementById('primeChapActComplRCC').innerHTML = + 'Prime RCC : ' + primeBaseRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }); + document.getElementById('primeChapActComplRCE').innerHTML = + 'Prime RCE : ' + primeBaseRCE.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }); + + // ========= Étape Marchandises (× par activité) + Mod CA ========= + const selections = getSelectedActivities(); + + for (let i = 0; i < primeBaseRCCparAct.length; i++) { + const actName = primeBaseRCCparAct[i].typeActivite; + const modMar = calcModMarchandises(modRCMar, actName, "RCC", "revisable"); + // Appliquer marchandises ET CA ensemble + primeBaseRCCparAct[i].primeBase = primeBaseRCCparAct[i].primeBase * modMar * modCA; + } + + if (document.getElementById('checkRCE').checked) { + for (let i = 0; i < primeBaseRCEparAct.length; i++) { + const actName = primeBaseRCEparAct[i].typeActivite; + const modMar = calcModMarchandises(modRCMar, actName, "RCE", "revisable"); + // Appliquer marchandises ET CA ensemble + primeBaseRCEparAct[i].primeBase = primeBaseRCEparAct[i].primeBase * modMar * modCA; + } + } + + // Recalcule totaux apres mods marchandises + CA + primeBaseRCC = primeBaseRCCparAct.reduce((total, item) => total + item.primeBase, 0); + primeBaseRCE = primeBaseRCEparAct.reduce((total, item) => total + item.primeBase, 0); + + // Maintenant primeRCC et primeRCE incluent déjà le mod CA + primeRCC = primeBaseRCC; + primeRCE = primeBaseRCE; + + // UI marchandises + document.getElementById('primeChapMarchRCC').innerHTML = + 'Prime RCC : ' + primeRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }); + document.getElementById('primeChapMarchRCE').innerHTML = + 'Prime RCE : ' + primeRCE.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }); + + // ========= Étape Zones (× max RCC / × max RCE) ========= + const { mRCC, mRCE } = getZoneMods(modRCZone); + primeRCC *= mRCC; + primeRCE *= mRCE; + + // UI zones + document.getElementById('primeChapZonesRCC').innerHTML = + 'Prime RCC : ' + primeRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }); + document.getElementById('primeChapZonesRCE').innerHTML = + 'Prime RCE : ' + primeRCE.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }); + + // ========= Étape Engagements complémentaires (×) ========= + const result = calcEngagCompl(modRCEngagCompl, primeRCC); + primeRCC = result.prime; + + // UI engagements + document.getElementById('primeEngValue').innerText = + 'Prime RCC : ' + primeRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }); + + const infoContainer = document.getElementById('primeEngInfos'); + infoContainer.innerHTML = ""; + result.infos.forEach(msg => { + const p = document.createElement("p"); + p.style.color = "#e53935"; + p.style.fontWeight = "300"; + p.style.fontSize = "0.85em"; + p.style.marginTop = "5px"; + p.style.fontStyle = "italic"; + p.innerText = msg; + infoContainer.appendChild(p); + }); // non necessaire, mais garder si utile, car fonctionne a 100% + + // ========= Étape Garanties additionnelles (RCE uniquement) ========= + const garAdd = calcGarAdd(modRCGarAdd, primeRCC, primeRCE); + // primeRCC reste inchangée (TPPC appliquée plus tard) + primeRCE = garAdd.primeRCE; // RCE avec Station lavage, Garage, CSE + + // UI RCC + const blocRCC = document.getElementById('primeChapGarAddRCC'); + blocRCC.innerHTML = 'Prime RCC : ' + primeRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + ''; + garAdd.infosRCC.forEach(msg => { + const p = document.createElement("p"); + p.style.color = "#e53935"; + p.style.fontWeight = "300"; + p.style.fontSize = "0.85em"; + p.style.marginTop = "5px"; + p.style.fontStyle = "italic"; + p.innerText = msg; + blocRCC.appendChild(p); + });// toujours inutile, pas necessaire + + // UI RCE + const blocRCE = document.getElementById('primeChapGarAddRCE'); + blocRCE.innerHTML = 'Prime RCE : ' + primeRCE.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + ''; + garAdd.infosRCE.forEach(msg => { + const p = document.createElement("p"); + p.style.color = "#e53935"; + p.style.fontWeight = "300"; + p.style.fontSize = "0.85em"; + p.style.marginTop = "5px"; + p.style.fontStyle = "italic"; + p.innerText = msg; + blocRCE.appendChild(p); + }); // toujours inutile, pas necessaire + + // ========= Étape Sinistres ========= + const sin = calcSinistre(modRCSinistre, primeRCC, primeRCE); + primeRCC = sin.primeRCC; + primeRCE = sin.primeRCE; + + // ========= Sauvegarder les primes BASE pour les tarifettes (après sinistre, avant franchise) ========= + const primeRCCavantFranchise = primeRCC; + const primeRCEavantFranchise = primeRCE; + + // Les totaux RCC et RCE sont maintenant prêts pour les franchises + const totalRCC = primeRCC; + const totalRCE = primeRCE; + + // PJ (calculée dans calcTarifettes selon prime totale) + primePJ = 0; + + primeGlobal = totalRCC + totalRCE + primePJ; + + // UI + document.getElementById('modCA').innerHTML = + 'Modulation CA :
x ' + modCA.toLocaleString('fr-FR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); + + const activiteMap = { + "Voiturier / Loueur": "Voiturier/Loueur", + "Commissionnaire de Transport": "Commissionnaire de Transport", + "Déménageur": "Déménageur", + "Logistique": "Logistique", + "Autocariste": "Autocariste", + "Autres activites": "Autres activites" + }; + + function getSelectedActivites() { + const activites = []; + document.querySelectorAll('label input[type="checkbox"]:checked').forEach(cb => { + const span = cb.parentElement.querySelector('span'); + if (span) { + const labelText = span.textContent.trim(); + if (activiteMap[labelText]) { + activites.push(activiteMap[labelText]); + } + } + }); + return activites; + } + + + const activites = getSelectedActivites(); + + return { + CA, + activites, + primeRCC: totalRCC, + primeRCE: totalRCE, + primeRCCbase: primeRCCavantFranchise, + primeRCEbase: primeRCEavantFranchise, + primePJ, + primeGlobal + }; + } + + function calcForfaitaire() { + // ========= Variables centrales ========= + let primeBaseRCC = 0; + let primeBaseRCE = 0; + let primeRCC = 0; + let primeRCE = 0; + let primePJ = 0; + let primeGlobal = 0; + + // Tableaux de travail par activité + let primeBaseRCCparAct = []; + let primeBaseRCEparAct = []; + + // ========= Récupération du nombre de véhicules ========= + const nbrVehicule = toNumber(document.getElementById('nbrVehicule')?.value); + // Déterminer si c'est 1 ou 2 véhicules (par défaut 1) + const nbVehiculeKey = (nbrVehicule === 2) ? "deuxVehicules" : "unVehicule"; + + // ========= Étape Activités (primes forfaitaires de base) ========= + const selections = getSelectedActivities(); + + selections.forEach(activity => { + const typeActivite = activity.typeActivite; + const inputElement = document.querySelector( + `input[name="selectAct${typeActivite}"], select[name="selectAct${typeActivite}"]` + ); + + if (inputElement) { + const capitalSaisi = toNumber(inputElement.value); + + if (capitalSaisi <= 0) { + return; // Skip cette activité + } + + // Récupération de la prime forfaitaire RCC + const grilleActRCC = modRCActRCC.forfaitaire[typeActivite]; + if (grilleActRCC) { + const tranches = Object.keys(grilleActRCC).map(Number).sort((a, b) => a - b); + const tranche = findClosestTranche(capitalSaisi, tranches); + const primeData = grilleActRCC[tranche]; + + if (primeData && typeof primeData[nbVehiculeKey] === 'number') { + const primeBase = primeData[nbVehiculeKey]; + primeBaseRCCparAct.push({ + typeActivite: typeActivite, + primeBase: primeBase + }); + + // Affichage du taux (ici c'est une prime fixe) + const rccDiv = document.getElementById("tauxBaseRCCact" + typeActivite); + if (rccDiv) { + rccDiv.innerText = "RCC : " + primeBase.toFixed(2) + " €"; + } + + // Info tranche si différente + if (capitalSaisi !== tranche) { + const rowDiv = inputElement.closest('.row'); + if (rowDiv) { + const oldInfo = rowDiv.querySelector('.info-tranche'); + if (oldInfo) oldInfo.remove(); + + const infoSpan = document.createElement('span'); + infoSpan.className = 'info-tranche'; + infoSpan.style.color = '#e53935'; + infoSpan.style.fontSize = '0.8em'; + infoSpan.style.fontStyle = 'italic'; + infoSpan.innerText = `(tranche ${tranche.toLocaleString('fr-FR')} €)`; + + rowDiv.appendChild(infoSpan); + } + } + } + } + + // Récupération de la prime forfaitaire RCE si coché + if (document.getElementById('checkRCE')?.checked) { + const grilleActRCE = modRCActRCE.forfaitaire[typeActivite]; + if (grilleActRCE && grilleActRCE[nbVehiculeKey]) { + const primeBaseRCE_val = grilleActRCE[nbVehiculeKey].optimale || 0; + primeBaseRCEparAct.push({ + typeActivite: typeActivite, + primeBase: primeBaseRCE_val + }); + + // Affichage + const rceDiv = document.getElementById("tauxBaseRCEact" + typeActivite); + if (rceDiv) { + rceDiv.innerText = "RCE : " + primeBaseRCE_val.toFixed(2) + " €"; + } + } + } + } + }); + + // Sommes des primes de base + primeBaseRCC = primeBaseRCCparAct.reduce((total, item) => total + item.primeBase, 0); + primeBaseRCE = primeBaseRCEparAct.reduce((total, item) => total + item.primeBase, 0); + + // UI (affichage) + document.getElementById('primeChapActRCC').innerHTML = + 'Prime de base RCC : ' + primeBaseRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + ''; + + document.getElementById('primeChapActRCE').innerHTML = + 'Prime de base RCE : ' + primeBaseRCE.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + ''; + + // ========= Étape Activités complémentaires ========= + for (let i = 0; i < primeBaseRCCparAct.length; i++) { + primeBaseRCCparAct[i].primeBase *= calcModActCompl(modRCActCompl, primeBaseRCCparAct[i].typeActivite, "RCC", "forfaitaire"); + } + + if (document.getElementById('checkRCE')?.checked) { + for (let i = 0; i < primeBaseRCEparAct.length; i++) { + primeBaseRCEparAct[i].primeBase *= calcModActCompl( + modRCActCompl, + primeBaseRCEparAct[i].typeActivite, + "RCE", + "forfaitaire" + ); + } + } + + // Re-sommes + primeBaseRCC = primeBaseRCCparAct.reduce((total, item) => total + item.primeBase, 0); + primeBaseRCE = primeBaseRCEparAct.reduce((total, item) => total + item.primeBase, 0); + + document.getElementById('primeChapActComplRCC').innerHTML = + 'Prime RCC : ' + primeBaseRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }); + document.getElementById('primeChapActComplRCE').innerHTML = + 'Prime RCE : ' + primeBaseRCE.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }); + + // ========= Étape Marchandises (× par activité) ========= + for (let i = 0; i < primeBaseRCCparAct.length; i++) { + const actName = primeBaseRCCparAct[i].typeActivite; + const modMar = calcModMarchandises(modRCMar, actName, "RCC", "forfaitaire"); + primeBaseRCCparAct[i].primeBase = primeBaseRCCparAct[i].primeBase * modMar; + } + + if (document.getElementById('checkRCE')?.checked) { + for (let i = 0; i < primeBaseRCEparAct.length; i++) { + const actName = primeBaseRCEparAct[i].typeActivite; + const modMar = calcModMarchandises(modRCMar, actName, "RCE", "forfaitaire"); + primeBaseRCEparAct[i].primeBase = primeBaseRCEparAct[i].primeBase * modMar; + } + } + + // Recalcule totaux après mods marchandises + primeBaseRCC = primeBaseRCCparAct.reduce((total, item) => total + item.primeBase, 0); + primeBaseRCE = primeBaseRCEparAct.reduce((total, item) => total + item.primeBase, 0); + + primeRCC = primeBaseRCC; + primeRCE = primeBaseRCE; + + // UI marchandises + document.getElementById('primeChapMarchRCC').innerHTML = + 'Prime RCC : ' + primeRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }); + document.getElementById('primeChapMarchRCE').innerHTML = + 'Prime RCE : ' + primeRCE.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }); + + // ========= Étape Zones (× max RCC / × max RCE) ========= + const { mRCC, mRCE } = getZoneMods(modRCZone); + primeRCC *= mRCC; + primeRCE *= mRCE; + + // UI zones + document.getElementById('primeChapZonesRCC').innerHTML = + 'Prime RCC : ' + primeRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }); + document.getElementById('primeChapZonesRCE').innerHTML = + 'Prime RCE : ' + primeRCE.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }); + + // ========= Étape Engagements complémentaires (×) ========= + const result = calcEngagCompl(modRCEngagCompl, primeRCC); + primeRCC = result.prime; + + // UI engagements + document.getElementById('primeEngValue').innerText = + 'Prime RCC : ' + primeRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }); + + const infoContainer = document.getElementById('primeEngInfos'); + infoContainer.innerHTML = ""; + result.infos.forEach(msg => { + const p = document.createElement("p"); + p.style.color = "#e53935"; + p.style.fontWeight = "300"; + p.style.fontSize = "0.85em"; + p.style.marginTop = "5px"; + p.style.fontStyle = "italic"; + p.innerText = msg; + infoContainer.appendChild(p); + }); + + // ========= Étape Garanties additionnelles (RCE uniquement) ========= + const garAdd = calcGarAdd(modRCGarAdd, primeRCC, primeRCE); + primeRCE = garAdd.primeRCE; + + // UI RCC + const blocRCC = document.getElementById('primeChapGarAddRCC'); + blocRCC.innerHTML = 'Prime RCC : ' + primeRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + ''; + garAdd.infosRCC.forEach(msg => { + const p = document.createElement("p"); + p.style.color = "#e53935"; + p.style.fontWeight = "300"; + p.style.fontSize = "0.85em"; + p.style.marginTop = "5px"; + p.style.fontStyle = "italic"; + p.innerText = msg; + blocRCC.appendChild(p); + }); + + // UI RCE + const blocRCE = document.getElementById('primeChapGarAddRCE'); + blocRCE.innerHTML = 'Prime RCE : ' + primeRCE.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + ''; + garAdd.infosRCE.forEach(msg => { + const p = document.createElement("p"); + p.style.color = "#e53935"; + p.style.fontWeight = "300"; + p.style.fontSize = "0.85em"; + p.style.marginTop = "5px"; + p.style.fontStyle = "italic"; + p.innerText = msg; + blocRCE.appendChild(p); + }); + + // ========= Étape Sinistres (OPTIONNEL en forfaitaire - basé sur CA) ========= + // Note: En forfaitaire, normalement pas de sinistre car pas de CA + // Mais on garde la logique au cas où il y aurait un CA saisi + const CA = toNumber(document.getElementById("chiffreAffaire")?.value); + if (CA > 0) { + const sin = calcSinistre(modRCSinistre, primeRCC, primeRCE); + primeRCC = sin.primeRCC; + primeRCE = sin.primeRCE; + } + + // ========= Sauvegarder les primes BASE pour les tarifettes ========= + const primeRCCavantFranchise = primeRCC; + const primeRCEavantFranchise = primeRCE; + + // Les totaux RCC et RCE sont maintenant prêts + const totalRCC = primeRCC; + const totalRCE = primeRCE; + + // PJ (calculée dans calcTarifettes selon prime totale) + primePJ = 0; + + primeGlobal = totalRCC + totalRCE + primePJ; + + const activiteMap = { + "Voiturier / Loueur": "Voiturier/Loueur", + "Commissionnaire de Transport": "Commissionnaire de Transport", + "Déménageur": "Déménageur", + "Logistique": "Logistique", + "Autocariste": "Autocariste", + "Autres activites": "Autres activites" + }; + + function getSelectedActivites() { + const activites = []; + document.querySelectorAll('label input[type="checkbox"]:checked').forEach(cb => { + const span = cb.parentElement.querySelector('span'); + if (span) { + const labelText = span.textContent.trim(); + if (activiteMap[labelText]) { + activites.push(activiteMap[labelText]); + } + } + }); + return activites; + } + + const activites = getSelectedActivites(); + + return { + CA: CA || 0, + activites, + primeRCC: totalRCC, + primeRCE: totalRCE, + primeRCCbase: primeRCCavantFranchise, + primeRCEbase: primeRCEavantFranchise, + primePJ, + primeGlobal + }; + } + + function getZoneMods(modRCZone) { + const zones = [ + { id: 'zone1', label: 'France Métropolitaine et pays limitrophes' }, + { id: 'zone2', label: 'Union Européenne' }, + { id: 'zone3', label: 'Autres pays européens sauf Russie et Ukraine (y compris UK et Norvège)' }, + { id: 'zone4', label: 'Pays du Maghreb et Amérique du Nord ( USA / Canada / Mexique )' }, + { id: 'zone5', label: 'Amérique Centrale et Sud / Caraïbes, Asie et Océanie' }, + { id: 'zone6', label: 'Afrique Hors Maghreb / Proche Orient / Moyen Orient' } + ]; + let mRCC = 1, mRCE = 1; + zones.forEach(z => { + const cb = document.getElementById(z.id); + if (cb && cb.checked) { + const m = modRCZone[z.label]; + if (m) { + if (typeof m.modRCC === 'number') mRCC = Math.max(mRCC, m.modRCC); + if (typeof m.modRCE === 'number') mRCE = Math.max(mRCE, m.modRCE); + } + } + }); + return { mRCC, mRCE }; + } + + + function handleLoadHistoriqueBtn() { + var selectedId = document.getElementById('idSelect').value; + + if (selectedId != "") { + fetch(`/contrat/update/${contrat.produit}/${contrat.id}/${selectedId}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }) + .then(response => response.json()) + .then(data => { + if (data.valid) { + window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=projet`; + } else { + console.log('Echec lors de la mise à jour de la relation id contrat - id client :', data); + } + }); + } + } + + //Appel pour recevoir les constantes + async function constantsJSON() { + try { + const responsesJSON = await Promise.all([ + fetch('/rc/modulo/CARC'), + fetch('/rc/modulo/activiteRCC'), + fetch('/rc/modulo/activiteRCE'), + fetch('/rc/modulo/activiteComplRC'), + fetch('/rc/modulo/marchandiseRC'), + fetch('/rc/modulo/zoneRC'), + fetch('/rc/modulo/engagComplRC'), + fetch('/rc/modulo/garAdditionelRC'), + fetch('/rc/modulo/sinistreRC'), + fetch('/rc/modulo/franchiseRC'), + fetch('/rc/modulo/primeMiniRC') + ]); + const jsonResponses = await Promise.all(responsesJSON.map(r => r.json())); // Récupérer toutes les réponses JSON + + // Extraire la valeur objRetourne de chaque réponse + [ + modRCCA, + modRCActRCC, + modRCActRCE, + modRCActCompl, + modRCMar, + modRCZone, + modRCEngagCompl, + modRCGarAdd, + modRCSinistre, + modRCFranchise, + modRCPrimeMini + ] = jsonResponses.map(response => response.objRetourne); // Adapter pour extraire objRetourne + } catch (err) { + throw err; + } + } + + function resetInputs() { + // Sélection des éléments input pourcentage + const pourcentInputs = document.querySelectorAll('.input-pourcent'); + // Calculer le nombre d'inputs visibles + const visibleInputs = Array.from(pourcentInputs).filter(input => input.offsetParent != null); + + // Vérifier s'il y a des inputs visibles + if (visibleInputs.length > 0) { + // Réinitialiser les valeurs + visibleInputs.forEach(p => { + p.value = ''; // Réinitialiser la valeur + const correspondingIsSetInput = document.getElementById('isSet' + p.id.replace('pourcent', '')); + correspondingIsSetInput.value = 'false'; // Réinitialiser isSet + p.classList.remove('set'); // Remettre le fond d'origine + }); + + // Calculer le pourcentage à répartir + const pourcentToAdd = (100 / visibleInputs.length).toFixed(2); + + // Répartir le pourcentage entre les inputs visibles + visibleInputs.forEach(p => { + p.value = pourcentToAdd; // Assigner la valeur calculée + // Ne pas changer isSet à true ici + // correspondingIsSetInput.value reste 'false' + }); + + // Mettre à jour l'indicateur + updatePercentageIndicator(100); + } + } + + function get_taux_base_RCC(grille_mod_RCC, cot) { + const tauxOptimaux = []; + const selections = getSelectedActivities(); + + selections.forEach(activity => { + const typeActivite = activity.typeActivite; + const inputElement = document.querySelector( + `input[name="selectAct${typeActivite}"], select[name="selectAct${typeActivite}"]` + ); + + if (inputElement) { + const capitalSaisi = toNumber(inputElement.value); + + if (capitalSaisi <= 0) { + return; + } + + if (cot === 'revisable') { + const grilleAct = grille_mod_RCC.revisable[typeActivite]; + if (grilleAct) { + const tranches = Object.keys(grilleAct).map(Number).sort((a, b) => a - b); + const tranche = findClosestTranche(capitalSaisi, tranches); + const tauxBase = grilleAct[tranche]; + + if (typeof tauxBase === 'number') { + // 1. Mettre à jour la div RCC avec uniquement le texte principal + const rccDiv = document.getElementById("tauxBaseRCCact" + typeActivite); + if (rccDiv) { + rccDiv.innerText = "RCC : " + tauxBase.toFixed(3) + " %"; + } + if (capitalSaisi !== tranche) { + const rowDiv = inputElement.closest('.row'); + if (rowDiv) { + const oldInfo = rowDiv.querySelector('.info-tranche'); + if (oldInfo) oldInfo.remove(); + + const infoSpan = document.createElement('span'); + infoSpan.className = 'info-tranche'; + infoSpan.style.color = '#e53935'; + infoSpan.style.fontSize = '0.8em'; + infoSpan.style.fontStyle = 'italic'; + infoSpan.innerText = `(tranche ${tranche.toLocaleString('fr-FR')} €)`; + + rowDiv.appendChild(infoSpan); + } + } + + tauxOptimaux.push({ typeActivite, capital: tranche, tauxBase }); + } + } + } else if (cot === 'forfaitaire') { + console.log("TODO FORFAITAIRE"); + } + } + }); + + return tauxOptimaux; + } + + + function get_taux_base_RCE(grille_mod_RCE, cot) { + const tauxOptimaux = []; + const selections = getSelectedActivities(); + + selections.forEach(activity => { + const typeActivite = activity.typeActivite; + const inputElement = document.querySelector(`input[name="selectAct${typeActivite}"], select[name="selectAct${typeActivite}"]`); + + if (inputElement) { + const capitalSaisi = toNumber(inputElement.value); + + // Si rien n'est saisi ou invalide, ignorer + if (capitalSaisi <= 0) { + return; + } + + // Traitement selon le type de cotisation + if (cot == 'revisable') { + if (grille_mod_RCE.revisable[typeActivite]) { + const tauxBase = grille_mod_RCE.revisable[typeActivite]["optimale"]; + document.getElementById("tauxBaseRCEact" + typeActivite).innerHTML = "RCE : " + tauxBase.toFixed(3) + " %" + tauxOptimaux.push({ typeActivite, tauxBase }); + } + } else if (cot == 'forfaitaire') { + console.log("TODO FORFAITAIRE"); // ehhh + } + } + }); + + return tauxOptimaux; + } + + function getSelectedActivities() { + const selections = []; + + // Récupérer le nombre de véhicules depuis l'input + const nombreVehicules = document.getElementById('nbrVehicule').value || null; // Valeur par défaut à null si vide + + if (document.getElementById('checkVoiturier').checked) { + const listActComplChecked = []; + const listMarChecked = []; + + // Récupérer les activités complémentaires + const actComplCheckboxes = document.querySelectorAll('[name="actComplVoiturier/Loueur"] input[type="checkbox"]:checked'); + actComplCheckboxes.forEach(checkbox => { + listActComplChecked.push(checkbox.nextElementSibling.textContent.trim()); + }); + + // Récupérer les marchandises + const marComplCheckboxes = document.querySelectorAll('[name="marVoiturier/Loueur"] input[type="checkbox"]:checked'); + marComplCheckboxes.forEach(checkbox => { + listMarChecked.push(checkbox.nextElementSibling.textContent.trim()); + }); + + selections.push({ + typeActivite: "Voiturier/Loueur", + nombreVehicules: nombreVehicules, + listActComplChecked: listActComplChecked, + listMarChecked: listMarChecked + }); + } + + if (document.getElementById('checkCommissionnaire').checked) { + const listActComplChecked = []; + const listMarChecked = []; + + // Récupérer les activités complémentaires + const actComplCheckboxes = document.querySelectorAll('[name="actComplCommissionnaire de Transport"] input[type="checkbox"]:checked'); + actComplCheckboxes.forEach(checkbox => { + listActComplChecked.push(checkbox.nextElementSibling.textContent.trim()); + }); + + // Récupérer les marchandises + const marComplCheckboxes = document.querySelectorAll('[name="marCommissionnaire de Transport"] input[type="checkbox"]:checked'); + marComplCheckboxes.forEach(checkbox => { + listMarChecked.push(checkbox.nextElementSibling.textContent.trim()); + }); + + selections.push({ + typeActivite: "Commissionnaire de Transport", + nombreVehicules: null, + listActComplChecked: listActComplChecked, + listMarChecked: listMarChecked + }); + } + + if (document.getElementById('checkDemenageur').checked) { + const listActComplChecked = []; + const listMarChecked = []; + + // Récupérer les activités complémentaires + const actComplCheckboxes = document.querySelectorAll('[name="actComplDéménageur"] input[type="checkbox"]:checked'); + actComplCheckboxes.forEach(checkbox => { + listActComplChecked.push(checkbox.nextElementSibling.textContent.trim()); + }); + + // Récupérer les marchandises + const marComplCheckboxes = document.querySelectorAll('[name="marDéménageur"] input[type="checkbox"]:checked'); + marComplCheckboxes.forEach(checkbox => { + listMarChecked.push(checkbox.nextElementSibling.textContent.trim()); + }); + + selections.push({ + typeActivite: "Déménageur", + nombreVehicules: nombreVehicules, + listActComplChecked: listActComplChecked, + listMarChecked: listMarChecked + }); + } + + if (document.getElementById('checkLogistique').checked) { + const listActComplChecked = []; + const listMarChecked = []; + + // Récupérer les activités complémentaires + const actComplCheckboxes = document.querySelectorAll('[name="actComplLogistique"] input[type="checkbox"]:checked'); + actComplCheckboxes.forEach(checkbox => { + listActComplChecked.push(checkbox.nextElementSibling.textContent.trim()); + }); + + // Récupérer les marchandises + const marComplCheckboxes = document.querySelectorAll('[name="marLogistique"] input[type="checkbox"]:checked'); + marComplCheckboxes.forEach(checkbox => { + listMarChecked.push(checkbox.nextElementSibling.textContent.trim()); + }); + + selections.push({ + typeActivite: "Logistique", + nombreVehicules: null, + listActComplChecked: listActComplChecked, + listMarChecked: listMarChecked + }); + } + + if (document.getElementById('checkAutres').checked) { + const listActComplChecked = []; + const listMarChecked = []; + + // Récupérer les activités complémentaires + const actComplCheckboxes = document.querySelectorAll('[name="actComplAutres activites"] input[type="checkbox"]:checked'); + actComplCheckboxes.forEach(checkbox => { + listActComplChecked.push(checkbox.nextElementSibling.textContent.trim()); + }); + + // Récupérer les marchandises + const marComplCheckboxes = document.querySelectorAll('[name="marAutres activites"] input[type="checkbox"]:checked'); + marComplCheckboxes.forEach(checkbox => { + listMarChecked.push(checkbox.nextElementSibling.textContent.trim()); + }); + + selections.push({ + typeActivite: "Autres activites", + nombreVehicules: nombreVehicules, + listActComplChecked: listActComplChecked, + listMarChecked: listMarChecked + }); + } + // Ajoutez d'autres cas si nécessaire + + return selections; + } + + // Fonction pour sauvegarder les données tarifRC dans la base + async function saveTarifRC() { + if (!rc || !contrat) { + console.error('Données manquantes pour sauvegarder le tarif RC'); + return { valid: false, message: 'Données manquantes' }; + } + + // Préparer les références aux champs selon les différents templates possibles + const caInput = getElementByIdFlexible('CA') || getElementByIdFlexible('chiffreAffaire'); + const nbVehInput = getElementByIdFlexible('nbVehicules') || getElementByIdFlexible('nbrVehicule'); + + const capitalVoiturierInput = getElementByIdFlexible('capitalVoiturier') || document.querySelector('input[name="selectActVoiturier/Loueur"]'); + const capitalCommissionnaireInput = getElementByIdFlexible('capitalCommissionnaire') || document.querySelector('input[name="selectActCommissionnaire de Transport"]') || document.querySelector('input[name="selectActCommissionnaireDeTransport"]'); + const capitalDemenageurInput = getElementByIdFlexible('capitalDemenageur') || document.querySelector('input[name="selectActDéménageur"]') || document.querySelector('input[name="selectActDemenageur"]'); + const capitalLogistiqueInput = getElementByIdFlexible('capitalLogistique') || document.querySelector('input[name="selectActLogistique"]'); + const capitalAutocaristeInput = getElementByIdFlexible('capitalAutocariste') || document.querySelector('input[name="selectActAutocariste"]'); + const capitalAutresInput = getElementByIdFlexible('capitalAutres') || document.querySelector('input[name="selectActAutres activites"]') || document.querySelector('input[name="selectActAutresActivites"]'); + + const pctVoiturierInput = getElementByIdFlexible('pourcent_voiturier') || getElementByIdFlexible('pourcentVoiturier/Loueur'); + const pctCommissionnaireInput = getElementByIdFlexible('pourcent_commissionnaire') || getElementByIdFlexible('pourcentCommissionnaire de Transport') || getElementByIdFlexible('pourcentCommissionnaireDeTransport'); + const pctDemenageurInput = getElementByIdFlexible('pourcent_demenageur') || getElementByIdFlexible('pourcentDéménageur') || getElementByIdFlexible('pourcentDemenageur'); + const pctLogistiqueInput = getElementByIdFlexible('pourcent_logistique') || getElementByIdFlexible('pourcentLogistique'); + const pctAutocaristeInput = getElementByIdFlexible('pourcent_autocariste') || getElementByIdFlexible('pourcentAutocariste'); + const pctAutresInput = getElementByIdFlexible('pourcent_autres') || getElementByIdFlexible('pourcentAutres activites') || getElementByIdFlexible('pourcentAutresActivites'); + + // ===== ÉTAPE 1: Collecter les données communes à sauvegarder dans RC principal ===== + const rcMainData = { + typeCotisation: document.querySelector('input[name="cotisation"]:checked')?.value, + chiffreAffaires: toNumber(caInput?.value ?? caInput?.textContent), + nombreVehicules: Math.max(0, Math.round(toNumber(nbVehInput?.value ?? nbVehInput?.textContent))), + checkRCE: document.getElementById('checkRCE')?.checked || false, + checkVoiturier: document.getElementById('checkVoiturier')?.checked || false, + capitalVoiturier: toNumber(capitalVoiturierInput?.value ?? capitalVoiturierInput?.textContent), + checkCommissionnaire: document.getElementById('checkCommissionnaire')?.checked || false, + capitalCommissionnaire: toNumber(capitalCommissionnaireInput?.value ?? capitalCommissionnaireInput?.textContent), + checkDemenageur: document.getElementById('checkDemenageur')?.checked || false, + capitalDemenageur: toNumber(capitalDemenageurInput?.value ?? capitalDemenageurInput?.textContent), + checkLogistique: document.getElementById('checkLogistique')?.checked || false, + capitalLogistique: toNumber(capitalLogistiqueInput?.value ?? capitalLogistiqueInput?.textContent), + checkAutocariste: document.getElementById('checkAutocariste')?.checked || false, + capitalAutocariste: toNumber(capitalAutocaristeInput?.value ?? capitalAutocaristeInput?.textContent), + checkAutres: document.getElementById('checkAutres')?.checked || false, + capitalAutres: toNumber(capitalAutresInput?.value ?? capitalAutresInput?.textContent), + + // Activités complémentaires (JSON) - collectées avec les bons noms + actComplVoiturier: collectActivitesComplJSON('voiturier'), + actComplCommissionnaire: collectActivitesComplJSON('commissionnaire'), + actComplDemenageur: collectActivitesComplJSON('demenageur'), + actComplLogistique: collectActivitesComplJSON('logistique'), + + // Marchandises (JSON) - collectées avec les bons noms + marchandisesVoiturier: collectMarchandisesJSON('voiturier'), + marchandisesCommissionnaire: collectMarchandisesJSON('commissionnaire'), + marchandisesDemenageur: collectMarchandisesJSON('demenageur'), + marchandisesLogistique: collectMarchandisesJSON('logistique'), + marchandisesAutocariste: collectMarchandisesJSON('autocariste'), + marchandisesAutres: collectMarchandisesJSON('autres'), + + // Zones + zone1: document.getElementById('zone1')?.checked || false, + zone2: document.getElementById('zone2')?.checked || false, + zone3: document.getElementById('zone3')?.checked || false, + zone4: document.getElementById('zone4')?.checked || false, + zone5: document.getElementById('zone5')?.checked || false, + zone6: document.getElementById('zone6')?.checked || false, + + //commentaire + commentaire: document.getElementById('commentaire')?.value, + }; + + // ===== LOGS DE DÉBOGAGE ===== + console.log('📊 === DÉBUT SAUVEGARDE TARIF RC ==='); + console.log('🔍 rcMainData:', rcMainData); + + // ===== ÉTAPE 2: Collecter les résultats de calculs pour tarifRC ===== + const tarifRCData = { + sinistre: toNumber(document.getElementById('sinistre')?.value), + pourcentageVoiturier: toNumber(pctVoiturierInput?.value ?? pctVoiturierInput?.textContent), + isSetVoiturier: Boolean(pctVoiturierInput?.value?.trim()), + pourcentageCommissionnaire: toNumber(pctCommissionnaireInput?.value ?? pctCommissionnaireInput?.textContent), + isSetCommissionnaire: Boolean(pctCommissionnaireInput?.value?.trim()), + pourcentageDemenageur: toNumber(pctDemenageurInput?.value ?? pctDemenageurInput?.textContent), + isSetDemenageur: Boolean(pctDemenageurInput?.value?.trim()), + pourcentageLogistique: toNumber(pctLogistiqueInput?.value ?? pctLogistiqueInput?.textContent), + isSetLogistique: Boolean(pctLogistiqueInput?.value?.trim()), + pourcentageAutocariste: toNumber(pctAutocaristeInput?.value ?? pctAutocaristeInput?.textContent), + isSetAutocariste: Boolean(pctAutocaristeInput?.value?.trim()), + pourcentageAutres: toNumber(pctAutresInput?.value ?? pctAutresInput?.textContent), + isSetAutres: Boolean(pctAutresInput?.value?.trim()), + + // Tarifs pour franchise 250 + primeRCC_250: toNumber(document.getElementById('rccFr250')?.textContent), + primeRCE_250: toNumber(document.getElementById('rceFr250')?.textContent), + primePJ_250: toNumber(document.getElementById('pjFr250')?.textContent), + primeTotal_250: toNumber(document.getElementById('priceFr250')?.textContent), + tauxRCC_250: toNumber(document.getElementById('tauxRccFr250')?.textContent), + tauxRCE_250: toNumber(document.getElementById('tauxRceFr250')?.textContent), + tauxGlobal_250: toNumber(document.getElementById('tauxGlobalFr250')?.textContent), + + // Tarifs pour franchise 400 + primeRCC_400: toNumber(document.getElementById('rccFr400')?.textContent), + primeRCE_400: toNumber(document.getElementById('rceFr400')?.textContent), + primePJ_400: toNumber(document.getElementById('pjFr400')?.textContent), + primeTotal_400: toNumber(document.getElementById('priceFr400')?.textContent), + tauxRCC_400: toNumber(document.getElementById('tauxRccFr400')?.textContent), + tauxRCE_400: toNumber(document.getElementById('tauxRceFr400')?.textContent), + tauxGlobal_400: toNumber(document.getElementById('tauxGlobalFr400')?.textContent), + + // Tarifs pour franchise 2000 + primeRCC_2000: toNumber(document.getElementById('rccFr2000')?.textContent), + primeRCE_2000: toNumber(document.getElementById('rceFr2000')?.textContent), + primePJ_2000: toNumber(document.getElementById('pjFr2000')?.textContent), + primeTotal_2000: toNumber(document.getElementById('priceFr2000')?.textContent), + tauxRCC_2000: toNumber(document.getElementById('tauxRccFr2000')?.textContent), + tauxRCE_2000: toNumber(document.getElementById('tauxRceFr2000')?.textContent), + tauxGlobal_2000: toNumber(document.getElementById('tauxGlobalFr2000')?.textContent), + + // Franchise choisie + franchiseChoisie: window.franchiseChoisie || null, + + // Engagements complémentaires (dans tarifRC, pas dans rc!) + checkDomImmat: document.getElementById('checkDomImmat')?.checked || false, + capitalDomImmat: toNumber(document.getElementById('inputDomImmat')?.value), + checkContConf: document.getElementById('checkContConf')?.checked || false, + capitalContConf: toNumber(document.getElementById('inputContConf')?.value), + checkDiffInv: document.getElementById('checkDiffInv')?.checked || false, + capitalDiffInv: toNumber(document.getElementById('inputDiffInv')?.value), + + // Garanties additionnelles (dans tarifRC, pas dans rc!) + checkStationLavage: document.getElementById('checkStationLavage')?.checked || false, + checkGarageInterne: document.getElementById('checkGarageInterne')?.checked || false, + checkCSE: document.getElementById('checkCSE')?.checked || false, + checkTPPC: document.getElementById('checkTPPC')?.checked || false, + capitalTPPC: toNumber(document.getElementById('selTPPCcapital')?.value), + vehiculesTPPC: Math.max(0, Math.round(toNumber(document.getElementById('selTPPCveh')?.value))), + checkPJ: document.getElementById('checkPJ')?.checked || false, + + tarifcommercial: toNumber(document.getElementById('tarifCom')?.value), + }; + + console.log('tarifRCData:', tarifRCData); + + try { + let idTarifRC; + let rcId = rc?.id; + + // ===== VÉRIFIER SI RC EXISTE, SINON LE CRÉER ===== + if (!rcId) { + console.log('RC n\'existe pas encore, création en cours...'); + const createRCResponse = await fetch(`/rc/create`, { + method: 'POST', + body: JSON.stringify({ typeCotisation: rcMainData.typeCotisation }), + headers: { 'Content-Type': 'application/json' }, + }); + const createRCData = await createRCResponse.json(); + + if (createRCData.valid) { + rcId = createRCData.rc.id; + // Mettre à jour le contrat avec le nouvel ID RC + await fetch(`/contrat/update/${contrat.produit}/${contrat.id}/${rcId}`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }); + } else { + console.error('Échec de la création de RC:', createRCData.message); + return { valid: false, message: 'Échec création RC' }; + } + } + + // ===== ÉTAPE 3: Sauvegarder/Mettre à jour tarifRC ===== + if (tarif && tarif.id) { + // Mettre à jour un enregistrement tarifRC existant + console.log(`📝 Mise à jour tarifRC existant (ID: ${tarif.id})`); + const response = await fetch(`/rc/tarif/update/${tarif.id}`, { + method: 'POST', + body: JSON.stringify(tarifRCData), + headers: { + 'Content-Type': 'application/json', + }, + }); + const data = await response.json(); + console.log('📥 Réponse serveur tarifRC update:', data); + if (data.valid) { + idTarifRC = data.tarifRc.id; + } else { + console.error('❌ Échec de la mise à jour de tarifRC:', data.message); + return { valid: false, message: data.message }; + } + } else { + // Créer un nouvel enregistrement tarifRC + console.log('📝 Création nouveau tarifRC'); + const response = await fetch(`/rc/tarif/create`, { + method: 'POST', + body: JSON.stringify(tarifRCData), + headers: { + 'Content-Type': 'application/json', + }, + }); + const data = await response.json(); + console.log('📥 Réponse serveur tarifRC create:', data); + if (data.valid) { + idTarifRC = data.tarifRc.id; + } else { + console.error('❌ Échec de la création de tarifRC:', data.message); + return { valid: false, message: data.message }; + } + } + + // ===== ÉTAPE 4: Mettre à jour RC principal avec les données communes ET la référence tarifRC ===== + rcMainData.tarifRC = idTarifRC; // Ajouter la référence à tarifRC + + console.log(`📝 Mise à jour RC principal (ID: ${rcId}) avec référence tarifRC: ${idTarifRC}`); + console.log('🔍 Données envoyées pour RC:', rcMainData); + + const updateRCResponse = await fetch(`/rc/update/${rcId}`, { + method: 'POST', + body: JSON.stringify(rcMainData), + headers: { + 'Content-Type': 'application/json', + }, + }); + const updateRCData = await updateRCResponse.json(); + console.log('📥 Réponse serveur RC update:', updateRCData); + + if (!updateRCData.valid) { + console.error('❌ Échec de la mise à jour de RC principal:', updateRCData.message); + return { valid: false, message: 'Échec mise à jour RC principal' }; + } + + console.log('✅ === TARIF RC SAUVEGARDÉ AVEC SUCCÈS ==='); + console.log('✅ RC ID:', rcId, '| TarifRC ID:', idTarifRC); + return { valid: true, idTarifRC, idRC: rcId }; + } catch (error) { + console.error('Erreur lors de la sauvegarde de tarifRC:', error); + return { valid: false, message: error.message }; + } + } + + // Fonction helper pour collecter les activités complémentaires + function collectActivitesComplJSON(typeActivite) { + let name; + switch(typeActivite.toLowerCase()) { + case 'voiturier': + name = 'actComplVoiturier/Loueur'; + break; + case 'commissionnaire': + name = 'actComplCommissionnaire de Transport'; + break; + case 'demenageur': + name = 'actComplDéménageur'; + break; + case 'logistique': + name = 'actComplLogistique'; + break; + default: + return JSON.stringify([]); + } + + const checkboxes = document.querySelectorAll(`[name="${name}"] input[type="checkbox"]:checked`); + const activites = []; + checkboxes.forEach(cb => { + const text = cb.nextElementSibling ? cb.nextElementSibling.textContent.trim() : cb.value; + activites.push(text); + }); + return JSON.stringify(activites); + } + + // Fonction helper pour collecter les marchandises + function collectMarchandisesJSON(typeActivite) { + let name; + switch(typeActivite.toLowerCase()) { + case 'voiturier': + name = 'marVoiturier/Loueur'; + break; + case 'commissionnaire': + name = 'marCommissionnaire de Transport'; + break; + case 'demenageur': + name = 'marDéménageur'; + break; + case 'logistique': + name = 'marLogistique'; + break; + case 'autocariste': + name = 'marAutocariste'; + break; + case 'autres': + name = 'marAutres activites'; + break; + default: + return JSON.stringify([]); + } + + const checkboxes = document.querySelectorAll(`[name="${name}"] input[type="checkbox"]:checked`); + const marchandises = []; + checkboxes.forEach(cb => { + const text = cb.nextElementSibling ? cb.nextElementSibling.textContent.trim() : cb.value; + marchandises.push(text); + }); + return JSON.stringify(marchandises); + } + + // Fonction pour gérer les clics sur les boutons de tariffettes + function setupTarifetteButtons() { + const tarifetteButtons = document.querySelectorAll('.franchise-card button[name]'); + tarifetteButtons.forEach(button => { + button.addEventListener('click', async function(e) { + e.preventDefault(); + const franchiseValue = this.getAttribute('name'); + + // Mettre à jour la variable globale et l'UI + window.franchiseChoisie = franchiseValue; + console.log(`Tariffette sélectionnée: ${franchiseValue}€`); + + // Mettre en surbrillance la carte sélectionnée + document.querySelectorAll('.franchise-card').forEach(c => c.classList.remove('selected')); + this.closest('.franchise-card').classList.add('selected'); + + // Ouvrir le modal de tarif commercial + openModalTarifCom(franchiseValue); + }); + }); + } + + // Fonction pour configurer les alertes de marchandises + function setupMarchandiseAlerts() { + // Alerte pour Animaux Vivants + document.querySelectorAll('[name^="mar"] input[type="checkbox"]').forEach(cb => { + cb.addEventListener('change', function() { + const label = this.nextElementSibling?.textContent.trim(); + if (label && label.includes('Animaux vivants') && this.checked) { + window.modalAnimauxVivants.open(); + } + if (label && label.includes('Transport de béton') && this.checked) { + window.modalTransportBeton.open(); + } + }); + }); + } + + // Fonction pour configurer les alertes d'activités + function setupActiviteAlerts() { + // Alerte pour Autocariste + RCE + const checkAutocariste = document.getElementById('checkAutocariste'); + const checkRCE = document.getElementById('checkRCE'); + + const checkBothAutocariste = () => { + if (checkAutocariste?.checked && checkRCE?.checked) { + window.modalAutocaristeRCE.open(); + } + }; + + if (checkAutocariste) checkAutocariste.addEventListener('change', checkBothAutocariste); + if (checkRCE) checkRCE.addEventListener('change', checkBothAutocariste); + } + + // Seuil de différence acceptable (5%) + const seuil = 5; + + // Fonction pour ouvrir le modal de tarif commercial + function openModalTarifCom(franchiseValue) { + // Récupérer le tarif de référence selon la franchise + let tarifRef = 0; + if (franchiseValue === '250') { + tarifRef = toNumber(document.getElementById('priceFr250')?.textContent); + } else if (franchiseValue === '400') { + tarifRef = toNumber(document.getElementById('priceFr400')?.textContent); + } else if (franchiseValue === 'mini300') { + tarifRef = toNumber(document.getElementById('priceFr2000')?.textContent); + } + + // Réinitialiser le modal + document.getElementById('tarifRefText').innerText = `Tarif de Référence : ${formatNumber(tarifRef, 2)} €`; + document.getElementById('tarifCom').value = ''; + document.getElementById('commentaire').value = ''; + document.getElementById('comm-OK').disabled = false; + document.getElementById('tarifCom-error').style.display = 'none'; + document.getElementById('col-commentaire').style.display = 'none'; + document.getElementById('qualiteDiv').style.display = 'none'; + document.getElementById('comm-OK').setAttribute('data-franchise', franchiseValue); + document.getElementById('comm-OK').setAttribute('data-tarif-ref', tarifRef); + + // Event listener pour le champ tarif commercial + const tarifComInput = document.getElementById('tarifCom'); + tarifComInput.removeEventListener('input', handleTarifComInput); + tarifComInput.addEventListener('input', handleTarifComInput); + + // Event listener pour le commentaire + const commentaireInput = document.getElementById('commentaire'); + commentaireInput.removeEventListener('input', handleCommentaireInput); + commentaireInput.addEventListener('input', handleCommentaireInput); + + // Ouvrir le modal + window.modalTarifCom.open(); + } + + // Fonction pour gérer l'input du tarif commercial + function handleTarifComInput(e) { + const tarifCom = parseFloat(e.target.value); + const tarifRef = parseFloat(document.getElementById('comm-OK').getAttribute('data-tarif-ref')); + + if (!tarifCom || tarifCom <= 0) { + document.getElementById('qualiteDiv').style.display = 'none'; + return; + } + + const diff = 100 * (tarifCom / tarifRef); + let qualitePrime = ''; + let emoji = ''; + let showComment = false; + + if (diff < (100 + seuil) && diff > (100 - seuil)) { + emoji = 'mood'; + showComment = false; + + if (diff > 100) { + qualitePrime = `Tarif correct (+${(diff - 100).toFixed(2)}%)`; + } else if (diff < 100) { + qualitePrime = `Tarif correct (-${(100 - diff).toFixed(2)}%)`; + } else { + qualitePrime = 'Le juste prix'; + emoji = 'thumb_up_alt'; + } + } else { + emoji = 'mood_bad'; + showComment = true; + + if (diff > (100 + seuil)) { + qualitePrime = `Tarif trop élevé (+${(diff - 100).toFixed(2)}%)`; + } else if (diff < (100 - seuil)) { + qualitePrime = `Tarif trop bas (-${(100 - diff).toFixed(2)}%)`; + } + } + + document.getElementById('qualiteDiv').style.display = 'block'; + document.getElementById('qualitePrime').innerText = qualitePrime; + document.getElementById('modalTarifCom-icon').innerText = emoji; + document.getElementById('modalTarifCom-icon').style.color = (emoji === 'mood_bad') ? 'red' : 'green'; + + if (showComment) { + document.getElementById('tarifCom-error').style.display = 'flex'; + document.getElementById('col-commentaire').style.display = 'flex'; + if (!document.getElementById('commentaire').value.trim()) { + document.getElementById('comm-OK').disabled = true; + } + } else { + document.getElementById('comm-OK').disabled = false; + document.getElementById('tarifCom-error').style.display = 'none'; + document.getElementById('col-commentaire').style.display = 'none'; + } + } + + // Fonction pour gérer l'input du commentaire + function handleCommentaireInput(e) { + const commentaire = e.target.value.trim(); + const tarifComError = document.getElementById('tarifCom-error').style.display !== 'none'; + + if (tarifComError) { + document.getElementById('comm-OK').disabled = !commentaire; + } + } + + // Fonction pour gérer la validation du tarif commercial + async function handleValidateTarifCom() { + const tarifCom = parseFloat(document.getElementById('tarifCom').value); + const commentaire = document.getElementById('commentaire').value.trim(); + const franchiseValue = document.getElementById('comm-OK').getAttribute('data-franchise'); + + if (!tarifCom || tarifCom <= 0) { + M.toast({html: 'Veuillez saisir un tarif commercial valide', classes: 'red'}); + return; + } + + + // Fermer le modal + window.modalTarifCom.close(); + + // Afficher un loader + M.toast({html: '⏳ Sauvegarde en cours...', classes: 'blue'}); + + // Sauvegarder le tarif + const saveResult = await saveTarifRC(); + + if (saveResult && saveResult.valid) { + M.toast({html: `Tarif sauvegardé avec succès !`, classes: 'green'}); + + // Rediriger vers la page projet après un court délai + setTimeout(() => { + console.log('🚀 Redirection vers projet...'); + // Construire l'URL de redirection vers projet + const numParcours = parcours?.numParcours; + if (numParcours) { + window.location.href = `navParcours?numParcours=${numParcours}&submenu=projet`; + } else { + M.toast({html: 'Erreur: impossible de rediriger', classes: 'red'}); + } + }, 1000); + } else { + M.toast({html: '❌ Erreur lors de la sauvegarde du tarif', classes: 'red'}); + } + } + + // Exposer les fonctions globalement pour y accéder depuis l'extérieur + window.initSubmenuForm = init; + window.saveTarifRC = saveTarifRC; +})(); \ No newline at end of file diff --git a/ecole/src/constantes/json-modulateur-rc.js b/ecole/src/constantes/json-modulateur-rc.js new file mode 100644 index 00000000..4550c440 --- /dev/null +++ b/ecole/src/constantes/json-modulateur-rc.js @@ -0,0 +1,1434 @@ +const modRCCA = { + // max CA : Modulation CA + 400000: 1.00, + 500000: 0.85, + 800000: 0.80, + 1000000: 0.70, + 1600000: 0.64, + 2000000: 0.51, + 2400000: 0.44, + 3000000: 0.38, + 3200000: 0.30, + 4000000: 0.28, + 5000000: 0.22, + 1234567890123456789: 0.20 +}; + +const modRCActRCC = { + revisable: { + // Capital:TauxBase + "Voiturier/Loueur": { + 5000: 0.16, + 10000: 0.16, + 15000: 0.16, + 20000: 0.16, + 25000: 0.17, + 30000: 0.17, + 50000: 0.17, + 60000: 0.18, + 100000: 0.19, + 150000: 0.20, + 200000: 0.21, + 300000: 0.22, + 400000: 0.23 + }, + "Commissionnaire de Transport": { + 100000: 0.08, + 150000: 0.10, + 200000: 0.11, + 300000: 0.12, + 400000: 0.13, + }, + "Déménageur": { + 5000: 0.32, + 10000: 0.32, + 15000: 0.32, + 20000: 0.32, + 25000: 0.34, + 30000: 0.34, + 50000: 0.34, + 60000: 0.36, + 100000: 0.38, + 150000: 0.40, + 200000: 0.42, + 300000: 0.44, + 400000: 0.46 + }, + "Logistique": { + 5000: 0.057, + 10000: 0.057, + 15000: 0.057, + 20000: 0.057, + 25000: 0.057, + 30000: 0.057, + 50000: 0.057, + 60000: 0.21, + 100000: 0.271, + 150000: 0.271, + 200000: 0.271, + 300000: 0.2, + 400000: 0.25 + }, + "Autres activites": { + 5000: 0.16, + 10000: 0.16, + 15000: 0.16, + 20000: 0.16, + 25000: 0.17, + 30000: 0.17, + 50000: 0.17, + 60000: 0.18, + 100000: 0.19, + 150000: 0.20, + 200000: 0.21, + 300000: 0.22, + 400000: 0.23 + } + }, + forfaitaire: { + // Capital : prime forfaitaire {1veh, 2veh} + "Voiturier/Loueur": { + 5000: { + unVehicule: 130, + deuxVehicules: 220 + }, + 10000: { + unVehicule: 160, + deuxVehicules: 270 + }, + 15000: { + unVehicule: 180, + deuxVehicules: 300 + }, + 20000: { + unVehicule: 190, + deuxVehicules: 320 + }, + 25000: { + unVehicule: 205, + deuxVehicules: 345 + }, + 30000: { + unVehicule: 205, + deuxVehicules: 345 + }, + 50000: { + unVehicule: 260, + deuxVehicules: 425 + }, + 60000: { + unVehicule: 295, + deuxVehicules: 480 + }, + 100000: { + unVehicule: 330, + deuxVehicules: 495 + }, + 150000: { + unVehicule: 370, + deuxVehicules: 555 + }, + 200000: { + unVehicule: 410, + deuxVehicules: 600 + }, + 300000: { + unVehicule: 490, + deuxVehicules: 730 + }, + 400000: { + unVehicule: 550, + deuxVehicules: 820 + } + }, + "Déménageur": { + 5000: { + unVehicule: 260, + deuxVehicules: 440 + }, + 10000: { + unVehicule: 320, + deuxVehicules: 540 + }, + 15000: { + unVehicule: 360, + deuxVehicules: 600 + }, + 20000: { + unVehicule: 380, + deuxVehicules: 640 + }, + 25000: { + unVehicule: 410, + deuxVehicules: 690 + }, + 30000: { + unVehicule: 450, + deuxVehicules: 750 + }, + 50000: { + unVehicule: 520, + deuxVehicules: 850 + }, + 60000: { + unVehicule: 590, + deuxVehicules: 960 + }, + 100000: { + unVehicule: 660, + deuxVehicules: 990 + }, + 150000: { + unVehicule: 740, + deuxVehicules: 1110 + }, + 200000: { + unVehicule: 820, + deuxVehicules: 1200 + }, + 300000: { + unVehicule: 980, + deuxVehicules: 1460 + }, + 400000: { + unVehicule: 1100, + deuxVehicules: 1640 + } + }, + "Autocariste": { + 25000: { + unVehicule: 114, + deuxVehicules: 228 + }, + 50000: { + unVehicule: 204, + deuxVehicules: 408 + }, + 75000: { + unVehicule: 294, + deuxVehicules: 588 + }, + 100000: { + unVehicule: 384, + deuxVehicules: 768 + }, + 125000: { + unVehicule: 474, + deuxVehicules: 948 + }, + 150000: { + unVehicule: 564, + deuxVehicules: 1128 + } + } + } +}; + +const modRCActRCE = { + revisable: { + "Voiturier/Loueur": { + mini: 0.06, + optimale: 0.08, + maxi: 0.1 + }, + "Commissionnaire de Transport": { + mini: 0.045, + optimale: 0.05, + maxi: 0.055 + }, + "Déménageur": { + mini: 0.12, + optimale: 0.16, + maxi: 0.2 + }, + "Logistique": { + mini: 0.06, + optimale: 0.08, + maxi: 0.1 + }, + "Autres activites": { + mini: 0.06, + optimale: 0.08, + maxi: 0.1 + } + }, + forfaitaire: { + "Voiturier/Loueur": { + unVehicule: { + mini: 105, + optimale: 115, + maxi: 125 + }, + deuxVehicules: { + mini: 140, + optimale: 150, + maxi: 160 + } + }, + "Déménageur": { + unVehicule: { + mini: 0, + optimale: 115, + maxi: 0 + }, + deuxVehicules: { + mini: 0, + optimale: 150, + maxi: 0 + } + }, + "Autocariste": { + unVehicule: { + mini: 0, + optimale: 0, + maxi: 0 + }, + deuxVehicules: { + mini: 0, + optimale: 0, + maxi: 0 + } + } + } +}; + +const modRCActCompl = { + revisable: { + "Voiturier/Loueur": { + "Voiturier y compris sous-traitance temporaire": { + modRCC: 1, + modRCE: 1 + }, + "Loueur de véhicule industriel avec conducteur": { + modRCC: 1, + modRCE: 1 + }, + "Coursier en 2 ou 3 roues": { + modRCC: 1, + modRCE: 1 + }, + "Montage de meuble, électroménager, branchement": { + modRCC: 1, + modRCE: 3 + }, + "Manutentionnaire - levageur / Loueur de matériel de levage avec opérateur": { + modRCC: 1, + modRCE: 3 + }, + "Accompagnement de transport exceptionnel": { + modRCC: 1, + modRCE: 1 + } + }, + "Commissionnaire de Transport": { + "Commissionnaire de transport multimodal - zone UE": { + modRCC: 1, + modRCE: 1 + }, + "Commissionnaire de transport multimodal": { + modRCC: 1.3, + modRCE: 1 + }, + "Transitaire": { + modRCC: 1, + modRCE: 1 + }, + "Représentant en Douane Enregistré": { + modRCC: 1.5, + modRCE: 1 + } + }, + "Déménageur": { + "Déménageur de particuliers par voie terrestre": { + modRCC: 1, + modRCE: 1 + }, + "Déménageur de particuliers par voie terrestre - garantie dommage": { + modRCC: 1, + modRCE: 1 + }, + "Déménageur d'entreprises": { + modRCC: 1, + modRCE: 1 + }, + "Déménageur interne": { + modRCC: 1, + modRCE: 1 + }, + "Garde-meubles": { + modRCC: 1, + modRCE: 1 + } + }, + "Logistique": { + "Entrepositaire - dépositaire": { + modRCC: 1, + modRCE: 1 + }, + "Gestion de stocks - préparation de commande": { + modRCC: 1.3, + modRCE: 1 + }, + "Empoteur": { + modRCC: 1, + modRCE: 1 + } + }, + "Autres activites": { + } + }, + forfaitaire: { + "Voiturier/Loueur": { + "Coursier en 2 ou 3 roues": { + modRCC: 1, + modRCE: 1 + }, + "Montage de meuble, électroménager, branchement": { + modRCC: 3, + modRCE: 3 + }, + "Manutentionnaire": { + modRCC: 1, + modRCE: 1 + }, + "Accompagnement de transport exceptionnel": { + modRCC: 1, + modRCE: 1 + } + }, + "Déménageur": { + "Garde Meuble": { + modRCC: 1, + modRCE: 1 + } + }, + "Autocariste": { + } + } +}; + +const modRCMar = { + revisable: { + "Voiturier/Loueur": { + "Marchandises ordinaires": { + modRCC: 1, + modRCE: 1 + }, + "Véhicules roulants": { + modRCC: 1.3, + modRCE: 1 + }, + "Engins de chantier": { + modRCC: 1.2, + modRCE: 1 + }, + "Objets indivisibles": { + modRCC: 1.2, + modRCE: 1 + }, + "Marchandises périssables": { + modRCC: 1.2, + modRCE: 1 + }, + "Marchandises en citerne": { + modRCC: 0.7, + modRCE: 1.5 + }, + "Animaux vivants": { + modRCC: 1, + modRCE: 1 + }, + "Marchandises en benne": { + modRCC: 1, + modRCE: 1 + }, + "Transport de béton": { + modRCC: 0.7, + modRCE: 1.5 + } + }, + "Commissionnaire de Transport": { + "Marchandises ordinaires": { + modRCC: 1, + modRCE: 1 + }, + "Véhicules roulants": { + modRCC: 1.3, + modRCE: 1 + }, + "Engins de chantier": { + modRCC: 1.2, + modRCE: 1 + }, + "Objets indivisibles": { + modRCC: 1.2, + modRCE: 1 + }, + "Marchandises périssables": { + modRCC: 1.2, + modRCE: 1 + }, + "Marchandises en citerne": { + modRCC: 0.7, + modRCE: 1.5 + }, + "Animaux vivants": { + modRCC: 1, + modRCE: 1 + }, + "Marchandises en benne": { + modRCC: 1, + modRCE: 1 + }, + "Transport de béton": { + modRCC: 0.7, + modRCE: 1.5 + } + }, + "Déménageur": { + "Mobiliers en déménagement": { + modRCC: 3, + modRCE: 2 + } + }, + "Logistique": { + "Marchandises ordinaires": { + modRCC: 1, + modRCE: 1 + }, + "Véhicules roulants": { + modRCC: 1.3, + modRCE: 1 + }, + "Engins de chantier": { + modRCC: 1.2, + modRCE: 1 + }, + "Objets indivisibles": { + modRCC: 1.2, + modRCE: 1 + }, + "Marchandises périssables": { + modRCC: 1.2, + modRCE: 1 + }, + "Marchandises en citerne": { + modRCC: 0.7, + modRCE: 1.5 + }, + "Animaux vivants": { + modRCC: 1, + modRCE: 1 + }, + "Marchandises en benne": { + modRCC: 1, + modRCE: 1 + }, + "Transport de béton": { + modRCC: 0.7, + modRCE: 1.5 + } + }, + "Autres activites": { + "Marchandises ordinaires": { + modRCC: 1, + modRCE: 1 + }, + "Véhicules roulants": { + modRCC: 1.3, + modRCE: 1 + }, + "Engins de chantier": { + modRCC: 1.2, + modRCE: 1 + }, + "Objets indivisibles": { + modRCC: 1.2, + modRCE: 1 + }, + "Marchandises périssables": { + modRCC: 1.2, + modRCE: 1 + }, + "Marchandises en citerne": { + modRCC: 0.7, + modRCE: 1.5 + }, + "Animaux vivants": { + modRCC: 1, + modRCE: 1 + }, + "Marchandises en benne": { + modRCC: 1, + modRCE: 1 + }, + "Transport de béton": { + modRCC: 0.7, + modRCE: 1.5 + } + } + }, + forfaitaire: { + "Voiturier/Loueur": { + "Marchandises ordinaires": { + modRCC: 1, + modRCE: 1 + }, + "Véhicules roulants": { + modRCC: 1.3, + modRCE: 1 + }, + "Engins de chantier": { + modRCC: 1.2, + modRCE: 1 + }, + "Objets indivisibles": { + modRCC: 1.2, + modRCE: 1 + }, + "Marchandises périssables": { + modRCC: 1.2, + modRCE: 1 + }, + "Marchandises en citerne": { + modRCC: 0.7, + modRCE: 1.5 + }, + "Animaux vivants": { + modRCC: 1, + modRCE: 1 + }, + "Marchandises en benne": { + modRCC: 1, + modRCE: 1 + }, + "Transport de béton": { + modRCC: 1, + modRCE: 1 + } + }, + "Déménageur": { + "Mobiliers en déménagement": { + modRCC: 3, + modRCE: 2 + } + }, + "Autocariste": { + "Marchandises ordinaires": { + modRCC: 1, + modRCE: 1 + }, + "Véhicules roulants": { + modRCC: 1.3, + modRCE: 1 + }, + "Marchandises en benne": { + modRCC: 1, + modRCE: 1 + }, + "Engins de chantier": { + modRCC: 1.2, + modRCE: 1 + }, + "Objets indivisibles": { + modRCC: 1.2, + modRCE: 1 + }, + "Marchandises périssables": { + modRCC: 1.2, + modRCE: 1 + }, + "Marchandises en citerne": { + modRCC: 0.7, + modRCE: 1.5 + }, + "Animaux vivants": { + modRCC: 1, + modRCE: 1 + }, + "Marchandises en benne": { + modRCC: 1, + modRCE: 1 + }, + "Transport de béton": { + modRCC: 1, + modRCE: 1 + } + } + } +}; + +const modRCZone = { + "France Métropolitaine et pays limitrophes": { + modRCC: 1, + modRCE: 1 + }, + "Union Européenne": { + modRCC: 1.1, + modRCE: 1 + }, + "Autres pays européens sauf Russie et Ukraine (y compris UK et Norvège)": { + modRCC: 1.3, + modRCE: 1 + }, + "Pays du Maghreb et Amérique du Nord ( USA / Canada / Mexique )": { + modRCC: 1.3, + modRCE: 1 + }, + "Amérique Centrale et Sud / Caraïbes, Asie et Océanie": { + modRCC: 1.3, + modRCE: 1 + }, + "Afrique Hors Maghreb / Proche Orient / Moyen Orient": { + modRCC: 1.3, + modRCE: 1 + } +}; + +const modRCEngagCompl = { + modRCC: { + // Tranche:Modulation + "Dommages immatériels": { + 15000: 1, + 50000: 1.025, + 100000: 1.05, + 150000: 1.08, + 300000: 1.10, + 400000: 1.13, + 500000: 1.15 + }, + "Contenants confiés": { + 25000: 0, + 50000: 500, + 100000: 1000 + }, + "Différence inventaire": { + 15000: 0, + 30000: 1000, + 50000: 3000 + } + } +}; + +const modRCGarAdd = { + modRCC: { + // Tranche:Modulation + "TPPC": { + 5000: 0, + 10000: 0.01, + 15000: 0.01, + 30000: 0.01 + }, + "Protection juridique": { + 0: 49.38, + 500: 80.25, + 1000: 119.93, + 2000: 209.88, + 3000: 320.11, + 5000: 509.70, + 7000: 720.46, + 10000: 990.30, + 15000: 1489.42, + 25000: 2389.77, + 40000: 2389.77 + } + }, + modRCE: { + "Station de lavage": 1000, + "Garage interne": 1500, + "Comité Social et Economique": 100 + } +}; + +const modRCSinistre = { + // pourcentage:modulation + 0.4: 1, + 0.7: 1.3, + 1: 1.5 +}; + +const modRCFranchise = { + "250": { + modRCC: 1, + modRCE: 1 + }, + "400": { + modRCC: 0.9, + modRCE: 0.9 + }, + "10% avec mini 300 € et maxi 2000": { + modRCC: 0.8, + modRCE: 0.8 + } +}; + +const modRCPrimeMini = { + revisable: { + //Tranche:Modulation + "Voiturier/Loueur": { + 5000: { + miniRCC: 330, + miniRCE: 330 + }, + 10000: { + miniRCC: 374, + miniRCE: 330 + }, + 15000: { + miniRCC: 396, + miniRCE: 330 + }, + 20000: { + miniRCC: 418, + miniRCE: 330 + }, + 25000: { + miniRCC: 462, + miniRCE: 330 + }, + 30000: { + miniRCC: 484, + miniRCE: 330 + }, + 50000: { + miniRCC: 550, + miniRCE: 330 + }, + 60000: { + miniRCC: 616, + miniRCE: 330 + }, + 100000: { + miniRCC: 660, + miniRCE: 330 + }, + 150000: { + miniRCC: 770, + miniRCE: 330 + }, + 200000: { + miniRCC: 880, + miniRCE: 330 + }, + 300000: { + miniRCC: 1100, + miniRCE: 330 + }, + 400000: { + miniRCC: 1320, + miniRCE: 330 + } + }, + "Commissionnaire de Transport": { + 5000: { + miniRCC: 0, + miniRCE: 0 + }, + 10000: { + miniRCC: 0, + miniRCE: 0 + }, + 15000: { + miniRCC: 0, + miniRCE: 0 + }, + 20000: { + miniRCC: 0, + miniRCE: 0 + }, + 25000: { + miniRCC: 0, + miniRCE: 0 + }, + 30000: { + miniRCC: 0, + miniRCE: 0 + }, + 50000: { + miniRCC: 0, + miniRCE: 0 + }, + 60000: { + miniRCC: 0, + miniRCE: 0 + }, + 100000: { + miniRCC: 1200, + miniRCE: 150 + }, + 150000: { + miniRCC: 1300, + miniRCE: 150 + }, + 200000: { + miniRCC: 1300, + miniRCE: 150 + }, + 300000: { + miniRCC: 1600, + miniRCE: 150 + }, + 400000: { + miniRCC: 1800, + miniRCE: 150 + } + }, + "Déménageur": { + 5000: { + miniRCC: 594, + miniRCE: 660 + }, + 10000: { + miniRCC: 673, + miniRCE: 660 + }, + 15000: { + miniRCC: 713, + miniRCE: 660 + }, + 20000: { + miniRCC: 752, + miniRCE: 660 + }, + 25000: { + miniRCC: 832, + miniRCE: 660 + }, + 30000: { + miniRCC: 871, + miniRCE: 660 + }, + 50000: { + miniRCC: 990, + miniRCE: 660 + }, + 60000: { + miniRCC: 1109, + miniRCE: 660 + }, + 100000: { + miniRCC: 1188, + miniRCE: 660 + }, + 150000: { + miniRCC: 1386, + miniRCE: 660 + }, + 200000: { + miniRCC: 1584, + miniRCE: 660 + }, + 300000: { + miniRCC: 1980, + miniRCE: 660 + }, + 400000: { + miniRCC: 2376, + miniRCE: 660 + } + }, + "Logistique": { + 5000: { + miniRCC: 0, + miniRCE: 0 + }, + 10000: { + miniRCC: 0, + miniRCE: 0 + }, + 15000: { + miniRCC: 0, + miniRCE: 0 + }, + 20000: { + miniRCC: 0, + miniRCE: 0 + }, + 25000: { + miniRCC: 0, + miniRCE: 0 + }, + 30000: { + miniRCC: 557, + miniRCE: 150 + }, + 50000: { + miniRCC: 633, + miniRCE: 150 + }, + 60000: { + miniRCC: 708, + miniRCE: 150 + }, + 100000: { + miniRCC: 759, + miniRCE: 150 + }, + 150000: { + miniRCC: 886, + miniRCE: 150 + }, + 200000: { + miniRCC: 1012, + miniRCE: 150 + }, + 300000: { + miniRCC: 1265, + miniRCE: 150 + }, + 400000: { + miniRCC: 1518, + miniRCE: 150 + } + }, + "Autocariste": { + 5000: { + miniRCC: 500, + miniRCE: 150 + }, + 10000: { + miniRCC: 500, + miniRCE: 150 + }, + 15000: { + miniRCC: 550, + miniRCE: 150 + }, + 20000: { + miniRCC: 550, + miniRCE: 150 + }, + 25000: { + miniRCC: 620, + miniRCE: 150 + }, + 30000: { + miniRCC: 620, + miniRCE: 150 + }, + 50000: { + miniRCC: 660, + miniRCE: 150 + }, + 60000: { + miniRCC: 660, + miniRCE: 150 + }, + 100000: { + miniRCC: 700, + miniRCE: 150 + }, + 150000: { + miniRCC: 700, + miniRCE: 150 + }, + 200000: { + miniRCC: 750, + miniRCE: 150 + }, + 300000: { + miniRCC: 850, + miniRCE: 150 + }, + 400000: { + miniRCC: 850, + miniRCE: 150 + } + }, + "Autres activites": { + 5000: { + miniRCC: 500, + miniRCE: 150 + }, + 10000: { + miniRCC: 500, + miniRCE: 150 + }, + 15000: { + miniRCC: 550, + miniRCE: 150 + }, + 20000: { + miniRCC: 550, + miniRCE: 150 + }, + 25000: { + miniRCC: 620, + miniRCE: 150 + }, + 30000: { + miniRCC: 620, + miniRCE: 150 + }, + 50000: { + miniRCC: 660, + miniRCE: 150 + }, + 60000: { + miniRCC: 660, + miniRCE: 150 + }, + 100000: { + miniRCC: 700, + miniRCE: 150 + }, + 150000: { + miniRCC: 700, + miniRCE: 150 + }, + 200000: { + miniRCC: 750, + miniRCE: 150 + }, + 300000: { + miniRCC: 850, + miniRCE: 150 + }, + 400000: { + miniRCC: 850, + miniRCE: 150 + } + } + }, + forfaitaire: { + //Tranche:Value Mini + "Voiturier/Loueur": { + 5000: { + miniRCC: 150, + miniRCE: 150 + }, + 10000: { + miniRCC: 170, + miniRCE: 150 + }, + 15000: { + miniRCC: 180, + miniRCE: 150 + }, + 20000: { + miniRCC: 190, + miniRCE: 150 + }, + 25000: { + miniRCC: 210, + miniRCE: 150 + }, + 30000: { + miniRCC: 220, + miniRCE: 150 + }, + 50000: { + miniRCC: 250, + miniRCE: 150 + }, + 60000: { + miniRCC: 280, + miniRCE: 150 + }, + 100000: { + miniRCC: 300, + miniRCE: 150 + }, + 150000: { + miniRCC: 350, + miniRCE: 150 + }, + 200000: { + miniRCC: 400, + miniRCE: 150 + }, + 300000: { + miniRCC: 500, + miniRCE: 150 + }, + 400000: { + miniRCC: 600, + miniRCE: 150 + } + }, + "Commissionnaire de Transport": { + 5000: { + miniRCC: 0, + miniRCE: 0 + }, + 10000: { + miniRCC: 0, + miniRCE: 0 + }, + 15000: { + miniRCC: 0, + miniRCE: 0 + }, + 20000: { + miniRCC: 0, + miniRCE: 0 + }, + 25000: { + miniRCC: 0, + miniRCE: 0 + }, + 30000: { + miniRCC: 0, + miniRCE: 0 + }, + 50000: { + miniRCC: 0, + miniRCE: 0 + }, + 60000: { + miniRCC: 0, + miniRCE: 0 + }, + 100000: { + miniRCC: 0, + miniRCE: 0 + }, + 150000: { + miniRCC: 0, + miniRCE: 0 + }, + 200000: { + miniRCC: 0, + miniRCE: 0 + }, + 300000: { + miniRCC: 0, + miniRCE: 0 + }, + 400000: { + miniRCC: 0, + miniRCE: 0 + } + }, + "Déménageur": { + 5000: { + miniRCC: 270, + miniRCE: 300 + }, + 10000: { + miniRCC: 306, + miniRCE: 300 + }, + 15000: { + miniRCC: 324, + miniRCE: 300 + }, + 20000: { + miniRCC: 342, + miniRCE: 300 + }, + 25000: { + miniRCC: 378, + miniRCE: 300 + }, + 30000: { + miniRCC: 396, + miniRCE: 300 + }, + 50000: { + miniRCC: 450, + miniRCE: 300 + }, + 60000: { + miniRCC: 504, + miniRCE: 300 + }, + 100000: { + miniRCC: 540, + miniRCE: 300 + }, + 150000: { + miniRCC: 630, + miniRCE: 300 + }, + 200000: { + miniRCC: 720, + miniRCE: 300 + }, + 300000: { + miniRCC: 900, + miniRCE: 300 + }, + 400000: { + miniRCC: 1080, + miniRCE: 300 + } + }, + "Logistique": { + 5000: { + miniRCC: 0, + miniRCE: 0 + }, + 10000: { + miniRCC: 0, + miniRCE: 0 + }, + 15000: { + miniRCC: 0, + miniRCE: 0 + }, + 20000: { + miniRCC: 0, + miniRCE: 0 + }, + 25000: { + miniRCC: 0, + miniRCE: 0 + }, + 30000: { + miniRCC: 0, + miniRCE: 0 + }, + 50000: { + miniRCC: 0, + miniRCE: 0 + }, + 60000: { + miniRCC: 0, + miniRCE: 0 + }, + 100000: { + miniRCC: 0, + miniRCE: 0 + }, + 150000: { + miniRCC: 0, + miniRCE: 0 + }, + 200000: { + miniRCC: 0, + miniRCE: 0 + }, + 300000: { + miniRCC: 0, + miniRCE: 0 + }, + 400000: { + miniRCC: 0, + miniRCE: 0 + } + }, + "Autocariste": { + 5000: { + miniRCC: 270, + miniRCE: 300 + }, + 10000: { + miniRCC: 306, + miniRCE: 300 + }, + 15000: { + miniRCC: 324, + miniRCE: 300 + }, + 20000: { + miniRCC: 342, + miniRCE: 300 + }, + 25000: { + miniRCC: 378, + miniRCE: 300 + }, + 30000: { + miniRCC: 396, + miniRCE: 300 + }, + 50000: { + miniRCC: 450, + miniRCE: 300 + }, + 60000: { + miniRCC: 504, + miniRCE: 300 + }, + 100000: { + miniRCC: 540, + miniRCE: 300 + }, + 150000: { + miniRCC: 630, + miniRCE: 300 + }, + 200000: { + miniRCC: 720, + miniRCE: 300 + }, + 300000: { + miniRCC: 900, + miniRCE: 300 + }, + 400000: { + miniRCC: 1080, + miniRCE: 300 + } + }, + "Autres activites": { + 5000: { + miniRCC: 0, + miniRCE: 0 + }, + 10000: { + miniRCC: 0, + miniRCE: 0 + }, + 15000: { + miniRCC: 0, + miniRCE: 0 + }, + 20000: { + miniRCC: 0, + miniRCE: 0 + }, + 25000: { + miniRCC: 0, + miniRCE: 0 + }, + 30000: { + miniRCC: 0, + miniRCE: 0 + }, + 50000: { + miniRCC: 0, + miniRCE: 0 + }, + 60000: { + miniRCC: 0, + miniRCE: 0 + }, + 100000: { + miniRCC: 0, + miniRCE: 0 + }, + 150000: { + miniRCC: 0, + miniRCE: 0 + }, + 200000: { + miniRCC: 0, + miniRCE: 0 + }, + 300000: { + miniRCC: 0, + miniRCE: 0 + }, + 400000: { + miniRCC: 0, + miniRCE: 0 + } + } + } +}; + +module.exports = { + modRCCA, + modRCActRCC, + modRCActRCE, + modRCActCompl, + modRCMar, + modRCZone, + modRCEngagCompl, + modRCGarAdd, + modRCSinistre, + modRCFranchise, + modRCPrimeMini +}; \ No newline at end of file diff --git a/ecole/src/controllers/generateRcController.js b/ecole/src/controllers/generateRcController.js index 47a4a468..a4d09fe3 100644 --- a/ecole/src/controllers/generateRcController.js +++ b/ecole/src/controllers/generateRcController.js @@ -8,157 +8,196 @@ const path = require("path"); const moment = require("moment"); const parcoursService = require("../services/parcoursService"); const contratService = require("../services/contratService"); +const userService = require("../services/userService"); const globalService = require("../services/globalService"); +//const projetformrc = require("../../public/js/projet-form-rc"); +//const moduloRC = require("../constantes/json-modulateur-rc"); useless pour le moment ? require("moment/locale/fr"); moment.locale("fr"); +// Fonctions helper pour récupérer les valeurs selon la franchise choisie +function getSelectedTarifReference(tarifRC) { + const franchise = tarifRC.franchiseChoisie; + if (franchise === '250') return tarifRC.primeTotal_250; + if (franchise === '400') return tarifRC.primeTotal_400; + if (franchise === 'mini300') return tarifRC.primeTotal_2000; + return null; +} + +function getSelectedPrime(tarifRC, type) { + const franchise = tarifRC.franchiseChoisie; + if (!franchise) return 0; + + const suffix = franchise === 'mini300' ? '2000' : franchise; + const fieldName = `prime${type}_${suffix}`; + return tarifRC[fieldName] || 0; +} + +function getSelectedTaux(tarifRC, type) { + const franchise = tarifRC.franchiseChoisie; + if (!franchise) return 0; + + const suffix = franchise === 'mini300' ? '2000' : franchise; + const fieldName = `taux${type}_${suffix}`; + return tarifRC[fieldName] || 0; +} + router.post("/rc/projet/:numParcours", async (req, res) => { - const content = fs.readFileSync( - path.resolve("src/templates/template-projet-rc.docx"), - "binary" - ); - - const zip = new PizZip(content); - const doc = new Docxtemplater(zip, { paragraphLoop: true, linebreaks: true }); - const numParcours = req.params.numParcours.toUpperCase(); - - const parcours = await parcoursService.getParcoursByNumParcours(numParcours); - const contrat = await contratService.getContratById(parcours.contrat); - const client = contrat?.["@expand"]?.client || {}; - const intermediaire = contrat?.["@expand"]?.intermediaire || {}; - const rc = contrat?.["@expand"]?.enCours || {}; - - const listAssAdd = []; - try { - rc.assureAdditionnel.forEach((objet) => { - listAssAdd.push( - objet.nom + + const content = fs.readFileSync( + path.resolve("src/templates/template-projet-rc.docx"), + "binary" + ); + + const zip = new PizZip(content); + const doc = new Docxtemplater(zip, { paragraphLoop: true, linebreaks: true }); + const numParcours = req.params.numParcours.toUpperCase(); + + const parcours = await parcoursService.getParcoursByNumParcours(numParcours); + const contrat = await contratService.getContratById(parcours.contrat); + const client = contrat?.["@expand"]?.client || {}; + const intermediaire = contrat?.["@expand"]?.intermediaire || {}; + + // Récupérer la collection rc avec ses relations (APRÈS placerDansEnCours, c'est dans enCours) + const rcFull = contrat?.["@expand"]?.enCours; + if (!rcFull) { + logger.log('error', 'No RC found for contrat:', contrat.id); + return res.status(404).send("Aucune donnée RC trouvée pour ce contrat"); + } + + // Les données sont déjà expandées par contratService + const rc = rcFull?.["@expand"]?.projetRC || {}; + + const listAssAdd = []; + + // Traiter les assurés additionnels s'ils existent + if (rc.assureAdditionnel && Array.isArray(rc.assureAdditionnel)) { + rc.assureAdditionnel.forEach((objet) => { + listAssAdd.push( + objet.nom + " - Adresse : " + objet.adresse + " - Siret : " + objet.siret - ); - }); - } catch (error) { } - - // Conditions zone - hasMondeEntier = false; - hasZone1 = false; - hasZone2 = false; - hasZone3 = false; - hasZone4 = false; - hasZone5 = false; - hasZone6 = false; - hasActiviteButNotMultimodal = false; // Attention trick pour les zones géographiques dans le cas de multimodal - hasZone456 = false; - - // Cas monde entier - if ( - rc.zone1 && - rc.zone2 && - rc.zone3 && - rc.zone4 && - rc.zone5 && - rc.zone6 && - (rc.actVoiturier || - rc.actLoueur || - rc.actDouane || - rc.actDemPar || - rc.actDemParDom || - rc.actDemParAdv || - rc.actDemEntr || - rc.actDemInterne || - rc.actGardeMeuble || - rc.actEntDep || - rc.actPrestaLog || - rc.actLevageur) - ) { - hasMondeEntier = true; - } - - // Cas date du jour d'édition - let dateNow; - - dateNow = moment().format("DD MMMM YYYY"); - - // Cas une ou plusieurs zone(s) spécifique(s) + cas zone456 - if (hasMondeEntier == false && (rc.actVoiturier || rc.actLoueur || rc.actDouane || rc.actDemPar || rc.actDemParDom || rc.actDemParAct || rc.actDemEntr || rc.actDemInterne || rc.actGardeMeuble || rc.actEntDep || rc.actPrestaLog || rc.actLevageur || rc.actDemParAdv)) { - if (rc.zone1) { - hasZone1 = true; + ); + }); } - if (rc.zone2) { - hasZone2 = true; + + // Conditions zone + let hasMondeEntier = false; + let hasZone1 = false; + let hasZone2 = false; + let hasZone3 = false; + let hasZone4 = false; + let hasZone5 = false; + let hasZone6 = false; + let hasActiviteButNotMultimodal = false; // Attention trick pour les zones géographiques dans le cas de multimodal + let hasZone456 = false; + + // Cas monde entier + if ( + rc.zone1 && + rc.zone2 && + rc.zone3 && + rc.zone4 && + rc.zone5 && + rc.zone6 && + (rc.actVoiturier || + rc.actLoueur || + rc.actDouane || + rc.actDemPar || + rc.actDemParDom || + rc.actDemParAdv || + rc.actDemEntr || + rc.actDemInterne || + rc.actGardeMeuble || + rc.actEntDep || + rc.actPrestaLog || + rc.actLevageur) + ) { + hasMondeEntier = true; } - if (rc.zone3) { - hasZone3 = true; + + // Cas date du jour d'édition + let dateNow = moment().format("DD MMMM YYYY"); + + // Cas une ou plusieurs zone(s) spécifique(s) + cas zone456 + if (hasMondeEntier == false && (rc.actVoiturier || rc.actLoueur || rc.actDouane || rc.actDemPar || rc.actDemParDom || rc.actDemParAct || rc.actDemEntr || rc.actDemInterne || rc.actGardeMeuble || rc.actEntDep || rc.actPrestaLog || rc.actLevageur || rc.actDemParAdv)) { + if (rc.zone1) { + hasZone1 = true; + } + if (rc.zone2) { + hasZone2 = true; + } + if (rc.zone3) { + hasZone3 = true; + } + if (rc.zone4) { + hasZone4 = true; + hasZone456 = true; + } + if (rc.zone5) { + hasZone5 = true; + hasZone456 = true; + } + if (rc.zone6) { + hasZone6 = true; + hasZone456 = true; + } } - if (rc.zone4) { - hasZone4 = true; - hasZone456 = true; + + // Cas Activité multimodal + Au minimum une zone + if (rc.actMultimodal) { + if (hasZone1 || hasZone2 || hasZone3 || hasZone456 || hasMondeEntier) { + hasActiviteButNotMultimodal = true; + } } - if (rc.zone5) { - hasZone5 = true; - hasZone456 = true; + + let hasMondeEntierOrMultimodal, hasNotMondeEntierOrMultimodal; + if (rc.actMultimodal || hasMondeEntier) { + hasMondeEntierOrMultimodal = true; + hasNotMondeEntierOrMultimodal = false; + } else { + hasMondeEntierOrMultimodal = false; + hasNotMondeEntierOrMultimodal = true; } - if (rc.zone6) { - hasZone6 = true; - hasZone456 = true; + + // Conditions Extensions RCC + let extRCC = false; + + if ( rc.extRCCModifCalArrim == true || rc.extRCCFerroutage == true || rc.extRCCFraisRecons == true || rc.extRCCConfie == true || rc.extRCCTPPC == true || rc.extRCCRegie == true || rc.extRCCSansMontageDemontage == true ) { + extRCC = true; } - } - // Cas Activité multimodal + Au minimum une zone - if (rc.actMultimodal) { - if (hasZone1 || hasZone2 || hasZone3 || hasZone456 || hasMondeEntier) { - hasActiviteButNotMultimodal = true; + // Conditions Extensions RCE + let extRCE = false; + + if (rc.extRCEMontageDemontage == true || rc.extRCEBraDebra == true) { + extRCE = true; } - } - if (rc.actMultimodal || hasMondeEntier) { - hasMondeEntierOrMultimodal = true; - hasNotMondeEntierOrMultimodal = false; - } else { - hasMondeEntierOrMultimodal = false; - hasNotMondeEntierOrMultimodal = true; - } + // Conditions Activitées + let hasActiviteDemenageurGardeMeuble = false; + if ( rc.actDemPar == true || rc.actDemEntr == true || rc.actDemParDom == true || rc.actDemParAdv == true || rc.actDemInterne) { + hasActiviteDemenageurGardeMeuble = true; + } - // Conditions Extensions RCC - let extRCC = false; + let oneOfActiviteDemenageurParticulier = false; + if ( rc.actDemPar == true || rc.actDemParDom == true || rc.actDemParAdv == true ) { + oneOfActiviteDemenageurParticulier = true; + } - if ( rc.extRCCModifCalArrim == true || rc.extRCCFerroutage == true || rc.extRCCFraisRecons == true || rc.extRCCConfie == true || rc.extRCCTPPC == true || rc.extRCCRegie == true || rc.extRCCSansMontageDemontage == true ) { - extRCC = true; - } + let coorDem = ""; + if ( (rc.actDemPar == true || rc.actDemParDom == true || rc.actDemParAdv == true) && (rc.actDemEntr == true || rc.actDemInterne == true) && rc.actGardeMeuble == true) { + coorDem = ","; + } else if ( (rc.actDemPar == true || rc.actDemParDom == true || rc.actDemParAdv == true) && (rc.actDemEntr == true || rc.actDemInterne == true) && rc.actGardeMeuble == false ) { + coorDem = " et"; + } - // Conditions Extensions RCC - let extRCE = false; + // Variables numériques + const franchiseTarif = "250"; - if ( rc.extRCEMontageDemontage == true || rc.extRCEBraDebra == true) { - extRCE = true; - } - - // Conditions Activitées - let hasActiviteDemenageurGardeMeuble = false; - if ( rc.actDemPar == true || rc.actDemEntr == true || rc.actDemParDom == true || rc.actDemParAdv == true || rc.actDemInterne) { - hasActiviteDemenageurGardeMeuble = true; - } - - let oneOfActiviteDemenageurParticulier = false; - if ( rc.actDemPar == true || rc.actDemParDom == true || rc.actDemParAdv == true ) { - oneOfActiviteDemenageurParticulier = true; - } - - let coorDem = ""; - if ( (rc.actDemPar == true || rc.actDemParDom == true || rc.actDemParAdv == true) && (rc.actDemEntr == true || rc.actDemInterne == true) && rc.actGardeMeuble == true) { - coorDem = ","; - } else if ( (rc.actDemPar == true || rc.actDemParDom == true || rc.actDemParAdv == true) && (rc.actDemEntr == true || rc.actDemInterne == true) && rc.actGardeMeuble == false ) { - coorDem = " et"; - } - - // Variables numériques - const franchiseTarif = "250"; - - try { doc.render({ // Client nomClient: client.nom, @@ -303,51 +342,310 @@ router.post("/rc/projet/:numParcours", async (req, res) => { fraisRepFraction: globalService.customFormatNumber(rc.cotFraisTTC, true), ca: globalService.customFormatNumber(rc.ca, true), }); + + const buf = doc.getZip().generate({ type: "nodebuffer" }); + + const currentDate = new Date(); + + // Formatage de la date au format "JJ-MM-AAAA-HH-MM-SS" + const day = String(currentDate.getDate()).padStart(2, "0"); + const month = String(currentDate.getMonth() + 1).padStart(2, "0"); + const year = currentDate.getFullYear(); + const hours = String(currentDate.getHours()).padStart(2, "0"); + const minutes = String(currentDate.getMinutes()).padStart(2, "0"); + const seconds = String(currentDate.getSeconds()).padStart(2, "0"); + const formattedDate = `${day}-${month}-${year}-${hours}-${minutes}-${seconds}`; + + // Génération du nom de fichier + const sanitizedClientNom = client.nom + .replace(/[^\w\s.-]/gi, "") + .replace(/\s+/g, "-"); + const filename = `Projet-${contrat.produit}-${parcours.numParcours}-${sanitizedClientNom}-${formattedDate}`; + + // Définit le type de contenu et un nom de fichier par défaut pour le téléchargement + res.setHeader( + "Content-Type", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + ); + + res.setHeader( + "Content-Disposition", + "attachment; filename=" + filename + ".docx" + ); + + // Envoie le buffer au client, déclenchant le téléchargement + res.send(buf); } catch (error) { - const e = { - message: error.message, - name: error.name, - stack: error.stack, - properties: error.properties, - }; - logger.log('error', JSON.stringify({ error: e })); - - // Envoyez une réponse d'erreur si le rendu échoue - return res.status(500).send("Erreur lors de la génération du document"); + logger.log('error', 'Error in RC projet generation:', error); + return res.status(500).send("Erreur lors de la génération du projet RC"); } - - const buf = doc.getZip().generate({ type: "nodebuffer" }); - - const currentDate = new Date(); - - // Formatage de la date au format "JJ-MM-AAAA-HH-MM-SS" - const day = String(currentDate.getDate()).padStart(2, "0"); - const month = String(currentDate.getMonth() + 1).padStart(2, "0"); - const year = currentDate.getFullYear(); - const hours = String(currentDate.getHours()).padStart(2, "0"); - const minutes = String(currentDate.getMinutes()).padStart(2, "0"); - const seconds = String(currentDate.getSeconds()).padStart(2, "0"); - const formattedDate = `${day}-${month}-${year}-${hours}-${minutes}-${seconds}`; - - // Génération du nom de fichier - const sanitizedClientNom = client.nom - .replace(/[^\w\s.-]/gi, "") - .replace(/\s+/g, "-"); - const filename = `Projet-${contrat.produit}-${parcours.numParcours}-${sanitizedClientNom}-${formattedDate}`; - - // Définit le type de contenu et un nom de fichier par défaut pour le téléchargement - res.setHeader( - "Content-Type", - "application/vnd.openxmlformats-officedocument.wordprocessingml.document" - ); - - res.setHeader( - "Content-Disposition", - "attachment; filename=" + filename + ".docx" - ); - - // Envoie le buffer au client, déclenchant le téléchargement - res.send(buf); }); -module.exports = router; +router.post("/rc/tarif/:numParcours", async (req, res) => { + try { + const content = fs.readFileSync( + path.resolve("src/templates/template-declinaison-tarifaire-rc.docx"), + "binary" + ); + + const zip = new PizZip(content); + const doc = new Docxtemplater(zip, { paragraphLoop: true, linebreaks: true }); + + const numParcours = req.params.numParcours.toUpperCase(); + const parcours = await parcoursService.getParcoursByNumParcours(numParcours); + const contrat = await contratService.getContratById(parcours.contrat); + const client = contrat?.["@expand"]?.client || {}; + const user = await userService.getUserById(parcours.dernierUtilisateur); + + // Récupérer la collection rc avec ses relations (APRÈS placerDansEnCours, c'est dans enCours) + const rcFull = contrat?.["@expand"]?.enCours; + if (!rcFull) { + logger.log('error', 'No RC found for contrat:', contrat.id); + return res.status(404).send("Aucune donnée RC trouvée pour ce contrat"); + } + + // Les données sont déjà expandées par contratService + const rc = rcFull?.["@expand"]?.tarifRC || {}; + const rcMain = rcFull || {}; + + // Formatage des taux avec maximum 2 décimales + function formatTaux(taux) { + if (!taux) return 0; + return parseFloat(taux).toFixed(2); + } + + // Préparer les données des activités avec leurs marchandises et activités complémentaires + const activites = []; + + // Voiturier/Loueur + if (rcMain.checkVoiturier || rcMain.checkLoueur) { + activites.push({ + type: 'Voiturier/Loueur', + capital: rcMain.capitalVoiturier || 0, + pourcentage: rc.pourcentageVoiturier || 0, + marchandises: rcMain.marchandisesVoiturier || [], + activitesCompl: rcMain.activitesVoiturier || [] + }); + } + + // Commissionnaire de Transport + if (rcMain.checkCommissionnaire) { + activites.push({ + type: 'Commissionnaire de Transport', + capital: rcMain.capitalCommissionnaire || 0, + pourcentage: rc.pourcentageCommissionnaire || 0, + marchandises: rcMain.marchandisesCommissionnaire || [], + activitesCompl: rcMain.activitesCommissionnaire || [] + }); + } + + // Déménageur + if (rcMain.checkDemenageur) { + activites.push({ + type: 'Déménageur', + capital: rcMain.capitalDemenageur || 0, + pourcentage: rc.pourcentageDemenageur || 0, + marchandises: rcMain.marchandisesDemenageur || [], + activitesCompl: rcMain.activitesDemenageur || [] + }); + } + + // Logistique + if (rcMain.checkLogistique) { + activites.push({ + type: 'Logistique', + capital: rcMain.capitalLogistique || 0, + pourcentage: rc.pourcentageLogistique || 0, + marchandises: rcMain.marchandisesLogistique || [], + activitesCompl: rcMain.activitesLogistique || [] + }); + } + + // Autocariste + if (rcMain.checkAutocariste) { + activites.push({ + type: 'Autocariste', + capital: rcMain.capitalAutocariste || 0, + pourcentage: rc.pourcentageAutocariste || 0, + marchandises: rcMain.marchandisesAutocariste || [], + activitesCompl: rcMain.activitesAutocariste || [] + }); + } + + // Autres activités + if (rcMain.checkAutres) { + activites.push({ + type: 'Autres activités', + capital: rcMain.capitalAutres || 0, + pourcentage: rc.pourcentageAutres || 0, + marchandises: rcMain.marchandisesAutres || [], + activitesCompl: rcMain.activitesAutres || [] + }); + } + + // Préparer les zones + const zones = []; + if (rcMain.zone1) zones.push("Zone 1"); + if (rcMain.zone2) zones.push("Zone 2"); + if (rcMain.zone3) zones.push("Zone 3"); + if (rcMain.zone4) zones.push("Zone 4"); + if (rcMain.zone5) zones.push("Zone 5"); + if (rcMain.zone6) zones.push("Zone 6"); + + // Préparer les garanties additionnelles + const garantiesAdditionnelles = []; + if (rc.checkStationLavage) garantiesAdditionnelles.push("Station de lavage"); + if (rc.checkGarageInterne) garantiesAdditionnelles.push("Garage interne"); + if (rc.checkCSE) garantiesAdditionnelles.push("CSE"); + if (rc.checkTPPC) garantiesAdditionnelles.push(`TPPC (Capital: ${rc.capitalTPPC || 0}€, Véhicules: ${rc.vehiculesTPPC || 0})`); + if (rc.checkPJ) garantiesAdditionnelles.push("Protection Juridique"); + + // Préparer les engagements complémentaires + const engagements = []; + if (rc.checkDomImmat) engagements.push(`Dommages immatériels (Capital: ${rc.capitalDomImmat || 0}€)`); + if (rc.checkContConf) engagements.push(`Contenu confié (Capital: ${rc.capitalContConf || 0}€)`); + if (rc.checkDiffInv) engagements.push(`Différence d'inventaire (Capital: ${rc.capitalDiffInv || 0}€)`); + + let dateNow = moment().format("DD MMMM YYYY"); + + doc.render({ + // Infos générales + matricule: user.matricule, + date: dateNow, + typeCotisation: rcMain.typeCotisation || "Non défini", + hasforfaitaire: !(rcMain.typeCotisation === "forfaitaire" || (!rcMain.chiffreAffaires || rcMain.chiffreAffaires === 0)), + hasRCE: rcMain.checkRCE || false, + hasContrat: !!contrat.numContrat, + numContrat: contrat.numContrat, + hasSaisine: !!contrat.numSaisine, + numSaisine: contrat.numSaisine, + numeroCS: contrat.numSaisine || contrat.numContrat, + nomAssure: client.nom, + ca: rcMain.chiffreAffaires || 0, + hasNbVehicule: (rcMain.nombreVehicules || 0) > 0, + nbVehicule: rcMain.nombreVehicules || 0, + + // Activités principales + hasVoiturierLoueur: rcMain.checkVoiturier || rcMain.checkLoueur, + capitalAssureVoiturierLoueur: rcMain.capitalVoiturier || 0, + pourcentageVoiturierLoueur: rc.pourcentageVoiturier || 0, + marchandiseVoiturierLoueur: rcMain.marchandisesVoiturier || [], + activiteVoiturierLoueur: rcMain.actComplVoiturier || [], + + hasComTransport: rcMain.checkCommissionnaire || false, + capitalAssureComTransport: rcMain.capitalCommissionnaire || 0, + pourcentageComTransport: rc.pourcentageCommissionnaire || 0, + marchandiseComTransport: rcMain.marchandisesCommissionnaire || [], + activiteComTransport: rcMain.actComplCommissionnaire || [], + + hasDemenageur: rcMain.checkDemenageur || false, + capitalAssureDemenageur: rcMain.capitalDemenageur || 0, + pourcentageDemenageur: rc.pourcentageDemenageur || 0, + marchandiseDemenageur: rcMain.marchandisesDemenageur || [], + activiteDemenageur: rcMain.actComplDemenageur || [], + + hasLogistique: rcMain.checkLogistique || false, + capitalAssureLogistique: rcMain.capitalLogistique || 0, + pourcentageLogistique: rc.pourcentageLogistique || 0, + marchandiseLogistique: rcMain.marchandisesLogistique || [], + activiteLogistique: rcMain.actComplLogistique || [], + + hasAutocariste: rcMain.checkAutocariste || false, + capitalAssureAutocariste: rcMain.capitalAutocariste || 0, + pourcentageAutocariste: rc.pourcentageAutocariste || 0, + marchandiseAutocariste: rcMain.marchandisesAutocariste || [], + activiteAutocariste: rcMain.activitesAutocariste || [], + + hasAutre: rcMain.checkAutres || false, + capitalAssureAutre: rcMain.capitalAutres || 0, + pourcentageAutre: rc.pourcentageAutres || 0, + marchandiseAutre: rcMain.marchandisesAutres || [], + //activiteAutre: rcMain.activitesAutres || [], existe pas dans ejs + + // Zones géographiques + zones: zones, + + // Garanties additionnelles + hasGarantieAdd: garantiesAdditionnelles.length > 0, + garantieAdd: garantiesAdditionnelles, + + // Engagements complémentaires + hasEngagement: engagements.length > 0, + engagement: engagements, + + // Tarifs sélectionnés + franchise: rc.franchiseChoisie || rc.franchiseSelectionnee, + tarifReference: getSelectedTarifReference(rc), + tarifCommercial: rc.tarifcommercial, + primeRCC: getSelectedPrime(rc, 'RCC'), + tauxRCC: formatTaux(getSelectedTaux(rc, 'RCC')), + hasRCE: rcMain.checkRCE, + primeRCE: getSelectedPrime(rc, 'RCE'), + tauxRCE: formatTaux(getSelectedTaux(rc, 'RCE')), + hasPrimePJ: rc.checkPJ && getSelectedPrime(rc, 'PJ') > 0, + primePJ: getSelectedPrime(rc, 'PJ'), + tauxGlobal: formatTaux(getSelectedTaux(rc, 'Global')), + + + // Propositions franchise 250 + tarifRefP1: rc.primeTotal_250 || 0, + pRCCP1: rc.primeRCC_250 || 0, + tRCCP1: formatTaux(rc.tauxRCC_250), + pRCEP1: rc.primeRCE_250 || 0, + tRCEP1: formatTaux(rc.tauxRCE_250), + primePJP1: rc.primePJ_250 || 0, + tauxGlobalP1: formatTaux(rc.tauxGlobal_250), + + // Propositions franchise 400 + tarifRefP2: rc.primeTotal_400 || 0, + pRCCP2: rc.primeRCC_400 || 0, + tRCCP2: formatTaux(rc.tauxRCC_400), + pRCEP2: rc.primeRCE_400 || 0, + tRCEP2: formatTaux(rc.tauxRCE_400), + primePJP2: rc.primePJ_400 || 0, + tauxGlobalP2: formatTaux(rc.tauxGlobal_400), + + // Propositions franchise 2000 + tarifRefP3: rc.primeTotal_2000 || 0, + pRCCP3: rc.primeRCC_2000 || 0, + tRCCP3: formatTaux(rc.tauxRCC_2000), + pRCEP3: rc.primeRCE_2000 || 0, + tRCEP3: formatTaux(rc.tauxRCE_2000), + primePJP3: rc.primePJ_2000 || 0, + tauxGlobalP3: formatTaux(rc.tauxGlobal_2000), + }); + + const buf = doc.getZip().generate({ type: "nodebuffer" }); + + const currentDate = new Date(); + + // Formatage de la date au format "JJ-MM-AAAA-HH-MM-SS" + const day = String(currentDate.getDate()).padStart(2, "0"); + const month = String(currentDate.getMonth() + 1).padStart(2, "0"); + const year = currentDate.getFullYear(); + const hours = String(currentDate.getHours()).padStart(2, "0"); + const minutes = String(currentDate.getMinutes()).padStart(2, "0"); + const seconds = String(currentDate.getSeconds()).padStart(2, "0"); + const formattedDate = `${day}-${month}-${year}-${hours}-${minutes}-${seconds}`; + + const sanitizedClientNom = client.nom + .replace(/[^\w\s.-]/gi, "") + .replace(/\s+/g, "-"); + + const filename = `Tarif-RC-${parcours.numParcours}-${sanitizedClientNom}-${formattedDate}`; + + res.setHeader( + "Content-Type", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + ); + res.setHeader("Content-Disposition", "attachment; filename=" + filename + ".docx"); + res.send(buf); + } catch (error) { + logger.log("error", 'Error in RC tarif generation:', error); + return res.status(500).send("Erreur lors de la génération du tarif RC"); + } +}); + + + +module.exports = router; \ No newline at end of file diff --git a/ecole/src/controllers/navParcoursController.js b/ecole/src/controllers/navParcoursController.js index 7957d553..62cf03e5 100644 --- a/ecole/src/controllers/navParcoursController.js +++ b/ecole/src/controllers/navParcoursController.js @@ -22,7 +22,7 @@ router.get('/contrat', async (req, res) => { }); router.get('/tarifrc', async (req, res) => { - renderPage('dev.ejs', res, {}, true); + renderPage('tarifformrc.ejs', res, {}, true); }); router.get('/tariffac', async (req, res) => { diff --git a/ecole/src/controllers/rcController.js b/ecole/src/controllers/rcController.js index 5eb55239..cc863d6e 100644 --- a/ecole/src/controllers/rcController.js +++ b/ecole/src/controllers/rcController.js @@ -1,12 +1,152 @@ const express = require('express'); const router = express.Router(); const rcService = require('../services/rcService'); +const constantesJSON = require("../constantes/json-modulateur-rc"); +const logger = require('../utils/logger'); +// ===== Routes RC principale ===== router.post('/create', async (req, res) => { - const data = req.body; - const rc = await rcService.createRc(data); + try { + const data = req.body; + const rc = await rcService.createRc(data); + res.json({ valid: Boolean(rc), rc }); + } catch (error) { + logger.log("error", "Error creating RC:", error); + res.status(500).json({ valid: false, error: "Internal Server Error" }); + } +}); - res.json({ valid: Boolean(rc), rc }); +router.get('/:id', async (req, res) => { + try { + const rc = await rcService.getRcById(req.params.id); + res.json({ valid: Boolean(rc), rc }); + } catch (error) { + logger.log("error", "Error getting RC:", error); + res.status(500).json({ valid: false, error: "Internal Server Error" }); + } +}); + +router.post('/update/:id', async (req, res) => { + try { + const rc = await rcService.updateRc(req.params.id, req.body); + res.json({ valid: Boolean(rc), rc }); + } catch (error) { + logger.log("error", "Error updating RC:", error); + res.status(500).json({ valid: false, error: "Internal Server Error" }); + } +}); + +// ===== Routes TarifRC ===== +router.post('/tarif/create', async (req, res) => { + try { + const data = req.body; + const tarifRc = await rcService.createTarifRc(data); + res.json({ valid: Boolean(tarifRc), tarifRc }); + } catch (error) { + logger.log("error", "Error creating TarifRC:", error); + res.status(500).json({ valid: false, error: "Internal Server Error" }); + } +}); + +router.get('/tarif/:id', async (req, res) => { + try { + const tarifRc = await rcService.getTarifRcById(req.params.id); + res.json({ valid: Boolean(tarifRc), tarifRc }); + } catch (error) { + logger.log("error", "Error getting TarifRC:", error); + res.status(500).json({ valid: false, error: "Internal Server Error" }); + } +}); + +router.post('/tarif/update/:id', async (req, res) => { + try { + const tarifRc = await rcService.updateTarifRc(req.params.id, req.body); + res.json({ valid: Boolean(tarifRc), tarifRc }); + } catch (error) { + logger.log("error", "Error updating TarifRC:", error); + res.status(500).json({ valid: false, error: "Internal Server Error" }); + } +}); + +// ===== Routes ProjetRC ===== +router.post('/projet/create', async (req, res) => { + try { + const data = req.body; + const projetRc = await rcService.createProjetRc(data); + res.json({ valid: Boolean(projetRc), projetRc }); + } catch (error) { + logger.log("error", "Error creating ProjetRC:", error); + res.status(500).json({ valid: false, error: "Internal Server Error" }); + } +}); + +router.get('/projet/:id', async (req, res) => { + try { + const projetRc = await rcService.getProjetRcById(req.params.id); + res.json({ valid: Boolean(projetRc), projetRc }); + } catch (error) { + logger.log("error", "Error getting ProjetRC:", error); + res.status(500).json({ valid: false, error: "Internal Server Error" }); + } +}); + +router.post('/projet/update/:id', async (req, res) => { + try { + const projetRc = await rcService.updateProjetRc(req.params.id, req.body); + res.json({ valid: Boolean(projetRc), projetRc }); + } catch (error) { + logger.log("error", "Error updating ProjetRC:", error); + res.status(500).json({ valid: false, error: "Internal Server Error" }); + } +}); + +// ===== Routes Modulateurs ===== +router.get("/modulo/:objDemande", async (req, res) => { + const objDemande = req.params.objDemande; + var objRetourne + + switch (objDemande) { + case "CARC": + objRetourne = constantesJSON.modRCCA; + break; + case "activiteRCC": + objRetourne = constantesJSON.modRCActRCC; + break; + case "activiteRCE": + objRetourne = constantesJSON.modRCActRCE; + break; + case "activiteComplRC": + objRetourne = constantesJSON.modRCActCompl; + break; + case "marchandiseRC": + objRetourne = constantesJSON.modRCMar; + break; + case "zoneRC": + objRetourne = constantesJSON.modRCZone; + break; + case "engagComplRC": + objRetourne = constantesJSON.modRCEngagCompl; + break; + case "garAdditionelRC": + objRetourne = constantesJSON.modRCGarAdd ; + break; + case "sinistreRC": + objRetourne = constantesJSON.modRCSinistre; + break; + case "franchiseRC": + objRetourne = constantesJSON.modRCFranchise; + break; + case "primeMiniRC": + objRetourne = constantesJSON.modRCPrimeMini; + break; + } + + try { + res.json({valid: Boolean(objRetourne), objRetourne}); + } catch (error) { + logger.log("error", `Error finding constant ${objDemande}:`, error); + res.status(500).json({valid: false, error: "Internal Server Error"}); + } }); module.exports = router; \ No newline at end of file diff --git a/ecole/src/db/pb_data/data.db b/ecole/src/db/pb_data/data.db index c7402141..8a065ea0 100644 Binary files a/ecole/src/db/pb_data/data.db and b/ecole/src/db/pb_data/data.db differ diff --git a/ecole/src/db/pb_data/data.db-shm b/ecole/src/db/pb_data/data.db-shm index fe9ac284..19889b16 100644 Binary files a/ecole/src/db/pb_data/data.db-shm and b/ecole/src/db/pb_data/data.db-shm differ diff --git a/ecole/src/db/pb_data/data.db-wal b/ecole/src/db/pb_data/data.db-wal index e69de29b..01d6ba37 100644 Binary files a/ecole/src/db/pb_data/data.db-wal and b/ecole/src/db/pb_data/data.db-wal differ diff --git a/ecole/src/db/pb_data/logs.db b/ecole/src/db/pb_data/logs.db index de9bbfb3..a9c46b80 100644 Binary files a/ecole/src/db/pb_data/logs.db and b/ecole/src/db/pb_data/logs.db differ diff --git a/ecole/src/db/pb_data/logs.db-shm b/ecole/src/db/pb_data/logs.db-shm index fdfdf0ac..85ce056d 100644 Binary files a/ecole/src/db/pb_data/logs.db-shm and b/ecole/src/db/pb_data/logs.db-shm differ diff --git a/ecole/src/db/pb_data/logs.db-wal b/ecole/src/db/pb_data/logs.db-wal index e6bc7706..df2eb83a 100644 Binary files a/ecole/src/db/pb_data/logs.db-wal and b/ecole/src/db/pb_data/logs.db-wal differ diff --git a/ecole/src/services/contratService.js b/ecole/src/services/contratService.js index e8f692ac..5fe56a10 100644 --- a/ecole/src/services/contratService.js +++ b/ecole/src/services/contratService.js @@ -45,14 +45,33 @@ async function createContrat() { async function expandProjetTarif(resultat) { const produit = resultat?.['produit'].toLowerCase() - const idProjet = resultat?.['@expand']?.[produit]?.['projet'] || undefined - const idTarif = resultat?.['@expand']?.[produit]?.['tarif'] || undefined - - const expand = { - projet: (idProjet) ? await db.records.getOne(produit + "projet", idProjet) : null, - tarif: (idTarif) ? await db.records.getOne(produit + "tarif", idTarif) : null - } + // RC utilise tarifRC/projetRC, les autres produits utilisent tarif/projet + let idProjet, idTarif, collectionProjet, collectionTarif; + if (produit === 'rc') { + idProjet = resultat?.['@expand']?.[produit]?.['projetRC'] || undefined + idTarif = resultat?.['@expand']?.[produit]?.['tarifRC'] || undefined + collectionProjet = 'projetRC'; // Nom de collection RC + collectionTarif = 'tarifRC'; // Nom de collection RC + } else { + idProjet = resultat?.['@expand']?.[produit]?.['projet'] || undefined + idTarif = resultat?.['@expand']?.[produit]?.['tarif'] || undefined + collectionProjet = produit + "projet"; // tppcprojet, facprojet + collectionTarif = produit + "tarif"; // tppctarif, factarif (n'existe pas mais bon) + } + + // Pour RC, inclure à la fois les clés RC spécifiques (tarifRC/projetRC) et les clés génériques (tarif/projet) + // afin de rester compatible avec l'ancien front qui lisait `tarif`/`projet`. + const expand = { + projet: idProjet ? await db.records.getOne(collectionProjet, idProjet) : null, + tarif: idTarif ? await db.records.getOne(collectionTarif, idTarif) : null, + }; + + if (produit === 'rc') { + expand.projetRC = expand.projet; + expand.tarifRC = expand.tarif; + } + resultat['@expand'][produit] = {...resultat['@expand'][produit], '@expand': expand} return resultat } diff --git a/ecole/src/services/rcService.js b/ecole/src/services/rcService.js index 736df79a..21171b96 100644 --- a/ecole/src/services/rcService.js +++ b/ecole/src/services/rcService.js @@ -1,10 +1,55 @@ const { db } = require('../db/db-connect'); const logger = require('../utils/logger'); +// ===== Collection RC principale ===== async function createRc(data) { return await db.records.create('rc', data); } +async function getRcById(id) { + return await db.records.getOne('rc', id, { + expand: 'tarifRC,projetRC' + }); +} + +async function updateRc(id, data) { + return await db.records.update('rc', id, data); +} + +// ===== Collection TarifRC ===== +async function createTarifRc(data) { + return await db.records.create('tarifRC', data); +} + +async function getTarifRcById(id) { + return await db.records.getOne('tarifRC', id); +} + +async function updateTarifRc(id, data) { + return await db.records.update('tarifRC', id, data); +} + +// ===== Collection ProjetRC ===== +async function createProjetRc(data) { + return await db.records.create('projetRC', data); +} + +async function getProjetRcById(id) { + return await db.records.getOne('projetRC', id); +} + +async function updateProjetRc(id, data) { + return await db.records.update('projetRC', id, data); +} + module.exports = { - createRc + createRc, + getRcById, + updateRc, + createTarifRc, + getTarifRcById, + updateTarifRc, + createProjetRc, + getProjetRcById, + updateProjetRc }; \ No newline at end of file diff --git a/ecole/src/templates/template-declinaison-tarifaire-rc.docx b/ecole/src/templates/template-declinaison-tarifaire-rc.docx new file mode 100644 index 00000000..64ad83ee Binary files /dev/null and b/ecole/src/templates/template-declinaison-tarifaire-rc.docx differ diff --git a/ecole/src/templates/template-projet-rc.docx b/ecole/src/templates/template-projet-rc.docx index dc3031e5..f6b360ce 100644 Binary files a/ecole/src/templates/template-projet-rc.docx and b/ecole/src/templates/template-projet-rc.docx differ diff --git a/ecole/views/layout.ejs b/ecole/views/layout.ejs index 54099ed9..0ea299c6 100644 --- a/ecole/views/layout.ejs +++ b/ecole/views/layout.ejs @@ -63,6 +63,12 @@ + + + + + + diff --git a/ecole/views/projetformrc.ejs b/ecole/views/projetformrc.ejs index b1b1df2e..a9cab874 100644 --- a/ecole/views/projetformrc.ejs +++ b/ecole/views/projetformrc.ejs @@ -931,7 +931,9 @@ - + + + @@ -943,7 +945,9 @@ - + + + @@ -1181,3 +1185,26 @@ Fermer + + + diff --git a/ecole/views/tarifformrc.ejs b/ecole/views/tarifformrc.ejs new file mode 100644 index 00000000..83748a1e --- /dev/null +++ b/ecole/views/tarifformrc.ejs @@ -0,0 +1,1252 @@ +
+
+
+
+
+ +
+
+ +
+
+
+ +
+
+
+ assignmentEléments d'appréciation sur l'entreprise : +
+
+
Veuillez renseigner les éléments d'appréciation sur l'entreprise ci-dessous :
+
+
+ +
+
+ + +
+
+ +
+
+ + + +
+
+ +
+ +
+
+ +
+
+
+ check_boxChoix des garanties : +
+
+
Veuillez renseigner les garanties du contrat :
+
+
+ +
+
+ + +
+
+
+ +
+
+
+
+ check_boxActivités principales : +
+
+
+ Total : 0% +
+ +
+
+
+
Veuillez renseigner les activités du contrat :
+
+
+
+ + + + + + +
+ +
+
+
+
+ Voiturier / Loueur +
+
+ + Exemples : 5000, 10000, 25000, 100000, 150000, 400000 +
+
+ + % du chiffre d'affaires + +
+
+ Taux de base : +
+
+ RCC : 0.000 % +
+ +
+
+
+
+ + + + + + + + + + +
+ +
+
+ Prime de base RCC : 000 000.00 € +
+ X mod. CA : 000 000.00 € +
+ +
+
+ +
+
+
+ check_boxActivités complémentaires : +
+
+
Veuillez renseigner les activités complémentaires du contrat :
+
+
+ +
+
+
+
+ Complément d'activité de : Voiturier / Loueur +
+
+ + + + + + +
+
+
+
+ + + + + + +
+ +
+
+ Prime RCC : 000 000.00 € +
+ +
+
+ +
+
+
+ local_shippingMarchandises : +
+
+
Veuillez renseigner les marchandises du contrat par activités :
+
+
+ +
+
+
+
+ Marchandises pour : Voiturier / Loueur +
+ +
+ + + + + + + + + +
+
+
+
+ + + + + + + + + + +
+ +
+
+ Prime RCC : 000 000.00 € +
+ +
+
+ +
+
+
+ publicInformations sur les zones géographiques : +
+
+
Veuillez renseigner la territorialité du contrat :
+
+
+
+
+
+ +
+ + +
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+
+ +
+
+ Prime RCC : 000 000.00 € +
+ +
+
+ +
+
+
+ check_boxEngagements complémentaires : +
+
+
Veuillez renseigner les engagements complémentaires du contrat :
+
+
+
+
+
+
+
+ RCC + +
+ +
+
+
+ +
+
+
+
+ RCC + +
+ +
+
+
+ +
+
+
+
+ RCC + +
+ +
+
+
+
+ +
+
+ Prime RCC : 000 000.00 € +
+
+
+
+ +
+
+
+ check_boxGaranties additionnelles : +
+
+
Veuillez renseigner les garanties additionnelles du contrat :
+
+
+
+
+
+
+
+ RCC + +
+ +
+
+
+ +
+
+
+ RCC + +
+
+
+
+ + + +
+
+ Prime RCC : 000 000.00 € +
+ +
+
+ +
+
+
+ add_alertModulation antécédent sinistre + : +
+
+
Veuillez renseigner l'historique de sinistre du contrat :
+
+
+ +
+ + +
+
+ +
+
+ +
+
+
+ credit_cardPropositions tarifaires : +
+
+
Veuillez sélectionner un tarif adapté :
+
+
+ +
+
+
+
+
+ Franchise 250 €
+ 0.00 € +
+
+
+

Prime RCC : 0.00 €

+

Taux RCC : 0.000 %

+

Prime RCE : 0.00 €

+

Taux RCE : 0.000 %

+

Prime PJ : 0.00 €

+

Taux global : 0.000 %

+
+
+ +
+
+
+ +
+
+
+
+ Franchise 400 €
+ 0.00 € +
+
+
+

Prime RCC : 0.00 €

+

Taux RCC : 0.000 %

+

Prime RCE : 0.00 €

+

Taux RCE : 0.000 %

+

Prime PJ : 0.00 €

+

Taux global : 0.000 %

+
+
+ +
+
+
+ +
+
+
+
+ Franchise 10% avec min 300 € et max 2000 €
+ 0.00 € +
+
+
+

Prime RCC : 0.00 €

+

Taux RCC : 0.000 %

+

Prime RCE : 0.00 €

+

Taux RCE : 0.000 %

+

Prime PJ : 0.00 €

+

Taux global : 0.000 %

+
+
+ +
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file