personnal/ecole/public/js/rc/tarif-form-rc.js

4184 lines
180 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Initialise submenu form.
*/
function initSubmenuForm() {
// Accéder aux informations stockées du parcours
const parcours = JSON.parse(sessionStorage.getItem('parcours'));
}
/**
* Convertit number.
*/
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)
/**
* Formate number.
*/
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);
}
/**
* Recupere element by id flexible.
*/
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;
/**
* Synchronise rcfloating labels.
*/
function syncRCFloatingLabels() {
if (window.RCValidationUtils && typeof window.RCValidationUtils.syncFloatingLabels === 'function') {
window.RCValidationUtils.syncFloatingLabels(document);
}
}
/**
* Met a jour tarifettes visibility.
*/
function updateTarifettesVisibility() {
const tarifettesContainer = document.getElementById('tarifettesContainer');
if (!tarifettesContainer) return;
tarifettesContainer.classList.toggle('rc-tarifettes-hidden', rcTarifHasErrors);
}
// ═══════════════════════════════════════════════════════════════
// FONCTIONS HELPERS
// ═══════════════════════════════════════════════════════════════
// Fonction helper : trouver la tranche la plus proche
/**
* Trouve closest tranche.
*/
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];
}
/**
* Met a jour tarif choice buttons state.
*/
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.';
});
updateTarifettesVisibility();
}
/**
* Configure rcsafe validation.
*/
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'],
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.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.registerExternal('marchandises-valides', function () {
const visibleContainers = Array.from(document.querySelectorAll('[name^="mar"]')).filter((container) => {
return container && container.offsetParent !== null;
});
if (!visibleContainers.length) {
return { valid: true };
}
const hasAtLeastOneChecked = visibleContainers.some((container) => {
return Boolean(container.querySelector('input[type="checkbox"]:checked'));
});
if (hasAtLeastOneChecked) {
return { valid: true };
}
return {
valid: false,
message: 'Marchandises invalides : sélectionnez au moins une marchandise.'
};
});
rcTarifGuard.refresh();
updateTarifChoiceButtonsState();
}
// Fonction pour afficher un avertissement visuel de dépassement %
/**
* Affiche percentage warning.
*/
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)
/**
* Masque all primes.
*/
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 = '<span style="color:#f44336;font-weight:bold;"> % invalide (> 100%)</span>';
}
});
}
// Fonction pour mettre à jour l'indicateur visuel du total des pourcentages
/**
* Met a jour percentage indicator.
*/
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
/**
* Initialise la logique de cette fonction.
*/
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();
syncRCFloatingLabels();
updatePercentageIndicator(100); // Initialiser à 100%
calcGlobal();
setTimeout(() => {
if (rcTarifGuard) rcTarifGuard.refresh();
updateTarifChoiceButtonsState();
syncRCFloatingLabels();
}, 300);
})
}
// Configuration des listeners d'événements
/**
* Configure event listeners.
*/
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.addEventListener('change', function (event) {
const target = event.target;
if (!target) return;
if (!target.matches('[name^="mar"] input[type="checkbox"], [name^="actCompl"] input[type="checkbox"], #checkVoiturier, #checkCommissionnaire, #checkDemenageur, #checkLogistique, #checkAutocariste, #checkAutres, #zone1, #zone2, #zone3, #zone4, #zone5, #zone6')) {
return;
}
if (rcTarifGuard) rcTarifGuard.refresh();
updateTarifChoiceButtonsState();
});
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 lutilisateur 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"
}
/**
* Parse prefill array.
*/
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 [];
}
/**
* Normalise prefill value.
*/
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;
}
/**
* Gere build projet prefill delta.
*/
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;
}
/**
* Gere apply projet data to tarif.
*/
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
/**
* Gere populate form data.
*/
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');
syncRCFloatingLabels();
// Recalculer après pré-remplissage
setTimeout(() => {
calcGlobal();
syncRCFloatingLabels();
}, 500);
}
/**
* Calcule mod ca.
*/
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;
}
/**
* Calcule mod marchandises.
*/
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 <span> 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;
}
/**
* Recupere zone mods.
*/
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 };
}
/**
* Calcule mod act compl.
*/
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;
}
/**
* Calcule engag compl.
*/
function calcEngagCompl(data, primeRCC) {
let prime = primeRCC;
let surPrime = 0;
let modDommImmat = 1;
let infos = [];
/**
* Gere write to card.
*/
function writeToCard(inputId, message) {
const inputEl = document.getElementById(inputId);
if (!inputEl) return;
const cardContent = inputEl.closest('.card-content');
if (!cardContent) return;
// Supprime lancien 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
/**
* Trouve closest tranche.
*/
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 %
/**
* Affiche percentage warning.
*/
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)
/**
* Masque all primes.
*/
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 = '<span style="color:#f44336;font-weight:bold;"> % invalide (> 100%)</span>';
}
});
}
// Fonction pour afficher toutes les primes (quand % valide)
/**
* Affiche all primes.
*/
function showAllPrimes() {
}
// Fonction pour mettre à jour l'indicateur visuel du total des pourcentages
/**
* Met a jour percentage indicator.
*/
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';
}
}
/**
* Calcule gar add.
*/
function calcGarAdd(data, primeRCC, primeRCE) {
let primeRCCres = Number(primeRCC) || 0;
let primeRCEres = Number(primeRCE) || 0;
let surPrimeRCE = 0;
const infosRCC = [];
const infosRCE = [];
/**
* Gere write to card.
*/
function writeToCard(inputId, message) {
const inputEl = document.getElementById(inputId);
if (!inputEl) return;
const cardContent = inputEl.closest('.card-content');
if (!cardContent) return;
// Supprime lancien 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 };
}
/**
* Calcule sinistre.
*/
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 :<br>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 ---
/**
* Recupere max mini rcc.
*/
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;
}
/**
* Recupere max mini rce.
*/
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;
}
/**
* Calcule tarif rcc.
*/
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
};
}
/**
* Calcule tarifettes.
*/
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
/**
* Calcule pj.
*/
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;
}
/**
* Calcule global.
*/
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();
}
/**
* Calcule revisable.
*/
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 :<br>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 =
'<span>Prime de base RCC : ' + primeBaseRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + '</span>';
document.getElementById('primeChapActRCE').innerHTML =
'<span>Prime de base RCE : ' + primeBaseRCE.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + '</span>';
// ========= É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 =
'<span>Prime RCC : ' + primeBaseRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' });
document.getElementById('primeChapActComplRCE').innerHTML =
'<span>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 =
'<span>Prime RCC : ' + primeRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' });
document.getElementById('primeChapMarchRCE').innerHTML =
'<span>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 =
'<span>Prime RCC : ' + primeRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' });
document.getElementById('primeChapZonesRCE').innerHTML =
'<span>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 = '<span>Prime RCC : ' + primeRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + '</span>';
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 = '<span>Prime RCE : ' + primeRCE.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + '</span>';
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 :<br>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"
};
/**
* Recupere selected 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
};
}
/**
* Calcule forfaitaire.
*/
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 =
'<span>Prime de base RCC : ' + primeBaseRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + '</span>';
document.getElementById('primeChapActRCE').innerHTML =
'<span>Prime de base RCE : ' + primeBaseRCE.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + '</span>';
// ========= É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 =
'<span>Prime RCC : ' + primeBaseRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' });
document.getElementById('primeChapActComplRCE').innerHTML =
'<span>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 =
'<span>Prime RCC : ' + primeRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' });
document.getElementById('primeChapMarchRCE').innerHTML =
'<span>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 =
'<span>Prime RCC : ' + primeRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' });
document.getElementById('primeChapZonesRCE').innerHTML =
'<span>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 = '<span>Prime RCC : ' + primeRCC.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + '</span>';
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 = '<span>Prime RCE : ' + primeRCE.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' }) + '</span>';
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"
};
/**
* Recupere selected 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
};
}
/**
* Recupere zone mods.
*/
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 };
}
/**
* Gere load historique btn.
*/
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
/**
* Gere constants json.
*/
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;
}
}
/**
* Gere reset inputs.
*/
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);
}
}
/**
* Recupere taux base rcc.
*/
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;
}
/**
* Recupere taux base rce.
*/
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;
}
/**
* Recupere selected activities.
*/
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
/**
* Sauvegarde tarif rc.
*/
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
/**
* Collecte activites compl json.
*/
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
/**
* Collecte marchandises json.
*/
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
/**
* Configure tarifette buttons.
*/
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
/**
* Configure marchandise alerts.
*/
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
/**
* Configure activite alerts.
*/
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
/**
* Ouvre modal tarif com.
*/
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 = true;
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();
if (rcTarifGuard) rcTarifGuard.refresh();
}
// Fonction pour gérer l'input du tarif commercial
/**
* Gere tarif com input.
*/
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';
document.getElementById('tarifCom-error').style.display = 'none';
document.getElementById('col-commentaire').style.display = 'none';
document.getElementById('comm-OK').disabled = true;
if (rcTarifGuard) rcTarifGuard.refresh();
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';
}
if (rcTarifGuard) rcTarifGuard.refresh();
}
// Fonction pour gérer l'input du commentaire
/**
* Gere commentaire input.
*/
function handleCommentaireInput(e) {
const commentaire = e.target.value.trim();
const tarifCom = parseFloat(document.getElementById('tarifCom').value);
const tarifComError = document.getElementById('tarifCom-error').style.display !== 'none';
if (tarifComError) {
document.getElementById('comm-OK').disabled = !commentaire || !tarifCom || tarifCom <= 0;
} else {
document.getElementById('comm-OK').disabled = !tarifCom || tarifCom <= 0;
}
if (rcTarifGuard) rcTarifGuard.refresh();
}
// Fonction pour gérer la validation du tarif commercial
/**
* Gere validate tarif com.
*/
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;
})();