RC: nouveaux formulaires et synchro
This commit is contained in:
parent
0125e2ae69
commit
4919940a26
|
|
@ -1,5 +1,8 @@
|
|||
body {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background-color: white;
|
||||
color: black;
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
|
|
|
|||
|
|
@ -33,8 +33,16 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
let produit = parcours["@expand"].contrat.produit
|
||||
|
||||
const produitObj = contrat?.["@expand"]?.enCours || null;
|
||||
const tarif = produitObj?.["@expand"]?.tarif || null;
|
||||
const projet = produitObj?.["@expand"]?.projet || null;
|
||||
|
||||
// RC utilise tarifRC/projetRC, les autres produits utilisent tarif/projet
|
||||
let tarif, projet;
|
||||
if (produit === "rc") {
|
||||
tarif = produitObj?.["@expand"]?.tarifRC || null;
|
||||
projet = produitObj?.["@expand"]?.projetRC || null;
|
||||
} else {
|
||||
tarif = produitObj?.["@expand"]?.tarif || null;
|
||||
projet = produitObj?.["@expand"]?.projet || null;
|
||||
}
|
||||
|
||||
let scriptSrc;
|
||||
// let newScriptModuloSrc;
|
||||
|
|
@ -54,11 +62,21 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
scriptSrc = `/js/${submenu}-form.js`;
|
||||
}
|
||||
|
||||
// RC utilise tarifRC/projetRC, les autres produits utilisent tarif/projet
|
||||
let tarifId, projetId;
|
||||
if (produit === "rc") {
|
||||
tarifId = contrat?.["@expand"]?.enCours?.["@expand"]?.tarifRC?.id || null;
|
||||
projetId = contrat?.["@expand"]?.enCours?.["@expand"]?.projetRC?.id || null;
|
||||
} else {
|
||||
tarifId = contrat?.["@expand"]?.enCours?.["@expand"]?.tarif?.id || null;
|
||||
projetId = contrat?.["@expand"]?.enCours?.["@expand"]?.projet?.id || null;
|
||||
}
|
||||
|
||||
const etapes = {
|
||||
"client": contrat?.client || null,
|
||||
"intermediaire": contrat?.intermediaire || null,
|
||||
"tarif": contrat?.["@expand"]?.enCours?.["@expand"]?.tarif?.id || null,
|
||||
"projet": contrat?.["@expand"]?.enCours?.["@expand"]?.projet?.id || null,
|
||||
"tarif": tarifId,
|
||||
"projet": projetId,
|
||||
"contrat": null
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +97,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
document.getElementById('step-' + key).classList.add('line')
|
||||
}
|
||||
}
|
||||
showLoader();
|
||||
|
||||
// Charger le formulaire associé
|
||||
fetch(fetchUrl)
|
||||
|
|
@ -89,6 +106,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
|
||||
// Suppression de tout script précédemment chargé
|
||||
const oldScript = document.querySelector('script.dynamic-script');
|
||||
|
||||
if (oldScript) {
|
||||
oldScript.remove();
|
||||
}
|
||||
|
|
@ -120,26 +138,26 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
inputChanged = true
|
||||
})
|
||||
})
|
||||
hideLoader();
|
||||
})
|
||||
.catch(error => console.error('Error:', error));
|
||||
|
||||
//A MODIFIER UNE FOIS QUE RC SERA ADAPTé AU PARCOURS
|
||||
if (produit == "RC") {
|
||||
if (Object.keys(contrat?.["@expand"]?.enCours).length > 1) {
|
||||
document.getElementById('generateProject').disabled = false;
|
||||
}
|
||||
} else {
|
||||
// Enable / disable bouton generate project
|
||||
if (parcours["@expand"].contrat.client != '' && parcours["@expand"].contrat.intermediaire != '' && produitObj != undefined && projet != null) {
|
||||
document.getElementById('generateProject').disabled = false;
|
||||
}
|
||||
// Gestion des boutons de génération pour tous les produits
|
||||
const hasClient = parcours["@expand"]?.contrat?.client != '';
|
||||
const hasIntermediaire = parcours["@expand"]?.contrat?.intermediaire != '';
|
||||
const hasProduit = produitObj != undefined;
|
||||
|
||||
// Enable / disable bouton generate déclinaison
|
||||
if (parcours["@expand"].contrat.client != '' && parcours["@expand"].contrat.intermediaire != '' && produitObj != undefined && tarif != null) {
|
||||
// Bouton génération déclinaison tarifaire
|
||||
if (hasClient && hasIntermediaire && hasProduit && tarif != null) {
|
||||
document.getElementById('generateDeclinaison').disabled = false;
|
||||
} else {
|
||||
document.getElementById('generateDeclinaison').disabled = true;
|
||||
}
|
||||
|
||||
// Bouton génération projet
|
||||
if (hasClient && hasIntermediaire && hasProduit && projet != null) {
|
||||
document.getElementById('generateProject').disabled = false;
|
||||
} else {
|
||||
document.getElementById('generateProject').disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -157,9 +175,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
const parcours = JSON.parse(sessionStorage.getItem('parcours'));
|
||||
var produit = parcours["@expand"].contrat.produit
|
||||
|
||||
const btn = this // bouton "générer projet"
|
||||
btn.disabled = true; // le desactiver le temps du téléchargement
|
||||
|
||||
var fileName
|
||||
switch (produit.toLowerCase()) {
|
||||
case 'fac':
|
||||
|
|
@ -183,21 +198,26 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
link.download = fileName;
|
||||
link.click();
|
||||
})
|
||||
.finally(() => {
|
||||
btn.disabled = false; // réactiver le bouton a la fin du téléchargement
|
||||
})
|
||||
.catch(error => console.error('Error downloading file:', error));
|
||||
});
|
||||
|
||||
// Fonction de génération de projet
|
||||
document.getElementById('generateProject').addEventListener('click', function() {
|
||||
document.getElementById('generateProject').addEventListener('click', async function() {
|
||||
const numParcours = getNumParcoursFromURL();
|
||||
let filename;
|
||||
const parcours = JSON.parse(sessionStorage.getItem('parcours'));
|
||||
let produit = parcours["@expand"].contrat.produit
|
||||
|
||||
const btn = this // bouton "générer projet"
|
||||
btn.disabled = true; // le desactiver le temps du téléchargement
|
||||
// Sauvegarder les données du projet avant de générer le document (si RC)
|
||||
if (produit.toLowerCase() === 'rc' && typeof window.saveProjetRC === 'function') {
|
||||
console.log('Sauvegarde des données projet RC avant génération...');
|
||||
const saveResult = await window.saveProjetRC();
|
||||
if (!saveResult || !saveResult.valid) {
|
||||
console.error('Échec de la sauvegarde du projet RC');
|
||||
M.toast({html: 'Erreur lors de la sauvegarde du projet. Veuillez réessayer.'});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Envoi de la requête POST au serveur pour générer le projet
|
||||
fetch(`/generate/${produit}/projet/${numParcours}`, {
|
||||
|
|
@ -228,23 +248,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
window.URL.revokeObjectURL(url); // Nettoie l'URL objet
|
||||
a.remove(); // Supprime l'élément a du document
|
||||
})
|
||||
.finally(() => {
|
||||
btn.disabled = false; // réactiver le bouton a la fin du téléchargement
|
||||
})
|
||||
.catch(error => console.error('Erreur lors de la génération du projet:', error));
|
||||
});
|
||||
|
||||
|
||||
document.getElementById('generateDeclinaison').addEventListener('click', function() {
|
||||
document.getElementById('generateDeclinaison').addEventListener('click', async function() {
|
||||
const numParcours = getNumParcoursFromURL();
|
||||
let filename;
|
||||
const parcours = JSON.parse(sessionStorage.getItem('parcours'));
|
||||
let produit = parcours["@expand"].contrat.produit
|
||||
|
||||
const btn = this // bouton "générer déclinaison tarifaire"
|
||||
btn.disabled = true; // le desactiver le temps du téléchargement
|
||||
|
||||
// Envoi de la requête POST au serveur pour générer le projet
|
||||
// Envoi de la requête POST au serveur pour générer la déclinaison tarifaire
|
||||
fetch(`/generate/${produit}/tarif/${numParcours}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
|
@ -274,9 +288,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
window.URL.revokeObjectURL(url); // Nettoie l'URL objet
|
||||
a.remove(); // Supprime l'élément a du document
|
||||
})
|
||||
.finally(() => {
|
||||
btn.disabled = false; // réactiver le bouton a la fin du téléchargement
|
||||
})
|
||||
.catch(error => console.error('Erreur lors de la génération du projet:', error));
|
||||
});
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,647 @@
|
|||
/**
|
||||
* ═══════════════════════════════════════════════════════════════════════════
|
||||
* RC DATA MANAGER
|
||||
* ═══════════════════════════════════════════════════════════════════════════
|
||||
*
|
||||
* Ce module gère la collecte, la sauvegarde et le pré-remplissage des données
|
||||
* RC entre les formulaires Tarif et Projet.
|
||||
*
|
||||
* @requires rc-sync-utils.js
|
||||
* @author AXA Transport Team
|
||||
* @version 2.0.0
|
||||
* @since 2026-02-17
|
||||
*/
|
||||
|
||||
(function(window) {
|
||||
'use strict';
|
||||
|
||||
const { toNumber, getValue, setValue, getElementByIdFlexible } = window.RCSync;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// MAPPING DES CHAMPS TARIF ↔ PROJET
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Mapping complet des champs entre Tarif et Projet.
|
||||
* Permet la synchronisation bidirectionnelle.
|
||||
*
|
||||
* Structure: { tarifFieldId: projetFieldId }
|
||||
*/
|
||||
const FIELD_MAPPING = {
|
||||
// Informations générales
|
||||
'CA': 'CA',
|
||||
'chiffreAffaire': 'CA',
|
||||
'nbVehicules': 'nombreVehicules',
|
||||
'nbrVehicule': 'nombreVehicules',
|
||||
|
||||
// Type de cotisation
|
||||
'cotisation': 'typeCot',
|
||||
|
||||
// Activités RCC - Voiturier
|
||||
'checkVoiturier': 'actVoiturier',
|
||||
'capitalVoiturier': 'valueActVoiturier',
|
||||
|
||||
// Activités RCC - Commissionnaire (Multimodal)
|
||||
'checkCommissionnaire': 'actMultimodal',
|
||||
'capitalCommissionnaire': 'valueActMultimodal',
|
||||
|
||||
// Activités RCC - Déménageur
|
||||
'checkDemenageur': 'actDemEntr',
|
||||
'capitalDemenageur': 'valueActDemEntr',
|
||||
|
||||
// Activités RCC - Logistique
|
||||
'checkLogistique': 'actPrestaLog',
|
||||
'capitalLogistique': 'valueActPrestaLog',
|
||||
|
||||
// RCE
|
||||
'checkRCE': 'autresRC',
|
||||
|
||||
// Zones géographiques
|
||||
'zone1': 'zone1',
|
||||
'zone2': 'zone2',
|
||||
'zone3': 'zone3',
|
||||
'zone4': 'zone4',
|
||||
'zone5': 'zone5',
|
||||
'zone6': 'zone6',
|
||||
|
||||
// Protection Juridique
|
||||
'checkPJ': 'pj',
|
||||
|
||||
// Garanties additionnelles - Engagements complémentaires
|
||||
'checkDomImmat': 'extRCCConfie', // Simplifié
|
||||
'checkContConf': 'extRCCConfie',
|
||||
'checkTPPC': 'extRCCTPPC',
|
||||
|
||||
// Extensions RCC
|
||||
'checkStationLavage': 'extRCCModifCalArrim',
|
||||
|
||||
// Extensions RCE
|
||||
// (géré séparément car structure différente)
|
||||
|
||||
// Sinistralité
|
||||
'sinistre': 'nbSinistres3ans'
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// COLLECTE DES DONNÉES COMPLÈTES
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Collecte toutes les données du formulaire Tarif RC.
|
||||
* Cette fonction est exhaustive et capture TOUS les champs nécessaires.
|
||||
*
|
||||
* @returns {Object} Objet contenant toutes les données du tarif
|
||||
*
|
||||
* @example
|
||||
* const tarifData = collectAllTarifData();
|
||||
* console.log(tarifData.ca, tarifData.zones, tarifData.marchandises);
|
||||
*/
|
||||
function collectAllTarifData() {
|
||||
// Références flexibles aux éléments
|
||||
const getEl = getElementByIdFlexible;
|
||||
|
||||
const data = {
|
||||
// ═══ INFORMATIONS GÉNÉRALES ═══
|
||||
typeCotisation: document.querySelector('input[name="cotisation"]:checked')?.value || null,
|
||||
ca: toNumber(getValue('CA') || getValue('chiffreAffaire')),
|
||||
nombreVehicules: Math.max(0, Math.round(toNumber(getValue('nbVehicules') || getValue('nbrVehicule')))),
|
||||
|
||||
// ═══ ACTIVITÉS RCC ═══
|
||||
activites: {
|
||||
voiturier: {
|
||||
checked: getValue('checkVoiturier') || false,
|
||||
capital: toNumber(getValue('capitalVoiturier')),
|
||||
pourcentage: toNumber(getValue('pourcent_voiturier') || getValue('pourcentVoiturier/Loueur')),
|
||||
isSet: Boolean(getValue('pourcent_voiturier')?.trim())
|
||||
},
|
||||
commissionnaire: {
|
||||
checked: getValue('checkCommissionnaire') || false,
|
||||
capital: toNumber(getValue('capitalCommissionnaire')),
|
||||
pourcentage: toNumber(getValue('pourcent_commissionnaire')),
|
||||
isSet: Boolean(getValue('pourcent_commissionnaire')?.trim())
|
||||
},
|
||||
demenageur: {
|
||||
checked: getValue('checkDemenageur') || false,
|
||||
capital: toNumber(getValue('capitalDemenageur')),
|
||||
pourcentage: toNumber(getValue('pourcent_demenageur')),
|
||||
isSet: Boolean(getValue('pourcent_demenageur')?.trim())
|
||||
},
|
||||
logistique: {
|
||||
checked: getValue('checkLogistique') || false,
|
||||
capital: toNumber(getValue('capitalLogistique')),
|
||||
pourcentage: toNumber(getValue('pourcent_logistique')),
|
||||
isSet: Boolean(getValue('pourcent_logistique')?.trim())
|
||||
},
|
||||
autocariste: {
|
||||
checked: getValue('checkAutocariste') || false,
|
||||
capital: toNumber(getValue('capitalAutocariste')),
|
||||
pourcentage: toNumber(getValue('pourcent_autocariste')),
|
||||
isSet: Boolean(getValue('pourcent_autocariste')?.trim())
|
||||
},
|
||||
autres: {
|
||||
checked: getValue('checkAutres') || false,
|
||||
capital: toNumber(getValue('capitalAutres')),
|
||||
pourcentage: toNumber(getValue('pourcent_autres')),
|
||||
isSet: Boolean(getValue('pourcent_autres')?.trim())
|
||||
}
|
||||
},
|
||||
|
||||
// ═══ RCE ═══
|
||||
rce: {
|
||||
checked: getValue('checkRCE') || false
|
||||
},
|
||||
|
||||
// ═══ ACTIVITÉS COMPLÉMENTAIRES (JSON) ═══
|
||||
activitesComplementaires: {
|
||||
voiturier: collectActivitesComplJSON('voiturier'),
|
||||
commissionnaire: collectActivitesComplJSON('commissionnaire'),
|
||||
demenageur: collectActivitesComplJSON('demenageur'),
|
||||
logistique: collectActivitesComplJSON('logistique')
|
||||
},
|
||||
|
||||
// ═══ MARCHANDISES (JSON) ═══
|
||||
marchandises: {
|
||||
voiturier: collectMarchandisesJSON('voiturier'),
|
||||
commissionnaire: collectMarchandisesJSON('commissionnaire'),
|
||||
demenageur: collectMarchandisesJSON('demenageur'),
|
||||
logistique: collectMarchandisesJSON('logistique'),
|
||||
autocariste: collectMarchandisesJSON('autocariste'),
|
||||
autres: collectMarchandisesJSON('autres')
|
||||
},
|
||||
|
||||
// ═══ ZONES GÉOGRAPHIQUES ═══
|
||||
zones: {
|
||||
zone1: getValue('zone1') || false,
|
||||
zone2: getValue('zone2') || false,
|
||||
zone3: getValue('zone3') || false,
|
||||
zone4: getValue('zone4') || false,
|
||||
zone5: getValue('zone5') || false,
|
||||
zone6: getValue('zone6') || false
|
||||
},
|
||||
|
||||
// ═══ ENGAGEMENTS COMPLÉMENTAIRES ═══
|
||||
engagementsComplementaires: {
|
||||
domicileImmatriculation: {
|
||||
checked: getValue('checkDomImmat') || false,
|
||||
capital: toNumber(getValue('inputDomImmat'))
|
||||
},
|
||||
contenantConfie: {
|
||||
checked: getValue('checkContConf') || false,
|
||||
capital: toNumber(getValue('inputContConf'))
|
||||
},
|
||||
differenceInventaire: {
|
||||
checked: getValue('checkDiffInv') || false,
|
||||
capital: toNumber(getValue('inputDiffInv'))
|
||||
}
|
||||
},
|
||||
|
||||
// ═══ GARANTIES ADDITIONNELLES ═══
|
||||
garantiesAdditionnelles: {
|
||||
stationLavage: getValue('checkStationLavage') || false,
|
||||
garageInterne: getValue('checkGarageInterne') || false,
|
||||
cse: getValue('checkCSE') || false,
|
||||
tppc: {
|
||||
checked: getValue('checkTPPC') || false,
|
||||
capital: toNumber(getValue('selTPPCcapital')),
|
||||
vehicules: Math.max(0, Math.round(toNumber(getValue('selTPPCveh'))))
|
||||
},
|
||||
pj: getValue('checkPJ') || false
|
||||
},
|
||||
|
||||
// ═══ SINISTRALITÉ ═══
|
||||
sinistralite: {
|
||||
nombre3ans: toNumber(getValue('sinistre')),
|
||||
montant3ans: 0 // TODO: ajouter si champ existe
|
||||
},
|
||||
|
||||
// ═══ RÉSULTATS DE CALCUL ═══
|
||||
resultats: {
|
||||
// Franchise 250
|
||||
fr250: {
|
||||
primeRCC: toNumber(getEl('rccFr250')?.textContent),
|
||||
primeRCE: toNumber(getEl('rceFr250')?.textContent),
|
||||
primePJ: toNumber(getEl('pjFr250')?.textContent),
|
||||
primeTotal: toNumber(getEl('priceFr250')?.textContent),
|
||||
tauxRCC: toNumber(getEl('tauxRccFr250')?.textContent),
|
||||
tauxRCE: toNumber(getEl('tauxRceFr250')?.textContent),
|
||||
tauxGlobal: toNumber(getEl('tauxGlobalFr250')?.textContent)
|
||||
},
|
||||
// Franchise 400
|
||||
fr400: {
|
||||
primeRCC: toNumber(getEl('rccFr400')?.textContent),
|
||||
primeRCE: toNumber(getEl('rceFr400')?.textContent),
|
||||
primePJ: toNumber(getEl('pjFr400')?.textContent),
|
||||
primeTotal: toNumber(getEl('priceFr400')?.textContent),
|
||||
tauxRCC: toNumber(getEl('tauxRccFr400')?.textContent),
|
||||
tauxRCE: toNumber(getEl('tauxRceFr400')?.textContent),
|
||||
tauxGlobal: toNumber(getEl('tauxGlobalFr400')?.textContent)
|
||||
},
|
||||
// Franchise 2000
|
||||
fr2000: {
|
||||
primeRCC: toNumber(getEl('rccFr2000')?.textContent),
|
||||
primeRCE: toNumber(getEl('rceFr2000')?.textContent),
|
||||
primePJ: toNumber(getEl('pjFr2000')?.textContent),
|
||||
primeTotal: toNumber(getEl('priceFr2000')?.textContent),
|
||||
tauxRCC: toNumber(getEl('tauxRccFr2000')?.textContent),
|
||||
tauxRCE: toNumber(getEl('tauxRceFr2000')?.textContent),
|
||||
tauxGlobal: toNumber(getEl('tauxGlobalFr2000')?.textContent)
|
||||
},
|
||||
franchiseChoisie: window.franchiseChoisie || null,
|
||||
tarifCommercial: toNumber(getValue('tarifCom'))
|
||||
},
|
||||
|
||||
// ═══ COMMENTAIRE ═══
|
||||
commentaire: getValue('commentaire') || ''
|
||||
};
|
||||
|
||||
console.log('📊 Données Tarif collectées:', data);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fonction helper pour collecter les activités complémentaires depuis le formulaire.
|
||||
*
|
||||
* @param {string} typeActivite - Type d'activité ('voiturier', 'commissionnaire', etc.)
|
||||
* @returns {string} JSON array des activités cochées
|
||||
* @private
|
||||
*/
|
||||
function collectActivitesComplJSON(typeActivite) {
|
||||
let name;
|
||||
switch(typeActivite.toLowerCase()) {
|
||||
case 'voiturier':
|
||||
name = 'actComplVoiturier/Loueur';
|
||||
break;
|
||||
case 'commissionnaire':
|
||||
name = 'actComplCommissionnaire de Transport';
|
||||
break;
|
||||
case 'demenageur':
|
||||
name = 'actComplDéménageur';
|
||||
break;
|
||||
case 'logistique':
|
||||
name = 'actComplLogistique';
|
||||
break;
|
||||
default:
|
||||
return JSON.stringify([]);
|
||||
}
|
||||
|
||||
const checkboxes = document.querySelectorAll(`[name="${name}"] input[type="checkbox"]:checked`);
|
||||
const activites = [];
|
||||
checkboxes.forEach(cb => {
|
||||
const text = cb.nextElementSibling ? cb.nextElementSibling.textContent.trim() : cb.value;
|
||||
activites.push(text);
|
||||
});
|
||||
return JSON.stringify(activites);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fonction helper pour collecter les marchandises depuis le formulaire.
|
||||
*
|
||||
* @param {string} typeActivite - Type d'activité
|
||||
* @returns {string} JSON array des marchandises cochées
|
||||
* @private
|
||||
*/
|
||||
function collectMarchandisesJSON(typeActivite) {
|
||||
let name;
|
||||
switch(typeActivite.toLowerCase()) {
|
||||
case 'voiturier':
|
||||
name = 'marVoiturier/Loueur';
|
||||
break;
|
||||
case 'commissionnaire':
|
||||
name = 'marCommissionnaire de Transport';
|
||||
break;
|
||||
case 'demenageur':
|
||||
name = 'marDéménageur';
|
||||
break;
|
||||
case 'logistique':
|
||||
name = 'marLogistique';
|
||||
break;
|
||||
case 'autocariste':
|
||||
name = 'marAutocariste';
|
||||
break;
|
||||
case 'autres':
|
||||
name = 'marAutres activites';
|
||||
break;
|
||||
default:
|
||||
return JSON.stringify([]);
|
||||
}
|
||||
|
||||
const checkboxes = document.querySelectorAll(`[name="${name}"] input[type="checkbox"]:checked`);
|
||||
const marchandises = [];
|
||||
checkboxes.forEach(cb => {
|
||||
const text = cb.nextElementSibling ? cb.nextElementSibling.textContent.trim() : cb.value;
|
||||
marchandises.push(text);
|
||||
});
|
||||
return JSON.stringify(marchandises);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// PRÉ-REMPLISSAGE TARIF → PROJET
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Pré-remplit le formulaire Projet avec les données du Tarif.
|
||||
* Cette fonction est appelée quand l'utilisateur passe du Tarif au Projet.
|
||||
*
|
||||
* @param {Object} tarifData - Données complètes du tarif (de collectAllTarifData)
|
||||
*
|
||||
* @example
|
||||
* const tarifData = collectAllTarifData();
|
||||
* prefillProjetFromTarif(tarifData);
|
||||
*/
|
||||
function prefillProjetFromTarif(tarifData) {
|
||||
if (!tarifData) {
|
||||
console.warn('Pas de données tarif à pré-remplir');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('📝 Pré-remplissage Projet depuis Tarif...');
|
||||
|
||||
try {
|
||||
// ═══ INFORMATIONS GÉNÉRALES ═══
|
||||
|
||||
// CA
|
||||
if (tarifData.ca) {
|
||||
setValue('CA', tarifData.ca);
|
||||
console.log(' ✓ CA:', tarifData.ca);
|
||||
}
|
||||
|
||||
// Type de cotisation
|
||||
if (tarifData.typeCotisation) {
|
||||
const radio = document.querySelector(`input[name="typeCot"][value="${tarifData.typeCotisation}"]`);
|
||||
if (radio) {
|
||||
radio.checked = true;
|
||||
console.log(' ✓ Type cotisation:', tarifData.typeCotisation);
|
||||
}
|
||||
}
|
||||
|
||||
// Nombre de véhicules
|
||||
if (tarifData.nombreVehicules) {
|
||||
setValue('nombreVehicules', tarifData.nombreVehicules);
|
||||
console.log(' ✓ Véhicules:', tarifData.nombreVehicules);
|
||||
}
|
||||
|
||||
// ═══ ACTIVITÉS ═══
|
||||
|
||||
const activitySelector = document.getElementById('activity-selector');
|
||||
if (activitySelector && tarifData.activites) {
|
||||
const activitesToAdd = [];
|
||||
|
||||
if (tarifData.activites.voiturier?.checked) {
|
||||
activitesToAdd.push('Voiturier/Loueur');
|
||||
}
|
||||
if (tarifData.activites.commissionnaire?.checked) {
|
||||
activitesToAdd.push('Commissionnaire de Transport');
|
||||
}
|
||||
if (tarifData.activites.demenageur?.checked) {
|
||||
activitesToAdd.push('Déménageur d\'entreprises');
|
||||
}
|
||||
if (tarifData.activites.logistique?.checked) {
|
||||
activitesToAdd.push('Prestataire logistique');
|
||||
}
|
||||
if (tarifData.activites.autocariste?.checked) {
|
||||
activitesToAdd.push('Autocariste');
|
||||
}
|
||||
if (tarifData.activites.autres?.checked) {
|
||||
activitesToAdd.push('Autres activités');
|
||||
}
|
||||
|
||||
// Sélectionner les options dans le select
|
||||
Array.from(activitySelector.options).forEach(option => {
|
||||
if (activitesToAdd.includes(option.value)) {
|
||||
option.selected = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Trigger change pour créer les chips Materialize
|
||||
const event = new Event('change', { bubbles: true });
|
||||
activitySelector.dispatchEvent(event);
|
||||
|
||||
console.log(' ✓ Activités:', activitesToAdd.length);
|
||||
}
|
||||
|
||||
// ═══ MARCHANDISES ═══
|
||||
|
||||
const marchandiseSelector = document.getElementById('marchandise-selector');
|
||||
if (marchandiseSelector && tarifData.marchandises) {
|
||||
const marchandisesToSelect = [];
|
||||
|
||||
// Parser les marchandises de chaque type
|
||||
['voiturier', 'commissionnaire', 'demenageur', 'logistique', 'autocariste', 'autres'].forEach(type => {
|
||||
const marchArray = tarifData.marchandises[type];
|
||||
if (Array.isArray(marchArray)) {
|
||||
marchArray.forEach(m => marchandisesToSelect.push(m));
|
||||
}
|
||||
});
|
||||
|
||||
// Sélectionner dans le select
|
||||
Array.from(marchandiseSelector.options).forEach(option => {
|
||||
if (marchandisesToSelect.includes(option.text) || marchandisesToSelect.includes(option.value)) {
|
||||
option.selected = true;
|
||||
}
|
||||
});
|
||||
|
||||
const event = new Event('change', { bubbles: true });
|
||||
marchandiseSelector.dispatchEvent(event);
|
||||
|
||||
console.log(' ✓ Marchandises:', marchandisesToSelect.length);
|
||||
}
|
||||
|
||||
// ═══ ZONES GÉOGRAPHIQUES ═══
|
||||
|
||||
if (tarifData.zones) {
|
||||
let zonesCount = 0;
|
||||
Object.keys(tarifData.zones).forEach(zoneKey => {
|
||||
const checkbox = document.getElementById(zoneKey);
|
||||
if (checkbox && tarifData.zones[zoneKey]) {
|
||||
checkbox.checked = true;
|
||||
zonesCount++;
|
||||
}
|
||||
});
|
||||
console.log(' ✓ Zones:', zonesCount);
|
||||
}
|
||||
|
||||
// ═══ PROTECTION JURIDIQUE ═══
|
||||
|
||||
if (tarifData.garantiesAdditionnelles?.pj) {
|
||||
const switchPJ = document.getElementById('switchPJ');
|
||||
if (switchPJ) {
|
||||
switchPJ.checked = true;
|
||||
console.log(' ✓ PJ activée');
|
||||
|
||||
// Afficher la section PJ
|
||||
const pjSection = document.getElementById('pj-section');
|
||||
if (pjSection) pjSection.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
// ═══ RCE ═══
|
||||
|
||||
if (tarifData.rce?.checked) {
|
||||
const choixRCE = document.getElementById('choixRCE');
|
||||
if (choixRCE) {
|
||||
choixRCE.checked = true;
|
||||
console.log(' ✓ RCE activée');
|
||||
|
||||
// Afficher la section RCE
|
||||
const rceSection = document.getElementById('section-rce');
|
||||
if (rceSection) rceSection.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
// ═══ TPPC ═══
|
||||
|
||||
if (tarifData.garantiesAdditionnelles?.tppc?.checked) {
|
||||
const checkTPPC = document.getElementById('checkTPPC');
|
||||
if (checkTPPC) {
|
||||
checkTPPC.checked = true;
|
||||
|
||||
if (tarifData.garantiesAdditionnelles.tppc.capital) {
|
||||
setValue('capitalTPPC', tarifData.garantiesAdditionnelles.tppc.capital);
|
||||
}
|
||||
if (tarifData.garantiesAdditionnelles.tppc.vehicules) {
|
||||
setValue('vehiculesTPPC', tarifData.garantiesAdditionnelles.tppc.vehicules);
|
||||
}
|
||||
|
||||
console.log(' ✓ TPPC');
|
||||
}
|
||||
}
|
||||
|
||||
// ═══ ENGAGEMENTS COMPLÉMENTAIRES ═══
|
||||
|
||||
const engagements = tarifData.engagementsComplementaires;
|
||||
if (engagements) {
|
||||
if (engagements.domicileImmatriculation?.checked) {
|
||||
setValue('checkDomImmat', true);
|
||||
console.log(' ✓ Domicile immatriculation');
|
||||
}
|
||||
if (engagements.contenantConfie?.checked) {
|
||||
setValue('checkContConf', true);
|
||||
console.log(' ✓ Contenant confié');
|
||||
}
|
||||
}
|
||||
|
||||
// ═══ SINISTRALITÉ ═══
|
||||
|
||||
if (tarifData.sinistralite) {
|
||||
if (tarifData.sinistralite.nombre3ans) {
|
||||
setValue('nbSinistres3ans', tarifData.sinistralite.nombre3ans);
|
||||
}
|
||||
if (tarifData.sinistralite.montant3ans) {
|
||||
setValue('montantSinistres3ans', tarifData.sinistralite.montant3ans);
|
||||
}
|
||||
console.log(' ✓ Sinistralité');
|
||||
}
|
||||
|
||||
// ═══ RÉSULTATS TARIFAIRES ═══
|
||||
|
||||
if (tarifData.resultats) {
|
||||
const res = tarifData.resultats;
|
||||
|
||||
// Taux
|
||||
if (res.tauxRCCHT) setValue('tauxRCCHT', res.tauxRCCHT);
|
||||
if (res.tauxRCCTTC) setValue('tauxRCCTTC', res.tauxRCCTTC);
|
||||
if (res.tauxRCEHT) setValue('tauxRCEHT', res.tauxRCEHT);
|
||||
if (res.tauxRCETTC) setValue('tauxRCETTC', res.tauxRCETTC);
|
||||
if (res.tauxTotalHT) setValue('tauxTotalHT', res.tauxTotalHT);
|
||||
if (res.tauxTotalTTC) setValue('tauxTotalTTC', res.tauxTotalTTC);
|
||||
|
||||
// Cotisations
|
||||
if (res.cotRCCHT) setValue('cotRCCHT', res.cotRCCHT);
|
||||
if (res.cotRCCTTC) setValue('cotRCCTTC', res.cotRCCTTC);
|
||||
if (res.cotRCEHT) setValue('cotRCEHT', res.cotRCEHT);
|
||||
if (res.cotRCETTC) setValue('cotRCETTC', res.cotRCETTC);
|
||||
if (res.cotPJHT) setValue('cotPJHT', res.cotPJHT);
|
||||
if (res.cotPJTTC) setValue('cotPJTTC', res.cotPJTTC);
|
||||
if (res.cotTotalHT) setValue('cotTotalHT', res.cotTotalHT);
|
||||
if (res.cotTotalTTC) setValue('cotTotalTTC', res.cotTotalTTC);
|
||||
|
||||
console.log(' ✓ Résultats tarifaires');
|
||||
}
|
||||
|
||||
// Forcer la mise à jour des éléments Materialize
|
||||
if (window.M && window.M.FormSelect) {
|
||||
const selects = document.querySelectorAll('select');
|
||||
window.M.FormSelect.init(selects);
|
||||
}
|
||||
if (window.M && window.M.updateTextFields) {
|
||||
window.M.updateTextFields();
|
||||
}
|
||||
|
||||
console.log('✅ Pré-remplissage Projet terminé');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur lors du pré-remplissage Projet:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// PRÉ-REMPLISSAGE PROJET → TARIF
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Pré-remplit le formulaire Tarif avec les données du Projet.
|
||||
* Cette fonction est appelée quand l'utilisateur passe du Projet au Tarif.
|
||||
*
|
||||
* @param {Object} projetData - Données complètes du projet
|
||||
*
|
||||
* @example
|
||||
* prefillTarifFromProjet(projetData);
|
||||
*/
|
||||
function prefillTarifFromProjet(projetData) {
|
||||
if (!projetData) {
|
||||
console.warn('Pas de données projet à pré-remplir');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('📝 Pré-remplissage Tarif depuis Projet...');
|
||||
|
||||
try {
|
||||
// CA
|
||||
if (projetData.ca) {
|
||||
setValue('CA', projetData.ca);
|
||||
}
|
||||
|
||||
// Type de cotisation
|
||||
if (projetData.typeCot) {
|
||||
const radio = document.querySelector(`input[name="cotisation"][value="${projetData.typeCot}"]`);
|
||||
if (radio) radio.checked = true;
|
||||
}
|
||||
|
||||
// Zones géographiques
|
||||
['zone1', 'zone2', 'zone3', 'zone4', 'zone5', 'zone6'].forEach(zone => {
|
||||
if (projetData[zone]) {
|
||||
setValue(zone, true);
|
||||
}
|
||||
});
|
||||
|
||||
// PJ
|
||||
if (projetData.pj) {
|
||||
setValue('checkPJ', true);
|
||||
}
|
||||
|
||||
// RCE
|
||||
if (projetData.autresRC) {
|
||||
setValue('checkRCE', true);
|
||||
}
|
||||
|
||||
console.log('✅ Pré-remplissage Tarif terminé');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur lors du pré-remplissage Tarif:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// EXPORT PUBLIC
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
window.RCDataManager = {
|
||||
collectAllTarifData,
|
||||
prefillProjetFromTarif,
|
||||
prefillTarifFromProjet,
|
||||
FIELD_MAPPING
|
||||
};
|
||||
|
||||
console.log('✅ RC Data Manager loaded');
|
||||
|
||||
})(window);
|
||||
|
|
@ -0,0 +1,388 @@
|
|||
/**
|
||||
* ═══════════════════════════════════════════════════════════════════════════
|
||||
* RC SYNC ORCHESTRATOR
|
||||
* ═══════════════════════════════════════════════════════════════════════════
|
||||
*
|
||||
* Ce module orchestre la synchronisation entre Tarif RC et Projet RC.
|
||||
* Il s'intègre avec les formulaires existants sans les modifier.
|
||||
*
|
||||
* @requires rc-sync-utils.js
|
||||
* @requires rc-data-manager.js
|
||||
* @author AXA Transport Team
|
||||
* @version 2.0.0
|
||||
* @since 2026-02-17
|
||||
*/
|
||||
|
||||
(function(window) {
|
||||
'use strict';
|
||||
|
||||
// Attendre que les dépendances soient chargées
|
||||
if (!window.RCSync || !window.RCDataManager) {
|
||||
console.error('❌ Dépendances RC Sync manquantes');
|
||||
return;
|
||||
}
|
||||
|
||||
const { isChangeImpactingTarif, showReturnToTarifModal } = window.RCSync;
|
||||
const { collectAllTarifData, prefillProjetFromTarif, prefillTarifFromProjet } = window.RCDataManager;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// CONFIGURATION
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
const SESSION_STORAGE_KEYS = {
|
||||
TARIF_DATA: 'rc_tarif_validated_data',
|
||||
PROJET_DATA: 'rc_projet_data',
|
||||
TARIF_ORIGINAL: 'rc_tarif_original_for_comparison'
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// DÉTECTION DE LA PAGE ACTIVE
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Détecte la page active (tarif ou projet) depuis l'URL.
|
||||
*
|
||||
* @returns {'tarif'|'projet'|null} Page active ou null
|
||||
*/
|
||||
function detectActivePage() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const submenu = params.get('submenu');
|
||||
|
||||
if (submenu === 'tarif' || submenu === 'tarifrc') {
|
||||
return 'tarif';
|
||||
} else if (submenu === 'projet' || submenu === 'projetrc') {
|
||||
return 'projet';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// GESTION SESSIONSTORAGE
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Sauvegarde les données du tarif validé dans sessionStorage.
|
||||
*
|
||||
* @param {Object} tarifData - Données complètes du tarif
|
||||
*/
|
||||
function saveTarifDataToSession(tarifData) {
|
||||
try {
|
||||
sessionStorage.setItem(SESSION_STORAGE_KEYS.TARIF_DATA, JSON.stringify(tarifData));
|
||||
sessionStorage.setItem(SESSION_STORAGE_KEYS.TARIF_ORIGINAL, JSON.stringify(tarifData));
|
||||
console.log('✅ Données tarif sauvegardées en session');
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur sauvegarde session:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère les données du tarif depuis sessionStorage.
|
||||
*
|
||||
* @returns {Object|null} Données du tarif ou null
|
||||
*/
|
||||
function getTarifDataFromSession() {
|
||||
try {
|
||||
const data = sessionStorage.getItem(SESSION_STORAGE_KEYS.TARIF_DATA);
|
||||
return data ? JSON.parse(data) : null;
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur lecture session:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère les données originales du tarif pour comparaison.
|
||||
*
|
||||
* @returns {Object|null} Données originales du tarif
|
||||
*/
|
||||
function getTarifOriginalDataFromSession() {
|
||||
try {
|
||||
const data = sessionStorage.getItem(SESSION_STORAGE_KEYS.TARIF_ORIGINAL);
|
||||
return data ? JSON.parse(data) : null;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// HOOK: APRÈS VALIDATION TARIF
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Hook appelé après la validation du tarif commercial.
|
||||
* Collecte toutes les données et les sauvegarde en session.
|
||||
*
|
||||
* Cette fonction doit être appelée juste avant la redirection vers le projet.
|
||||
*/
|
||||
function onTarifValidated() {
|
||||
console.log('🎯 Hook: Tarif validé, collecte des données...');
|
||||
|
||||
try {
|
||||
// Collecter toutes les données du tarif
|
||||
const tarifData = collectAllTarifData();
|
||||
|
||||
// Sauvegarder en session pour le pré-remplissage projet
|
||||
saveTarifDataToSession(tarifData);
|
||||
|
||||
console.log('✅ Données tarif prêtes pour le projet');
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur hook tarif validé:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// INITIALISATION PAGE PROJET
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Initialise le formulaire projet au chargement.
|
||||
* Configure UNIQUEMENT la détection des changements impactants.
|
||||
* Le pré-remplissage est géré par prefillFromTarif() existant dans projet-form-RC.js
|
||||
*/
|
||||
function initProjetPage() {
|
||||
console.log('🚀 Initialisation RC Orchestrator pour page Projet...');
|
||||
|
||||
// Les données rc/tarif/projet sont DÉJÀ chargées depuis la base
|
||||
// par le code existant dans projet-form-RC.js
|
||||
// On configure juste la détection des changements
|
||||
|
||||
setTimeout(() => {
|
||||
setupProjetChangeDetection();
|
||||
}, 1000); // Attendre que prefillFromTarif() ait fini
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure la détection des changements impactants dans le projet.
|
||||
* Affiche un modal si l'utilisateur modifie un champ qui impacte le tarif.
|
||||
* Utilise les variables globales rc/tarif depuis projet-form-RC.js
|
||||
*/
|
||||
function setupProjetChangeDetection() {
|
||||
// Les données originales sont dans les variables globales window.tarif et window.rc
|
||||
// définies par projet-form-RC.js
|
||||
const tarifOriginal = window.tarif;
|
||||
const rcOriginal = window.rc;
|
||||
|
||||
if (!tarifOriginal && !rcOriginal) {
|
||||
console.log('ℹ️ Pas de tarif/rc, pas de détection');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('👁️ Configuration détection changements...');
|
||||
console.log('📋 Données originales:', { tarif: tarifOriginal, rc: rcOriginal });
|
||||
|
||||
// Liste COMPLÈTE des éléments à surveiller (tous les champs impactants)
|
||||
const elementsToWatch = [
|
||||
// CA et infos générales
|
||||
'CA', 'chiffreAffaire', 'nombreVehicules', 'nbrVehicule',
|
||||
|
||||
// Zones géographiques
|
||||
'zone1', 'zone2', 'zone3', 'zone4', 'zone5', 'zone6',
|
||||
|
||||
// Protection Juridique
|
||||
'switchPJ', 'checkPJ',
|
||||
|
||||
// RCE
|
||||
'choixRCE', 'checkRCE',
|
||||
|
||||
// TPPC
|
||||
'checkTPPC', 'capitalTPPC', 'vehiculesTPPC',
|
||||
|
||||
// Engagements complémentaires
|
||||
'checkDomImmat', 'checkContConf', 'checkDiffInv',
|
||||
|
||||
// Garanties additionnelles
|
||||
'checkStationLavage', 'checkGarageInterne', 'checkCSE',
|
||||
|
||||
// Sinistralité
|
||||
'nbSinistres3ans', 'montantSinistres3ans',
|
||||
|
||||
// Autres
|
||||
'programmeInternationale', 'participationResultat'
|
||||
];
|
||||
|
||||
// Ajouter des listeners sur tous les éléments surveillés
|
||||
elementsToWatch.forEach(elementId => {
|
||||
const element = document.getElementById(elementId);
|
||||
if (!element) return;
|
||||
|
||||
const eventType = element.type === 'checkbox' ? 'change' : 'blur';
|
||||
|
||||
element.addEventListener(eventType, function(e) {
|
||||
const fieldName = this.id;
|
||||
const newValue = this.type === 'checkbox' ? this.checked : this.value;
|
||||
|
||||
console.log(`🔍 Changement détecté: ${fieldName} = ${newValue}`);
|
||||
|
||||
// Vérifier si c'est un champ impactant
|
||||
if (isFieldImpactingTarif(fieldName)) {
|
||||
console.warn(`⚠️ "${fieldName}" impacte le tarif !`);
|
||||
showReturnToTarifModal(fieldName);
|
||||
} else {
|
||||
console.log(`ℹ️ "${fieldName}" n'impacte pas le tarif`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Surveiller les radio buttons (type de cotisation)
|
||||
const radioTypeCot = document.querySelectorAll('input[name="typeCot"]');
|
||||
radioTypeCot.forEach(radio => {
|
||||
radio.addEventListener('change', function() {
|
||||
console.log(`🔍 Changement type cotisation: ${this.value}`);
|
||||
console.warn(`⚠️ Type de cotisation impacte le tarif !`);
|
||||
showReturnToTarifModal('Type de cotisation');
|
||||
});
|
||||
});
|
||||
|
||||
// Surveiller le select activités
|
||||
const activitySelector = document.getElementById('activity-selector');
|
||||
if (activitySelector) {
|
||||
activitySelector.addEventListener('change', function() {
|
||||
const selectedValues = Array.from(this.selectedOptions).map(opt => opt.value);
|
||||
console.log(`🔍 Changement activités:`, selectedValues);
|
||||
console.warn(`⚠️ Activités impactent le tarif !`);
|
||||
showReturnToTarifModal('Activités');
|
||||
});
|
||||
}
|
||||
|
||||
// Surveiller le select marchandises
|
||||
const marchandiseSelector = document.getElementById('marchandise-selector');
|
||||
if (marchandiseSelector) {
|
||||
marchandiseSelector.addEventListener('change', function() {
|
||||
const selectedValues = Array.from(this.selectedOptions).map(opt => opt.value);
|
||||
console.log(`🔍 Changement marchandises:`, selectedValues);
|
||||
console.warn(`⚠️ Marchandises impactent le tarif !`);
|
||||
showReturnToTarifModal('Marchandises');
|
||||
});
|
||||
}
|
||||
|
||||
// Surveiller les boutons d'action sur les zones (Monde entier / Reset)
|
||||
['btnMondeEntier', 'btnReset'].forEach(btnId => {
|
||||
const btn = document.getElementById(btnId);
|
||||
if (!btn) return;
|
||||
btn.addEventListener('click', () => {
|
||||
console.log(`🔍 Changement zones via ${btnId}`);
|
||||
console.warn('⚠️ Zones géographiques impactent le tarif !');
|
||||
showReturnToTarifModal('Zones géographiques');
|
||||
});
|
||||
});
|
||||
|
||||
console.log('✅ Détection changements configurée sur tous les champs impactants');
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// INITIALISATION PAGE TARIF
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Initialise le formulaire tarif au chargement.
|
||||
* Pré-remplit depuis le projet si l'utilisateur vient du projet.
|
||||
*/
|
||||
function initTarifPage() {
|
||||
console.log('🚀 Initialisation page Tarif...');
|
||||
|
||||
// Vérifier si on vient du projet
|
||||
const projetData = JSON.parse(sessionStorage.getItem(SESSION_STORAGE_KEYS.PROJET_DATA) || 'null');
|
||||
|
||||
if (projetData && !getTarifDataFromSession()) {
|
||||
// On a des données projet mais pas de tarif validé
|
||||
// = L'utilisateur a commencé par le projet
|
||||
console.log('📥 Pré-remplissage depuis projet...');
|
||||
|
||||
setTimeout(() => {
|
||||
prefillTarifFromProjet(projetData);
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// INTERCEPTION DES FONCTIONS EXISTANTES
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Intercepte la fonction de validation du tarif commercial existante.
|
||||
* Ajoute notre hook avant la redirection.
|
||||
*/
|
||||
function interceptTarifValidation() {
|
||||
// Attendre que la fonction window.saveTarifRC soit disponible
|
||||
const checkInterval = setInterval(() => {
|
||||
if (window.saveTarifRC) {
|
||||
clearInterval(checkInterval);
|
||||
|
||||
// Sauvegarder la fonction originale
|
||||
const originalSaveTarifRC = window.saveTarifRC;
|
||||
|
||||
// Remplacer par notre version wrappée
|
||||
window.saveTarifRC = async function(...args) {
|
||||
console.log('🎯 Interception saveTarifRC...');
|
||||
|
||||
// Appeler la fonction originale
|
||||
const result = await originalSaveTarifRC.apply(this, args);
|
||||
|
||||
// Si succès, appeler notre hook
|
||||
if (result && result.valid) {
|
||||
onTarifValidated();
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
console.log('✅ saveTarifRC intercepté');
|
||||
}
|
||||
}, 100);
|
||||
|
||||
// Timeout après 5 secondes
|
||||
setTimeout(() => clearInterval(checkInterval), 5000);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// DÉMARRAGE AUTOMATIQUE
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Initialise l'orchestrateur au chargement de la page.
|
||||
*/
|
||||
function init() {
|
||||
console.log('🎼 RC Sync Orchestrator: Démarrage...');
|
||||
|
||||
const activePage = detectActivePage();
|
||||
console.log(`📄 Page active détectée: ${activePage || 'aucune'}`);
|
||||
|
||||
if (activePage === 'tarif') {
|
||||
interceptTarifValidation();
|
||||
|
||||
// Attendre que le formulaire soit initialisé
|
||||
setTimeout(() => {
|
||||
initTarifPage();
|
||||
}, 1000);
|
||||
|
||||
} else if (activePage === 'projet') {
|
||||
// Attendre que le formulaire soit initialisé
|
||||
setTimeout(() => {
|
||||
initProjetPage();
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
// Démarrage au chargement du DOM
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// EXPORT PUBLIC
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
window.RCOrchestrator = {
|
||||
onTarifValidated,
|
||||
initProjetPage,
|
||||
initTarifPage,
|
||||
saveTarifDataToSession,
|
||||
getTarifDataFromSession
|
||||
};
|
||||
|
||||
console.log('✅ RC Sync Orchestrator loaded');
|
||||
|
||||
})(window);
|
||||
|
|
@ -0,0 +1,464 @@
|
|||
/**
|
||||
* ═══════════════════════════════════════════════════════════════════════════
|
||||
* RC SYNCHRONIZATION UTILITIES
|
||||
* ═══════════════════════════════════════════════════════════════════════════
|
||||
*
|
||||
* Ce module contient toutes les fonctions utilitaires pour la synchronisation
|
||||
* bidirectionnelle entre les formulaires Tarif RC et Projet RC.
|
||||
*
|
||||
* @author AXA Transport Team
|
||||
* @version 2.0.0
|
||||
* @since 2026-02-17
|
||||
*/
|
||||
|
||||
(function(window) {
|
||||
'use strict';
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// CONSTANTES
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Liste exhaustive des champs qui impactent le calcul du tarif.
|
||||
* Si l'un de ces champs est modifié dans le projet, un modal
|
||||
* demandera à l'utilisateur de retourner au tarif.
|
||||
*
|
||||
* @constant {Array<string>}
|
||||
*/
|
||||
const TARIF_IMPACTING_FIELDS = [
|
||||
// Chiffre d'affaires et type de contrat
|
||||
'ca', 'chiffreAffaires', 'CA',
|
||||
'typeCotisation', 'cotisation',
|
||||
'nombreVehicules', 'nbVehicules',
|
||||
|
||||
// Activités RCC
|
||||
'checkVoiturier', 'capitalVoiturier', 'actVoiturier',
|
||||
'checkCommissionnaire', 'capitalCommissionnaire', 'actMultimodal',
|
||||
'checkDemenageur', 'capitalDemenageur',
|
||||
'checkLogistique', 'capitalLogistique',
|
||||
'checkAutocariste', 'capitalAutocariste',
|
||||
'checkAutres', 'capitalAutres',
|
||||
|
||||
// RCE
|
||||
'checkRCE', 'autresRC',
|
||||
|
||||
// Activités complémentaires
|
||||
'actComplVoiturier', 'actComplCommissionnaire', 'actComplDemenageur', 'actComplLogistique',
|
||||
'activitesVoiturier', 'activitesCommissionnaire', 'activitesDemenageur', 'activitesLogistique',
|
||||
|
||||
// Marchandises
|
||||
'marchandisesVoiturier', 'marchandisesCommissionnaire', 'marchandisesDemenageur',
|
||||
'marchandisesLogistique', 'marchandisesAutocariste', 'marchandisesAutres',
|
||||
'marOrdinaire', 'marRoulant', 'marEngins', 'marRoulantDem', 'marMobilerUsag',
|
||||
'marPerissable', 'marAnimaux', 'marCiterne', 'marBeton', 'marExceptionnels', 'marVrac',
|
||||
|
||||
// Zones géographiques
|
||||
'zone1', 'zone2', 'zone3', 'zone4', 'zone5', 'zone6',
|
||||
|
||||
// Extensions de garantie RCC
|
||||
'extRCCModifCalArrim', 'extRCCFerroutage', 'extRCCFraisRecons',
|
||||
'extRCCConfie', 'typeExtConfies', 'extRCCTPPC', 'extRCCRegie', 'extRCCSansMontageDemontage',
|
||||
'checkDomImmat', 'capitalDomImmat', 'checkContConf', 'capitalContConf',
|
||||
'checkDiffInv', 'capitalDiffInv', 'checkTPPC', 'capitalTPPC', 'vehiculesTPPC',
|
||||
|
||||
// Extensions de garantie RCE
|
||||
'extRCEBraDebra', 'extRCEMontageDemontage',
|
||||
|
||||
// Garanties additionnelles
|
||||
'checkStationLavage', 'checkGarageInterne', 'checkCSE', 'checkPJ', 'pj',
|
||||
|
||||
// Sinistralité
|
||||
'sinistre', 'nbSinistres3ans', 'montantSinistres3ans'
|
||||
];
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// HELPERS - MANIPULATION DE VALEURS
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Convertit une valeur en nombre en gérant les formats français et internationaux.
|
||||
* Gère les espaces, virgules, points, et valeurs nulles/undefined.
|
||||
*
|
||||
* @param {string|number|null|undefined} x - Valeur à convertir
|
||||
* @returns {number} Nombre converti ou 0 si impossible
|
||||
*
|
||||
* @example
|
||||
* toNumber("1 234,56") // 1234.56
|
||||
* toNumber("1.234,56") // 1234.56
|
||||
* toNumber("1,234.56") // 1234.56
|
||||
* toNumber(null) // 0
|
||||
*/
|
||||
function toNumber(x) {
|
||||
if (x == null) return 0;
|
||||
|
||||
let value = String(x).trim();
|
||||
if (!value) return 0;
|
||||
|
||||
value = value
|
||||
.replace(/\s/g, '')
|
||||
.replace(/[^\d.,-]/g, '');
|
||||
|
||||
if (!value) return 0;
|
||||
|
||||
const isNegative = value.startsWith('-');
|
||||
value = value.replace(/-/g, '');
|
||||
if (isNegative && value) {
|
||||
value = '-' + value;
|
||||
}
|
||||
|
||||
const hasComma = value.includes(',');
|
||||
const hasDot = value.includes('.');
|
||||
|
||||
if (hasComma) {
|
||||
value = value.replace(/\./g, '').replace(/,/g, '.');
|
||||
} else if (hasDot) {
|
||||
const dotMatches = value.match(/\./g);
|
||||
const dotCount = dotMatches ? dotMatches.length : 0;
|
||||
if (dotCount > 1) {
|
||||
const parts = value.split('.');
|
||||
const lastSegment = parts[parts.length - 1];
|
||||
if (lastSegment.length === 3) {
|
||||
value = parts.join('');
|
||||
} else {
|
||||
value = parts.slice(0, -1).join('') + '.' + lastSegment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const parsed = Number(value);
|
||||
return Number.isFinite(parsed) ? parsed : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère la valeur d'un élément par son ID de manière flexible.
|
||||
* Gère les différents types d'éléments (input, select, textarea, etc.)
|
||||
* et les cas où l'ID contient des caractères spéciaux.
|
||||
*
|
||||
* @param {string} id - ID de l'élément
|
||||
* @returns {HTMLElement|null} Élément trouvé ou null
|
||||
*
|
||||
* @example
|
||||
* const element = getElementByIdFlexible("my-element");
|
||||
*/
|
||||
function getElementByIdFlexible(id) {
|
||||
if (!id) return null;
|
||||
const direct = document.getElementById(id);
|
||||
if (direct) return direct;
|
||||
try {
|
||||
return document.querySelector(`[id="${id.replace(/"/g, '\\"')}"]`);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère la valeur d'un champ de formulaire de manière sécurisée.
|
||||
* Gère les inputs, selects, textareas, checkboxes, et contenus textuels.
|
||||
*
|
||||
* @param {string} elementId - ID de l'élément
|
||||
* @returns {string|number|boolean|null} Valeur du champ
|
||||
*
|
||||
* @example
|
||||
* getValue("ca") // "100000"
|
||||
* getValue("checkPJ") // true
|
||||
*/
|
||||
function getValue(elementId) {
|
||||
const element = getElementByIdFlexible(elementId);
|
||||
if (!element) return null;
|
||||
|
||||
if (element.type === 'checkbox') {
|
||||
return element.checked;
|
||||
} else if (element.type === 'radio') {
|
||||
const checked = document.querySelector(`input[name="${element.name}"]:checked`);
|
||||
return checked ? checked.value : null;
|
||||
} else if (element.tagName === 'SELECT') {
|
||||
return element.value;
|
||||
} else if (element.value !== undefined) {
|
||||
return element.value;
|
||||
} else {
|
||||
return element.textContent || element.innerText || null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Définit la valeur d'un champ de formulaire.
|
||||
* Gère automatiquement le type de champ et met à jour l'interface.
|
||||
*
|
||||
* @param {string} elementId - ID de l'élément
|
||||
* @param {any} value - Valeur à définir
|
||||
*
|
||||
* @example
|
||||
* setValue("ca", 100000);
|
||||
* setValue("checkPJ", true);
|
||||
*/
|
||||
function setValue(elementId, value) {
|
||||
const element = getElementByIdFlexible(elementId);
|
||||
if (!element) {
|
||||
console.warn(`Élément non trouvé: ${elementId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (element.type === 'checkbox') {
|
||||
element.checked = Boolean(value);
|
||||
} else if (element.type === 'radio') {
|
||||
const radio = document.querySelector(`input[name="${element.name}"][value="${value}"]`);
|
||||
if (radio) radio.checked = true;
|
||||
} else if (element.tagName === 'SELECT') {
|
||||
element.value = value;
|
||||
// Réinitialiser Materialize select si présent
|
||||
if (window.M && window.M.FormSelect) {
|
||||
const instance = window.M.FormSelect.getInstance(element);
|
||||
if (instance) instance.destroy();
|
||||
window.M.FormSelect.init(element);
|
||||
}
|
||||
} else if (element.value !== undefined) {
|
||||
element.value = value;
|
||||
} else {
|
||||
element.textContent = value;
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// COMPARAISON DE DONNÉES
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Compare deux tableaux pour vérifier leur égalité.
|
||||
* Effectue une comparaison profonde élément par élément.
|
||||
*
|
||||
* @param {Array} arr1 - Premier tableau
|
||||
* @param {Array} arr2 - Deuxième tableau
|
||||
* @returns {boolean} true si les tableaux sont égaux
|
||||
*
|
||||
* @example
|
||||
* arraysEqual([1,2,3], [1,2,3]) // true
|
||||
* arraysEqual([1,2], [1,2,3]) // false
|
||||
*/
|
||||
function arraysEqual(arr1, arr2) {
|
||||
if (!Array.isArray(arr1) || !Array.isArray(arr2)) return false;
|
||||
if (arr1.length !== arr2.length) return false;
|
||||
|
||||
const sorted1 = [...arr1].sort();
|
||||
const sorted2 = [...arr2].sort();
|
||||
|
||||
return sorted1.every((val, idx) => val === sorted2[idx]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare deux valeurs en tenant compte de leur type.
|
||||
* Gère les tableaux, objets, null, undefined, et valeurs primitives.
|
||||
*
|
||||
* @param {any} value1 - Première valeur
|
||||
* @param {any} value2 - Deuxième valeur
|
||||
* @returns {boolean} true si les valeurs sont égales
|
||||
*
|
||||
* @example
|
||||
* valuesEqual([1,2], [2,1]) // true (ordre indépendant)
|
||||
* valuesEqual(null, undefined) // true
|
||||
* valuesEqual(100, "100") // true (conversion automatique)
|
||||
*/
|
||||
function valuesEqual(value1, value2) {
|
||||
// Normaliser null et undefined
|
||||
if (value1 == null && value2 == null) return true;
|
||||
if (value1 == null || value2 == null) return false;
|
||||
|
||||
// Comparer les tableaux
|
||||
if (Array.isArray(value1) && Array.isArray(value2)) {
|
||||
return arraysEqual(value1, value2);
|
||||
}
|
||||
|
||||
// Comparer les objets
|
||||
if (typeof value1 === 'object' && typeof value2 === 'object') {
|
||||
return JSON.stringify(value1) === JSON.stringify(value2);
|
||||
}
|
||||
|
||||
// Comparer les nombres (avec conversion)
|
||||
if (!isNaN(value1) && !isNaN(value2)) {
|
||||
return toNumber(value1) === toNumber(value2);
|
||||
}
|
||||
|
||||
// Comparaison standard
|
||||
return value1 === value2;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// DÉTECTION DE CHANGEMENTS IMPACTANTS
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Vérifie si un champ donné impacte le calcul du tarif.
|
||||
* Se base sur la liste TARIF_IMPACTING_FIELDS.
|
||||
*
|
||||
* @param {string} fieldName - Nom du champ
|
||||
* @returns {boolean} true si le champ impacte le tarif
|
||||
*
|
||||
* @example
|
||||
* isFieldImpactingTarif("ca") // true
|
||||
* isFieldImpactingTarif("dateEffet") // false
|
||||
*/
|
||||
function isFieldImpactingTarif(fieldName) {
|
||||
return TARIF_IMPACTING_FIELDS.some(field =>
|
||||
fieldName.includes(field) || field.includes(fieldName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si un changement de valeur impacte le tarif.
|
||||
* Compare la nouvelle valeur avec les données originales du tarif.
|
||||
*
|
||||
* @param {string} fieldName - Nom du champ modifié
|
||||
* @param {any} newValue - Nouvelle valeur
|
||||
* @param {Object} tarifOriginalData - Données originales du tarif
|
||||
* @returns {boolean} true si le changement impacte le tarif
|
||||
*
|
||||
* @example
|
||||
* const impacted = isChangeImpactingTarif("ca", 200000, tarifData);
|
||||
* if (impacted) showReturnToTarifModal();
|
||||
*/
|
||||
function isChangeImpactingTarif(fieldName, newValue, tarifOriginalData) {
|
||||
// Vérifier si le champ est dans la liste des champs impactants
|
||||
if (!isFieldImpactingTarif(fieldName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Si pas de données originales, pas d'impact possible
|
||||
if (!tarifOriginalData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Récupérer la valeur originale
|
||||
const originalValue = tarifOriginalData[fieldName];
|
||||
|
||||
// Comparer les valeurs
|
||||
return !valuesEqual(newValue, originalValue);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// MODAL DE RETOUR AU TARIF
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Affiche le modal demandant à l'utilisateur de retourner au tarif.
|
||||
* Ce modal s'affiche quand une modification dans le projet impacte
|
||||
* le calcul du tarif.
|
||||
*
|
||||
* @param {string} [fieldName] - Nom du champ modifié (optionnel, pour info)
|
||||
*
|
||||
* @example
|
||||
* showReturnToTarifModal("ca");
|
||||
*/
|
||||
function showReturnToTarifModal(fieldName) {
|
||||
const modalId = 'modalRetourTarif';
|
||||
let modal = document.getElementById(modalId);
|
||||
|
||||
// Créer le modal s'il n'existe pas
|
||||
if (!modal) {
|
||||
modal = createReturnToTarifModal();
|
||||
document.body.appendChild(modal);
|
||||
}
|
||||
|
||||
// Mettre à jour le message si un champ est spécifié
|
||||
if (fieldName) {
|
||||
const messageEl = modal.querySelector('#modalRetourTarifMessage');
|
||||
if (messageEl) {
|
||||
messageEl.innerHTML = `
|
||||
Vous avez modifié <strong>"${fieldName}"</strong> qui impacte le calcul du tarif.
|
||||
<br><br>
|
||||
Vous devez retourner sur le formulaire Tarif pour recalculer et valider le nouveau tarif.
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// Ouvrir le modal
|
||||
if (window.M && window.M.Modal) {
|
||||
const instance = window.M.Modal.getInstance(modal) || window.M.Modal.init(modal);
|
||||
instance.open();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée l'élément DOM du modal de retour au tarif.
|
||||
*
|
||||
* @returns {HTMLElement} Élément modal créé
|
||||
* @private
|
||||
*/
|
||||
function createReturnToTarifModal() {
|
||||
const modal = document.createElement('div');
|
||||
modal.id = 'modalRetourTarif';
|
||||
modal.className = 'modal';
|
||||
|
||||
modal.innerHTML = `
|
||||
<div class="modal-content">
|
||||
<h5>⚠️ Modification impactant le tarif</h5>
|
||||
<p id="modalRetourTarifMessage">
|
||||
Vous avez modifié une donnée qui impacte le calcul du tarif.
|
||||
<br><br>
|
||||
<strong>Vous devez retourner sur le formulaire Tarif pour recalculer et valider le nouveau tarif.</strong>
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class="modal-close waves-effect waves-red btn-flat">Annuler</a>
|
||||
<a href="#!" class="waves-effect waves-green btn" onclick="window.RCSync.navigateToTarif()">
|
||||
Aller au Tarif
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
|
||||
return modal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate vers l'onglet Tarif depuis le Projet.
|
||||
*
|
||||
* @example
|
||||
* navigateToTarif();
|
||||
*/
|
||||
function navigateToTarif() {
|
||||
// Fermer le modal
|
||||
const modal = document.getElementById('modalRetourTarif');
|
||||
if (modal && window.M) {
|
||||
const instance = window.M.Modal.getInstance(modal);
|
||||
if (instance) instance.close();
|
||||
}
|
||||
|
||||
// Naviguer vers le tarif
|
||||
const numParcours = new URLSearchParams(window.location.search).get('numParcours');
|
||||
if (numParcours) {
|
||||
window.location.href = `/navParcours?numParcours=${numParcours}&submenu=tarif`;
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// EXPORT PUBLIC
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* API publique du module RC Sync.
|
||||
* Toutes les fonctions exportées ici sont accessibles via window.RCSync.
|
||||
*/
|
||||
window.RCSync = {
|
||||
// Helpers
|
||||
toNumber,
|
||||
getValue,
|
||||
setValue,
|
||||
getElementByIdFlexible,
|
||||
|
||||
// Comparaison
|
||||
arraysEqual,
|
||||
valuesEqual,
|
||||
|
||||
// Détection changements
|
||||
isFieldImpactingTarif,
|
||||
isChangeImpactingTarif,
|
||||
|
||||
// Modal
|
||||
showReturnToTarifModal,
|
||||
navigateToTarif,
|
||||
|
||||
// Constantes
|
||||
TARIF_IMPACTING_FIELDS
|
||||
};
|
||||
|
||||
console.log('✅ RC Sync Utils loaded');
|
||||
|
||||
})(window);
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -8,12 +8,43 @@ const path = require("path");
|
|||
const moment = require("moment");
|
||||
const parcoursService = require("../services/parcoursService");
|
||||
const contratService = require("../services/contratService");
|
||||
const userService = require("../services/userService");
|
||||
const globalService = require("../services/globalService");
|
||||
//const projetformrc = require("../../public/js/projet-form-rc");
|
||||
//const moduloRC = require("../constantes/json-modulateur-rc"); useless pour le moment ?
|
||||
|
||||
require("moment/locale/fr");
|
||||
moment.locale("fr");
|
||||
|
||||
// Fonctions helper pour récupérer les valeurs selon la franchise choisie
|
||||
function getSelectedTarifReference(tarifRC) {
|
||||
const franchise = tarifRC.franchiseChoisie;
|
||||
if (franchise === '250') return tarifRC.primeTotal_250;
|
||||
if (franchise === '400') return tarifRC.primeTotal_400;
|
||||
if (franchise === 'mini300') return tarifRC.primeTotal_2000;
|
||||
return null;
|
||||
}
|
||||
|
||||
function getSelectedPrime(tarifRC, type) {
|
||||
const franchise = tarifRC.franchiseChoisie;
|
||||
if (!franchise) return 0;
|
||||
|
||||
const suffix = franchise === 'mini300' ? '2000' : franchise;
|
||||
const fieldName = `prime${type}_${suffix}`;
|
||||
return tarifRC[fieldName] || 0;
|
||||
}
|
||||
|
||||
function getSelectedTaux(tarifRC, type) {
|
||||
const franchise = tarifRC.franchiseChoisie;
|
||||
if (!franchise) return 0;
|
||||
|
||||
const suffix = franchise === 'mini300' ? '2000' : franchise;
|
||||
const fieldName = `taux${type}_${suffix}`;
|
||||
return tarifRC[fieldName] || 0;
|
||||
}
|
||||
|
||||
router.post("/rc/projet/:numParcours", async (req, res) => {
|
||||
try {
|
||||
const content = fs.readFileSync(
|
||||
path.resolve("src/templates/template-projet-rc.docx"),
|
||||
"binary"
|
||||
|
|
@ -27,11 +58,21 @@ router.post("/rc/projet/:numParcours", async (req, res) => {
|
|||
const contrat = await contratService.getContratById(parcours.contrat);
|
||||
const client = contrat?.["@expand"]?.client || {};
|
||||
const intermediaire = contrat?.["@expand"]?.intermediaire || {};
|
||||
const rc = contrat?.["@expand"]?.enCours || {};
|
||||
|
||||
// Récupérer la collection rc avec ses relations (APRÈS placerDansEnCours, c'est dans enCours)
|
||||
const rcFull = contrat?.["@expand"]?.enCours;
|
||||
if (!rcFull) {
|
||||
logger.log('error', 'No RC found for contrat:', contrat.id);
|
||||
return res.status(404).send("Aucune donnée RC trouvée pour ce contrat");
|
||||
}
|
||||
|
||||
// Les données sont déjà expandées par contratService
|
||||
const rc = rcFull?.["@expand"]?.projetRC || {};
|
||||
|
||||
const listAssAdd = [];
|
||||
|
||||
try {
|
||||
// Traiter les assurés additionnels s'ils existent
|
||||
if (rc.assureAdditionnel && Array.isArray(rc.assureAdditionnel)) {
|
||||
rc.assureAdditionnel.forEach((objet) => {
|
||||
listAssAdd.push(
|
||||
objet.nom +
|
||||
|
|
@ -41,18 +82,18 @@ router.post("/rc/projet/:numParcours", async (req, res) => {
|
|||
objet.siret
|
||||
);
|
||||
});
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
// Conditions zone
|
||||
hasMondeEntier = false;
|
||||
hasZone1 = false;
|
||||
hasZone2 = false;
|
||||
hasZone3 = false;
|
||||
hasZone4 = false;
|
||||
hasZone5 = false;
|
||||
hasZone6 = false;
|
||||
hasActiviteButNotMultimodal = false; // Attention trick pour les zones géographiques dans le cas de multimodal
|
||||
hasZone456 = false;
|
||||
let hasMondeEntier = false;
|
||||
let hasZone1 = false;
|
||||
let hasZone2 = false;
|
||||
let hasZone3 = false;
|
||||
let hasZone4 = false;
|
||||
let hasZone5 = false;
|
||||
let hasZone6 = false;
|
||||
let hasActiviteButNotMultimodal = false; // Attention trick pour les zones géographiques dans le cas de multimodal
|
||||
let hasZone456 = false;
|
||||
|
||||
// Cas monde entier
|
||||
if (
|
||||
|
|
@ -79,9 +120,7 @@ router.post("/rc/projet/:numParcours", async (req, res) => {
|
|||
}
|
||||
|
||||
// Cas date du jour d'édition
|
||||
let dateNow;
|
||||
|
||||
dateNow = moment().format("DD MMMM YYYY");
|
||||
let dateNow = moment().format("DD MMMM YYYY");
|
||||
|
||||
// Cas une ou plusieurs zone(s) spécifique(s) + cas zone456
|
||||
if (hasMondeEntier == false && (rc.actVoiturier || rc.actLoueur || rc.actDouane || rc.actDemPar || rc.actDemParDom || rc.actDemParAct || rc.actDemEntr || rc.actDemInterne || rc.actGardeMeuble || rc.actEntDep || rc.actPrestaLog || rc.actLevageur || rc.actDemParAdv)) {
|
||||
|
|
@ -115,6 +154,7 @@ router.post("/rc/projet/:numParcours", async (req, res) => {
|
|||
}
|
||||
}
|
||||
|
||||
let hasMondeEntierOrMultimodal, hasNotMondeEntierOrMultimodal;
|
||||
if (rc.actMultimodal || hasMondeEntier) {
|
||||
hasMondeEntierOrMultimodal = true;
|
||||
hasNotMondeEntierOrMultimodal = false;
|
||||
|
|
@ -130,10 +170,10 @@ router.post("/rc/projet/:numParcours", async (req, res) => {
|
|||
extRCC = true;
|
||||
}
|
||||
|
||||
// Conditions Extensions RCC
|
||||
// Conditions Extensions RCE
|
||||
let extRCE = false;
|
||||
|
||||
if ( rc.extRCEMontageDemontage == true || rc.extRCEBraDebra == true) {
|
||||
if (rc.extRCEMontageDemontage == true || rc.extRCEBraDebra == true) {
|
||||
extRCE = true;
|
||||
}
|
||||
|
||||
|
|
@ -158,7 +198,6 @@ router.post("/rc/projet/:numParcours", async (req, res) => {
|
|||
// Variables numériques
|
||||
const franchiseTarif = "250";
|
||||
|
||||
try {
|
||||
doc.render({
|
||||
// Client
|
||||
nomClient: client.nom,
|
||||
|
|
@ -303,18 +342,6 @@ router.post("/rc/projet/:numParcours", async (req, res) => {
|
|||
fraisRepFraction: globalService.customFormatNumber(rc.cotFraisTTC, true),
|
||||
ca: globalService.customFormatNumber(rc.ca, true),
|
||||
});
|
||||
} catch (error) {
|
||||
const e = {
|
||||
message: error.message,
|
||||
name: error.name,
|
||||
stack: error.stack,
|
||||
properties: error.properties,
|
||||
};
|
||||
logger.log('error', JSON.stringify({ error: e }));
|
||||
|
||||
// Envoyez une réponse d'erreur si le rendu échoue
|
||||
return res.status(500).send("Erreur lors de la génération du document");
|
||||
}
|
||||
|
||||
const buf = doc.getZip().generate({ type: "nodebuffer" });
|
||||
|
||||
|
|
@ -348,6 +375,277 @@ router.post("/rc/projet/:numParcours", async (req, res) => {
|
|||
|
||||
// Envoie le buffer au client, déclenchant le téléchargement
|
||||
res.send(buf);
|
||||
} catch (error) {
|
||||
logger.log('error', 'Error in RC projet generation:', error);
|
||||
return res.status(500).send("Erreur lors de la génération du projet RC");
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/rc/tarif/:numParcours", async (req, res) => {
|
||||
try {
|
||||
const content = fs.readFileSync(
|
||||
path.resolve("src/templates/template-declinaison-tarifaire-rc.docx"),
|
||||
"binary"
|
||||
);
|
||||
|
||||
const zip = new PizZip(content);
|
||||
const doc = new Docxtemplater(zip, { paragraphLoop: true, linebreaks: true });
|
||||
|
||||
const numParcours = req.params.numParcours.toUpperCase();
|
||||
const parcours = await parcoursService.getParcoursByNumParcours(numParcours);
|
||||
const contrat = await contratService.getContratById(parcours.contrat);
|
||||
const client = contrat?.["@expand"]?.client || {};
|
||||
const user = await userService.getUserById(parcours.dernierUtilisateur);
|
||||
|
||||
// Récupérer la collection rc avec ses relations (APRÈS placerDansEnCours, c'est dans enCours)
|
||||
const rcFull = contrat?.["@expand"]?.enCours;
|
||||
if (!rcFull) {
|
||||
logger.log('error', 'No RC found for contrat:', contrat.id);
|
||||
return res.status(404).send("Aucune donnée RC trouvée pour ce contrat");
|
||||
}
|
||||
|
||||
// Les données sont déjà expandées par contratService
|
||||
const rc = rcFull?.["@expand"]?.tarifRC || {};
|
||||
const rcMain = rcFull || {};
|
||||
|
||||
// Formatage des taux avec maximum 2 décimales
|
||||
function formatTaux(taux) {
|
||||
if (!taux) return 0;
|
||||
return parseFloat(taux).toFixed(2);
|
||||
}
|
||||
|
||||
// Préparer les données des activités avec leurs marchandises et activités complémentaires
|
||||
const activites = [];
|
||||
|
||||
// Voiturier/Loueur
|
||||
if (rcMain.checkVoiturier || rcMain.checkLoueur) {
|
||||
activites.push({
|
||||
type: 'Voiturier/Loueur',
|
||||
capital: rcMain.capitalVoiturier || 0,
|
||||
pourcentage: rc.pourcentageVoiturier || 0,
|
||||
marchandises: rcMain.marchandisesVoiturier || [],
|
||||
activitesCompl: rcMain.activitesVoiturier || []
|
||||
});
|
||||
}
|
||||
|
||||
// Commissionnaire de Transport
|
||||
if (rcMain.checkCommissionnaire) {
|
||||
activites.push({
|
||||
type: 'Commissionnaire de Transport',
|
||||
capital: rcMain.capitalCommissionnaire || 0,
|
||||
pourcentage: rc.pourcentageCommissionnaire || 0,
|
||||
marchandises: rcMain.marchandisesCommissionnaire || [],
|
||||
activitesCompl: rcMain.activitesCommissionnaire || []
|
||||
});
|
||||
}
|
||||
|
||||
// Déménageur
|
||||
if (rcMain.checkDemenageur) {
|
||||
activites.push({
|
||||
type: 'Déménageur',
|
||||
capital: rcMain.capitalDemenageur || 0,
|
||||
pourcentage: rc.pourcentageDemenageur || 0,
|
||||
marchandises: rcMain.marchandisesDemenageur || [],
|
||||
activitesCompl: rcMain.activitesDemenageur || []
|
||||
});
|
||||
}
|
||||
|
||||
// Logistique
|
||||
if (rcMain.checkLogistique) {
|
||||
activites.push({
|
||||
type: 'Logistique',
|
||||
capital: rcMain.capitalLogistique || 0,
|
||||
pourcentage: rc.pourcentageLogistique || 0,
|
||||
marchandises: rcMain.marchandisesLogistique || [],
|
||||
activitesCompl: rcMain.activitesLogistique || []
|
||||
});
|
||||
}
|
||||
|
||||
// Autocariste
|
||||
if (rcMain.checkAutocariste) {
|
||||
activites.push({
|
||||
type: 'Autocariste',
|
||||
capital: rcMain.capitalAutocariste || 0,
|
||||
pourcentage: rc.pourcentageAutocariste || 0,
|
||||
marchandises: rcMain.marchandisesAutocariste || [],
|
||||
activitesCompl: rcMain.activitesAutocariste || []
|
||||
});
|
||||
}
|
||||
|
||||
// Autres activités
|
||||
if (rcMain.checkAutres) {
|
||||
activites.push({
|
||||
type: 'Autres activités',
|
||||
capital: rcMain.capitalAutres || 0,
|
||||
pourcentage: rc.pourcentageAutres || 0,
|
||||
marchandises: rcMain.marchandisesAutres || [],
|
||||
activitesCompl: rcMain.activitesAutres || []
|
||||
});
|
||||
}
|
||||
|
||||
// Préparer les zones
|
||||
const zones = [];
|
||||
if (rcMain.zone1) zones.push("Zone 1");
|
||||
if (rcMain.zone2) zones.push("Zone 2");
|
||||
if (rcMain.zone3) zones.push("Zone 3");
|
||||
if (rcMain.zone4) zones.push("Zone 4");
|
||||
if (rcMain.zone5) zones.push("Zone 5");
|
||||
if (rcMain.zone6) zones.push("Zone 6");
|
||||
|
||||
// Préparer les garanties additionnelles
|
||||
const garantiesAdditionnelles = [];
|
||||
if (rc.checkStationLavage) garantiesAdditionnelles.push("Station de lavage");
|
||||
if (rc.checkGarageInterne) garantiesAdditionnelles.push("Garage interne");
|
||||
if (rc.checkCSE) garantiesAdditionnelles.push("CSE");
|
||||
if (rc.checkTPPC) garantiesAdditionnelles.push(`TPPC (Capital: ${rc.capitalTPPC || 0}€, Véhicules: ${rc.vehiculesTPPC || 0})`);
|
||||
if (rc.checkPJ) garantiesAdditionnelles.push("Protection Juridique");
|
||||
|
||||
// Préparer les engagements complémentaires
|
||||
const engagements = [];
|
||||
if (rc.checkDomImmat) engagements.push(`Dommages immatériels (Capital: ${rc.capitalDomImmat || 0}€)`);
|
||||
if (rc.checkContConf) engagements.push(`Contenu confié (Capital: ${rc.capitalContConf || 0}€)`);
|
||||
if (rc.checkDiffInv) engagements.push(`Différence d'inventaire (Capital: ${rc.capitalDiffInv || 0}€)`);
|
||||
|
||||
let dateNow = moment().format("DD MMMM YYYY");
|
||||
|
||||
doc.render({
|
||||
// Infos générales
|
||||
matricule: user.matricule,
|
||||
date: dateNow,
|
||||
typeCotisation: rcMain.typeCotisation || "Non défini",
|
||||
hasforfaitaire: !(rcMain.typeCotisation === "forfaitaire" || (!rcMain.chiffreAffaires || rcMain.chiffreAffaires === 0)),
|
||||
hasRCE: rcMain.checkRCE || false,
|
||||
hasContrat: !!contrat.numContrat,
|
||||
numContrat: contrat.numContrat,
|
||||
hasSaisine: !!contrat.numSaisine,
|
||||
numSaisine: contrat.numSaisine,
|
||||
numeroCS: contrat.numSaisine || contrat.numContrat,
|
||||
nomAssure: client.nom,
|
||||
ca: rcMain.chiffreAffaires || 0,
|
||||
hasNbVehicule: (rcMain.nombreVehicules || 0) > 0,
|
||||
nbVehicule: rcMain.nombreVehicules || 0,
|
||||
|
||||
// Activités principales
|
||||
hasVoiturierLoueur: rcMain.checkVoiturier || rcMain.checkLoueur,
|
||||
capitalAssureVoiturierLoueur: rcMain.capitalVoiturier || 0,
|
||||
pourcentageVoiturierLoueur: rc.pourcentageVoiturier || 0,
|
||||
marchandiseVoiturierLoueur: rcMain.marchandisesVoiturier || [],
|
||||
activiteVoiturierLoueur: rcMain.actComplVoiturier || [],
|
||||
|
||||
hasComTransport: rcMain.checkCommissionnaire || false,
|
||||
capitalAssureComTransport: rcMain.capitalCommissionnaire || 0,
|
||||
pourcentageComTransport: rc.pourcentageCommissionnaire || 0,
|
||||
marchandiseComTransport: rcMain.marchandisesCommissionnaire || [],
|
||||
activiteComTransport: rcMain.actComplCommissionnaire || [],
|
||||
|
||||
hasDemenageur: rcMain.checkDemenageur || false,
|
||||
capitalAssureDemenageur: rcMain.capitalDemenageur || 0,
|
||||
pourcentageDemenageur: rc.pourcentageDemenageur || 0,
|
||||
marchandiseDemenageur: rcMain.marchandisesDemenageur || [],
|
||||
activiteDemenageur: rcMain.actComplDemenageur || [],
|
||||
|
||||
hasLogistique: rcMain.checkLogistique || false,
|
||||
capitalAssureLogistique: rcMain.capitalLogistique || 0,
|
||||
pourcentageLogistique: rc.pourcentageLogistique || 0,
|
||||
marchandiseLogistique: rcMain.marchandisesLogistique || [],
|
||||
activiteLogistique: rcMain.actComplLogistique || [],
|
||||
|
||||
hasAutocariste: rcMain.checkAutocariste || false,
|
||||
capitalAssureAutocariste: rcMain.capitalAutocariste || 0,
|
||||
pourcentageAutocariste: rc.pourcentageAutocariste || 0,
|
||||
marchandiseAutocariste: rcMain.marchandisesAutocariste || [],
|
||||
activiteAutocariste: rcMain.activitesAutocariste || [],
|
||||
|
||||
hasAutre: rcMain.checkAutres || false,
|
||||
capitalAssureAutre: rcMain.capitalAutres || 0,
|
||||
pourcentageAutre: rc.pourcentageAutres || 0,
|
||||
marchandiseAutre: rcMain.marchandisesAutres || [],
|
||||
//activiteAutre: rcMain.activitesAutres || [], existe pas dans ejs
|
||||
|
||||
// Zones géographiques
|
||||
zones: zones,
|
||||
|
||||
// Garanties additionnelles
|
||||
hasGarantieAdd: garantiesAdditionnelles.length > 0,
|
||||
garantieAdd: garantiesAdditionnelles,
|
||||
|
||||
// Engagements complémentaires
|
||||
hasEngagement: engagements.length > 0,
|
||||
engagement: engagements,
|
||||
|
||||
// Tarifs sélectionnés
|
||||
franchise: rc.franchiseChoisie || rc.franchiseSelectionnee,
|
||||
tarifReference: getSelectedTarifReference(rc),
|
||||
tarifCommercial: rc.tarifcommercial,
|
||||
primeRCC: getSelectedPrime(rc, 'RCC'),
|
||||
tauxRCC: formatTaux(getSelectedTaux(rc, 'RCC')),
|
||||
hasRCE: rcMain.checkRCE,
|
||||
primeRCE: getSelectedPrime(rc, 'RCE'),
|
||||
tauxRCE: formatTaux(getSelectedTaux(rc, 'RCE')),
|
||||
hasPrimePJ: rc.checkPJ && getSelectedPrime(rc, 'PJ') > 0,
|
||||
primePJ: getSelectedPrime(rc, 'PJ'),
|
||||
tauxGlobal: formatTaux(getSelectedTaux(rc, 'Global')),
|
||||
|
||||
|
||||
// Propositions franchise 250
|
||||
tarifRefP1: rc.primeTotal_250 || 0,
|
||||
pRCCP1: rc.primeRCC_250 || 0,
|
||||
tRCCP1: formatTaux(rc.tauxRCC_250),
|
||||
pRCEP1: rc.primeRCE_250 || 0,
|
||||
tRCEP1: formatTaux(rc.tauxRCE_250),
|
||||
primePJP1: rc.primePJ_250 || 0,
|
||||
tauxGlobalP1: formatTaux(rc.tauxGlobal_250),
|
||||
|
||||
// Propositions franchise 400
|
||||
tarifRefP2: rc.primeTotal_400 || 0,
|
||||
pRCCP2: rc.primeRCC_400 || 0,
|
||||
tRCCP2: formatTaux(rc.tauxRCC_400),
|
||||
pRCEP2: rc.primeRCE_400 || 0,
|
||||
tRCEP2: formatTaux(rc.tauxRCE_400),
|
||||
primePJP2: rc.primePJ_400 || 0,
|
||||
tauxGlobalP2: formatTaux(rc.tauxGlobal_400),
|
||||
|
||||
// Propositions franchise 2000
|
||||
tarifRefP3: rc.primeTotal_2000 || 0,
|
||||
pRCCP3: rc.primeRCC_2000 || 0,
|
||||
tRCCP3: formatTaux(rc.tauxRCC_2000),
|
||||
pRCEP3: rc.primeRCE_2000 || 0,
|
||||
tRCEP3: formatTaux(rc.tauxRCE_2000),
|
||||
primePJP3: rc.primePJ_2000 || 0,
|
||||
tauxGlobalP3: formatTaux(rc.tauxGlobal_2000),
|
||||
});
|
||||
|
||||
const buf = doc.getZip().generate({ type: "nodebuffer" });
|
||||
|
||||
const currentDate = new Date();
|
||||
|
||||
// Formatage de la date au format "JJ-MM-AAAA-HH-MM-SS"
|
||||
const day = String(currentDate.getDate()).padStart(2, "0");
|
||||
const month = String(currentDate.getMonth() + 1).padStart(2, "0");
|
||||
const year = currentDate.getFullYear();
|
||||
const hours = String(currentDate.getHours()).padStart(2, "0");
|
||||
const minutes = String(currentDate.getMinutes()).padStart(2, "0");
|
||||
const seconds = String(currentDate.getSeconds()).padStart(2, "0");
|
||||
const formattedDate = `${day}-${month}-${year}-${hours}-${minutes}-${seconds}`;
|
||||
|
||||
const sanitizedClientNom = client.nom
|
||||
.replace(/[^\w\s.-]/gi, "")
|
||||
.replace(/\s+/g, "-");
|
||||
|
||||
const filename = `Tarif-RC-${parcours.numParcours}-${sanitizedClientNom}-${formattedDate}`;
|
||||
|
||||
res.setHeader(
|
||||
"Content-Type",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
||||
);
|
||||
res.setHeader("Content-Disposition", "attachment; filename=" + filename + ".docx");
|
||||
res.send(buf);
|
||||
} catch (error) {
|
||||
logger.log("error", 'Error in RC tarif generation:', error);
|
||||
return res.status(500).send("Erreur lors de la génération du tarif RC");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
module.exports = router;
|
||||
|
|
@ -22,7 +22,7 @@ router.get('/contrat', async (req, res) => {
|
|||
});
|
||||
|
||||
router.get('/tarifrc', async (req, res) => {
|
||||
renderPage('dev.ejs', res, {}, true);
|
||||
renderPage('tarifformrc.ejs', res, {}, true);
|
||||
});
|
||||
|
||||
router.get('/tariffac', async (req, res) => {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,152 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const rcService = require('../services/rcService');
|
||||
const constantesJSON = require("../constantes/json-modulateur-rc");
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
// ===== Routes RC principale =====
|
||||
router.post('/create', async (req, res) => {
|
||||
try {
|
||||
const data = req.body;
|
||||
const rc = await rcService.createRc(data);
|
||||
|
||||
res.json({ valid: Boolean(rc), rc });
|
||||
} catch (error) {
|
||||
logger.log("error", "Error creating RC:", error);
|
||||
res.status(500).json({ valid: false, error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:id', async (req, res) => {
|
||||
try {
|
||||
const rc = await rcService.getRcById(req.params.id);
|
||||
res.json({ valid: Boolean(rc), rc });
|
||||
} catch (error) {
|
||||
logger.log("error", "Error getting RC:", error);
|
||||
res.status(500).json({ valid: false, error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/update/:id', async (req, res) => {
|
||||
try {
|
||||
const rc = await rcService.updateRc(req.params.id, req.body);
|
||||
res.json({ valid: Boolean(rc), rc });
|
||||
} catch (error) {
|
||||
logger.log("error", "Error updating RC:", error);
|
||||
res.status(500).json({ valid: false, error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
// ===== Routes TarifRC =====
|
||||
router.post('/tarif/create', async (req, res) => {
|
||||
try {
|
||||
const data = req.body;
|
||||
const tarifRc = await rcService.createTarifRc(data);
|
||||
res.json({ valid: Boolean(tarifRc), tarifRc });
|
||||
} catch (error) {
|
||||
logger.log("error", "Error creating TarifRC:", error);
|
||||
res.status(500).json({ valid: false, error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/tarif/:id', async (req, res) => {
|
||||
try {
|
||||
const tarifRc = await rcService.getTarifRcById(req.params.id);
|
||||
res.json({ valid: Boolean(tarifRc), tarifRc });
|
||||
} catch (error) {
|
||||
logger.log("error", "Error getting TarifRC:", error);
|
||||
res.status(500).json({ valid: false, error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/tarif/update/:id', async (req, res) => {
|
||||
try {
|
||||
const tarifRc = await rcService.updateTarifRc(req.params.id, req.body);
|
||||
res.json({ valid: Boolean(tarifRc), tarifRc });
|
||||
} catch (error) {
|
||||
logger.log("error", "Error updating TarifRC:", error);
|
||||
res.status(500).json({ valid: false, error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
// ===== Routes ProjetRC =====
|
||||
router.post('/projet/create', async (req, res) => {
|
||||
try {
|
||||
const data = req.body;
|
||||
const projetRc = await rcService.createProjetRc(data);
|
||||
res.json({ valid: Boolean(projetRc), projetRc });
|
||||
} catch (error) {
|
||||
logger.log("error", "Error creating ProjetRC:", error);
|
||||
res.status(500).json({ valid: false, error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/projet/:id', async (req, res) => {
|
||||
try {
|
||||
const projetRc = await rcService.getProjetRcById(req.params.id);
|
||||
res.json({ valid: Boolean(projetRc), projetRc });
|
||||
} catch (error) {
|
||||
logger.log("error", "Error getting ProjetRC:", error);
|
||||
res.status(500).json({ valid: false, error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/projet/update/:id', async (req, res) => {
|
||||
try {
|
||||
const projetRc = await rcService.updateProjetRc(req.params.id, req.body);
|
||||
res.json({ valid: Boolean(projetRc), projetRc });
|
||||
} catch (error) {
|
||||
logger.log("error", "Error updating ProjetRC:", error);
|
||||
res.status(500).json({ valid: false, error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
// ===== Routes Modulateurs =====
|
||||
router.get("/modulo/:objDemande", async (req, res) => {
|
||||
const objDemande = req.params.objDemande;
|
||||
var objRetourne
|
||||
|
||||
switch (objDemande) {
|
||||
case "CARC":
|
||||
objRetourne = constantesJSON.modRCCA;
|
||||
break;
|
||||
case "activiteRCC":
|
||||
objRetourne = constantesJSON.modRCActRCC;
|
||||
break;
|
||||
case "activiteRCE":
|
||||
objRetourne = constantesJSON.modRCActRCE;
|
||||
break;
|
||||
case "activiteComplRC":
|
||||
objRetourne = constantesJSON.modRCActCompl;
|
||||
break;
|
||||
case "marchandiseRC":
|
||||
objRetourne = constantesJSON.modRCMar;
|
||||
break;
|
||||
case "zoneRC":
|
||||
objRetourne = constantesJSON.modRCZone;
|
||||
break;
|
||||
case "engagComplRC":
|
||||
objRetourne = constantesJSON.modRCEngagCompl;
|
||||
break;
|
||||
case "garAdditionelRC":
|
||||
objRetourne = constantesJSON.modRCGarAdd ;
|
||||
break;
|
||||
case "sinistreRC":
|
||||
objRetourne = constantesJSON.modRCSinistre;
|
||||
break;
|
||||
case "franchiseRC":
|
||||
objRetourne = constantesJSON.modRCFranchise;
|
||||
break;
|
||||
case "primeMiniRC":
|
||||
objRetourne = constantesJSON.modRCPrimeMini;
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
res.json({valid: Boolean(objRetourne), objRetourne});
|
||||
} catch (error) {
|
||||
logger.log("error", `Error finding constant ${objDemande}:`, error);
|
||||
res.status(500).json({valid: false, error: "Internal Server Error"});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -45,12 +45,31 @@ async function createContrat() {
|
|||
|
||||
async function expandProjetTarif(resultat) {
|
||||
const produit = resultat?.['produit'].toLowerCase()
|
||||
const idProjet = resultat?.['@expand']?.[produit]?.['projet'] || undefined
|
||||
const idTarif = resultat?.['@expand']?.[produit]?.['tarif'] || undefined
|
||||
|
||||
// RC utilise tarifRC/projetRC, les autres produits utilisent tarif/projet
|
||||
let idProjet, idTarif, collectionProjet, collectionTarif;
|
||||
if (produit === 'rc') {
|
||||
idProjet = resultat?.['@expand']?.[produit]?.['projetRC'] || undefined
|
||||
idTarif = resultat?.['@expand']?.[produit]?.['tarifRC'] || undefined
|
||||
collectionProjet = 'projetRC'; // Nom de collection RC
|
||||
collectionTarif = 'tarifRC'; // Nom de collection RC
|
||||
} else {
|
||||
idProjet = resultat?.['@expand']?.[produit]?.['projet'] || undefined
|
||||
idTarif = resultat?.['@expand']?.[produit]?.['tarif'] || undefined
|
||||
collectionProjet = produit + "projet"; // tppcprojet, facprojet
|
||||
collectionTarif = produit + "tarif"; // tppctarif, factarif (n'existe pas mais bon)
|
||||
}
|
||||
|
||||
// Pour RC, inclure à la fois les clés RC spécifiques (tarifRC/projetRC) et les clés génériques (tarif/projet)
|
||||
// afin de rester compatible avec l'ancien front qui lisait `tarif`/`projet`.
|
||||
const expand = {
|
||||
projet: (idProjet) ? await db.records.getOne(produit + "projet", idProjet) : null,
|
||||
tarif: (idTarif) ? await db.records.getOne(produit + "tarif", idTarif) : null
|
||||
projet: idProjet ? await db.records.getOne(collectionProjet, idProjet) : null,
|
||||
tarif: idTarif ? await db.records.getOne(collectionTarif, idTarif) : null,
|
||||
};
|
||||
|
||||
if (produit === 'rc') {
|
||||
expand.projetRC = expand.projet;
|
||||
expand.tarifRC = expand.tarif;
|
||||
}
|
||||
|
||||
resultat['@expand'][produit] = {...resultat['@expand'][produit], '@expand': expand}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,55 @@
|
|||
const { db } = require('../db/db-connect');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
// ===== Collection RC principale =====
|
||||
async function createRc(data) {
|
||||
return await db.records.create('rc', data);
|
||||
}
|
||||
|
||||
async function getRcById(id) {
|
||||
return await db.records.getOne('rc', id, {
|
||||
expand: 'tarifRC,projetRC'
|
||||
});
|
||||
}
|
||||
|
||||
async function updateRc(id, data) {
|
||||
return await db.records.update('rc', id, data);
|
||||
}
|
||||
|
||||
// ===== Collection TarifRC =====
|
||||
async function createTarifRc(data) {
|
||||
return await db.records.create('tarifRC', data);
|
||||
}
|
||||
|
||||
async function getTarifRcById(id) {
|
||||
return await db.records.getOne('tarifRC', id);
|
||||
}
|
||||
|
||||
async function updateTarifRc(id, data) {
|
||||
return await db.records.update('tarifRC', id, data);
|
||||
}
|
||||
|
||||
// ===== Collection ProjetRC =====
|
||||
async function createProjetRc(data) {
|
||||
return await db.records.create('projetRC', data);
|
||||
}
|
||||
|
||||
async function getProjetRcById(id) {
|
||||
return await db.records.getOne('projetRC', id);
|
||||
}
|
||||
|
||||
async function updateProjetRc(id, data) {
|
||||
return await db.records.update('projetRC', id, data);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createRc
|
||||
createRc,
|
||||
getRcById,
|
||||
updateRc,
|
||||
createTarifRc,
|
||||
getTarifRcById,
|
||||
updateTarifRc,
|
||||
createProjetRc,
|
||||
getProjetRcById,
|
||||
updateProjetRc
|
||||
};
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -63,6 +63,12 @@
|
|||
<script src="/js/loader.js"></script>
|
||||
<!-- Script pour la navigation AJAX -->
|
||||
<script src="/js/navigation.js"></script>
|
||||
<!-- Utilitaires de synchronisation RC -->
|
||||
<script src="/js/rc-sync-utils.js"></script>
|
||||
<!-- Gestionnaire de données RC -->
|
||||
<script src="/js/rc-data-manager.js"></script>
|
||||
<!-- Orchestrateur de synchronisation RC -->
|
||||
<script src="/js/rc-orchestrator.js"></script>
|
||||
|
||||
</main>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -931,7 +931,9 @@
|
|||
<input type="text" name="cotRCEHT" id="cotRCEHT" placeholder="00.00" />
|
||||
<span id="cotRCEHT-error" class="helper-text red-text"></span>
|
||||
</td>
|
||||
<td><input type="text" name="cotRCETaux" id="cotRCETaux" value="9" disabled /></td>
|
||||
<td>
|
||||
<input type="text" name="cotRCETaux" id="cotRCETaux" value="9" disabled />
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="cotRCETTC" id="cotRCETTC" placeholder="00.00" />
|
||||
<span id="cotRCETTC-error" class="helper-text red-text"></span>
|
||||
|
|
@ -943,7 +945,9 @@
|
|||
<input type="text" name="cotPJHT" id="cotPJHT" placeholder="100.00" />
|
||||
<span id="cotPJHT-error" class="helper-text red-text"></span>
|
||||
</td>
|
||||
<td><input type="text" name="cotPJTaux" id="cotPJTaux" value="13.4" disabled /></td>
|
||||
<td>
|
||||
<input type="text" name="cotPJTaux" id="cotPJTaux" value="13.4" disabled />
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="cotPJTTC" id="cotPJTTC" placeholder="113.40" />
|
||||
<span id="cotPJTTC-error" class="helper-text red-text"></span>
|
||||
|
|
@ -1181,3 +1185,26 @@
|
|||
<a class="modal-close waves-effect waves-green btn-flat">Fermer</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL modification & liaison tarif -->
|
||||
<div id="modalModif" class="modal modalAlert">
|
||||
<div class="modal-content">
|
||||
<h4>Attention</h4>
|
||||
<p>
|
||||
Si vous modifiez cette information, la prime calculée à l'étape "Tarif" sera incorrecte, ce qui entraînera
|
||||
la suppression du tarif de référence associé à ce contrat.
|
||||
</p>
|
||||
|
||||
<p>Cela s'applique aux informations suivantes :</p>
|
||||
<ul class="modalRed">
|
||||
<li>Activité assurée</li>
|
||||
<li>Garanties</li>
|
||||
<li>Extensions de Garanties impactant le tarif</li>
|
||||
<li>Type de Cotisation (avec un type de contrat en cotisation forfaitaire) </li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a id="modif-OK" class="modal-close waves-effect btn-flat red darken-1">Modifier dans Tarif</a>
|
||||
<a id="modif-NO" class="modal-close waves-effect btn-flat indigo darken-4">Annuler</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue