chore(rc): push complet sync tarif/projet et donnees locales
This commit is contained in:
parent
cc7d3d9e08
commit
bb695a820e
|
|
@ -115,23 +115,26 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
const script = document.createElement('script');
|
||||
script.src = scriptSrc
|
||||
script.className = 'dynamic-script';
|
||||
document.body.appendChild(script);
|
||||
|
||||
script.onload = async function() {
|
||||
if (submenu === "tarif" || submenu == "projet") {
|
||||
//RELOAD PARCOURS & CONTRAT
|
||||
loadParcours(numParcours);
|
||||
const parcours = JSON.parse(sessionStorage.getItem('parcours'));
|
||||
if (parcours) {
|
||||
const contratId = parcours?.["@expand"]?.contrat?.id || null;
|
||||
loadContrat(contratId);
|
||||
try {
|
||||
// Recharger les donnees avant d'initialiser le script du formulaire.
|
||||
await loadParcours(numParcours);
|
||||
const latestParcours = JSON.parse(sessionStorage.getItem('parcours'));
|
||||
const contratId = latestParcours?.["@expand"]?.contrat?.id || null;
|
||||
if (contratId) {
|
||||
await loadContrat(contratId);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erreur lors du rafraichissement parcours/contrat:', error);
|
||||
}
|
||||
}
|
||||
|
||||
script.onload = function() {
|
||||
if (typeof window.initSubmenuForm === 'function') {
|
||||
window.initSubmenuForm();
|
||||
}
|
||||
};
|
||||
document.body.appendChild(script);
|
||||
|
||||
document.querySelectorAll('input').forEach((input) => {
|
||||
input.addEventListener('input', function () {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,15 +1,5 @@
|
|||
/**
|
||||
* ═══════════════════════════════════════════════════════════════════════════
|
||||
* 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
|
||||
* Utilitaires de synchro RC (collecte + pré-remplissage Tarif/Projet).
|
||||
*/
|
||||
|
||||
(function(window) {
|
||||
|
|
@ -22,10 +12,8 @@
|
|||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Mapping complet des champs entre Tarif et Projet.
|
||||
* Permet la synchronisation bidirectionnelle.
|
||||
*
|
||||
* Structure: { tarifFieldId: projetFieldId }
|
||||
* Mapping des champs Tarif <-> Projet.
|
||||
* Format: { idTarif: idProjet }.
|
||||
*/
|
||||
const FIELD_MAPPING = {
|
||||
// Informations générales
|
||||
|
|
@ -87,14 +75,7 @@
|
|||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* 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);
|
||||
* Lit l'ensemble des champs utiles depuis le formulaire tarif.
|
||||
*/
|
||||
function collectAllTarifData() {
|
||||
// Références flexibles aux éléments
|
||||
|
|
@ -211,7 +192,8 @@
|
|||
// ═══ SINISTRALITÉ ═══
|
||||
sinistralite: {
|
||||
nombre3ans: toNumber(getValue('sinistre')),
|
||||
montant3ans: 0 // TODO: ajouter si champ existe
|
||||
// Pas de champ montant dans le formulaire actuel.
|
||||
montant3ans: 0
|
||||
},
|
||||
|
||||
// ═══ RÉSULTATS DE CALCUL ═══
|
||||
|
|
@ -254,16 +236,12 @@
|
|||
commentaire: getValue('commentaire') || ''
|
||||
};
|
||||
|
||||
console.log('📊 Données Tarif collectées:', data);
|
||||
console.log('Donnees tarif collectees:', 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
|
||||
* Récupère les activités complémentaires cochées pour un type d'activité.
|
||||
*/
|
||||
function collectActivitesComplJSON(typeActivite) {
|
||||
let name;
|
||||
|
|
@ -354,7 +332,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
console.log('📝 Pré-remplissage Projet depuis Tarif...');
|
||||
console.log('Pre-remplissage Projet depuis Tarif...');
|
||||
|
||||
try {
|
||||
// ═══ INFORMATIONS GÉNÉRALES ═══
|
||||
|
|
@ -362,7 +340,7 @@
|
|||
// CA
|
||||
if (tarifData.ca) {
|
||||
setValue('CA', tarifData.ca);
|
||||
console.log(' ✓ CA:', tarifData.ca);
|
||||
console.log(' CA:', tarifData.ca);
|
||||
}
|
||||
|
||||
// Type de cotisation
|
||||
|
|
@ -370,14 +348,14 @@
|
|||
const radio = document.querySelector(`input[name="typeCot"][value="${tarifData.typeCotisation}"]`);
|
||||
if (radio) {
|
||||
radio.checked = true;
|
||||
console.log(' ✓ Type cotisation:', tarifData.typeCotisation);
|
||||
console.log(' Type cotisation:', tarifData.typeCotisation);
|
||||
}
|
||||
}
|
||||
|
||||
// Nombre de véhicules
|
||||
if (tarifData.nombreVehicules) {
|
||||
setValue('nombreVehicules', tarifData.nombreVehicules);
|
||||
console.log(' ✓ Véhicules:', tarifData.nombreVehicules);
|
||||
console.log(' Vehicules:', tarifData.nombreVehicules);
|
||||
}
|
||||
|
||||
// ═══ ACTIVITÉS ═══
|
||||
|
|
@ -416,7 +394,7 @@
|
|||
const event = new Event('change', { bubbles: true });
|
||||
activitySelector.dispatchEvent(event);
|
||||
|
||||
console.log(' ✓ Activités:', activitesToAdd.length);
|
||||
console.log(' Activites:', activitesToAdd.length);
|
||||
}
|
||||
|
||||
// ═══ MARCHANDISES ═══
|
||||
|
|
@ -443,7 +421,7 @@
|
|||
const event = new Event('change', { bubbles: true });
|
||||
marchandiseSelector.dispatchEvent(event);
|
||||
|
||||
console.log(' ✓ Marchandises:', marchandisesToSelect.length);
|
||||
console.log(' Marchandises:', marchandisesToSelect.length);
|
||||
}
|
||||
|
||||
// ═══ ZONES GÉOGRAPHIQUES ═══
|
||||
|
|
@ -457,7 +435,7 @@
|
|||
zonesCount++;
|
||||
}
|
||||
});
|
||||
console.log(' ✓ Zones:', zonesCount);
|
||||
console.log(' Zones:', zonesCount);
|
||||
}
|
||||
|
||||
// ═══ PROTECTION JURIDIQUE ═══
|
||||
|
|
@ -466,7 +444,7 @@
|
|||
const switchPJ = document.getElementById('switchPJ');
|
||||
if (switchPJ) {
|
||||
switchPJ.checked = true;
|
||||
console.log(' ✓ PJ activée');
|
||||
console.log(' PJ activee');
|
||||
|
||||
// Afficher la section PJ
|
||||
const pjSection = document.getElementById('pj-section');
|
||||
|
|
@ -480,7 +458,7 @@
|
|||
const choixRCE = document.getElementById('choixRCE');
|
||||
if (choixRCE) {
|
||||
choixRCE.checked = true;
|
||||
console.log(' ✓ RCE activée');
|
||||
console.log(' RCE activee');
|
||||
|
||||
// Afficher la section RCE
|
||||
const rceSection = document.getElementById('section-rce');
|
||||
|
|
@ -502,7 +480,7 @@
|
|||
setValue('vehiculesTPPC', tarifData.garantiesAdditionnelles.tppc.vehicules);
|
||||
}
|
||||
|
||||
console.log(' ✓ TPPC');
|
||||
console.log(' TPPC');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -512,11 +490,11 @@
|
|||
if (engagements) {
|
||||
if (engagements.domicileImmatriculation?.checked) {
|
||||
setValue('checkDomImmat', true);
|
||||
console.log(' ✓ Domicile immatriculation');
|
||||
console.log(' Domicile immatriculation');
|
||||
}
|
||||
if (engagements.contenantConfie?.checked) {
|
||||
setValue('checkContConf', true);
|
||||
console.log(' ✓ Contenant confié');
|
||||
console.log(' Contenant confie');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -529,7 +507,7 @@
|
|||
if (tarifData.sinistralite.montant3ans) {
|
||||
setValue('montantSinistres3ans', tarifData.sinistralite.montant3ans);
|
||||
}
|
||||
console.log(' ✓ Sinistralité');
|
||||
console.log(' Sinistralite');
|
||||
}
|
||||
|
||||
// ═══ RÉSULTATS TARIFAIRES ═══
|
||||
|
|
@ -555,7 +533,7 @@
|
|||
if (res.cotTotalHT) setValue('cotTotalHT', res.cotTotalHT);
|
||||
if (res.cotTotalTTC) setValue('cotTotalTTC', res.cotTotalTTC);
|
||||
|
||||
console.log(' ✓ Résultats tarifaires');
|
||||
console.log(' Resultats tarifaires');
|
||||
}
|
||||
|
||||
// Forcer la mise à jour des éléments Materialize
|
||||
|
|
@ -567,10 +545,10 @@
|
|||
window.M.updateTextFields();
|
||||
}
|
||||
|
||||
console.log('✅ Pré-remplissage Projet terminé');
|
||||
console.log('Pre-remplissage Projet termine');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur lors du pré-remplissage Projet:', error);
|
||||
console.error('Erreur lors du pre-remplissage Projet:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -593,7 +571,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
console.log('📝 Pré-remplissage Tarif depuis Projet...');
|
||||
console.log('Pre-remplissage Tarif depuis Projet...');
|
||||
|
||||
try {
|
||||
// CA
|
||||
|
|
@ -624,10 +602,10 @@
|
|||
setValue('checkRCE', true);
|
||||
}
|
||||
|
||||
console.log('✅ Pré-remplissage Tarif terminé');
|
||||
console.log('Pre-remplissage Tarif termine');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur lors du pré-remplissage Tarif:', error);
|
||||
console.error('Erreur lors du pre-remplissage Tarif:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -642,6 +620,6 @@
|
|||
FIELD_MAPPING
|
||||
};
|
||||
|
||||
console.log('✅ RC Data Manager loaded');
|
||||
console.log('RC Data Manager loaded');
|
||||
|
||||
})(window);
|
||||
|
|
|
|||
|
|
@ -1,16 +1,5 @@
|
|||
/**
|
||||
* ═══════════════════════════════════════════════════════════════════════════
|
||||
* 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
|
||||
* Orchestrateur de synchro RC entre les écrans Tarif et Projet.
|
||||
*/
|
||||
|
||||
(function(window) {
|
||||
|
|
@ -18,12 +7,12 @@
|
|||
|
||||
// Attendre que les dépendances soient chargées
|
||||
if (!window.RCSync || !window.RCDataManager) {
|
||||
console.error('❌ Dépendances RC Sync manquantes');
|
||||
console.error('Dependances RC Sync manquantes');
|
||||
return;
|
||||
}
|
||||
|
||||
const { isChangeImpactingTarif, showReturnToTarifModal } = window.RCSync;
|
||||
const { collectAllTarifData, prefillProjetFromTarif, prefillTarifFromProjet } = window.RCDataManager;
|
||||
const { isFieldImpactingTarif, showReturnToTarifModal } = window.RCSync;
|
||||
const { collectAllTarifData, prefillTarifFromProjet } = window.RCDataManager;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// CONFIGURATION
|
||||
|
|
@ -40,9 +29,7 @@
|
|||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Détecte la page active (tarif ou projet) depuis l'URL.
|
||||
*
|
||||
* @returns {'tarif'|'projet'|null} Page active ou null
|
||||
* Détecte si on est sur la page tarif ou projet.
|
||||
*/
|
||||
function detectActivePage() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
|
|
@ -57,50 +44,52 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Détecte le produit courant à partir de la session.
|
||||
*
|
||||
* @returns {string|null} Code produit en minuscule
|
||||
*/
|
||||
function detectCurrentProduct() {
|
||||
try {
|
||||
const contrat = JSON.parse(sessionStorage.getItem('contrat') || 'null');
|
||||
const fromContrat = contrat?.produit;
|
||||
if (fromContrat) return String(fromContrat).toLowerCase();
|
||||
|
||||
const parcours = JSON.parse(sessionStorage.getItem('parcours') || 'null');
|
||||
const fromParcours = parcours?.["@expand"]?.contrat?.produit;
|
||||
return fromParcours ? String(fromParcours).toLowerCase() : null;
|
||||
} catch (error) {
|
||||
console.warn('Impossible de lire le produit courant:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// GESTION SESSIONSTORAGE
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Sauvegarde les données du tarif validé dans sessionStorage.
|
||||
*
|
||||
* @param {Object} tarifData - Données complètes du tarif
|
||||
* Sauvegarde le snapshot du tarif validé en sessionStorage.
|
||||
*/
|
||||
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');
|
||||
console.log('Donnees tarif sauvegardees en session');
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur sauvegarde session:', 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
|
||||
* Lit les données tarif sauvegardées en sessionStorage.
|
||||
*/
|
||||
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) {
|
||||
console.error('Erreur lecture session:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -110,13 +99,10 @@
|
|||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Hook appelé après validation tarif pour garder l'état en session.
|
||||
*/
|
||||
function onTarifValidated() {
|
||||
console.log('🎯 Hook: Tarif validé, collecte des données...');
|
||||
console.log('Hook tarif valide: collecte des donnees');
|
||||
|
||||
try {
|
||||
// Collecter toutes les données du tarif
|
||||
|
|
@ -125,9 +111,9 @@
|
|||
// Sauvegarder en session pour le pré-remplissage projet
|
||||
saveTarifDataToSession(tarifData);
|
||||
|
||||
console.log('✅ Données tarif prêtes pour le projet');
|
||||
console.log('Donnees tarif pretes pour le projet');
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur hook tarif validé:', error);
|
||||
console.error('Erreur hook tarif valide:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,12 +122,17 @@
|
|||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Initialisation côté projet.
|
||||
* Le pré-remplissage reste géré dans projet-form-rc.js.
|
||||
*/
|
||||
function initProjetPage() {
|
||||
console.log('🚀 Initialisation RC Orchestrator pour page Projet...');
|
||||
console.log('Initialisation RC Orchestrator pour la page Projet');
|
||||
|
||||
const currentProduct = detectCurrentProduct();
|
||||
if (currentProduct === 'rc') {
|
||||
console.log('Projet RC detecte: la gestion modal est deja faite dans projet-form-rc.js');
|
||||
return;
|
||||
}
|
||||
|
||||
// Les données rc/tarif/projet sont DÉJÀ chargées depuis la base
|
||||
// par le code existant dans projet-form-RC.js
|
||||
|
|
@ -153,9 +144,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Fallback générique de détection d'impact sur la page projet.
|
||||
*/
|
||||
function setupProjetChangeDetection() {
|
||||
// Les données originales sont dans les variables globales window.tarif et window.rc
|
||||
|
|
@ -164,12 +153,12 @@
|
|||
const rcOriginal = window.rc;
|
||||
|
||||
if (!tarifOriginal && !rcOriginal) {
|
||||
console.log('ℹ️ Pas de tarif/rc, pas de détection');
|
||||
console.log('Pas de tarif/rc, pas de detection');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('👁️ Configuration détection changements...');
|
||||
console.log('📋 Données originales:', { tarif: tarifOriginal, rc: rcOriginal });
|
||||
console.log('Configuration de la detection des changements');
|
||||
console.log('Donnees originales:', { tarif: tarifOriginal, rc: rcOriginal });
|
||||
|
||||
// Liste COMPLÈTE des éléments à surveiller (tous les champs impactants)
|
||||
const elementsToWatch = [
|
||||
|
|
@ -212,14 +201,14 @@
|
|||
const fieldName = this.id;
|
||||
const newValue = this.type === 'checkbox' ? this.checked : this.value;
|
||||
|
||||
console.log(`🔍 Changement détecté: ${fieldName} = ${newValue}`);
|
||||
console.log(`Changement detecte: ${fieldName} = ${newValue}`);
|
||||
|
||||
// Vérifier si c'est un champ impactant
|
||||
if (isFieldImpactingTarif(fieldName)) {
|
||||
console.warn(`⚠️ "${fieldName}" impacte le tarif !`);
|
||||
console.warn(`"${fieldName}" impacte le tarif`);
|
||||
showReturnToTarifModal(fieldName);
|
||||
} else {
|
||||
console.log(`ℹ️ "${fieldName}" n'impacte pas le tarif`);
|
||||
console.log(`"${fieldName}" n'impacte pas le tarif`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -228,8 +217,8 @@
|
|||
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 !`);
|
||||
console.log(`Changement type cotisation: ${this.value}`);
|
||||
console.warn('Type de cotisation impacte le tarif');
|
||||
showReturnToTarifModal('Type de cotisation');
|
||||
});
|
||||
});
|
||||
|
|
@ -239,8 +228,8 @@
|
|||
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 !`);
|
||||
console.log('Changement activites:', selectedValues);
|
||||
console.warn('Activites impactent le tarif');
|
||||
showReturnToTarifModal('Activités');
|
||||
});
|
||||
}
|
||||
|
|
@ -250,8 +239,8 @@
|
|||
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 !`);
|
||||
console.log('Changement marchandises:', selectedValues);
|
||||
console.warn('Marchandises impactent le tarif');
|
||||
showReturnToTarifModal('Marchandises');
|
||||
});
|
||||
}
|
||||
|
|
@ -261,13 +250,13 @@
|
|||
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 !');
|
||||
console.log(`Changement zones via ${btnId}`);
|
||||
console.warn('Zones geographiques impactent le tarif');
|
||||
showReturnToTarifModal('Zones géographiques');
|
||||
});
|
||||
});
|
||||
|
||||
console.log('✅ Détection changements configurée sur tous les champs impactants');
|
||||
console.log('Detection des changements configuree');
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
|
@ -279,7 +268,7 @@
|
|||
* Pré-remplit depuis le projet si l'utilisateur vient du projet.
|
||||
*/
|
||||
function initTarifPage() {
|
||||
console.log('🚀 Initialisation page Tarif...');
|
||||
console.log('Initialisation page Tarif');
|
||||
|
||||
// Vérifier si on vient du projet
|
||||
const projetData = JSON.parse(sessionStorage.getItem(SESSION_STORAGE_KEYS.PROJET_DATA) || 'null');
|
||||
|
|
@ -287,7 +276,7 @@
|
|||
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...');
|
||||
console.log('Pre-remplissage depuis projet');
|
||||
|
||||
setTimeout(() => {
|
||||
prefillTarifFromProjet(projetData);
|
||||
|
|
@ -314,7 +303,7 @@
|
|||
|
||||
// Remplacer par notre version wrappée
|
||||
window.saveTarifRC = async function(...args) {
|
||||
console.log('🎯 Interception saveTarifRC...');
|
||||
console.log('Interception de saveTarifRC');
|
||||
|
||||
// Appeler la fonction originale
|
||||
const result = await originalSaveTarifRC.apply(this, args);
|
||||
|
|
@ -327,7 +316,7 @@
|
|||
return result;
|
||||
};
|
||||
|
||||
console.log('✅ saveTarifRC intercepté');
|
||||
console.log('saveTarifRC intercepte');
|
||||
}
|
||||
}, 100);
|
||||
|
||||
|
|
@ -343,10 +332,10 @@
|
|||
* Initialise l'orchestrateur au chargement de la page.
|
||||
*/
|
||||
function init() {
|
||||
console.log('🎼 RC Sync Orchestrator: Démarrage...');
|
||||
console.log('RC Sync Orchestrator: demarrage');
|
||||
|
||||
const activePage = detectActivePage();
|
||||
console.log(`📄 Page active détectée: ${activePage || 'aucune'}`);
|
||||
console.log(`Page active detectee: ${activePage || 'aucune'}`);
|
||||
|
||||
if (activePage === 'tarif') {
|
||||
interceptTarifValidation();
|
||||
|
|
@ -383,6 +372,6 @@
|
|||
getTarifDataFromSession
|
||||
};
|
||||
|
||||
console.log('✅ RC Sync Orchestrator loaded');
|
||||
console.log('RC Sync Orchestrator loaded');
|
||||
|
||||
})(window);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,5 @@
|
|||
/**
|
||||
* ═══════════════════════════════════════════════════════════════════════════
|
||||
* 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
|
||||
* Fonctions utilitaires partagées entre les écrans RC Tarif et Projet.
|
||||
*/
|
||||
|
||||
(function(window) {
|
||||
|
|
@ -19,11 +10,8 @@
|
|||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* 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>}
|
||||
* Champs qui influencent le calcul du tarif.
|
||||
* On s'en sert pour savoir quand proposer un retour vers l'onglet Tarif.
|
||||
*/
|
||||
const TARIF_IMPACTING_FIELDS = [
|
||||
// Chiffre d'affaires et type de contrat
|
||||
|
|
@ -76,17 +64,8 @@
|
|||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Convertit une valeur texte/nombre en nombre JS.
|
||||
* Accepte les formats FR/EN (espaces, virgules, points).
|
||||
*/
|
||||
function toNumber(x) {
|
||||
if (x == null) return 0;
|
||||
|
|
@ -130,15 +109,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* 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");
|
||||
* Récupère un élément par id, avec fallback querySelector.
|
||||
*/
|
||||
function getElementByIdFlexible(id) {
|
||||
if (!id) return null;
|
||||
|
|
@ -152,15 +123,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Lit la valeur d'un champ de formulaire selon son type.
|
||||
*/
|
||||
function getValue(elementId) {
|
||||
const element = getElementByIdFlexible(elementId);
|
||||
|
|
@ -181,15 +144,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
* Ecrit une valeur dans un champ de formulaire selon son type.
|
||||
*/
|
||||
function setValue(elementId, value) {
|
||||
const element = getElementByIdFlexible(elementId);
|
||||
|
|
@ -218,83 +173,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// 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
|
||||
* Dit si un nom de champ fait partie des champs qui influencent le tarif.
|
||||
*/
|
||||
function isFieldImpactingTarif(fieldName) {
|
||||
return TARIF_IMPACTING_FIELDS.some(field =>
|
||||
|
|
@ -302,74 +186,43 @@
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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");
|
||||
* Ouvre le modal "modif tarif" déjà présent dans la vue projet.
|
||||
*/
|
||||
function showReturnToTarifModal(fieldName) {
|
||||
const modalId = 'modalRetourTarif';
|
||||
let modal = document.getElementById(modalId);
|
||||
|
||||
// Créer le modal s'il n'existe pas
|
||||
const modal = document.getElementById('modalModif');
|
||||
if (!modal) {
|
||||
modal = createReturnToTarifModal();
|
||||
document.body.appendChild(modal);
|
||||
console.warn('Modal "modalModif" introuvable');
|
||||
return;
|
||||
}
|
||||
|
||||
// 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.
|
||||
`;
|
||||
}
|
||||
console.warn(`Modification impactant le tarif: ${fieldName}`);
|
||||
}
|
||||
|
||||
const okBtn = document.getElementById('modif-OK');
|
||||
const noBtn = document.getElementById('modif-NO');
|
||||
|
||||
if (okBtn) {
|
||||
okBtn.onclick = (event) => {
|
||||
event?.preventDefault?.();
|
||||
navigateToTarif();
|
||||
};
|
||||
}
|
||||
|
||||
if (noBtn) {
|
||||
noBtn.onclick = (event) => {
|
||||
event?.preventDefault?.();
|
||||
if (!window.M || !window.M.Modal) return;
|
||||
const instance = window.M.Modal.getInstance(modal);
|
||||
if (instance) instance.close();
|
||||
};
|
||||
}
|
||||
|
||||
// Ouvrir le modal
|
||||
if (window.M && window.M.Modal) {
|
||||
const instance = window.M.Modal.getInstance(modal) || window.M.Modal.init(modal);
|
||||
instance.open();
|
||||
|
|
@ -377,50 +230,29 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
* Redirige vers l'onglet Tarif depuis le Projet.
|
||||
*/
|
||||
function navigateToTarif() {
|
||||
// Fermer le modal
|
||||
const modal = document.getElementById('modalRetourTarif');
|
||||
const modal = document.getElementById('modalModif');
|
||||
if (modal && window.M) {
|
||||
const instance = window.M.Modal.getInstance(modal);
|
||||
if (instance) instance.close();
|
||||
}
|
||||
|
||||
// Si on est sur le formulaire projet, on garde un snapshot local
|
||||
// pour pré-remplir le tarif juste après la navigation.
|
||||
try {
|
||||
if (typeof window.collectProjetDataForTarifPrefill === 'function') {
|
||||
const projetData = window.collectProjetDataForTarifPrefill();
|
||||
if (projetData) {
|
||||
sessionStorage.setItem('rc_projet_data', JSON.stringify(projetData));
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Impossible de stocker les donnees projet avant redirection:', error);
|
||||
}
|
||||
|
||||
// Naviguer vers le tarif
|
||||
const numParcours = new URLSearchParams(window.location.search).get('numParcours');
|
||||
if (numParcours) {
|
||||
|
|
@ -434,7 +266,6 @@
|
|||
|
||||
/**
|
||||
* API publique du module RC Sync.
|
||||
* Toutes les fonctions exportées ici sont accessibles via window.RCSync.
|
||||
*/
|
||||
window.RCSync = {
|
||||
// Helpers
|
||||
|
|
@ -443,13 +274,8 @@
|
|||
setValue,
|
||||
getElementByIdFlexible,
|
||||
|
||||
// Comparaison
|
||||
arraysEqual,
|
||||
valuesEqual,
|
||||
|
||||
// Détection changements
|
||||
isFieldImpactingTarif,
|
||||
isChangeImpactingTarif,
|
||||
|
||||
// Modal
|
||||
showReturnToTarifModal,
|
||||
|
|
@ -459,6 +285,6 @@
|
|||
TARIF_IMPACTING_FIELDS
|
||||
};
|
||||
|
||||
console.log('✅ RC Sync Utils loaded');
|
||||
console.log('RC Sync Utils loaded');
|
||||
|
||||
})(window);
|
||||
|
|
|
|||
|
|
@ -929,6 +929,327 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
// Le bouton Annuler ferme automatiquement le modal grâce à la classe "modal-close"
|
||||
}
|
||||
|
||||
function parsePrefillArray(value) {
|
||||
if (Array.isArray(value)) return value;
|
||||
if (typeof value === 'string') {
|
||||
try {
|
||||
const parsed = JSON.parse(value);
|
||||
return Array.isArray(parsed) ? parsed : [];
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function normalizePrefillValue(value) {
|
||||
if (Array.isArray(value)) {
|
||||
return value
|
||||
.map((item) => normalizePrefillValue(item))
|
||||
.sort((a, b) => String(a).localeCompare(String(b), 'fr'));
|
||||
}
|
||||
|
||||
if (value && typeof value === 'object') {
|
||||
const normalized = {};
|
||||
Object.keys(value).sort().forEach((key) => {
|
||||
normalized[key] = normalizePrefillValue(value[key]);
|
||||
});
|
||||
return normalized;
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) return '';
|
||||
const numeric = toNumber(trimmed);
|
||||
if (!Number.isNaN(numeric) && trimmed.match(/^-?[\d\s,\.]+$/)) {
|
||||
return numeric;
|
||||
}
|
||||
return trimmed.toLowerCase();
|
||||
}
|
||||
|
||||
if (value == null) return null;
|
||||
return value;
|
||||
}
|
||||
|
||||
function buildProjetPrefillDelta(snapshot, baseline) {
|
||||
if (!snapshot || typeof snapshot !== 'object') return null;
|
||||
if (!baseline || typeof baseline !== 'object') return snapshot;
|
||||
|
||||
const delta = {};
|
||||
Object.keys(snapshot).forEach((key) => {
|
||||
const currentValue = normalizePrefillValue(snapshot[key]);
|
||||
const baselineValue = normalizePrefillValue(baseline[key]);
|
||||
|
||||
if (JSON.stringify(currentValue) !== JSON.stringify(baselineValue)) {
|
||||
delta[key] = snapshot[key];
|
||||
}
|
||||
});
|
||||
|
||||
return Object.keys(delta).length > 0 ? delta : null;
|
||||
}
|
||||
|
||||
function applyProjetDataToTarif(projetSource) {
|
||||
if (!projetSource || typeof projetSource !== 'object') return;
|
||||
|
||||
const hasOwn = (key) => Object.prototype.hasOwnProperty.call(projetSource, key);
|
||||
const hasAny = (keys) => keys.some(hasOwn);
|
||||
const normalize = (value) => String(value || '')
|
||||
.normalize('NFD')
|
||||
.replace(/[\u0300-\u036f]/g, '')
|
||||
.toLowerCase()
|
||||
.trim();
|
||||
|
||||
const toProjetNumber = (value) => {
|
||||
if (value == null) return null;
|
||||
const raw = String(value).trim();
|
||||
if (!raw || raw.toLowerCase() === 'nous consulter') return null;
|
||||
const parsed = toNumber(raw);
|
||||
return Number.isFinite(parsed) ? parsed : null;
|
||||
};
|
||||
|
||||
const pickNumber = (...keys) => {
|
||||
for (const key of keys) {
|
||||
const parsed = toProjetNumber(projetSource[key]);
|
||||
if (parsed != null) return parsed;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const setCheckboxState = (id, checked, dispatchClick) => {
|
||||
const element = document.getElementById(id);
|
||||
if (!element) return;
|
||||
element.checked = Boolean(checked);
|
||||
if (dispatchClick) {
|
||||
element.dispatchEvent(new Event('click'));
|
||||
}
|
||||
};
|
||||
|
||||
const setFirstValue = (elements, value) => {
|
||||
if (value == null) return;
|
||||
for (const element of elements) {
|
||||
if (element) {
|
||||
element.value = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const typeCotisation = projetSource.typeCot || projetSource.typeCotisation;
|
||||
if (typeCotisation) {
|
||||
const radio = document.getElementById(typeCotisation) || document.querySelector(`input[name="cotisation"][value="${typeCotisation}"]`);
|
||||
if (radio) {
|
||||
radio.checked = true;
|
||||
radio.dispatchEvent(new Event('change'));
|
||||
}
|
||||
}
|
||||
|
||||
if (hasOwn('ca')) {
|
||||
const caField = getElementByIdFlexible('CA') || getElementByIdFlexible('chiffreAffaire');
|
||||
if (caField) {
|
||||
const rawCA = String(projetSource.ca || '').trim();
|
||||
caField.value = (!rawCA || rawCA.toLowerCase() === 'nous consulter') ? '' : rawCA;
|
||||
}
|
||||
}
|
||||
|
||||
const nbVehiculeField = getElementByIdFlexible('nbVehicules') || getElementByIdFlexible('nbrVehicule');
|
||||
const nbVehFromProjet = toProjetNumber(projetSource.nombreVehicules ?? projetSource.nbVehicules);
|
||||
const nbVehFromTable = Array.isArray(projetSource.designationVehicule) ? projetSource.designationVehicule.length : null;
|
||||
if (nbVehiculeField) {
|
||||
if (nbVehFromProjet != null) {
|
||||
nbVehiculeField.value = Math.max(0, Math.round(nbVehFromProjet));
|
||||
} else if (nbVehFromTable != null && nbVehFromTable > 0) {
|
||||
nbVehiculeField.value = nbVehFromTable;
|
||||
}
|
||||
}
|
||||
|
||||
const activityMappings = [
|
||||
{
|
||||
keys: ['actVoiturier', 'actLoueur'],
|
||||
checkboxId: 'checkVoiturier',
|
||||
capitalKeys: ['valueActVoiturier', 'valueActLoueur'],
|
||||
capitalFields: [
|
||||
getElementByIdFlexible('capitalVoiturier'),
|
||||
document.querySelector('input[name="selectActVoiturier/Loueur"]')
|
||||
]
|
||||
},
|
||||
{
|
||||
keys: ['actMultimodal'],
|
||||
checkboxId: 'checkCommissionnaire',
|
||||
capitalKeys: ['valueActMultimodal'],
|
||||
capitalFields: [
|
||||
getElementByIdFlexible('capitalCommissionnaire'),
|
||||
document.querySelector('input[name="selectActCommissionnaire de Transport"]'),
|
||||
document.querySelector('input[name="selectActCommissionnaireDeTransport"]')
|
||||
]
|
||||
},
|
||||
{
|
||||
keys: ['actDemEntr', 'actDemInterne', 'actDemPar', 'actDemParDom', 'actDemParAdv', 'actGardeMeuble'],
|
||||
checkboxId: 'checkDemenageur',
|
||||
capitalKeys: ['valueActDemEntr', 'valueActDemInterne', 'valueActDemPar', 'valueActDemParDom', 'valueActDemParAdv'],
|
||||
capitalFields: [
|
||||
getElementByIdFlexible('capitalDemenageur'),
|
||||
document.querySelector('input[name="selectActDéménageur"]'),
|
||||
document.querySelector('input[name="selectActDemenageur"]')
|
||||
]
|
||||
},
|
||||
{
|
||||
keys: ['actPrestaLog', 'actEntDep'],
|
||||
checkboxId: 'checkLogistique',
|
||||
capitalKeys: ['valueActPrestaLog', 'valueActEntDep'],
|
||||
capitalFields: [
|
||||
getElementByIdFlexible('capitalLogistique'),
|
||||
document.querySelector('input[name="selectActLogistique"]')
|
||||
]
|
||||
},
|
||||
{
|
||||
keys: ['actAutocariste'],
|
||||
checkboxId: 'checkAutocariste',
|
||||
capitalKeys: ['valueActAutocariste'],
|
||||
capitalFields: [
|
||||
getElementByIdFlexible('capitalAutocariste'),
|
||||
document.querySelector('input[name="selectActAutocariste"]')
|
||||
]
|
||||
},
|
||||
{
|
||||
keys: ['actAutres'],
|
||||
checkboxId: 'checkAutres',
|
||||
capitalKeys: ['valueActAutres'],
|
||||
capitalFields: [
|
||||
getElementByIdFlexible('capitalAutres'),
|
||||
document.querySelector('input[name="selectActAutres activites"]'),
|
||||
document.querySelector('input[name="selectActAutresActivites"]')
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
activityMappings.forEach((mapping) => {
|
||||
if (!hasAny(mapping.keys)) return;
|
||||
const selected = mapping.keys.some((key) => Boolean(projetSource[key]));
|
||||
setCheckboxState(mapping.checkboxId, selected, true);
|
||||
if (selected) {
|
||||
const capitalValue = pickNumber(...mapping.capitalKeys);
|
||||
setFirstValue(mapping.capitalFields, capitalValue);
|
||||
}
|
||||
});
|
||||
|
||||
if (hasAny(['zone1', 'zone2', 'zone3', 'zone4', 'zone5', 'zone6'])) {
|
||||
const zone1 = Boolean(projetSource.zone1);
|
||||
const zone2 = Boolean(projetSource.zone2);
|
||||
const zone3 = Boolean(projetSource.zone3);
|
||||
const zone4 = Boolean(projetSource.zone4);
|
||||
const zone5 = Boolean(projetSource.zone5);
|
||||
const zone6 = Boolean(projetSource.zone6);
|
||||
|
||||
const zone1El = document.getElementById('zone1');
|
||||
const zone2El = document.getElementById('zone2');
|
||||
const zone3El = document.getElementById('zone3');
|
||||
const zone4El = document.getElementById('zone4');
|
||||
const zone5El = document.getElementById('zone5');
|
||||
const zone6El = document.getElementById('zone6');
|
||||
|
||||
if (zone1El) {
|
||||
zone1El.checked = zone1 || zone2 || zone3;
|
||||
zone1El.disabled = zone2 || zone3;
|
||||
}
|
||||
if (zone2El) {
|
||||
zone2El.checked = zone2 || zone3;
|
||||
zone2El.disabled = zone3;
|
||||
}
|
||||
if (zone3El) zone3El.checked = zone3;
|
||||
if (zone4El) zone4El.checked = zone4;
|
||||
if (zone5El) zone5El.checked = zone5;
|
||||
if (zone6El) zone6El.checked = zone6;
|
||||
}
|
||||
|
||||
if (hasOwn('autresRC')) {
|
||||
setCheckboxState('checkRCE', Boolean(projetSource.autresRC), true);
|
||||
}
|
||||
|
||||
if (hasOwn('pj')) {
|
||||
setCheckboxState('checkPJ', Boolean(projetSource.pj), false);
|
||||
}
|
||||
|
||||
const activitesComplementairesMap = [
|
||||
{ field: 'activitesVoiturier', container: 'actComplVoiturier/Loueur' },
|
||||
{ field: 'activitesCommissionnaire', container: 'actComplCommissionnaire de Transport' },
|
||||
{ field: 'activitesDemenageur', container: 'actComplDéménageur' },
|
||||
{ field: 'activitesLogistique', container: 'actComplLogistique' }
|
||||
];
|
||||
|
||||
activitesComplementairesMap.forEach(({ field, container }) => {
|
||||
if (!hasOwn(field)) return;
|
||||
const wanted = parsePrefillArray(projetSource[field]);
|
||||
const wantedSet = new Set(wanted.map((item) => String(item).trim()));
|
||||
const checkboxes = document.querySelectorAll(`[name="${container}"] input[type="checkbox"]`);
|
||||
checkboxes.forEach((checkbox) => {
|
||||
const label = checkbox.nextElementSibling ? checkbox.nextElementSibling.textContent.trim() : checkbox.value;
|
||||
checkbox.checked = wantedSet.has(label);
|
||||
});
|
||||
});
|
||||
|
||||
const marchandiseKeys = [
|
||||
'marOrdinaire',
|
||||
'marRoulant',
|
||||
'marEngins',
|
||||
'marRoulantDem',
|
||||
'marMobilerUsag',
|
||||
'marPerissable',
|
||||
'marAnimaux',
|
||||
'marCiterne',
|
||||
'marBeton',
|
||||
'marExceptionnels',
|
||||
'marVrac'
|
||||
];
|
||||
|
||||
if (hasAny(marchandiseKeys)) {
|
||||
const flags = {
|
||||
marOrdinaire: Boolean(projetSource.marOrdinaire),
|
||||
marRoulant: Boolean(projetSource.marRoulant),
|
||||
marEngins: Boolean(projetSource.marEngins),
|
||||
marRoulantDem: Boolean(projetSource.marRoulantDem),
|
||||
marMobilerUsag: Boolean(projetSource.marMobilerUsag),
|
||||
marPerissable: Boolean(projetSource.marPerissable),
|
||||
marAnimaux: Boolean(projetSource.marAnimaux),
|
||||
marCiterne: Boolean(projetSource.marCiterne),
|
||||
marBeton: Boolean(projetSource.marBeton),
|
||||
marExceptionnels: Boolean(projetSource.marExceptionnels),
|
||||
marVrac: Boolean(projetSource.marVrac)
|
||||
};
|
||||
|
||||
const shouldSelectMarchandise = (label) => {
|
||||
const text = normalize(label);
|
||||
if (!text) return false;
|
||||
if (flags.marRoulantDem && text.includes('vehicules roulants') && text.includes('demenagement')) return true;
|
||||
if (flags.marRoulant && text.includes('vehicules roulants') && !text.includes('demenagement')) return true;
|
||||
if (flags.marOrdinaire && text.includes('ordinaires')) return true;
|
||||
if (flags.marEngins && text.includes('engins de chantier')) return true;
|
||||
if (flags.marMobilerUsag && text.includes('mobiliers')) return true;
|
||||
if (flags.marPerissable && text.includes('perissables')) return true;
|
||||
if (flags.marAnimaux && text.includes('animaux vivants')) return true;
|
||||
if (flags.marCiterne && text.includes('citerne')) return true;
|
||||
if (flags.marBeton && text.includes('beton')) return true;
|
||||
if (flags.marExceptionnels && text.includes('exceptionnels')) return true;
|
||||
if (flags.marVrac && (text.includes('benne') || text.includes('vrac'))) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
[
|
||||
'marVoiturier/Loueur',
|
||||
'marCommissionnaire de Transport',
|
||||
'marDéménageur',
|
||||
'marLogistique',
|
||||
'marAutocariste',
|
||||
'marAutres activites'
|
||||
].forEach((container) => {
|
||||
const checkboxes = document.querySelectorAll(`[name="${container}"] input[type="checkbox"]`);
|
||||
checkboxes.forEach((checkbox) => {
|
||||
const label = checkbox.nextElementSibling ? checkbox.nextElementSibling.textContent : checkbox.value;
|
||||
checkbox.checked = shouldSelectMarchandise(label);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Peupler le formulaire avec les données
|
||||
function populateFormData() {
|
||||
//Poupulate select historique
|
||||
|
|
@ -984,7 +1305,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
return;
|
||||
}
|
||||
|
||||
console.log('🔄 Pré-remplissage du formulaire tarif avec les données RC:', rc);
|
||||
console.log('Pre-remplissage du formulaire tarif avec les donnees RC:', rc);
|
||||
|
||||
// Type de cotisation
|
||||
if (rc.typeCotisation) {
|
||||
|
|
@ -1095,7 +1416,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
{ field: 'actComplLogistique', name: 'actComplLogistique' }
|
||||
];
|
||||
|
||||
console.log('🔄 Pré-remplissage des activités complémentaires...');
|
||||
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"]`);
|
||||
|
|
@ -1105,18 +1426,18 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
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);
|
||||
console.log(` ${field}:`, activites);
|
||||
activites.forEach(actText => {
|
||||
// Chercher la checkbox dont le span adjacent contient ce texte
|
||||
allCheckboxes.forEach(cb => {
|
||||
const label = cb.nextElementSibling?.textContent.trim();
|
||||
if (label === actText) {
|
||||
cb.checked = true;
|
||||
console.log(` ✓ Coché: ${actText}`);
|
||||
console.log(` Coche: ${actText}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (e) { console.error(`❌ Erreur parsing ${field}:`, e); }
|
||||
} catch (e) { console.error(`Erreur parsing ${field}:`, e); }
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -1130,7 +1451,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
{ field: 'marchandisesAutres', name: 'marAutres activites' }
|
||||
];
|
||||
|
||||
console.log('🔄 Pré-remplissage des marchandises...');
|
||||
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"]`);
|
||||
|
|
@ -1140,18 +1461,18 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
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);
|
||||
console.log(` ${field}:`, marchandises);
|
||||
marchandises.forEach(marText => {
|
||||
// Chercher la checkbox dont le span adjacent contient ce texte
|
||||
allCheckboxes.forEach(cb => {
|
||||
const label = cb.nextElementSibling?.textContent.trim();
|
||||
if (label === marText) {
|
||||
cb.checked = true;
|
||||
console.log(` ✓ Coché: ${marText}`);
|
||||
console.log(` Coche: ${marText}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (e) { console.error(`❌ Erreur parsing ${field}:`, e); }
|
||||
} catch (e) { console.error(`Erreur parsing ${field}:`, e); }
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -1160,8 +1481,8 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
ensureDefaultMarchandisesVoiturier();
|
||||
|
||||
// Pré-remplir les pourcentages (depuis tarifRC)
|
||||
// Préférer l'objet tarif si présent, sinon retomber sur l'expansion RC
|
||||
const tarifSource = tarif || rc?.["@expand"]?.tarifRC || rc?.tarifRC || rc || null;
|
||||
// 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 {
|
||||
|
|
@ -1268,7 +1589,33 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
}
|
||||
}
|
||||
|
||||
console.log('✅ Formulaire tarif pré-rempli avec succès');
|
||||
// Pré-remplissage Projet -> Tarif
|
||||
// - si snapshot session: appliquer seulement les champs modifies sur Projet
|
||||
// - sinon: utiliser Projet uniquement si on n'a pas de tarif persistant
|
||||
let sessionProjetData = null;
|
||||
try {
|
||||
const storedProjetData = sessionStorage.getItem('rc_projet_data');
|
||||
sessionProjetData = storedProjetData ? JSON.parse(storedProjetData) : null;
|
||||
} catch (error) {
|
||||
sessionProjetData = null;
|
||||
}
|
||||
|
||||
let projetPrefillSource = null;
|
||||
if (sessionProjetData) {
|
||||
projetPrefillSource = buildProjetPrefillDelta(sessionProjetData, projet);
|
||||
} else if (!tarifSource && !sessionTarifData && projet) {
|
||||
projetPrefillSource = projet;
|
||||
}
|
||||
|
||||
if (projetPrefillSource) {
|
||||
applyProjetDataToTarif(projetPrefillSource);
|
||||
}
|
||||
|
||||
if (sessionProjetData) {
|
||||
sessionStorage.removeItem('rc_projet_data');
|
||||
}
|
||||
|
||||
console.log('Formulaire tarif pre-rempli avec succes');
|
||||
|
||||
// Recalculer après pré-remplissage
|
||||
setTimeout(() => {
|
||||
|
|
@ -2967,8 +3314,8 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
};
|
||||
|
||||
// ===== LOGS DE DÉBOGAGE =====
|
||||
console.log('📊 === DÉBUT SAUVEGARDE TARIF RC ===');
|
||||
console.log('🔍 rcMainData:', rcMainData);
|
||||
console.log('=== DEBUT SAUVEGARDE TARIF RC ===');
|
||||
console.log('rcMainData:', rcMainData);
|
||||
|
||||
// ===== ÉTAPE 2: Collecter les résultats de calculs pour tarifRC =====
|
||||
const tarifRCData = {
|
||||
|
|
@ -3068,7 +3415,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
// ===== ÉTAPE 3: Sauvegarder/Mettre à jour tarifRC =====
|
||||
if (tarif && tarif.id) {
|
||||
// Mettre à jour un enregistrement tarifRC existant
|
||||
console.log(`📝 Mise à jour tarifRC existant (ID: ${tarif.id})`);
|
||||
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),
|
||||
|
|
@ -3077,16 +3424,16 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
},
|
||||
});
|
||||
const data = await response.json();
|
||||
console.log('📥 Réponse serveur tarifRC update:', data);
|
||||
console.log('Reponse serveur tarifRC update:', data);
|
||||
if (data.valid) {
|
||||
idTarifRC = data.tarifRc.id;
|
||||
} else {
|
||||
console.error('❌ Échec de la mise à jour de tarifRC:', data.message);
|
||||
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('📝 Création nouveau tarifRC');
|
||||
console.log('Creation nouveau tarifRC');
|
||||
const response = await fetch(`/rc/tarif/create`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(tarifRCData),
|
||||
|
|
@ -3095,11 +3442,11 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
},
|
||||
});
|
||||
const data = await response.json();
|
||||
console.log('📥 Réponse serveur tarifRC create:', data);
|
||||
console.log('Reponse serveur tarifRC create:', data);
|
||||
if (data.valid) {
|
||||
idTarifRC = data.tarifRc.id;
|
||||
} else {
|
||||
console.error('❌ Échec de la création de tarifRC:', data.message);
|
||||
console.error('Echec de la creation de tarifRC:', data.message);
|
||||
return { valid: false, message: data.message };
|
||||
}
|
||||
}
|
||||
|
|
@ -3107,8 +3454,8 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
// ===== ÉTAPE 4: Mettre à jour RC principal avec les données communes ET la référence tarifRC =====
|
||||
rcMainData.tarifRC = idTarifRC; // Ajouter la référence à tarifRC
|
||||
|
||||
console.log(`📝 Mise à jour RC principal (ID: ${rcId}) avec référence tarifRC: ${idTarifRC}`);
|
||||
console.log('🔍 Données envoyées pour RC:', rcMainData);
|
||||
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',
|
||||
|
|
@ -3118,15 +3465,15 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
},
|
||||
});
|
||||
const updateRCData = await updateRCResponse.json();
|
||||
console.log('📥 Réponse serveur RC update:', updateRCData);
|
||||
console.log('Reponse serveur RC update:', updateRCData);
|
||||
|
||||
if (!updateRCData.valid) {
|
||||
console.error('❌ Échec de la mise à jour de RC principal:', updateRCData.message);
|
||||
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 SAUVEGARDÉ AVEC SUCCÈS ===');
|
||||
console.log('✅ RC ID:', rcId, '| TarifRC ID:', idTarifRC);
|
||||
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);
|
||||
|
|
@ -3374,7 +3721,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
window.modalTarifCom.close();
|
||||
|
||||
// Afficher un loader
|
||||
M.toast({html: '⏳ Sauvegarde en cours...', classes: 'blue'});
|
||||
M.toast({html: 'Sauvegarde en cours...', classes: 'blue'});
|
||||
|
||||
// Sauvegarder le tarif
|
||||
const saveResult = await saveTarifRC();
|
||||
|
|
@ -3384,7 +3731,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
|
||||
// Rediriger vers la page projet après un court délai
|
||||
setTimeout(() => {
|
||||
console.log('🚀 Redirection vers projet...');
|
||||
console.log('Redirection vers projet...');
|
||||
// Construire l'URL de redirection vers projet
|
||||
const numParcours = parcours?.numParcours;
|
||||
if (numParcours) {
|
||||
|
|
@ -3394,7 +3741,7 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
|
|||
}
|
||||
}, 1000);
|
||||
} else {
|
||||
M.toast({html: '❌ Erreur lors de la sauvegarde du tarif', classes: 'red'});
|
||||
M.toast({html: 'Erreur lors de la sauvegarde du tarif', classes: 'red'});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue