From 4919940a268143f7babfa885eacc53df01803020 Mon Sep 17 00:00:00 2001
From: Alexis Burnaz <48258099+alxsbrz@users.noreply.github.com>
Date: Thu, 19 Mar 2026 10:26:15 +0100
Subject: [PATCH] RC: nouveaux formulaires et synchro
---
ecole/public/css/global.css | 3 +
ecole/public/js/nav-parcours.js | 95 +-
ecole/public/js/projet-form-rc.js | 2244 +++++++++--
ecole/public/js/rc-data-manager.js | 647 ++++
ecole/public/js/rc-orchestrator.js | 388 ++
ecole/public/js/rc-sync-utils.js | 464 +++
ecole/public/js/tarif-form-rc.js | 3376 +++++++++++++++++
ecole/src/constantes/json-modulateur-rc.js | 1434 +++++++
ecole/src/controllers/generateRcController.js | 640 +++-
.../src/controllers/navParcoursController.js | 2 +-
ecole/src/controllers/rcController.js | 146 +-
ecole/src/db/pb_data/data.db | Bin 1318912 -> 905216 bytes
ecole/src/db/pb_data/data.db-shm | Bin 32768 -> 32768 bytes
ecole/src/db/pb_data/data.db-wal | Bin 0 -> 1297832 bytes
ecole/src/db/pb_data/logs.db | Bin 4767744 -> 1884160 bytes
ecole/src/db/pb_data/logs.db-shm | Bin 32768 -> 32768 bytes
ecole/src/db/pb_data/logs.db-wal | Bin 4136512 -> 4185952 bytes
ecole/src/services/contratService.js | 33 +-
ecole/src/services/rcService.js | 47 +-
.../template-declinaison-tarifaire-rc.docx | Bin 0 -> 41760 bytes
ecole/src/templates/template-projet-rc.docx | Bin 175534 -> 178116 bytes
ecole/views/layout.ejs | 6 +
ecole/views/projetformrc.ejs | 31 +-
ecole/views/tarifformrc.ejs | 1252 ++++++
24 files changed, 10322 insertions(+), 486 deletions(-)
create mode 100644 ecole/public/js/rc-data-manager.js
create mode 100644 ecole/public/js/rc-orchestrator.js
create mode 100644 ecole/public/js/rc-sync-utils.js
create mode 100644 ecole/public/js/tarif-form-rc.js
create mode 100644 ecole/src/constantes/json-modulateur-rc.js
create mode 100644 ecole/src/templates/template-declinaison-tarifaire-rc.docx
create mode 100644 ecole/views/tarifformrc.ejs
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 = `
+
+
⚠️ Modification impactant le tarif
+
+ Vous avez modifié une donnée qui impacte le calcul du tarif.
+
+ Vous devez retourner sur le formulaire Tarif pour recalculer et valider le nouveau tarif.
+
+
+
+ `;
+
+ 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 c7402141acae8e4b7145cb81ac0b91115d9f4446..8a065ea0a58ddbdd6b7319e8ba13d916bdd1ef6e 100644
GIT binary patch
delta 67818
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
aEz_A(j@v9{X-E0K58^0!jj;pK==mQX^k^pl
literal 1318912
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