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
let rcTarifGuard = null;
let rcTarifHasErrors = false;
// ═══════════════════════════════════════════════════════════════
// 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];
}
function updateTarifChoiceButtonsState() {
const buttons = document.querySelectorAll('.franchise-card button[name]');
buttons.forEach((button) => {
const shouldDisable = rcTarifHasErrors;
button.disabled = shouldDisable;
if (!shouldDisable) {
button.removeAttribute('title');
return;
}
button.title = 'Corrigez les erreurs de saisie avant de sélectionner un tarif.';
});
}
function setupRCSafeValidation() {
if (!window.RCValidationUtils || typeof window.RCValidationUtils.createGuard !== 'function') {
return;
}
rcTarifGuard = window.RCValidationUtils.createGuard({
summaryId: 'rcTarifBlockingSummary',
summaryTitle: 'Impossible de choisir un tarif ou de continuer car :',
blockTargets: ['#generateDeclinaison', '#generateProject', '#comm-OK'],
onChange: function (messages) {
rcTarifHasErrors = messages.length > 0;
updateTarifChoiceButtonsState();
}
});
rcTarifGuard.registerField('#chiffreAffaire', {
profile: 'numeric',
label: "Chiffre d'affaires",
min: 0,
positive: true,
requiredWhen: function () {
return document.querySelector('input[name="cotisation"]:checked')?.value === 'revisable';
}
});
rcTarifGuard.registerField('#nbrVehicule', {
profile: 'integer',
label: 'Nombre de véhicule(s)',
min: 1,
max: 2,
requiredWhen: function () {
return document.querySelector('input[name="cotisation"]:checked')?.value === 'forfaitaire';
}
});
rcTarifGuard.registerField('#sinistre', {
profile: 'numeric',
label: 'Montant de sinistres annuel',
min: 0
});
rcTarifGuard.observe('.input-pourcent', {
profile: 'numeric',
label: "Pourcentage d'activité",
min: 0,
max: 100,
requiredWhen: function (field) {
return field && field.offsetParent !== null;
},
activeWhen: function (field) {
return field && field.offsetParent !== null;
}
});
const capitalFieldNames = [
'selectActVoiturier/Loueur',
'selectActCommissionnaire de Transport',
'selectActDéménageur',
'selectActLogistique',
'selectActAutocariste',
'selectActAutres activites'
];
capitalFieldNames.forEach(function (fieldName) {
const field = document.getElementsByName(fieldName)[0];
if (!field) return;
rcTarifGuard.registerField(field, {
profile: 'numeric',
label: 'Capital à assurer',
min: 0,
positive: true,
requiredWhen: function () {
return field.offsetParent !== null;
},
activeWhen: function () {
return field.offsetParent !== null;
}
});
});
rcTarifGuard.registerField('#inputDomImmat', {
profile: 'numeric',
label: 'Capital dommages immatériels',
min: 0,
positive: true,
requiredWhen: function () {
return Boolean(document.getElementById('checkDomImmat')?.checked);
},
activeWhen: function () {
return Boolean(document.getElementById('checkDomImmat')?.checked);
}
});
rcTarifGuard.registerField('#inputContConf', {
profile: 'numeric',
label: 'Capital contenants confiés',
min: 0,
positive: true,
requiredWhen: function () {
return Boolean(document.getElementById('checkContConf')?.checked);
},
activeWhen: function () {
return Boolean(document.getElementById('checkContConf')?.checked);
}
});
rcTarifGuard.registerField('#inputDiffInv', {
profile: 'numeric',
label: "Capital différence inventaire",
min: 0,
positive: true,
requiredWhen: function () {
return Boolean(document.getElementById('checkDiffInv')?.checked);
},
activeWhen: function () {
return Boolean(document.getElementById('checkDiffInv')?.checked);
}
});
rcTarifGuard.registerField('#selTPPCcapital', {
profile: 'numeric',
label: 'Capital TPPC',
min: 0,
positive: true,
requiredWhen: function () {
return Boolean(document.getElementById('checkTPPC')?.checked);
},
activeWhen: function () {
return Boolean(document.getElementById('checkTPPC')?.checked);
}
});
rcTarifGuard.registerField('#selTPPCveh', {
profile: 'integer',
label: 'Nombre de véhicules TPPC',
min: 1,
max: 10,
requiredWhen: function () {
return Boolean(document.getElementById('checkTPPC')?.checked);
},
activeWhen: function () {
return Boolean(document.getElementById('checkTPPC')?.checked);
}
});
rcTarifGuard.registerField('#tarifCom', {
profile: 'numeric',
label: 'Tarif commercial',
min: 0,
positive: true,
requiredWhen: function () {
return Boolean(document.getElementById('modalTarifCom')?.classList.contains('open'));
},
activeWhen: function () {
return Boolean(document.getElementById('modalTarifCom')?.classList.contains('open'));
}
});
rcTarifGuard.registerField('#commentaire', {
profile: 'text',
label: 'Commentaire explicatif',
requiredWhen: function () {
return document.getElementById('tarifCom-error')?.style.display !== 'none';
},
activeWhen: function () {
return document.getElementById('col-commentaire')?.style.display !== 'none';
}
});
rcTarifGuard.observe('#tabAdvaloTerrestre input[type="text"], #tabAdvaloMultimodal input[type="text"], #tabAdvaloAerien input[type="text"]', {
profile: 'number_or_consulter',
label: 'Valeur ad valorem',
min: 0,
positive: true,
decimals: 3,
required: false
});
rcTarifGuard.refresh();
updateTarifChoiceButtonsState();
}
// 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();
setupRCSafeValidation();
updatePercentageIndicator(100); // Initialiser à 100%
calcGlobal();
setTimeout(() => {
if (rcTarifGuard) rcTarifGuard.refresh();
updateTarifChoiceButtonsState();
}, 300);
})
}
// 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"
}
function parsePrefillArray(value) {
if (Array.isArray(value)) return value;
if (typeof value === 'string') {
try {
const parsed = JSON.parse(value);
return Array.isArray(parsed) ? parsed : [];
} catch (error) {
return [];
}
}
return [];
}
function normalizePrefillValue(value) {
if (Array.isArray(value)) {
return value
.map((item) => normalizePrefillValue(item))
.sort((a, b) => String(a).localeCompare(String(b), 'fr'));
}
if (value && typeof value === 'object') {
const normalized = {};
Object.keys(value).sort().forEach((key) => {
normalized[key] = normalizePrefillValue(value[key]);
});
return normalized;
}
if (typeof value === 'string') {
const trimmed = value.trim();
if (!trimmed) return '';
const numeric = toNumber(trimmed);
if (!Number.isNaN(numeric) && trimmed.match(/^-?[\d\s,\.]+$/)) {
return numeric;
}
return trimmed.toLowerCase();
}
if (value == null) return null;
return value;
}
function buildProjetPrefillDelta(snapshot, baseline) {
if (!snapshot || typeof snapshot !== 'object') return null;
if (!baseline || typeof baseline !== 'object') return snapshot;
const delta = {};
Object.keys(snapshot).forEach((key) => {
const currentValue = normalizePrefillValue(snapshot[key]);
const baselineValue = normalizePrefillValue(baseline[key]);
if (JSON.stringify(currentValue) !== JSON.stringify(baselineValue)) {
delta[key] = snapshot[key];
}
});
return Object.keys(delta).length > 0 ? delta : null;
}
function applyProjetDataToTarif(projetSource) {
if (!projetSource || typeof projetSource !== 'object') return;
const hasOwn = (key) => Object.prototype.hasOwnProperty.call(projetSource, key);
const hasAny = (keys) => keys.some(hasOwn);
const normalize = (value) => String(value || '')
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLowerCase()
.trim();
const toProjetNumber = (value) => {
if (value == null) return null;
const raw = String(value).trim();
if (!raw || raw.toLowerCase() === 'nous consulter') return null;
const parsed = toNumber(raw);
return Number.isFinite(parsed) ? parsed : null;
};
const pickNumber = (...keys) => {
for (const key of keys) {
const parsed = toProjetNumber(projetSource[key]);
if (parsed != null) return parsed;
}
return null;
};
const setCheckboxState = (id, checked, dispatchClick) => {
const element = document.getElementById(id);
if (!element) return;
element.checked = Boolean(checked);
if (dispatchClick) {
element.dispatchEvent(new Event('click'));
}
};
const setFirstValue = (elements, value) => {
if (value == null) return;
for (const element of elements) {
if (element) {
element.value = value;
return;
}
}
};
const typeCotisation = projetSource.typeCot || projetSource.typeCotisation;
if (typeCotisation) {
const radio = document.getElementById(typeCotisation) || document.querySelector(`input[name="cotisation"][value="${typeCotisation}"]`);
if (radio) {
radio.checked = true;
radio.dispatchEvent(new Event('change'));
}
}
if (hasOwn('ca')) {
const caField = getElementByIdFlexible('CA') || getElementByIdFlexible('chiffreAffaire');
if (caField) {
const rawCA = String(projetSource.ca || '').trim();
caField.value = (!rawCA || rawCA.toLowerCase() === 'nous consulter') ? '' : rawCA;
}
}
const nbVehiculeField = getElementByIdFlexible('nbVehicules') || getElementByIdFlexible('nbrVehicule');
const nbVehFromProjet = toProjetNumber(projetSource.nombreVehicules ?? projetSource.nbVehicules);
const nbVehFromTable = Array.isArray(projetSource.designationVehicule) ? projetSource.designationVehicule.length : null;
if (nbVehiculeField) {
if (nbVehFromProjet != null) {
nbVehiculeField.value = Math.max(0, Math.round(nbVehFromProjet));
} else if (nbVehFromTable != null && nbVehFromTable > 0) {
nbVehiculeField.value = nbVehFromTable;
}
}
const activityMappings = [
{
keys: ['actVoiturier', 'actLoueur'],
checkboxId: 'checkVoiturier',
capitalKeys: ['valueActVoiturier', 'valueActLoueur'],
capitalFields: [
getElementByIdFlexible('capitalVoiturier'),
document.querySelector('input[name="selectActVoiturier/Loueur"]')
]
},
{
keys: ['actMultimodal'],
checkboxId: 'checkCommissionnaire',
capitalKeys: ['valueActMultimodal'],
capitalFields: [
getElementByIdFlexible('capitalCommissionnaire'),
document.querySelector('input[name="selectActCommissionnaire de Transport"]'),
document.querySelector('input[name="selectActCommissionnaireDeTransport"]')
]
},
{
keys: ['actDemEntr', 'actDemInterne', 'actDemPar', 'actDemParDom', 'actDemParAdv', 'actGardeMeuble'],
checkboxId: 'checkDemenageur',
capitalKeys: ['valueActDemEntr', 'valueActDemInterne', 'valueActDemPar', 'valueActDemParDom', 'valueActDemParAdv'],
capitalFields: [
getElementByIdFlexible('capitalDemenageur'),
document.querySelector('input[name="selectActDéménageur"]'),
document.querySelector('input[name="selectActDemenageur"]')
]
},
{
keys: ['actPrestaLog', 'actEntDep'],
checkboxId: 'checkLogistique',
capitalKeys: ['valueActPrestaLog', 'valueActEntDep'],
capitalFields: [
getElementByIdFlexible('capitalLogistique'),
document.querySelector('input[name="selectActLogistique"]')
]
},
{
keys: ['actAutocariste'],
checkboxId: 'checkAutocariste',
capitalKeys: ['valueActAutocariste'],
capitalFields: [
getElementByIdFlexible('capitalAutocariste'),
document.querySelector('input[name="selectActAutocariste"]')
]
},
{
keys: ['actAutres'],
checkboxId: 'checkAutres',
capitalKeys: ['valueActAutres'],
capitalFields: [
getElementByIdFlexible('capitalAutres'),
document.querySelector('input[name="selectActAutres activites"]'),
document.querySelector('input[name="selectActAutresActivites"]')
]
}
];
activityMappings.forEach((mapping) => {
if (!hasAny(mapping.keys)) return;
const selected = mapping.keys.some((key) => Boolean(projetSource[key]));
setCheckboxState(mapping.checkboxId, selected, true);
if (selected) {
const capitalValue = pickNumber(...mapping.capitalKeys);
setFirstValue(mapping.capitalFields, capitalValue);
}
});
if (hasAny(['zone1', 'zone2', 'zone3', 'zone4', 'zone5', 'zone6'])) {
const zone1 = Boolean(projetSource.zone1);
const zone2 = Boolean(projetSource.zone2);
const zone3 = Boolean(projetSource.zone3);
const zone4 = Boolean(projetSource.zone4);
const zone5 = Boolean(projetSource.zone5);
const zone6 = Boolean(projetSource.zone6);
const zone1El = document.getElementById('zone1');
const zone2El = document.getElementById('zone2');
const zone3El = document.getElementById('zone3');
const zone4El = document.getElementById('zone4');
const zone5El = document.getElementById('zone5');
const zone6El = document.getElementById('zone6');
if (zone1El) {
zone1El.checked = zone1 || zone2 || zone3;
zone1El.disabled = zone2 || zone3;
}
if (zone2El) {
zone2El.checked = zone2 || zone3;
zone2El.disabled = zone3;
}
if (zone3El) zone3El.checked = zone3;
if (zone4El) zone4El.checked = zone4;
if (zone5El) zone5El.checked = zone5;
if (zone6El) zone6El.checked = zone6;
}
if (hasOwn('autresRC')) {
setCheckboxState('checkRCE', Boolean(projetSource.autresRC), true);
}
if (hasOwn('pj')) {
setCheckboxState('checkPJ', Boolean(projetSource.pj), false);
}
const activitesComplementairesMap = [
{ field: 'activitesVoiturier', container: 'actComplVoiturier/Loueur' },
{ field: 'activitesCommissionnaire', container: 'actComplCommissionnaire de Transport' },
{ field: 'activitesDemenageur', container: 'actComplDéménageur' },
{ field: 'activitesLogistique', container: 'actComplLogistique' }
];
activitesComplementairesMap.forEach(({ field, container }) => {
if (!hasOwn(field)) return;
const wanted = parsePrefillArray(projetSource[field]);
const wantedSet = new Set(wanted.map((item) => String(item).trim()));
const checkboxes = document.querySelectorAll(`[name="${container}"] input[type="checkbox"]`);
checkboxes.forEach((checkbox) => {
const label = checkbox.nextElementSibling ? checkbox.nextElementSibling.textContent.trim() : checkbox.value;
checkbox.checked = wantedSet.has(label);
});
});
const marchandiseKeys = [
'marOrdinaire',
'marRoulant',
'marEngins',
'marRoulantDem',
'marMobilerUsag',
'marPerissable',
'marAnimaux',
'marCiterne',
'marBeton',
'marExceptionnels',
'marVrac'
];
if (hasAny(marchandiseKeys)) {
const flags = {
marOrdinaire: Boolean(projetSource.marOrdinaire),
marRoulant: Boolean(projetSource.marRoulant),
marEngins: Boolean(projetSource.marEngins),
marRoulantDem: Boolean(projetSource.marRoulantDem),
marMobilerUsag: Boolean(projetSource.marMobilerUsag),
marPerissable: Boolean(projetSource.marPerissable),
marAnimaux: Boolean(projetSource.marAnimaux),
marCiterne: Boolean(projetSource.marCiterne),
marBeton: Boolean(projetSource.marBeton),
marExceptionnels: Boolean(projetSource.marExceptionnels),
marVrac: Boolean(projetSource.marVrac)
};
const shouldSelectMarchandise = (label) => {
const text = normalize(label);
if (!text) return false;
if (flags.marRoulantDem && text.includes('vehicules roulants') && text.includes('demenagement')) return true;
if (flags.marRoulant && text.includes('vehicules roulants') && !text.includes('demenagement')) return true;
if (flags.marOrdinaire && text.includes('ordinaires')) return true;
if (flags.marEngins && text.includes('engins de chantier')) return true;
if (flags.marMobilerUsag && text.includes('mobiliers')) return true;
if (flags.marPerissable && text.includes('perissables')) return true;
if (flags.marAnimaux && text.includes('animaux vivants')) return true;
if (flags.marCiterne && text.includes('citerne')) return true;
if (flags.marBeton && text.includes('beton')) return true;
if (flags.marExceptionnels && text.includes('exceptionnels')) return true;
if (flags.marVrac && (text.includes('benne') || text.includes('vrac'))) return true;
return false;
};
[
'marVoiturier/Loueur',
'marCommissionnaire de Transport',
'marDéménageur',
'marLogistique',
'marAutocariste',
'marAutres activites'
].forEach((container) => {
const checkboxes = document.querySelectorAll(`[name="${container}"] input[type="checkbox"]`);
checkboxes.forEach((checkbox) => {
const label = checkbox.nextElementSibling ? checkbox.nextElementSibling.textContent : checkbox.value;
checkbox.checked = shouldSelectMarchandise(label);
});
});
}
}
// 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);
}
// Helpers défauts (au cas où aucune donnée côté RC)
const ensureDefaultActComplVoiturier = () => {
const container = document.querySelector('[name="actComplVoiturier/Loueur"]');
if (!container) return;
const checkboxes = Array.from(container.querySelectorAll('input[type="checkbox"]'));
const anyChecked = checkboxes.some(cb => cb.checked);
if (!anyChecked) {
checkboxes.forEach((cb, idx) => {
if (idx <= 1) cb.checked = true; // Voiturier + Loueur
});
}
};
const ensureDefaultMarchandisesVoiturier = () => {
const container = document.querySelector('[name="marVoiturier/Loueur"]');
if (!container) return;
const checkboxes = Array.from(container.querySelectorAll('input[type="checkbox"]'));
const anyChecked = checkboxes.some(cb => cb.checked);
if (!anyChecked && checkboxes.length > 0) {
checkboxes[0].checked = true; // Marchandises ordinaires par défaut
}
};
// ===== PRÉ-REMPLIR LE FORMULAIRE AVEC LES DONNÉES RC DE LA BASE =====
if (!rc) {
console.log('Aucune donnée RC à pré-remplir');
ensureDefaultActComplVoiturier();
ensureDefaultMarchandisesVoiturier();
return;
}
console.log('Pre-remplissage du formulaire tarif avec les donnees 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('Pre-remplissage des activites complementaires...');
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(` Coche: ${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('Pre-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(` Coche: ${marText}`);
}
});
});
} catch (e) { console.error(`Erreur parsing ${field}:`, e); }
}
});
// Valeurs par défaut si aucune marchandise/activité compl. remontée
ensureDefaultActComplVoiturier();
ensureDefaultMarchandisesVoiturier();
// Pré-remplir les pourcentages (depuis tarifRC)
// Priorité au tarif persistant; ne pas retomber sur rc pour ces champs.
const tarifSource = tarif || rc?.["@expand"]?.tarifRC || rc?.tarifRC || 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');
}
}
}
// Pré-remplissage Projet -> Tarif
// - si snapshot session: appliquer seulement les champs modifies sur Projet
// - sinon: utiliser Projet uniquement si on n'a pas de tarif persistant
let sessionProjetData = null;
try {
const storedProjetData = sessionStorage.getItem('rc_projet_data');
sessionProjetData = storedProjetData ? JSON.parse(storedProjetData) : null;
} catch (error) {
sessionProjetData = null;
}
let projetPrefillSource = null;
if (sessionProjetData) {
projetPrefillSource = buildProjetPrefillDelta(sessionProjetData, projet);
} else if (!tarifSource && !sessionTarifData && projet) {
projetPrefillSource = projet;
}
if (projetPrefillSource) {
applyProjetDataToTarif(projetPrefillSource);
}
if (sessionProjetData) {
sessionStorage.removeItem('rc_projet_data');
}
console.log('Formulaire tarif pre-rempli avec succes');
// 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();
if (rcTarifGuard) rcTarifGuard.refresh();
updateTarifChoiceButtonsState();
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);
}
if (rcTarifGuard) rcTarifGuard.refresh();
updateTarifChoiceButtonsState();
}
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('=== DEBUT 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 a 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('Reponse serveur tarifRC update:', data);
if (data.valid) {
idTarifRC = data.tarifRc.id;
} else {
console.error('Echec de la mise a jour de tarifRC:', data.message);
return { valid: false, message: data.message };
}
} else {
// Créer un nouvel enregistrement tarifRC
console.log('Creation 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('Reponse serveur tarifRC create:', data);
if (data.valid) {
idTarifRC = data.tarifRc.id;
} else {
console.error('Echec de la creation 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 a jour RC principal (ID: ${rcId}) avec reference tarifRC: ${idTarifRC}`);
console.log('Donnees envoyees 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('Reponse serveur RC update:', updateRCData);
if (!updateRCData.valid) {
console.error('Echec de la mise a jour de RC principal:', updateRCData.message);
return { valid: false, message: 'Échec mise à jour RC principal' };
}
console.log('=== TARIF RC SAUVEGARDE AVEC SUCCES ===');
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;
}
if (rcTarifGuard && rcTarifGuard.refresh().length > 0) {
M.toast({html: 'Corrigez les erreurs du formulaire avant de valider ce tarif.', 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;
})();