PageSourceSearch

https://www.bike-parts-honda.de/assets/javascript/basket/javascript_basket.js?ver=1.246

js bike-parts-honda.de collected 2026-10-07 21:32:41 UTC 129,326 bytes, 3,797 lines download raw bytes

1const promises_form_fac = [];
2let isModalOpen = false;
3document.addEventListener("DOMContentLoaded", async function () {
4	// Sync (non bloquants)
5	if (document.querySelectorAll(".JS_table_panier_parts form").length) add_basket();
6	if (document.querySelector("#table_panier_shop form")) add_basket();
7	if (document.getElementById("panier_select_vehicule")) basket_switch_vehicule();
8	if (document.querySelector("#modif_adresse")) modif_adresse();
9	if (document.querySelector("#modif_adresse_facturation")) modif_adresse_facturation();
10	if (document.querySelector("#modif_info")) modif_info();
11	if (document.querySelector("#modif_comm")) modif_comm();
12	if (document.querySelector("#check_differente_adresse")) check_differente_adresse();
13	if (document.querySelector(".modal_supp")) action_delete_line_basket();
14	if (document.querySelector(".qty-input")) action_update_line_basket();
15	if (document.querySelector("#form_basket_save")) save_basket();
16	if (document.querySelector("#form_card_payment")) await set_transaction_on_progress();
17	// if (document.querySelector("#form_card_payment")) check_transaction_on_progress();
18	if (document.querySelectorAll(".form_transform_devis").length > 0) {
19		transform_devis();
20		delete_devis();
21	}
22	if (document.querySelectorAll(".btn-payment ").length > 0) {
23		collapse_elements_payment();
24		// select_elements_payment(); // à toi de voir si tu le réactives
25	}
26	if (document.querySelector("#checkbox_condition_vente")) {
27		document.getElementById("checkbox_condition_vente").addEventListener("change", function () {
28			if (this.checked && document.getElementById("cgv_error")) removeError("cgv_error");
29		});
30	}
31
32	// Promo : Prétraitement spécial
33	if (document.querySelector("#form_promo")) {
34		const elements = document.querySelectorAll(".JS_cart_ref_part");
35		elements.forEach(el => {
36			if (el.textContent.trim() === "FRPG") set_free_delivery("FRPG");
37		});
38
39		const promoSupp = document.querySelector("#form_panier_supp_code_promo");
40		if (promoSupp) {
41			const promoForm = document.querySelector("#form_promo");
42			const code = promoSupp.querySelector("[name=code_promo]").value;
43			promoForm.querySelector("#code_promo").value = code;
44			document.querySelector("#JS_collapse_code_promo").innerHTML =
45				promoForm.querySelector(`[value*="${code}"]`).innerHTML;
46		}
47	}
48
49	// Async en parallèle (indépendants)
50	await Promise.all([
51		(async () => { if (document.querySelector("#form_panier_commentaire")) await form_panier_commentaire(); })(),
52		(async () => { if (document.querySelector("#form_panier_information")) await form_panier_information(); })(),
53		(async () => { if (document.querySelector("#form_adr_liv")) {
54			await form_adr_liv();
55			await cache_current_delivery_address();
56		}})(),
57		(async () => { if (document.querySelector("#form_basket_add_code_promo")) await form_promo(); })(),
58		(async () => { if (document.querySelector("#form_basket_delete_code_promo")) await form_delete_promo(); })(),
59		(async () => { if (document.querySelector("#form_adr_fact")) await form_adr_fac(); })(),
60		(async () => { if (document.querySelector("#form_basket_login")) await form_login(); })(),
61
62		(async () => { if (document.querySelectorAll('.choix_pts_relais').length) await choix_pts_relais(); })(),
63		(async () => { if (document.querySelector("#view_step_basket") || document.querySelector("#empty_basket")) await getBasketInformations(); })(),
64
65	]);
66
67	// await check_basket_errors();
68
69
70	if (document.querySelector("#form_panier_commentaire")) {
71		submit_panier_commentaire();
72	}
73
74	if (document.querySelector("#pays_facturation")) {
75		await check_country_is_valid(document.querySelector("#pays_facturation").value);
76		document.querySelector("#pays_facturation").addEventListener("change", async function () {
77			show_ajax_loader();
78			try {
79				const promises = [];
80				const pays = jQuery('#pays_facturation').val(); // valeur du pays après changement
81
82				// Recheck des champs specifiques.
83				let pro = false
84				if (document.querySelector("#entreprise_facturation").value.trim() !== "") {
85					pro = true;
86				}
87				await get_basket_facturation_option(pays,pro)
88
89				// si TVA est requise
90				const list_pays_TVA = getInputRequired("TVA");
91				const num_intracom_facturation = document.querySelector("#num_intracom_facturation");
92				if (list_pays_TVA && list_pays_TVA.includes(pays)) {
93					num_intracom_facturation.setAttribute('required', 'required');
94				} else {
95					num_intracom_facturation.removeAttribute('required');
96				}
97
98				if (num_intracom_facturation && num_intracom_facturation.value !== "") {
99					await check_tva_intracom(this.form, "facturation");
100				}
101
102				// promises.push(get_vat_changed_info());
103				// promises.push(check_country_is_valid(this.value));
104				promises.push(set_prefix_by_coutry(pays, "facturation"));
105
106				await Promise.all(promises);
107				pays_auto_province(this.form);
108			} catch (error) {
109				logDebug('Erreur lors du changement de pays :', error);
110			} finally {
111				hide_ajax_loader();
112			}
113		});
114	}
115
116
117	if (document.querySelector("#form_panier_mobile_coliship")) {
118		await form_panier_mobile_coliship();
119	}
120
121	if (document.querySelector("#form_panier_payment")) {
122		await form_panier_payment(document.querySelector("#form_panier_payment"));
123	}
124
125	if (document.querySelector("#entreprise_facturation")) {
126		let timeout;
127		document.querySelector("#entreprise_facturation").addEventListener("input", function() {
128			clearTimeout(timeout);
129
130			timeout = setTimeout(async () => {
131				let pro = false
132				if (this.value.trim() !== "") {
133					pro = true;
134				}
135				await get_basket_facturation_option(false, pro);
136			}, 250);
137		});
138	}
139
140	// FORMULAIRES ADRESSES //
141	if (document.querySelector("#collapse_basket_facturation") && document.querySelector("#collapse_basket_livraison")) {
142		gestion_collapse_adresse("facturation");
143		gestion_collapse_adresse("livraison");
144	}
145});
146
147
148
149function gestion_collapse_adresse(type) {
150	let adresseElement = document.getElementById(`basket_${type}_adresse`);
151	let collapseElement = document.getElementById(`basket_form_${type}`);
152	if (!collapseElement) {
153		return;
154	}
155	let bsCollapseElement = new bootstrap.Collapse(collapseElement, {toggle: false});
156	let otherType = type === "facturation" ? "livraison" : "facturation";
157	let otherCollapseElement = document.getElementById(`basket_form_${otherType}`);
158	let bsOtherCollapseElement = new bootstrap.Collapse(otherCollapseElement, {toggle: false});
159
160
161	adresseElement.addEventListener('click', async function () {
162
163
164		if (!otherCollapseElement.classList.contains('show') && !collapseElement.classList.contains('show')) {
165
166			if (type === "livraison") {
167				await get_cache_current_delivery_address();
168				await unset_delivery_mode();
169				disabled_inputs_form_adresse_livraison(false);
170				await check_pts_relais();
171				await update_form_adresse_livraison();
172				document.getElementById("check_differente_adresse").checked = false;
173			}
174
175			var infosForm = {"collapse": true};
176
177			// Appeler les deux fonctions d'update et attendre qu'elles se terminent
178			await update_both_labels_info(infosForm, infosForm);
179			bsCollapseElement.show();
180			bsOtherCollapseElement.hide();
181
182			document.getElementById("basket_facturation_adresse").classList.remove("bg-disabled");
183			document.getElementById("basket_livraison_adresse").classList.remove("bg-disabled");
184			if (bsCollapseElement._element.id === "basket_form_facturation") {
185				document.getElementById("basket_livraison_adresse").classList.add("bg-disabled");
186			} else if (bsCollapseElement._element.id === "basket_form_livraison") {
187				document.getElementById("basket_facturation_adresse").classList.add("bg-disabled");
188			}
189		}
190	});
191
192}
193
194function basket_switch_vehicule() {
195	document.getElementById("panier_select_vehicule").addEventListener("change", async function () {
196		await get_vehicule();
197	});
198}
199
200async function form_adr_fac() {
201	document.querySelector("#form_adr_fact").addEventListener("submit", async function (event) {
202
203		event.preventDefault(); // Empêche l'envoi du formulaire
204		await check_tva_intracom( this, "facturation");
205		await check_cp(this, "facturation");
206		// await check_form_code_fiscal(this, "facturation");
207		this.classList.remove('was-validated'); // Ajoute la classe pour afficher les erreurs
208		if (!this.checkValidity()) {
209			event.stopPropagation(); // Stoppe la propagation de l'événement
210			this.classList.add('was-validated'); // Ajoute la classe pour afficher les erreurs
211			return; // Sort de la fonction pour éviter de continuer l'exécution
212		}
213
214		show_ajax_loader();
215		const is_valid = validate_form(this);
216		if (is_valid) {
217			// Initialisation des objets pour les données du formulaire
218			const formData = new FormData();
219			const infos_form = {};
220			let infos_form_livraison = {};
221			// Sélection des inputs visibles et non masqués
222			document.querySelectorAll("#form_adr_fact input, #form_adr_fact select").forEach(element => {
223				const parent = element.closest('.input-group') || element;
224				if (!parent.classList.contains('d-none') && !element.classList.contains('d-none')) {
225					formData.append(element.name, element.value);
226				}
227			});
228
229			// Conversion de FormData en un objet JavaScript
230			formData.forEach((value, key) => {
231				if (key.endsWith('_v3')) {
232					key = key.replace('_v3', '');
233				}
234				if (key.endsWith('_facturation')) {
235					key = key.replace('_facturation', '');
236				}
237				infos_form[key] = value;
238			});
239
240			const params = new URLSearchParams();
241			params.append('csrf_test_name', document.querySelector("[name=csrf_test_name]").value);
242			params.append('adresse', JSON.stringify(infos_form));
243			try {
244				const response = await fetch(get_protocol_domain_name() + "/panier_v3/save_adresse_facturation", {
245					method: 'POST', headers: {
246						'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
247					}, body: params,
248					mode: 'cors',
249					credentials: 'same-origin'
250				});
251
252				if (response.ok) {
253					const data = await response.text();
254					var valid = JSON.parse(data);
255					if (valid["status"] === "success") {
256						const promises = [];
257						var other_pays = false;
258						infos_form["collapse"] = false;
259
260						if (infos_form["pays"] !== document.querySelector("#pays_livraison").value) {
261							other_pays = true;
262							promises.push(set_identic_livraison_to_facturation());
263							infos_form_livraison = infos_form;
264						}
265
266						promises.push(update_both_labels_info(infos_form,infos_form_livraison));
267						promises.push(get_navigation());
268						promises.push(get_vat_changed_info());
269						await Promise.all(promises);
270						await check_country_is_valid(document.querySelector("#pays_facturation").value);
271						var myCollapse_2 = document.querySelector("#basket_form_facturation");
272						var bsCollapse_2 = new bootstrap.Collapse(myCollapse_2, {
273							toggle: false
274						});
275						bsCollapse_2.hide();
276						removeError("adr_errors")
277
278						if (other_pays) {
279							await get_basket_message(infos_form["pays_i"]);
280						}
281						await get_basket_footer_message();
282						await get_recapitulatif_basket_view();
283						await check_pts_relais();
284					} else {
285						await valid_form_ajax(valid.errors, document.querySelector("#form_adr_fact"),"facturation");
286					}
287
288				} else {
289					throw new Error('Response not OK');
290				}
291			} catch (error) {
292				logDebug('Erreur lors de la requête :', error);
293			} finally {
294				hide_ajax_loader();
295			}
296		}
297	});
298}
299
300async function form_adr_liv() {
301	document.querySelector("#form_adr_liv").addEventListener("submit", async function (event) {
302		event.preventDefault();
303		await check_cp(this, "livraison");
304
305		if (!this.checkValidity()) {
306			event.stopPropagation(); // Stoppe la propagation de l'événement
307			this.classList.add('was-validated'); // Ajoute la classe pour afficher les erreurs
308			return; // Sort de la fonction pour éviter de continuer l'exécution
309		}
310
311		show_ajax_loader();
312		validate_form(this);
313		try {
314			const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
315
316			var fields = {
317				"nom": "nom",
318				"prenom": "prenom",
319				"entreprise": "entreprise",
320				"ad": "ad",
321				"ad1": "complement_adresse",
322				"cp": "cp",
323				"ville": "ville",
324				"telephone": "telephone",
325				"pays_livraison": "pays"
326			};
327
328			var infos_form = {};
329
330			for (var key in fields) {
331				var input = this.querySelector("[name=" + fields[key] + "]");
332				if (input) {
333					infos_form[key] = input.value;
334				}
335			}
336
337			if (document.querySelector("#province_livraison")) {
338				infos_form["province"] = document.querySelector("#province_livraison").value;
339			}
340
341			const params = new URLSearchParams();
342			params.append('csrf_test_name', csrf_test_name);
343			Object.entries(infos_form).forEach(([key, value]) => {
344				params.append(key, value);
345			});
346
347			await save_address_livraison(infos_form, params);
348
349
350		} catch (error) {
351			logDebug('Erreur lors de la requête :', error);
352		} finally {
353			hide_ajax_loader();
354		}
355	});
356}
357
358async function save_address_livraison(infos_form, params, by_selected_pts_relais = false) {
359	const response = await fetch(get_protocol_domain_name() + "/panier_v3/save_adresse_livraison", {
360		method: 'POST', headers: {
361			'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
362		}, body: params,
363		mode: 'cors',
364		credentials: 'same-origin'
365	});
366
367	if (response.ok) {
368		const data = await response.json();
369		if (data.status === 'success') {
370			if (!by_selected_pts_relais) {
371				await check_pts_relais();
372			}
373			infos_form.identic = data.identic;
374			infos_form.collapse = false;
375			await update_both_labels_info([], infos_form);
376
377			var myCollapse_2 = document.querySelector("#basket_form_livraison");
378			var bsCollapse_2 = new bootstrap.Collapse(myCollapse_2, {toggle: false});
379			bsCollapse_2.hide();
380			removeError("adr_errors")
381			await cache_current_delivery_address();
382			await get_recapitulatif_basket_view();
383
384		} else {
385			await valid_form_ajax(data.errors, document.querySelector("#form_adr_liv"), "");
386		}
387		remove_button_loader(document.querySelector("#btn_adresse"));
388	} else {
389		throw new Error('Response not OK');
390	}
391}
392
393async function cache_current_delivery_address(telephone) {
394	try {
395		const form = document.querySelector("#form_adr_liv");
396		const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
397		const infos_form = {
398			"nom": form.querySelector("[name=nom]").value,
399			"prenom": form.querySelector("[name=prenom]").value,
400			"entreprise": form.querySelector("[name=entreprise]").value,
401			"ad": form.querySelector("[name=ad]").value,
402			"complement_adresse": form.querySelector("[name=complement_adresse]").value,
403			"cp": form.querySelector("[name=cp]").value,
404			"ville": form.querySelector("[name=ville]").value,
405			"telephone": telephone ?? form.querySelector("[name=telephone]").value,
406			"pays_livraison": form.querySelector("[name=pays]").value
407		};
408
409		if (form.querySelector("[name=province]")) {
410			infos_form["province"] = form.querySelector("[name=province]").value;
411		}
412
413		infos_form["is_pts_relais"] = false;
414		if (document.querySelectorAll(".delivery-domicile").length > 0) {
415			document.querySelectorAll(".delivery-domicile").forEach(function (el) {
416				if (el.classList.contains("show") && el.parentElement.classList.contains("show")) {
417					infos_form["is_pts_relais"] = true;
418				}
419			});
420		}
421
422		const params = new URLSearchParams();
423		params.append('csrf_test_name', csrf_test_name);
424		Object.entries(infos_form).forEach(([key, value]) => {
425			params.append(key, value);
426		});
427
428		await fetch(get_protocol_domain_name() + "/panier_v3/cache_current_delivery_address", {
429			method: 'POST', headers: {
430				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
431			}, body: params, mode: 'cors', credentials: 'same-origin'
432		});
433
434	} catch (error) {
435		logDebug('Erreur lors de la requête :', error);
436	}
437}
438
439async function get_cache_current_delivery_address() {
440	try {
441		show_ajax_loader();
442		const response = await fetch(get_protocol_domain_name() + "/panier_v3/get_cache_current_delivery_address", {
443			method: 'GET',
444			headers: {
445				'Content-Type': 'application/json',
446				'X-Requested-With': 'XMLHttpRequest'
447			},
448			mode: 'cors',
449			credentials: 'same-origin'
450		});
451
452		if (response.ok) {
453			const data = await response.json();
454			// Reformatage des données pour correspondre à ton `infos_form`
455			const infos_form = {
456				nom: data.nom || "",
457				prenom: data.prenom || "",
458				entreprise: data.societe || "", // ici c'est "societe" côté PHP
459				ad: data.adresse_1 || "",
460				complement_adresse: data.adresse_2 || "",
461				cp: data.code_postal || "",
462				ville: data.ville || "",
463				telephone: data.telephone || "",
464				pays_livraison: data.pays || ""
465			};
466
467			if (data.province) {
468				infos_form.province = data.province;
469			}
470
471			const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
472
473			const params = new URLSearchParams();
474			params.append('csrf_test_name', csrf_test_name);
475			Object.entries(infos_form).forEach(([key, value]) => {
476				params.append(key, value);
477			});
478			await save_address_livraison(infos_form, params, true);
479
480		}
481	} catch (error) {
482		logDebug('Erreur lors de la requête :', error);
483	} finally {
484		hide_ajax_loader();
485	}
486}
487
488async function get_vat_changed_info() {
489	const csrfToken = document.querySelector("[name=csrf_test_name]")?.value;
490	const paysFournisseur = document.querySelector("#pays_fournisseur")?.value;
491	const paysClient = document.querySelector("#pays_facturation")?.value || document.querySelector("#pays_client")?.value;
492
493	if (!csrfToken || !paysFournisseur || !paysClient) {
494		logDebug("Certains champs requis sont manquants.");
495		return;
496	}
497
498	const params = new URLSearchParams({
499		csrf_test_name: csrfToken,
500		pays_fournisseur: paysFournisseur,
501		pays_client: paysClient
502	});
503
504	try {
505		const response = await fetchWithRetries(get_protocol_domain_name() + "/panier_v3/get_basket_vat_changed", {
506			method: 'POST', headers: {
507				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
508			}, body: params, mode: 'cors', credentials: 'same-origin'
509		});
510
511		const infoElement = document.querySelector("#basket_vat_changed_info");
512
513		if (!infoElement) return;
514
515		if (response.ok) {
516			const result = await response.text();
517			infoElement.classList.toggle("d-block", Boolean(result));
518			infoElement.classList.toggle("d-none", !result);
519		}
520	} catch (error) {
521		logDebug('Erreur lors de la requête :', error);
522		throw error; // Rejeter l'erreur pour la gérer à l'extérieur si nécessaire
523	}
524}
525
526async function form_panier_information() {
527	document.querySelector("#form_panier_information").addEventListener("submit", function (event) {
528		if (!event.target.checkValidity()) {
529			event.preventDefault(); // Empêche l'envoi du formulaire si invalide
530			event.stopPropagation();
531		}
532		event.target.classList.add('was-validated'); // Ajoute une classe pour montrer l'état de validation
533	}, false)
534}
535
536async function form_panier_commentaire() {
537	document.querySelector("#form_panier_commentaire").addEventListener("submit", function (event) {
538		if (!event.target.checkValidity()) {
539			event.preventDefault(); // Empêche l'envoi du formulaire si invalide
540			event.stopPropagation();
541		}
542		event.target.classList.add('was-validated'); // Ajoute une classe pour montrer l'état de validation
543	}, false);
544}
545
546async function form_promo() {
547	if (document.querySelector("#form_basket_add_code_promo")) {
548		document.querySelector("#form_basket_add_code_promo").addEventListener("submit", async function (event) {
549			event.preventDefault(); // Empêche l'envoi du formulaire si invalide
550			show_ajax_loader();
551			try {
552				const csrf_test_name = this.querySelector("[name=csrf_test_name]").value;
553				const code_promo = this.querySelector("[name=input_basket_code_promo]").value;
554				if (code_promo) {
555					const infos_form = {
556						"code_promo": code_promo,
557					};
558
559					const params = new URLSearchParams();
560					params.append('csrf_test_name', csrf_test_name);
561					Object.entries(infos_form).forEach(([key, value]) => {
562						params.append(key, value);
563					});
564
565					const response = await fetch(get_protocol_domain_name() + "/panier_v3/add_code_promo", {
566						method: 'POST', headers: {
567							'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
568						}, body: params,
569						mode: 'cors',
570						credentials: 'same-origin'
571					});
572
573					if (response.ok) {
574						const data = await response.json();
575						if (data.status === 'success') {
576							await get_recapitulatif_basket_view();
577							if (document.querySelector(".panier-tab")) {
578								await get_tables_baskets()
579							}
580							if (document.querySelector("#delivery_area_all")) {
581								await get_delivery_mod_view();
582								await load_choix_livr();
583								await choix_pts_relais();
584							}
585						} else {
586							if (data.redirect) {
587								window.location.href = data.redirect; // Redirection vers la confirmation
588							}
589							document.querySelector("#input_basket_code_promo_error").classList.add("d-block");
590							document.querySelector("#input_basket_code_promo_error").innerText = data.message;
591						}
592					} else {
593						throw new Error('Response not OK');
594					}
595				} else {
596					if (document.querySelector("#input_basket_code_promo_error").classList.contains("d-block")) {
597						document.querySelector("#input_basket_code_promo_error").classList.remove("d-block");
598						document.querySelector("#input_basket_code_promo_error").innerText = "";
599					}
600				}
601			} catch (error) {
602				logDebug('Erreur lors de la requête :', error);
603			} finally {
604				hide_ajax_loader();
605			}
606		});
607	}
608
609}
610
611async function form_delete_promo() {
612	if (document.querySelector("#form_basket_delete_code_promo")) {
613		document.querySelector("#form_basket_delete_code_promo").addEventListener("submit", async function (event) {
614			event.preventDefault(); // Empêche l'envoi du formulaire si invalide
615			show_ajax_loader();
616			try {
617				const csrf_test_name = this.querySelector("[name=csrf_test_name]").value;
618
619				const params = new URLSearchParams();
620				params.append('csrf_test_name', csrf_test_name);
621
622				const response = await fetch(get_protocol_domain_name() + "/panier_v3/delete_code_promo", {
623					method: 'POST', headers: {
624						'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
625					}, body: params,
626					mode: 'cors',
627					credentials: 'same-origin'
628				});
629
630				if (response.ok) {
631					const data = await response.json();
632					if (data.status === 'success') {
633						await get_recapitulatif_basket_view();
634						if (document.querySelector(".panier-tab")) {
635							await get_tables_baskets()
636						}
637						if (document.querySelector("#delivery_area_all")) {
638							await get_delivery_mod_view();
639							await load_choix_livr();
640							await choix_pts_relais();
641						}
642					} else {
643						if (data.redirect) {
644							window.location.href = data.redirect; // Redirection vers la confirmation
645						}
646					}
647				} else {
648					throw new Error('Response not OK');
649				}
650			} catch (error) {
651				logDebug('Erreur lors de la requête :', error);
652			} finally {
653				hide_ajax_loader();
654			}
655		});
656
657	}
658}
659
660async function form_panier_mobile_coliship() {
661	const form = document.querySelector("#form_panier_mobile_coliship");
662	if (!form) return;
663
664	form.addEventListener("submit", async function (e) {
665		e.preventDefault();
666		show_ajax_loader();
667
668		const input = this.querySelector("#choix_livraison_mobile");
669		const reason = document.querySelector("#paiement_valider_reason_mobile");
670		input.setCustomValidity("");
671		reason?.classList.add("d-none");
672
673		try {
674			const params = new URLSearchParams();
675			params.append("csrf_test_name", this.querySelector("[name=csrf_test_name]")?.value || "");
676			params.append("mobile_coliship", input.value);
677
678			const response = await fetch(get_protocol_domain_name() + "/panier_v3/add_mobile_coliship", {
679				method: "POST",
680				headers: {
681					"Content-Type": "application/x-www-form-urlencoded",
682					"X-Requested-With": "XMLHttpRequest",
683					"Accept": "application/json",
684				},
685				body: params.toString(),
686				mode: "cors",
687				credentials: "same-origin",
688			});
689
690			if (!response.ok) throw new Error("Response not OK");
691			const data = await response.json();
692			if (data.success) {
693				const mobile = input.value.replace(/^0(?=[67]\d{8}$)/, "");
694				await cache_current_delivery_address(mobile);
695				await update_form_adresse_livraison();
696
697				var infos_form = {
698					"nom": document.querySelector("#nom_livraison").value,
699					"prenom": document.querySelector("#prenom_livraison").value,
700					"societe": document.querySelector("#entreprise_livraison").value,
701					"adresse_1": document.querySelector("#ad_livraison").value,
702					"adresse_2": document.querySelector("#complement_adresse_livraison").value,
703					"code_postal": document.querySelector("#cp_livraison").value,
704					"ville": document.querySelector("#ville_livraison").value,
705					"telephone": mobile,
706					"pays": document.querySelector("#pays_livraison").value,
707				};
708				infos_form["province"] = (document.querySelector("#province_livraison")) ? document.querySelector("#province_livraison").value : "";
709
710				await update_both_labels_info([], infos_form);
711
712				document.querySelector("#div_info_livraison")?.classList.add("d-none");
713			} else {
714				input.setCustomValidity(await trad("_MISSMATCH_MOBILE"));
715				reason?.classList.remove("d-none");
716				input.reportValidity();
717			}
718		} catch (err) {
719			input.setCustomValidity(await trad("_MISSMATCH_MOBILE"));
720			input.reportValidity();
721		} finally {
722			hide_ajax_loader();
723		}
724	});
725}
726
727
728async function form_panier_payment(form) {
729	removeError("payment");
730
731	let payment_mod = false;
732	if (form) {
733		payment_mod = form.querySelector("[name=choix_payment]:checked")?.value || "";
734	}
735	// Vérifie si un mode de paiement est sélectionné
736	if (!payment_mod || !form) {
737		addError("payment", await trad("_PAYMENT_NO_SELECTED"));
738		hide_ajax_loader();
739		return false; // ❌ Ne pas continuer si aucun paiement n'est sélectionné
740	}
741
742	return true;
743}
744
745// async function check_payment_conditions(form, maxRetries = 5, retries = 0) {
746// 	const csrf = form.querySelector("[name=csrf_test_name]").value;
747// 	const payment_mod = form.querySelector("[name=choix_payment]:checked").value;
748// 	const pays = form.querySelector("[name=pays]")?.value || "";
749// 	const pro = form.querySelector("[name=pro]").value;
750//
751// 	show_ajax_loader();
752// 	try {
753// 		const params = new URLSearchParams();
754// 		params.append('csrf_test_name', encodeURIComponent(csrf));
755// 		params.append('payment_name', encodeURIComponent(payment_mod));
756// 		params.append('pays', encodeURIComponent(pays));
757// 		params.append('pro', encodeURIComponent(pro));
758//
759// 		const response = await fetch(get_protocol_domain_name() + "/panier_v3/get_payment_conditions", {
760// 			method: 'POST',
761// 			headers: {
762// 				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
763// 			},
764// 			body: params,
765// 			mode: 'cors',
766// 			credentials: 'same-origin'
767// 		});
768//
769// 		if (response.ok) {
770// 			const result = await response.json();
771// 			if (result["card_max_amount"] > 0) {
772//
773// 			}
774// 			debugger;
775// 		} else {
776// 			throw new Error('Réponse non valide');
777// 		}
778// 	} catch (error) {
779// 		if (retries < maxRetries) {
780// 			return check_payment_conditions(form, maxRetries, retries + 1);
781// 		}
782// 	} finally {
783// 		// Cache toujours le loader après l'exécution (succès ou échec)
784// 		hide_ajax_loader();
785// 	}
786// }
787
788// Fonction auxiliaire pour les retries avec fetch
789
790
791async function set_identic_livraison_to_facturation(identic = true) {
792	const csrf_test_name = encodeURIComponent(document.querySelector("[name=csrf_test_name]").value);
793	const replace_adresse = encodeURIComponent(document.querySelector("[name=replace_adresse]").value);
794
795	const params = new URLSearchParams();
796	params.append('csrf_test_name', csrf_test_name);
797	params.append('replace_adresse', replace_adresse);
798
799	try {
800		show_ajax_loader();
801		const response = await fetchWithRetries(get_protocol_domain_name() + "/panier_v3/save_adresse_livraison_identic_to_facturation", {
802			method: 'POST', headers: {
803				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
804			}, body: params,
805			mode: 'cors',
806			credentials: 'same-origin'
807		});
808
809		if (response.ok) {
810			const responseData = await response.json();
811			if (responseData.error) {
812				logDebug("Error");
813			} else {
814
815				var infos_form = {
816					"nom": document.querySelector("#nom_facturation").value,
817					"prenom": document.querySelector("#prenom_facturation").value,
818					"societe": document.querySelector("#entreprise_facturation").value,
819					"adresse_1": document.querySelector("#ad_facturation").value,
820					"adresse_2": document.querySelector("#ad1_facturation").value,
821					"code_postal": document.querySelector("#cp_facturation").value,
822					"ville": document.querySelector("#ville_facturation").value,
823					"telephone": document.querySelector("#telephone_facturation").value,
824					"pays": document.querySelector("#pays_facturation").value,
825					"identic": identic
826				};
827				infos_form["province"] = (document.querySelector("#province_facturation")) ? document.querySelector("#province_facturation").value : "";
828
829				const promises = [];
830				promises.push(update_both_labels_info([], infos_form));
831				promises.push(update_form_adresse_livraison());
832				await Promise.all(promises);
833
834				// Attention la mise en cache de l'adresse de livraison doit impérativement être faites APRES update_form_adresse_livraison
835				// Dans le Promises.all rien n'assure que ce soit le cas.
836				await cache_current_delivery_address();
837
838				check_differente_adresse();
839
840				// PROVINCE
841				if (document.querySelector("#province")) {
842					document.querySelector("#province_div").innerHTML = "";
843				}
844				if (document.querySelector("#province_facturation") && document.querySelector("#province_facturation").value !== "") {
845					await get_provinces_html(document.querySelector("#pays_facturation").value, document.querySelector("#province_facturation").value, "facturation", document.querySelector("#pays_facturation").form);
846					jQuery('.province_toggle').show();
847				}
848				////
849			}
850			hide_ajax_loader();
851		} else {
852			hide_ajax_loader();
853		}
854	} catch (error) {
855		hide_ajax_loader();
856		logDebug('Erreur lors de la requête :', error);
857	}
858}
859function submit_panier_commentaire() {
860	let typingTimer; // Identifiant du timer, maintenant scoper à cette fonction
861	const doneTypingInterval = 1500; // Temps d'attente en millisecondes (1.30 secondes)
862
863	// Fonction pour enregistrer le commentaire
864	async function saveComment() {
865		const formulaire = document.querySelector("#form_panier_commentaire");
866		if (!validate_form(formulaire)) {
867			logDebug("Erreurs de validation du formulaire");
868			return false;
869		}
870
871		const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
872		const commentaire_basket = document.querySelector("#commentaire_basket") ? document.querySelector("#commentaire_basket").value : "";
873
874		const params = new URLSearchParams();
875		params.append('csrf_test_name', csrf_test_name);
876		params.append('commentaire_basket', commentaire_basket);
877
878		try {
879			const response = await fetch(get_protocol_domain_name() + "/panier_v3/save_basket_commentary", {
880				method: 'POST',
881				headers: {
882					'Content-Type': 'application/x-www-form-urlencoded',
883					'X-Requested-With': 'XMLHttpRequest'
884				},
885				body: params.toString(),
886				mode: 'cors',
887				credentials: 'same-origin'
888			});
889
890			if (response.ok) {
891				return true; // Retourner true pour indiquer le succès
892			} else {
893				return false;
894			}
895		} catch (error) {
896			logDebug('Erreur lors de la requête :', error);
897			return false;
898		}
899	}
900
901	// Événement pour détecter la saisie dans le textarea
902	const textarea = document.querySelector("#commentaire_basket");
903	if (textarea) {
904		textarea.addEventListener("keyup", () => {
905			clearTimeout(typingTimer); // Réinitialiser le timer
906			typingTimer = setTimeout(() => {
907				saveComment(); // Appeler la fonction après 2 secondes d'inactivité
908			}, doneTypingInterval);
909		});
910
911		textarea.addEventListener("keydown", () => {
912			clearTimeout(typingTimer); // Réinitialiser le timer si une touche est enfoncée
913		});
914	}
915}
916
917async function submit_panier_information(maxRetries = 5, retries = 0) {
918
919	var formulaire = document.querySelector("#form_panier_information");
920	if (!validate_form(formulaire)) {
921		logDebug("Erreurs de validation du formulaire");
922		return false;
923	}
924
925	let csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
926	let type_carte_grise = document.getElementById("type_carte_grise") ? document.querySelector("#type_carte_grise").value : "";
927	let numero_serie = document.getElementById("numero_serie") ? document.querySelector("#numero_serie").value : "";
928	let couleur_moto = document.getElementById("couleur_moto") ? document.querySelector("#couleur_moto").value : "";
929
930	let ask_for_verif = document.getElementById("flexCheckDefault") ? (document.querySelector("#flexCheckDefault").checked ? 1 : 0) : 0;
931
932	let params = new URLSearchParams();
933	params.append('csrf_test_name', csrf_test_name);
934	params.append('type_carte_grise', type_carte_grise);
935	params.append('numero_serie', numero_serie);
936	params.append('couleur_moto', couleur_moto);
937	params.append('ask_for_verif', ask_for_verif);
938	if (document.querySelector("#numero_serie") && document.querySelector("#numero_serie").getAttribute("minlength")) {
939		params.append('numero_serie_required', true);
940	}
941
942	try {
943		const response = await fetch_with_retries(get_protocol_domain_name() + "/panier_v3/save_basket_information", {
944			method: 'POST', headers: {
945				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
946			}, body: params.toString(),
947			mode: 'cors',
948			credentials: 'same-origin'
949		});
950		if (response.ok) {
951			return response.ok;
952		} else {
953			throw new Error('Nombre maximal de tentatives atteint');
954
955		}
956
957	} catch (error) {
958		logDebug('Erreur lors de la requête :', error);
959		return false;
960	}
961}
962
963async function submit_panier_cgv() {
964
965	var formulaire = document.querySelector("#form_panier_cgv");
966	if (!validate_form(formulaire)) {
967		logDebug("Erreurs de validation du formulaire");
968		return false;
969	}
970
971	let csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
972	let cgv = document.getElementById("checkbox_condition_vente").checked ? true : false;
973
974	let params = new URLSearchParams();
975	params.append('csrf_test_name', csrf_test_name);
976	params.append('cgv', cgv);
977	try {
978		const response = await fetch_with_retries(get_protocol_domain_name() + "/panier_v3/save_basket_cgv", {
979			method: 'POST', headers: {
980				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
981			}, body: params.toString(),
982			mode: 'cors',
983			credentials: 'same-origin'
984		});
985		if (response.ok) {
986			const result = await response.json();
987			if (result.url) {
988				window.location.href = result.url; // Redirection vers la confirmation
989			} else {
990				return result.res;
991			}
992		} else {
993
994		}
995
996	} catch (error) {
997		logDebug('Erreur lors de la requête :', error);
998		return false;
999	}
1000}
1001
1002async function update_both_labels_info(facturationInfos, livraisonInfos) {
1003	// show_ajax_loader();
1004	const [facturationResponse, livraisonResponse] = await Promise.all([update_labels_info_adresses("/panier_v3/get_basket_facturation_view", facturationInfos), update_labels_info_adresses("/panier_v3/get_basket_livraison_view", livraisonInfos)]);
1005	// Mettre à jour le DOM après avoir reçu les deux réponses
1006	if (livraisonResponse && facturationResponse) {
1007		// Exemple d'utilisation d'innerHTML pour mettre à jour le DOM
1008		document.querySelector("#collapse_basket_livraison").innerHTML = livraisonResponse;
1009		document.querySelector("#collapse_basket_facturation").innerHTML = facturationResponse;
1010
1011		// Réinitialiser les collapses après mise à jour du DOM
1012		gestion_collapse_adresse("facturation");
1013		gestion_collapse_adresse("livraison");
1014	} else {
1015		window.location.href = "/" + await trad('_ROUTE_PANIER_AFFICHER')
1016	}
1017}
1018
1019async function update_labels_info_adresses(url, infos_form) {
1020	var csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
1021
1022	const params = new URLSearchParams();
1023	params.append('csrf_test_name', csrf_test_name);
1024
1025	if (infos_form) {
1026		const field = url.includes("facturation") ? 'adresse_facturation' : 'adresse_livraison';
1027		params.append(field, JSON.stringify(infos_form)); // encodé automatiquement
1028	}
1029
1030	try {
1031		const response = await fetchWithRetries(get_protocol_domain_name() + url, {
1032			method: 'POST', headers: {
1033				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
1034			}, body: params,
1035			mode: 'cors',
1036			credentials: 'same-origin'
1037		});
1038
1039		if (response.ok) {
1040			return  await response.text();
1041		}
1042	} catch (error) {
1043		// Gérer les erreurs
1044		logDebug('Erreur lors de la requête :', error);
1045		throw error;
1046	}
1047}
1048
1049async function update_labels_info_adresse_livraison(infos_form) {
1050	var csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
1051	var params = 'csrf_test_name=' + encodeURIComponent(csrf_test_name);
1052	if (infos_form) {
1053		params += '&adresse_livraison=' + JSON.stringify(infos_form);
1054	}
1055	try {
1056		const response = await fetchWithRetries(get_protocol_domain_name() + "/panier_v3/get_basket_livraison_view", {
1057			method: 'POST', headers: {
1058				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
1059			}, body: params,
1060			mode: 'cors',
1061			credentials: 'same-origin'
1062		});
1063
1064		if (response.ok) {
1065			const data = await response.text();
1066			if (data == "false") {
1067				window.location.href = "/" + await trad('_ROUTE_PANIER_AFFICHER')
1068			} else {
1069				document.getElementById("collapse_basket_livraison").innerHTML = data;
1070				gestion_collapse_adresse("livraison");
1071			}
1072		} else {
1073			window.location.href = "/" + await trad('_ROUTE_PANIER_AFFICHER')
1074		}
1075	} catch (error) {
1076		// Gérer les erreurs
1077		logDebug('Erreur lors de la requête :', error);
1078	}
1079}
1080
1081async function update_delivery_area_info_adresse_livraison(num_panier, maxRetries = 5, retries = 0) {
1082	const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
1083
1084	const params = new URLSearchParams();
1085	params.append('csrf_test_name', csrf_test_name);
1086	params.append('num_panier', num_panier);
1087
1088	try {
1089		const response = await fetch(get_protocol_domain_name() + "/panier_v3/get_adresse_livraison_view", {
1090			method: 'POST', headers: {
1091				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
1092			}, body: params,
1093			mode: 'cors',
1094			credentials: 'same-origin'
1095		});
1096
1097		if (response.ok) {
1098			const data = await response.text();
1099			document.getElementById("views_panier_livraison_" + num_panier).innerHTML = data;
1100		} else {
1101			if (retries < maxRetries) {
1102				retries++;
1103				logDebug("Tentative " + retries + " de " + maxRetries);
1104				// Réessayer la requête
1105				return update_delivery_area_info_adresse_livraison(num_panier, maxRetries, retries);
1106			} else {
1107				throw new Error('Nombre maximal de tentatives atteint');
1108			}
1109		}
1110	} catch (error) {
1111		// Gérer les erreurs
1112		logDebug('Erreur lors de la requête :', error);
1113	}
1114}
1115
1116async function update_form_adresse_livraison(maxRetries = 5, retries = 0) {
1117	var csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
1118	var params = 'csrf_test_name=' + encodeURIComponent(csrf_test_name);
1119
1120	try {
1121		const response = await fetch(get_protocol_domain_name() + "/panier_v3/get_form_adresse_livraison_view", {
1122			method: 'POST', headers: {
1123				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
1124			}, body: params,
1125			mode: 'cors',
1126			credentials: 'same-origin'
1127		});
1128
1129		if (response.ok) {
1130			const data = await response.text();
1131			document.getElementById("basket_form_livraison").innerHTML = data;
1132			set_prefix_by_coutry(document.querySelector("#pays_livraison").value, "livraison")
1133
1134			document.querySelector("#cp_livraison").addEventListener("change", async function () {
1135				document.querySelector("#cp_livraison").value = document.querySelector("#cp_livraison").value.trim();
1136				document.querySelector("#cp_livraison").value = document.querySelector("#cp_livraison").value.toUpperCase();
1137				await check_cp(document.getElementById("basket_form_livraison"), "livraison");
1138			});
1139
1140			if (document.querySelector("#check_differente_adresse")) check_differente_adresse();
1141
1142			await form_adr_liv();
1143		} else {
1144			if (retries < maxRetries) {
1145				retries++;
1146				logDebug("Tentative " + retries + " de " + maxRetries);
1147				// Réessayer la requête
1148				return update_form_adresse_livraison(maxRetries, retries);
1149			} else {
1150				throw new Error('Nombre maximal de tentatives atteint');
1151			}
1152		}
1153	} catch (error) {
1154		// Gérer les erreurs
1155		logDebug('Erreur lors de la requête :', error);
1156	}
1157}
1158
1159function disabled_inputs_form_adresse_livraison(disabled = true) {
1160	document.getElementById("ad_livraison").disabled = disabled;
1161	document.getElementById("complement_adresse_livraison").disabled = disabled;
1162	document.getElementById("cp_livraison").disabled = disabled;
1163	document.getElementById("ville_livraison").disabled = disabled;
1164	document.getElementById("check_differente_adresse").checked = false;
1165}
1166
1167///////////////////////////////
1168
1169function check_differente_adresse() {
1170	document.querySelector("#check_differente_adresse").addEventListener("change", async function () {
1171		if (this.checked) {
1172			var myCollapse_2 = document.querySelector("#basket_form_livraison");
1173			var bsCollapse_2 = new bootstrap.Collapse(myCollapse_2, {toggle: false});
1174			bsCollapse_2.hide();
1175			var infos_form = [];
1176
1177			infos_form["collapse"] = false;
1178			// const promises = [];
1179
1180			// promises.push(set_identic_livraison_to_facturation());
1181			await set_identic_livraison_to_facturation();
1182			// promises.push(update_both_labels_info(infos_form));
1183			//
1184			// await Promise.all(promises);
1185		}
1186	});
1187}
1188
1189// async function verif_is_pts_relais() {
1190// 	if (document.getElementById("is_pts_relais").value === "true") {
1191// 		return false;
1192// 	}
1193// }
1194
1195///////////////
1196// Fonction pour ajouter un élément au panier
1197
1198function add_basket() {
1199	document.querySelectorAll(".JS_table_panier_parts form").forEach(function (form) {
1200		form.addEventListener("submit", function (event) {
1201			event.preventDefault();
1202			addToBasket(form);
1203		});
1204	});
1205
1206	document.querySelectorAll("#table_panier_shop form").forEach(function (form) {
1207		form.addEventListener("submit", function (event) {
1208			event.preventDefault();
1209			addToBasket(form);
1210		});
1211	});
1212}
1213
1214function addToBasket(form) {
1215	show_ajax_loader();
1216	var csrf_test_name = getInputValue(form, 'input[name=csrf_test_name]');
1217
1218	var type_add_basket = getInputValue(form, 'input[name=type_add_basket]');
1219	var params = new URLSearchParams();
1220	params.append('csrf_test_name', csrf_test_name);
1221	params.append('type_add_basket', type_add_basket);
1222
1223	params.append('recherche', getInputValue(form, 'input[name=id]'));
1224	params.append('libelle_piece', getInputValue(form, 'input[name=libelle_piece]'));
1225
1226	const unite_de_vente = getInputValue(form, 'input[name=unite_de_vente]') || 1;
1227
1228	params.append('unite_de_vente', unite_de_vente);
1229
1230	switch(type_add_basket) {
1231		case "stop_affaire":
1232			params = addToBasketStopAffaire(form,params);
1233			break;
1234		case "parts":
1235			params = addToBasketParts(form,params);
1236			break;
1237		case "shop":
1238			params = addToBasketShop(form,params);
1239			break;
1240		case "classic_red":
1241			params = addToBasketClassicRed(form,params);
1242			break;
1243
1244	}
1245
1246
1247	fetch(get_protocol_domain_name() + "/panier_v3/add_basket", {
1248		method: "POST",
1249		headers: {
1250			'Content-Type': 'application/x-www-form-urlencoded',
1251			'X-Requested-With': 'XMLHttpRequest'
1252		},
1253		body: params
1254	})
1255		.then(response => response.text())
1256		.then(data => {
1257			const response = JSON.parse(data);
1258			if (response["stop_here"]) {
1259				updateBasketModal(csrf_test_name, response);
1260			} else {
1261				document.querySelectorAll('.resultat_ajout_panier').forEach(function (element) {
1262					element.innerHTML = data;
1263				});
1264				updateBasketModal(csrf_test_name, params);
1265			}
1266
1267		})
1268		.catch(error => logDebug("Erreur lors de l'ajout au panier:", error)).finally(hide_ajax_loader);
1269
1270}
1271
1272function addToBasketTarifPortSupp(form,params) {
1273	return params;
1274
1275}
1276function addToBasketParts(form,params) {
1277	if (getInputValue(form, 'input[name=qte_table_parts]')) {
1278		params.append('quantite', getInputValue(form, 'input[name=qte_table_parts]'));
1279	} else {
1280		params.append('quantite', getInputValue(form, 'input[name=qty_shop]'));
1281	}
1282	return params;
1283}
1284
1285function addToBasketTarif(form,params) {
1286	params.append('vehicule', getInputValue(form, 'input[name=vehicule]'));
1287	params.append('id_v', getInputValue(form, 'input[name=id_v]'));
1288	params.append('v', getInputValue(form, 'input[name=v]'));
1289	params.append('v_n', getInputValue(form, 'input[name=v_n]'));
1290	params.append('quantite', getInputValue(form, 'input[name=qty_shop]'));
1291	return params;
1292
1293}
1294
1295function addToBasketShop(form,params) {
1296	params.append('id_prod', getInputValue(form, 'input[name=id_prod]'));
1297	params.append('codecat', getInputValue(form, 'input[name=codecat]'));
1298	params.append('type_commande', getInputValue(form, 'input[name=type_commande]'));
1299	params.append('quantite', getInputValue(form, 'input[name=qty_shop]'));
1300
1301	return params;
1302
1303}
1304
1305function addToBasketClassicRed(form,params) {
1306	params.append('quantite', getInputValue(form, 'input[name=qty]'));
1307	params.append('id_prod', getInputValue(form, 'input[name=id_prod]'));
1308	params.append('codecat', getInputValue(form, 'input[name=codecat]'));
1309	params.append('type_commande', getInputValue(form, 'input[name=type_commande]'));
1310	params.append('prix_achat', getInputValue(form, 'input[name=prix_achat]'));
1311
1312	return params;
1313
1314}
1315
1316function  addToBasketStopAffaire(form,params) {
1317	params.append('quantite', getInputValue(form, 'input[name=qty_shop-sa]'));
1318	return params;
1319}
1320
1321function updateBasketModal(csrf_test_name,params) {
1322	if (!(params instanceof URLSearchParams)) {
1323		params = new URLSearchParams(params);
1324	}
1325	params.append("csrf_test_name",csrf_test_name);
1326
1327	fetch(get_protocol_domain_name() + "/panier_v3/panier_modal", {
1328		method: "POST",
1329		headers: {
1330			"Content-Type": "application/x-www-form-urlencoded"
1331		},
1332		body: params
1333	})
1334		.then(response => response.text())
1335		.then(data => {
1336			if (document.getElementById('panier_modal')) {
1337				document.getElementById('panier_modal').innerHTML = data;
1338				showModal('basket_modal_add_items');
1339			}
1340
1341		})
1342		.catch(error => logDebug("Erreur lors de la mise à jour du panier:", error));
1343}
1344
1345// Fonction principale pour ajouter un écouteur d'événement sur chaque formulaire de panier
1346function action_update_line_basket() {
1347	const qtyMinusButtons = document.querySelectorAll('.qty-count-panier--minus');
1348	const qtyPlusButtons = document.querySelectorAll('.qty-count-panier--add');
1349	const qtyInputs = document.querySelectorAll('.product-qty-panier');
1350
1351	let updateTimer;
1352	const debounceDelay = 300; // Délai avant mise à jour
1353
1354	// Fonction pour mettre à jour la quantité
1355	function updateQuantity(input, newQty) {
1356		input.value = newQty;
1357		input.dataset.previousQty = newQty;
1358	}
1359
1360	// Fonction de debounce pour gérer la mise à jour
1361	function handleUpdate(input) {
1362		clearTimeout(updateTimer);
1363
1364		const priceElements =[];
1365
1366		let priceElement = input.closest('.tr-panier').querySelector('.basket_price');
1367
1368		if (priceElement && !priceElement.classList.contains('spinner-border')) {
1369			priceElements.push(priceElement);
1370		}
1371
1372		// Ajouter la classe placeholder pour tous les éléments de priceElements
1373		priceElements.forEach(el => addSpinner(el));
1374		toggleQtyButtons(input, true);
1375
1376		updateTimer = setTimeout(() => {
1377
1378			const form = input.closest('form');
1379			update_line_basket(form).then(() => {
1380				setTimeout(() => {
1381					priceElements.forEach(el => removeSpinner(el));
1382					toggleQtyButtons(input, false);
1383				}, 200);
1384			}).catch(error => {
1385				logDebug("Erreur de mise à jour:", error);
1386				priceElements.forEach(el => removeSpinner(el));
1387				toggleQtyButtons(input, false);
1388			});
1389		}, debounceDelay);
1390	}
1391
1392	function toggleQtyButtons(input, disabled) {
1393		const container = input.closest('.qty-input');
1394		if (!container) return;
1395
1396		const minusBtn = container.querySelector('.qty-count-panier--minus');
1397		const plusBtn = container.querySelector('.qty-count-panier--add');
1398
1399		if (minusBtn) minusBtn.disabled = disabled;
1400		if (plusBtn) plusBtn.disabled = disabled;
1401	}
1402
1403	function addSpinner(element) {
1404		const spinnerHTML = `<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>`;
1405		const priceContent = element.textContent; // Sauvegarder le texte actuel
1406
1407		// Ajouter un data attribut pour conserver l'ancien texte
1408		element.setAttribute('data-original-content', priceContent.trim());
1409		element.innerHTML = spinnerHTML; // Remplacer par le spinner
1410	}
1411
1412	// Fonction pour enlever le spinner et restaurer le contenu original
1413	function removeSpinner(element) {
1414		const originalContent = element.getAttribute('data-original-content');
1415		if (originalContent !== null) {
1416			element.textContent = originalContent; // Restaurer le texte original
1417			element.removeAttribute('data-original-content'); // Supprimer l'attribut temporaire
1418		}
1419	}
1420
1421
1422	// Ajouter les écouteurs d'événements pour les boutons -
1423	qtyMinusButtons.forEach(button => {
1424		button.addEventListener('click', function () {
1425			const input = this.nextElementSibling;
1426			// récupération de la valeur du pas d'incrementation
1427			const increment = parseInt(this.parentElement.dataset.unite) || 1;
1428			let currentQty = parseInt(input.value) || 0;
1429
1430			if (currentQty >= increment) {
1431				currentQty -= increment;
1432				updateQuantity(input, currentQty);
1433				if(document.getElementById('view_step_basket')) handleUpdate(input);
1434			}
1435
1436			if (currentQty === 0) {
1437				const id = input.id.split('_').pop();
1438				const form = input.closest('form');
1439
1440				const onConfirm = () => delete_line_basket(form);
1441				const onCancel = () => {
1442					updateQuantity(input, currentQty + increment);
1443					if(document.getElementById('view_step_basket')) handleUpdate(input)
1444				}
1445
1446				open_modal_delete_line_basket(id, onConfirm, onCancel);
1447			}
1448		});
1449	});
1450
1451	// Ajouter les écouteurs d'événements pour les boutons +
1452	qtyPlusButtons.forEach(button => {
1453		button.addEventListener('click', function () {
1454			const input = this.previousElementSibling;
1455			// récupération de la valeur du pas d'incrementation
1456			const increment = parseInt(this.parentElement.dataset.unite) || 1;
1457			let currentQty = parseInt(input.value) || 0;
1458			const maxQty = parseInt(input.getAttribute('max'));
1459
1460			if (isNaN(maxQty) || currentQty < maxQty) {
1461				currentQty += increment;
1462				updateQuantity(input, currentQty);
1463				if(document.getElementById('view_step_basket')) handleUpdate(input);
1464			}
1465		});
1466	});
1467
1468	// Écouteurs pour les inputs de quantité
1469	qtyInputs.forEach(input => {
1470		let previousQty = input.value;
1471
1472		input.addEventListener('focus', function () {
1473			previousQty = this.value;
1474		});
1475
1476		input.addEventListener('keydown', function (event) {
1477			if (event.key === 'Enter') {
1478				event.preventDefault();
1479				handleUpdate(this);
1480			}
1481		});
1482
1483		input.addEventListener('change', function () {
1484			const currentQty = parseInt(this.value) || 0;
1485
1486			if (currentQty === 0) {
1487				const id = this.id.split('_').pop();
1488				const form = this.closest('form');
1489
1490				const onConfirm = () => delete_line_basket(form);
1491				const onCancel = () => updateQuantity(this, previousQty);
1492
1493				open_modal_delete_line_basket(id, onConfirm, onCancel);
1494			} else {
1495				updateQuantity(this, currentQty);
1496				handleUpdate(this);
1497			}
1498		});
1499
1500		// Empêche la soumission du formulaire parent si défini
1501		const form = input.closest('form');
1502		if (form) {
1503			form.addEventListener('submit', event => event.preventDefault());
1504		}
1505	});
1506}
1507
1508function open_modal_delete_line_basket(id, onConfirm, onCancel) {
1509
1510	if (isModalOpen) {
1511		return;
1512	}
1513	const modal = document.getElementById('modal_supp_' + id);
1514	const modalInstance = bootstrap.Modal.getOrCreateInstance(modal);
1515
1516	isModalOpen = true;
1517
1518	modal.querySelector('.btn-confirm').onclick = () => {
1519		onConfirm();
1520		modalInstance.hide();
1521	};
1522
1523	modal.querySelector('.btn-cancel').onclick = () => {
1524		onCancel();
1525		modalInstance.hide();
1526	};
1527
1528	// Écouter l'événement de fermeture du modal
1529	modal.addEventListener('hidden.bs.modal', () => {
1530		isModalOpen = false;
1531		onCancel();
1532		modalInstance.hide();
1533
1534	});
1535
1536	modalInstance.show();
1537}
1538
1539function action_delete_line_basket() {
1540	var modals_supp = document.querySelectorAll(".modal_supp");
1541	var form_modal_delete = "";
1542	for (var x = 0; x < modals_supp.length; x++) {
1543		form_modal_delete = modals_supp[x].querySelector("[name=form_panier_supp]");
1544		form_modal_delete.addEventListener("submit", async function (event) {
1545			event.preventDefault();
1546			await delete_line_basket(this);
1547		});
1548	}
1549
1550}
1551
1552async function delete_line_basket(form) {
1553	var params = new URLSearchParams();
1554	params.append('csrf_test_name', document.querySelector("[name=csrf_test_name]").value);
1555
1556	if (form.querySelector("[name=id_ligne]")) {
1557		params.append('id_ligne', form.querySelector("[name=id_ligne]").value);
1558		params.append('id_entete', form.querySelector("[name=id_entete]").value);
1559	}
1560
1561	if (form.querySelector("[name=code_promo]")) {
1562		params.append('code_promo', form.querySelector("[name=code_promo]").value);
1563		if (document.querySelector("#JS_collapse_code_promo")) {
1564			document.querySelector("#JS_collapse_code_promo").innerHTML = await trad("_FORM_PANIER_CODE_PROMO_MISSING");
1565		}
1566	}
1567
1568	fetch(get_protocol_domain_name() + "/panier_v3/supprimer_panier_ligne", {
1569		method: 'POST', headers: {
1570			'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
1571		}, body: params, mode: 'cors', // Optionally set the CORS mode
1572		credentials: 'same-origin' // Include cookies in the request (if any)
1573	}).then(function (response) {
1574		return response.json();
1575	}).then(function (res) {
1576		if (res["nb_ligne"] == 0 && res["url"]) {
1577			window.location.href = res["url"];
1578		} else {
1579			var promise_get_tables_basket = get_tables_baskets(form.closest(".div_panier_table"), true);
1580			promise_get_tables_basket.then(function () {
1581
1582			}).catch(function (error) {
1583				logDebug(error);
1584			});
1585
1586			refresh_compteur_panier(res["nb_ligne"]);
1587
1588			// check_pts_rts_relais();
1589			var modal = bootstrap.Modal.getOrCreateInstance(document.getElementById("modal_supp_" + params.get('id_ligne')));
1590			modal.hide();
1591
1592			if (form.querySelector("[name=code_promo]")) {
1593				unset_free_delivery();
1594			}
1595		}
1596	}).catch(function (error) {
1597		logDebug('Error:', error);
1598	});
1599
1600}
1601
1602function update_line_basket(form) {
1603	var params = new URLSearchParams();
1604	params.append('csrf_test_name', document.querySelector("[name=csrf_test_name]").value);
1605
1606	if (form.querySelector("[name=id_ligne]")) {
1607		params.append('id_ligne', form.querySelector("[name=id_ligne]").value);
1608		params.append('id_entete', form.querySelector("[name=id_entete]").value);
1609		params.append('qty', form.querySelector("[name=product-qty]").value);
1610	}
1611
1612	var qty = parseInt(params.get('qty'), 10);
1613	if (qty === 0) {
1614		const onConfirm = () => {
1615			delete_line_basket(form);
1616		};
1617
1618		const onCancel = () => {
1619			return Promise.resolve();
1620		};
1621
1622		open_modal_delete_line_basket(params.get('id_ligne'), onConfirm, onCancel);
1623		return Promise.resolve();
1624	} else {
1625		return fetch(get_protocol_domain_name() + "/panier_v3/update_panier_ligne", {
1626			method: 'POST', headers: {
1627				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
1628			}, body: params, mode: 'cors', // Optionally set the CORS mode
1629			credentials: 'same-origin' // Include cookies in the request (if any)
1630		}).then(function (response) {
1631			return response.json();
1632		}).then(function (res) {
1633			if (res["nb_ligne"] == 0 && res["url"]) {
1634				location.href = res["url"];
1635			} else {
1636				return get_tables_baskets(form.closest(".div_panier_table"));
1637
1638			}
1639		}).catch(function (error) {
1640			logDebug('Error:', error);
1641		});
1642	}
1643}
1644
1645function get_tables_baskets(table, loader = false) {
1646	if (loader) {
1647		show_ajax_loader();
1648	}
1649	return new Promise(function (resolve, reject) {
1650		fetch(get_protocol_domain_name() + "/panier_v3/ajax_get_tables_baskets", {
1651			method: "GET", headers: {
1652				"Content-Type": "application/json", "X-Requested-With": "XMLHttpRequest"
1653			}
1654		})
1655			.then(function (response) {
1656				if (response.ok) {
1657					return response.text();
1658				} else {
1659					throw new Error("get_tables_baskets failed with status: " + response.status);
1660				}
1661			})
1662			.then(async function (data) {
1663				if (table) {
1664					table.innerHTML = data;
1665				} else {
1666					document.querySelector("#view_step_basket").innerHTML = data;
1667				}
1668
1669				action_delete_line_basket();
1670				action_update_line_basket();
1671				reload_view_header_contact_concess();
1672				await get_recapitulatif_basket_view();
1673				await get_basket_footer_message();
1674
1675				resolve(true);
1676			})
1677			.catch(function (error) {
1678				reject(error);
1679			}).finally(hide_ajax_loader);
1680	});
1681}
1682
1683
1684async function get_vehicule() {
1685	var csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
1686	var id = jQuery('#panier_select_vehicule').val();
1687	var vhc_selected = id !== 'autre' ? 'true' : 'false';
1688
1689	var params = new URLSearchParams();
1690	params.append('id', id);
1691	params.append('csrf_test_name', csrf_test_name);
1692	params.append('vhc_selected', vhc_selected);
1693
1694	try {
1695		const response = await fetch('/panier_v3/get_vehicule', {
1696			method: 'POST', headers: {
1697				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
1698			}, body: params.toString(),
1699			mode: 'cors',
1700			credentials: 'same-origin'
1701		});
1702
1703		if (response.ok) {
1704			const vehicule = await response.json();
1705
1706			jQuery('#numero_serie').removeAttr("value").val(vehicule.numero_serie);
1707			jQuery('#type_carte_grise').removeAttr("value").val(vehicule.carte_grise);
1708			jQuery('#couleur_moto').removeAttr("value").val(vehicule.couleur);
1709		} else {
1710			logDebug('Erreur lors de la requête :', response.statusText);
1711		}
1712	} catch (error) {
1713		logDebug('Erreur lors de la requête :', error);
1714	}
1715}
1716
1717function refresh_compteur_panier(nb_ligne) {
1718	var res_ajout_panier = document.querySelectorAll(".resultat_ajout_panier")
1719	for (var i = 0; i < res_ajout_panier.length; i++) {
1720		res_ajout_panier[i].innerHTML = nb_ligne;
1721	}
1722}
1723
1724// Ajout des écouteurs d'événements pour les boutons
1725
1726window.onload = () => {
1727	if (document.getElementById("next_basket") || document.getElementById("back_basket")) {
1728		init_navigation();
1729	}
1730	remove_placeholders();
1731};
1732
1733function add_placeholders(button) {
1734	button.classList.add("placeholder");
1735	// button.classList.add("placeholder-dynamique");
1736	button.classList.add("disabled");
1737	button.disbaled = true;
1738}
1739function remove_placeholders() {
1740	// Sélectionne tous les boutons avec la classe "placeholder"
1741	const placeholders = document.querySelectorAll("button.placeholder");
1742	placeholders.forEach(button => {
1743
1744		//Specifique payment
1745		const alertExists = document.querySelector("#basket_payment_alert");
1746
1747		if (button.id !== "next_basket" || !alertExists) {
1748				button.classList.remove("placeholder"); // Retire la classe
1749				button.classList.remove("disabled"); // Retire la classe
1750				button.disabled = false; // Réactive le bouton
1751		}
1752	});
1753}
1754function init_navigation() {
1755	if (document.getElementById("next_basket")) {
1756		document.getElementById("next_basket").addEventListener("click", nextStep);
1757		document.getElementById("next_basket").addEventListener("touchstart", nextStep);
1758	}
1759	if (document.getElementById("back_basket")) {
1760		document.getElementById("back_basket").addEventListener("click", previousStep);
1761		document.getElementById("back_basket").addEventListener("touchstart", previousStep);
1762
1763	}
1764}
1765
1766async function validateAddressStep() {
1767	let formIsValid = true;
1768	removeError("adr_errors");
1769
1770	// 🔹 Validation du formulaire de facturation
1771	if (document.querySelector("#form_adr_fact")) {
1772		await check_tva_intracom(document.querySelector("#form_adr_fact"), "facturation");
1773		await Promise.all(promises_form_fac);
1774
1775		const formFact = document.querySelector("#form_adr_fact");
1776		const validFact = validate_form(formFact);
1777
1778		if (!validFact && !document.querySelector("#basket_form_facturation").classList.contains("show")) {
1779			new bootstrap.Collapse("#basket_form_facturation").show();
1780		} else if (document.querySelector("#basket_form_facturation").classList.contains("show")) {
1781			addError("adr_errors", await trad("_JS_CART_FORM_OPEN"));
1782			form_validation(formFact);
1783			formIsValid = false;
1784		}
1785	}
1786
1787	// 🔹 Validation du formulaire de livraison
1788	if (formIsValid) {
1789		if (document.querySelector("#form_adr_liv")) {
1790			const formLiv = document.querySelector("#form_adr_liv");
1791			const validLiv = validate_form(formLiv);
1792
1793			if (!validLiv && !document.querySelector("#basket_form_livraison").classList.contains("show")) {
1794				new bootstrap.Collapse("#basket_form_livraison").show();
1795			} else if (document.querySelector("#basket_form_livraison").classList.contains("show")) {
1796				addError("adr_errors", await trad("_JS_CART_FORM_OPEN"));
1797				form_validation(formLiv);
1798				formIsValid = false;
1799			}
1800		}
1801	}
1802
1803	if (formIsValid) {
1804		if (document.querySelector("#div_info_livraison") && !document.querySelector("#div_info_livraison").classList.contains("d-none")) {
1805			document.querySelector("#alert_telephone").classList.add("d-block");
1806			formIsValid = false;			
1807		}
1808	}
1809
1810	return formIsValid;
1811}
1812
1813
1814// 📌 Vérifie la validité du paiement
1815async function validatePaymentStep() {
1816	let formIsValid = true;
1817
1818	// 🔹 Validation du formulaire d'information
1819	if (document.querySelector("#form_panier_information")) {
1820		formIsValid = validate_form(document.querySelector("#form_panier_information")) && formIsValid;
1821	}
1822
1823	if (formIsValid) {
1824		const form = document.getElementById("form_basket_payment");
1825		formIsValid = await form_panier_payment(form);
1826	}
1827	return formIsValid;
1828}
1829
1830// 📌 Effectue la requête AJAX pour passer à l'étape suivante
1831async function submitNextStep(step, maxRetries, retries) {
1832	let csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
1833	const params = new URLSearchParams({
1834		step: step,
1835		action: "next",
1836		csrf_test_name: csrf_test_name,
1837	});
1838
1839	// 🔹 Loader timeout pour affichage si délai > 250ms
1840	let loaderTimeout = setTimeout(show_ajax_loader, 200);
1841
1842	if (step === "step_payment") {
1843		// 🔹 Vérifie si la case CGV est présente et ajoute sa valeur
1844		const cgvCheckbox = document.getElementById("checkbox_condition_vente");
1845		if (cgvCheckbox) {
1846			params.append("cgv_check", cgvCheckbox.checked);
1847		}
1848
1849		// 🔹 Récupère la valeur du bouton radio sélectionné dans le formulaire de paiement
1850		const selectedPayment = document.querySelector("#form_basket_payment [name=choix_payment]:checked");
1851		if (selectedPayment) {
1852			params.append("payment", selectedPayment.value);
1853		}
1854	}
1855
1856	try {
1857		const response = await fetch_with_retries(
1858			get_protocol_domain_name() + "/panier_v3/navigation",
1859			{
1860				method: 'POST',
1861				headers: {
1862					'Content-Type': 'application/x-www-form-urlencoded',
1863					'X-Requested-With': 'XMLHttpRequest'
1864				},
1865				body: params.toString(),
1866				mode: 'cors',
1867				credentials: 'same-origin'
1868			},
1869			maxRetries,
1870			retries
1871		);
1872
1873		clearTimeout(loaderTimeout);
1874
1875		if (response.ok) {
1876			const responseData = await response.json();
1877			if (responseData.valid) {
1878				if (responseData.requires_form_submission) {
1879					try {
1880						const submissionResult = await submitGeneratedForm(
1881							responseData.form_action,
1882							responseData.form_fields
1883						);
1884					} catch (formError) {
1885						logDebug("Erreur lors de la soumission asynchrone du formulaire :", formError);
1886						hide_ajax_loader();
1887
1888					}
1889				} else if (responseData.path){
1890					switch (responseData.path) {
1891						case "views_form_google_pay":
1892							const googlePayButton = document.querySelector("#views_form_google_pay #container button");
1893							if (googlePayButton) {
1894								await transaction_on_progress();
1895								googlePayButton.click();
1896							} else {
1897								logDebug("Bouton Google Pay introuvable !");
1898							}
1899							break;
1900						case "views_form_paypal":
1901							const paypalForm = document.querySelector("#views_form_paypal form");
1902							if (paypalForm) {
1903								await transaction_on_progress();
1904								paypalForm.submit(); // 🔹 Soumet automatiquement le formulaire
1905							} else {
1906								logDebug("Formulaire PayPal introuvable !");
1907							}
1908							break;
1909						case "views_form_bank_hondapl":
1910							const bankLink = document.querySelector("#views_form_bank_hondapl a");
1911							if (bankLink) {
1912								await transaction_on_progress();
1913								bankLink.click();
1914							} else {
1915								logDebug("Lien bancaire introuvable !");
1916							}
1917							break;
1918						case "views_form_bank_hondaua":
1919							const hondaUaForm = document.querySelector("#views_form_bank_hondaua form");
1920							if (hondaUaForm) {
1921								try {
1922									await transaction_on_progress();
1923									hondaUaForm.submit();
1924								} catch (error) {
1925									logDebug("Impossible de soumettre le formulaire");
1926								}
1927							} else {
1928								logDebug("Formulaire Honda UA introuvable !");
1929							}
1930							break;
1931						case "views_form_bank_hondath":
1932							const hondaThForm = document.querySelector("#views_form_bank_hondath form");
1933							if (hondaThForm) {
1934								try {
1935									await transaction_on_progress();
1936									hondaThForm.submit();
1937								} catch (error) {
1938									logDebug("Impossible de soumettre le formulaire");
1939								}
1940							} else {
1941								logDebug("Formulaire Honda UA introuvable !");
1942							}
1943							break;
1944					}
1945				} else {
1946					window.location.href = responseData.url;
1947				}
1948			} else {
1949				if (responseData.is_multi_basket) {
1950					if (document.querySelector("#delivery_area_all")) {
1951						await get_delivery_mod_view();
1952						await load_choix_livr();
1953						await choix_pts_relais();
1954					}
1955				}
1956
1957				if (responseData.error_return) {
1958					window.location.reload();
1959				}
1960
1961				await get_navigation(responseData.msg);
1962				hide_ajax_loader();
1963			}
1964		}
1965	} catch (error) {
1966		logDebug('Error in submitNextStep : ', error);
1967		hide_ajax_loader();
1968		clearTimeout(loaderTimeout);
1969	}
1970}
1971
1972async function submitGeneratedForm(formAction, formFields) {
1973	show_ajax_loader();
1974	let csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
1975	const params = new URLSearchParams({
1976		csrf_test_name: csrf_test_name,
1977	});
1978	params.append("type", formFields);
1979	try {
1980		const response = await fetch(get_protocol_domain_name() + formAction, {
1981			headers: {
1982				'Content-Type': 'application/x-www-form-urlencoded',
1983			},
1984			method: 'POST',
1985			body: params,
1986			mode: 'cors',
1987			credentials: 'same-origin'
1988		});
1989		if (!response.ok) {
1990			logDebug("Erreur lors de la soumission du formulaire :", response.statusText);
1991			hide_ajax_loader();
1992			throw new Error('Form submission failed');
1993		} else {
1994			const responseData = await response.json();
1995			if (responseData.valid && responseData.url) {
1996				window.location.href = responseData.url; // 🔹 Redirection en JS
1997			} else {
1998				hide_ajax_loader();
1999			}
2000		}
2001
2002	} catch (error) {
2003		logDebug("Erreur réseau lors de la soumission du formulaire :", error);
2004		hide_ajax_loader();
2005		throw error;
2006	}
2007}
2008// 📌 Fonction principale orchestrant les étapes
2009async function nextStep(maxRetries = 5, retries = 0) {
2010	const step = document.querySelector("#step_basket").value;
2011	let formIsValid = true;
2012
2013	if (step === "step_address") {
2014		formIsValid = await validateAddressStep();
2015	} else if (step === "step_payment") {
2016		show_ajax_loader();
2017		formIsValid = await validatePaymentStep();
2018		removeError("payment_open");
2019		if (document.getElementById("checkbox_condition_vente")) {
2020			removeError("cgv");
2021			if (!document.getElementById("checkbox_condition_vente").checked) {
2022				addError("cgv",await trad("_NEED_CGV"));
2023			}
2024		}
2025	} else if (step === "step_divers") {
2026		const promises = [];
2027		if (document.querySelector("#form_panier_information")) {
2028			promises.push(submit_panier_information());
2029		}
2030		if (promises.length > 0) {
2031			await Promise.all(promises);
2032		}
2033	}
2034	if (have_errors() && formIsValid) {
2035		formIsValid = false;
2036	}
2037	if (formIsValid) {
2038		await submitNextStep(step, maxRetries, retries);
2039	} else {
2040		hide_ajax_loader();
2041	}
2042}
2043
2044// Fonction pour le bouton "Retour"
2045async function previousStep(maxRetries = 5, retries = 0) {
2046	const step = document.querySelector("#step_basket").value;
2047	let csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
2048
2049	const params = new URLSearchParams();
2050	params.append('step', step);
2051	params.append('action', "previous");
2052	params.append('csrf_test_name', csrf_test_name);
2053
2054	// Variable de controle de délai
2055	let loaderTimeout
2056	// Démarre le timer pour vérifier si l'utilisateur attend plus de 250ms
2057	loaderTimeout = setTimeout(() => {
2058		show_ajax_loader(); // Affiche le loader si le délai dépasse 250ms
2059	}, 200);
2060	try {
2061
2062		const response = await fetch(get_protocol_domain_name() + "/panier_v3/navigation", {
2063			method: 'POST', headers: {
2064				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
2065			}, body: params.toString(),
2066			mode: 'cors',
2067			credentials: 'same-origin'
2068		});
2069
2070		// Lorsque la réponse est reçue, on annule le timer et on cache le loader
2071		clearTimeout(loaderTimeout);
2072
2073		if (response.ok) {
2074			const responseData = await response.json(); // Parse the response as JSON
2075			if (responseData.valid) {
2076				window.location.href = responseData.url;
2077			}
2078		} else {
2079			if (retries < maxRetries) {
2080				retries++;
2081				logDebug(`Tentative ${retries} de ${maxRetries}`);
2082				// Réessayer la requête
2083				return nextStep(maxRetries, retries); // Correction : passer les arguments
2084			} else {
2085				throw new Error('Nombre maximal de tentatives atteint');
2086			}
2087		}
2088	} catch (error) {
2089		logDebug('Error in navigateToNextStep:', error);
2090		clearTimeout(loaderTimeout);
2091	}
2092}
2093
2094async function get_navigation(msg, maxRetries = 5, retries = 0) {
2095	const csrf_test_name = encodeURIComponent(document.querySelector("[name=csrf_test_name]").value);
2096	// const errors = msg;
2097
2098	let errors_list = collectErrors(); // Récupérer les erreurs de la liste ul+
2099	errors_list = Object.assign({}, errors_list); // Convertir errors_list en objet
2100
2101	// Ajouter les erreurs de msg à errors_list
2102	if (msg) {
2103		for (const key in msg) {
2104			if (msg.hasOwnProperty(key)) {
2105				errors_list[key] = msg[key];
2106			}
2107		}
2108	}
2109	const errors = JSON.stringify(errors_list); // Convertir la liste complète en JSON
2110	const params = new URLSearchParams();
2111	const step_basket = document.getElementById("step_basket").value;
2112	params.append('csrf_test_name', csrf_test_name);
2113	params.append('errors', errors);
2114	params.append('step_basket', step_basket);
2115
2116	try {
2117		const response = await fetch(get_protocol_domain_name() + "/panier_v3/ajax_get_navigation_view", {
2118			method: 'POST', headers: {
2119				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
2120			}, body: params,
2121			mode: 'cors',
2122			credentials: 'same-origin'
2123		});
2124
2125		if (response.ok) {
2126			const text = await response.text(); // Correction : await pour récupérer le texte de la réponse
2127			document.getElementById("basket_navigation").innerHTML = text;
2128			init_navigation();
2129			remove_placeholders();
2130		} else {
2131			if (retries < maxRetries) {
2132				retries++;
2133				logDebug("Tentative " + retries + " de " + maxRetries);
2134				// Réessayer la requête
2135				return get_navigation(msg, maxRetries, retries); // Correction : passer les arguments
2136			} else {
2137				throw new Error('Nombre maximal de tentatives atteint');
2138			}
2139		}
2140	} catch (error) {
2141		logDebug('Error get_navigation:', error);
2142	}
2143}
2144
2145async function choix_pts_relais() {
2146	const choix_pts_relais = document.querySelectorAll('.choix_pts_relais');
2147	for (let i = 0; i < choix_pts_relais.length; i++) {
2148		choix_pts_relais[i].addEventListener("change", async function () {
2149			try {
2150				const collapse_livraison = document.getElementById('basket_form_livraison');
2151				const bs_collapse_livraison = new bootstrap.Collapse(collapse_livraison, {
2152					toggle: false
2153				})
2154				bs_collapse_livraison.hide();
2155
2156				const num_panier = encodeURIComponent(this.name.split('_')[3]);
2157				await unset_delivery_mode(num_panier);
2158				await load_choix_livr(this);
2159				await get_recapitulatif_basket_view();
2160				var infos_form = [];
2161				infos_form["collapse"] = false;
2162				await update_both_labels_info(infos_form, infos_form)
2163				removeError("adr_errors");
2164
2165			} catch (error) {
2166				logDebug('Error choix_pts_relais:', error);
2167			}
2168		});
2169	}
2170}
2171
2172async function unset_delivery_mode(num_panier = "", maxRetries = 5, retries = 0) {
2173	const csrf_test_name = encodeURIComponent(document.querySelector("[name=csrf_test_name]").value);
2174	const params = new URLSearchParams();
2175	params.append('csrf_test_name', csrf_test_name);
2176	params.append('num_panier', num_panier);
2177	try {
2178		const response = await fetch(get_protocol_domain_name() + "/panier_v3/u
2178nset_delivery_mode", {
2179			method: 'POST', headers: {
2180				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
2181			}, body: params,
2182			mode: 'cors',
2183			credentials: 'same-origin'
2184		});
2185
2186		if (response.ok) {
2187			removeError("mode_livraison_error");
2188		} else {
2189			if (retries < maxRetries) {
2190				retries++;
2191				logDebug("Tentative " + retries + " de " + maxRetries);
2192				// Réessayer la requête
2193				return unset_delivery_mode(num_panier, maxRetries, retries);
2194			} else {
2195				throw new Error('Nombre maximal de tentatives atteint');
2196			}
2197		}
2198	} catch (error) {
2199		logDebug('Error unset_delivery_mode:', error);
2200	} finally {
2201
2202	}
2203}
2204
2205async function check_delivery_pro() {
2206	const params = new URLSearchParams();
2207	params.append('csrf_test_name', document.querySelector("[name=csrf_test_name]").value);
2208
2209	const selectedPoint = document.querySelector('.choix_pts_relais:checked');
2210	if (selectedPoint) {
2211		const idPtsRelais = selectedPoint.id.split('_')[2];
2212		params.append('id_pts_relais', idPtsRelais);
2213	}
2214
2215	try {
2216		const response = await fetch(get_protocol_domain_name() + '/panier_v3/check_delivery_pro', {
2217			method: 'POST',
2218			headers: {
2219				'Content-Type': 'application/x-www-form-urlencoded',
2220				'X-Requested-With': 'XMLHttpRequest'
2221			},
2222			body: params,
2223			mode: 'cors',
2224			credentials: 'same-origin'
2225		});
2226
2227		if (response.ok) {
2228			const result = await response.text();
2229			console.log('Résultat check_delivery_pro:', result.trim());
2230
2231		} else {
2232			console.error("Erreur HTTP:", response.status);
2233		}
2234	} catch (error) {
2235		console.error('Erreur fetch check_delivery_pro:', error);
2236	}
2237}
2238
2239
2240async function check_country_is_valid(pays) {
2241	const params = new URLSearchParams();
2242	params.append('csrf_test_name', encodeURIComponent(document.querySelector("[name=csrf_test_name]").value));
2243	params.append('pays', encodeURIComponent(pays));
2244	params.append('direct_request', encodeURIComponent("true"));
2245	removeError("country_blocked");
2246	removeError("payment_blocked");
2247	removeError("mode_livraison_error");
2248	try {
2249		const response = await fetchWithRetries(get_protocol_domain_name() + '/panier_v3/check_country_is_valid', {
2250			method: 'POST',
2251			headers: {
2252				'Content-Type': 'application/x-www-form-urlencoded',
2253				'X-Requested-With': 'XMLHttpRequest'
2254			},
2255			body: params,
2256			mode: 'cors',
2257			credentials: 'same-origin'
2258		});
2259
2260		if (response.ok) {
2261			const data = await response.json();
2262			if (!data["valid"]) {
2263				if (data["msg"]["country_blocked"]) {
2264					addError("country_blocked", data["msg"]["country_blocked"]);
2265				}
2266				if (data["msg"]["payment_blocked"]) {
2267					addError("payment_blocked", data["msg"]["payment_blocked"]);
2268				}
2269
2270				add_placeholders(document.querySelector("#next_basket"));
2271			} else {
2272				remove_placeholders();
2273			}
2274			return data;
2275		}
2276
2277	} catch (error) {
2278		logDebug('Erreur:', error);
2279		return { valid: false, msg: { error: "Erreur de communication avec le serveur." } };
2280	}
2281}
2282
2283async function check_delivery_pro_usage(id_choix_pts_relais) {
2284	try {
2285		const response = await check_delivery_pro();
2286
2287		// Votre logique de traitement basée sur la réponse ici
2288		if (response === "") {
2289			document.querySelector("[name=entreprise]").required = true;
2290			if (document.querySelector("[name=entreprise]").value === "") {
2291				open_close_form_adresse_livraison("open");
2292			}
2293		} else {
2294			document.querySelector("[name=entreprise]").required = false;
2295		}
2296
2297	} catch (error) {
2298		logDebug('Error during check_delivery_pro:', error);
2299	}
2300}
2301
2302async function check_exclude_area(id_choix_pts_relais, cp, pays, selected_value, maxRetries = 5, retries = 0) {
2303
2304	let response = false;
2305	const params = new URLSearchParams();
2306	params.append('csrf_test_name', document.querySelector("[name=csrf_test_name]").value);
2307	params.append('code_postal', cp);
2308	params.append('pays', pays);
2309	params.append('direct_request', 'true');
2310
2311	params.append('id_pts_relais', id_choix_pts_relais);
2312
2313	setTimeout(async () => {
2314		try {
2315			const ajax_check_exclude_area = await fetch(get_protocol_domain_name() + "/panier_v3/cp_check_exclude_area", {
2316				method: 'POST', headers: {
2317					'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
2318				}, body: params,
2319				mode: 'cors',
2320				credentials: 'same-origin'
2321			});
2322
2323			if (ajax_check_exclude_area.ok) {
2324				response = await ajax_check_exclude_area.text();
2325			} else {
2326				if (retries < maxRetries) {
2327					retries++;
2328					logDebug("Tentative " + retries + " de " + maxRetries);
2329					// Réessayer la requête
2330					return check_exclude_area(id_choix_pts_relais, cp, pays, selected_value, maxRetries, retries);
2331				} else {
2332					throw new Error('Nombre maximal de tentatives atteint');
2333				}
2334			}
2335		} catch (error) {
2336			logDebug('Error:', error);
2337		} finally {
2338
2339		}
2340	}, 1000); // Attendre 1 seconde avant d'envoyer la requête
2341
2342	return response;
2343}
2344
2345function check_adresse_pr(elem) {
2346	var bsCollapse = new bootstrap.Collapse(elem, {
2347		toggle: false
2348	})
2349	bsCollapse.show();
2350}
2351
2352function delete_sms_colisimo() {
2353	var ajax_request_sms_field = new XMLHttpRequest();
2354	ajax_request_sms_field.open("GET", get_protocol_domain_name() + "/panier_v3/delete_mobile_coliship", true);
2355	ajax_request_sms_field.setRequestHeader('Content-Type', 'application/json');
2356	ajax_request_sms_field.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
2357	ajax_request_sms_field.send();
2358}
2359
2360async function check_pts_relais(maxRetries = 5, retries = 0) {
2361	try {
2362		const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
2363		const params = 'csrf_test_name=' + encodeURIComponent(csrf_test_name) + '&pays=' + encodeURIComponent(document.querySelector("#pays_facturation").value);
2364
2365		const response = await fetch(get_protocol_domain_name() + "/panier_v3/have_pts_relais", {
2366			method: 'POST', headers: {
2367				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
2368			}, body: params,
2369			mode: 'cors',
2370			credentials: 'same-origin'
2371		});
2372
2373		if (response.ok) {
2374			const data = await response.text();
2375			if (data === "true") {
2376				await get_delivery_mod_view();
2377				await load_choix_livr();
2378				await choix_pts_relais();
2379				await form_panier_mobile_coliship();
2380			} else {
2381				document.querySelector("#delivery_area_all").innerHTML = "";
2382			}
2383		} else {
2384			if (retries < maxRetries) {
2385				retries++;
2386				logDebug("Tentative " + retries + " de " + maxRetries);
2387				// Réessayer la requête
2388				return check_pts_relais(maxRetries, retries);
2389			} else {
2390				throw new Error('Nombre maximal de tentatives atteint');
2391			}
2392		}
2393	} catch (error) {
2394		logDebug('Erreur lors de la requête :', error);
2395	}
2396}
2397
2398
2399async function get_delivery_mod_view() {
2400	try {
2401		const response = await fetchWithRetries(get_protocol_domain_name() + "/panier_v3/get_delivery_mod_view", {
2402			method: 'GET', headers: {
2403				'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest'
2404			},
2405			mode: 'cors',
2406			credentials: 'same-origin'
2407		});
2408
2409		if (response.ok) {
2410			const data = await response.text();
2411			if (document.getElementById("delivery_area_all").innerHTML !== data) {
2412				document.getElementById("delivery_area_all").innerHTML = data;
2413				button_collapse_delivery_mod();
2414			}
2415		}
2416	} catch (error) {
2417		logDebug('Erreur lors de la requête :', error);
2418	}
2419}
2420
2421async function get_recapitulatif_basket_view(maxRetries = 5, retries = 0) {
2422	try {
2423		const response = await fetchWithRetries(get_protocol_domain_name() + "/panier_v3/get_recapitulatif_basket", {
2424			method: 'GET', headers: {
2425				'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest'
2426			},
2427			mode: 'cors',
2428			credentials: 'same-origin'
2429		});
2430
2431		if (response.ok) {
2432			const data = await response.text();
2433			const basketRecapitulatif = document.querySelector("#basket_recapitulatif");
2434			if (basketRecapitulatif.innerHTML !== data) {
2435				basketRecapitulatif.innerHTML = data;
2436			}
2437			await form_promo();
2438			await form_delete_promo();
2439			save_basket()
2440		}
2441	} catch (error) {
2442		logDebug('Erreur lors de la requête :', error);
2443	}
2444}
2445
2446async function get_basket_message($pays, maxRetries = 5, retries = 0) {
2447
2448	const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
2449	const params = new URLSearchParams();
2450	params.append('csrf_test_name', csrf_test_name);
2451	params.append('pays', $pays);
2452	try {
2453		const response = await fetch(get_protocol_domain_name() + "/panier_v3/get_basket_message", {
2454			method: 'POST',
2455			headers: {
2456				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
2457			},
2458			body: params,
2459			mode: 'cors',
2460			credentials: 'same-origin'
2461		});
2462
2463		if (response.ok) {
2464			const data = await response.text();
2465			const basketMessage = document.querySelector("#basket_message");
2466			if (basketMessage.innerHTML !== data) {
2467				basketMessage.innerHTML = data;
2468			}
2469		} else {
2470			if (retries < maxRetries) {
2471				retries++;
2472				logDebug("Tentative " + retries + " de " + maxRetries);
2473				// Réessayer la requête
2474				return get_basket_message($pays, maxRetries, retries);
2475			} else {
2476				throw new Error('Nombre maximal de tentatives atteint');
2477			}
2478		}
2479	} catch (error) {
2480		logDebug('Erreur lors de la requête :', error);
2481	}
2482}
2483async function get_basket_footer_message() {
2484
2485	const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
2486	const params = new URLSearchParams();
2487	params.append('csrf_test_name', csrf_test_name);
2488	try {
2489		const response = await fetchWithRetries(get_protocol_domain_name() + "/panier_v3/get_basket_footer_message", {
2490			method: 'POST',
2491			headers: {
2492				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
2493			},
2494			body: params,
2495			mode: 'cors',
2496			credentials: 'same-origin'
2497		});
2498
2499		if (response.ok) {
2500			const data = await response.text();
2501			const basketMessage = document.querySelector("#basket_footer_message");
2502			if (basketMessage.innerHTML !== data) {
2503				basketMessage.innerHTML = data;
2504			}
2505		}
2506	} catch (error) {
2507		logDebug('Erreur lors de la requête :', error);
2508	}
2509}
2510
2511async function check_phone_missing() {
2512	var divMobile = document.querySelector("#div_info_livraison");
2513	if (!divMobile) {
2514		return;
2515	}
2516	divMobile.classList.add("d-none");
2517
2518	try {
2519		const response = await fetchWithRetries(get_protocol_domain_name() + "/panier_v3/check_mobile_coliship", {
2520			method: 'GET', headers: {
2521				'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest'
2522			},
2523			mode: 'cors',
2524			credentials: 'same-origin'
2525		});
2526
2527		if (response.ok) {
2528			const responseData = await response.text();
2529			if (responseData === "false") {
2530				divMobile.classList.remove("d-none");
2531				if (document.querySelector('#choix_livraison_mobile') && document.querySelector('#choix_livraison_mobile').value == "") {
2532					const JS_collapse_form_info_livraison = document.querySelector("#form_info_livraison");
2533					const bsCollapse = new bootstrap.Collapse(JS_collapse_form_info_livraison, {
2534						toggle: false
2535					});
2536					bsCollapse.show();
2537				}
2538			}
2539		}
2540	} catch (error) {
2541		logDebug('Error check_phone_missing:', error);
2542	}
2543}
2544
2545async function load_choix_livr(choice) {
2546
2547	show_ajax_loader();
2548	const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
2549	let selected_value_error = false;
2550	let selected_value = "";
2551	let id_choix_delivery_mod = "";
2552	if (choice) {
2553		selected_value = choice.value;
2554		id_choix_delivery_mod = choice.id.split('_')[2];
2555	}
2556
2557	if (selected_value !== "") {
2558		await get_cache_current_delivery_address();
2559
2560		let params = 'csrf_test_name=' + encodeURIComponent(csrf_test_name);
2561		params += '&ad=' + encodeURIComponent(document.querySelector("#ad_livraison").value)
2562		params += '&ville=' + encodeURIComponent(document.querySelector("#ville_livraison").value)
2563		params += '&cp=' + encodeURIComponent(document.querySelector("#cp_livraison").value)
2564		params += '&id_choix_delivery_mod=' + encodeURIComponent(id_choix_delivery_mod)
2565		if (document.querySelector("#div_info_livraison")) {
2566			let divMobile = document.querySelector("#div_info_livraison");
2567			if (!divMobile.classList.contains("d-none")) {
2568				divMobile.classList.add("d-none");
2569			}
2570		}
2571
2572		const delivery_area = choice.closest(".delivery_area");
2573		let collapses_points_relais = delivery_area.querySelectorAll(".collapse");
2574		collapses_points_relais.forEach(function (element) {
2575			if (element.classList.contains("collapse_sms")) {
2576				return;
2577			}
2578			var bscollapse_element = new bootstrap.Collapse(element, {
2579				toggle: false
2580			})
2581			element.innerHTML = "";
2582			bscollapse_element.hide();
2583		});
2584
2585		let mycollapse_point_relais = document.getElementById('collapse_point_relais_' + id_choix_delivery_mod)
2586		let bscollapse_point_relais = new bootstrap.Collapse(mycollapse_point_relais, {
2587			toggle: false
2588		})
2589
2590		let cp_exclude_area = document.querySelector("#cp_livraison").value;
2591		let pays_exclude_area = document.querySelector("#pays_livraison").value
2592		let exclude_area = check_exclude_area(id_choix_delivery_mod, cp_exclude_area, pays_exclude_area, selected_value)
2593
2594		const promises = [];
2595
2596		// promises.push(check_delivery_pro_usage(id_choix_delivery_mod));
2597
2598		switch (selected_value) {
2599			//on declenche la fonction ajax et on recharge la page sur succes
2600			case 'Formulaire':
2601				promises.push(set_choice_domicile(choice));
2602				// promises.push(get_cache_current_delivery_address());
2603
2604				break;
2605			//on deroule la liste des points
2606			case 'Autre':
2607				bscollapse_point_relais.show();
2608				await get_colissimo_pts_relais(mycollapse_point_relais, params);
2609				await check_phone_missing();
2610				submit_choix_relais()
2611
2612				break;
2613			/****** Display colissimo points ******/
2614			case 'Colissimo':
2615				bscollapse_point_relais.show();
2616				promises.push(load_widget_colissimo_div(mycollapse_point_relais, id_choix_delivery_mod));
2617				promises.push(widget_colissimo(choice, mycollapse_point_relais, id_choix_delivery_mod, csrf_test_name));
2618
2619				delete_sms_colisimo();
2620				submit_choix_relais()
2621
2622				break;
2623			/****** Display mondial relay points ******/
2624			case 'MR':
2625				bscollapse_point_relais.show();
2626				widget_mondial_relay(id_choix_delivery_mod);
2627				break;
2628			/****** Display DPD points ******/
2629			case 'DPD':
2630				bscollapse_point_relais.show();
2631				promises.push(fetchPointsRelaisDPD(choice, mycollapse_point_relais, id_choix_delivery_mod, exclude_area));
2632
2633				submit_choix_relais()
2634
2635				break;
2636
2637		}
2638
2639		await Promise.all(promises);
2640
2641		if (!selected_value_error) {
2642			set_ajax_input_error("cp_livraison", "");
2643			set_ajax_input_error("entreprise_livraison", "");
2644			if (exclude_area === "") {
2645				if (exclude_area === "") {
2646					set_ajax_input_error("cp_livraison",await trad("_CP_EXCLUDE_AREA_ERROR"));
2647				}
2648			}
2649		}
2650	}
2651	hide_ajax_loader();
2652}
2653
2654button_collapse_delivery_mod();
2655
2656function button_collapse_delivery_mod() {
2657	const buttons = document.querySelectorAll(".button_collapse_delivery_mod");
2658	if (buttons) {
2659		buttons.forEach(button => {
2660			button.addEventListener('click', async function () {
2661				const num_panier = encodeURIComponent(this.id.split('_')[4]);
2662				const elementName = "choix_pts_relais_" + num_panier;
2663				const checkedElement = document.querySelector("[name='" + elementName + "']:checked");
2664				try {
2665					await load_choix_livr(checkedElement);
2666					await unset_delivery_mode(num_panier);
2667					await choix_pts_relais();
2668
2669					// await set_identic_livraison_to_facturation();
2670				} catch (error) {
2671					logDebug('Erreur lors de l\'exécution des fonctions asynchrones :', error);
2672				}
2673			});
2674		});
2675	}
2676}
2677
2678submit_choix_relais()
2679
2680function submit_choix_relais() {
2681	const radioButtons = document.querySelectorAll(".radio_choix_pr");
2682	if (radioButtons.length > 0) {
2683		radioButtons.forEach(button => {
2684
2685			button.addEventListener('click', function () {
2686				// Soumettre le formulaire parent
2687				const form = this.closest("form");
2688				if (form) {
2689					form.requestSubmit(); // Utiliser requestSubmit pour éviter de bypass le submit event listener
2690				}
2691			});
2692		});
2693	}
2694}
2695
2696// DOMICILE
2697async function set_choice_domicile(choice) {
2698	const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
2699	const id_delivery_mode = encodeURIComponent(choice.id.split('_')[2]);
2700	const num_panier = encodeURIComponent(choice.name.split('_')[3]);
2701
2702	const params = new URLSearchParams();
2703	params.append('csrf_test_name', csrf_test_name);
2704	params.append('id_delivery_mode', id_delivery_mode);
2705	params.append('num_panier', num_panier);
2706
2707	try {
2708		const response = await fetchWithRetries(get_protocol_domain_name() + "/panier_v3/choix_livraison_domicile", {
2709			method: 'POST', headers: {
2710				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
2711			}, body: params,
2712			mode: 'cors',
2713			credentials: 'same-origin'
2714		});
2715
2716		if (response.ok) {
2717			const mycollapse_views_panier_livraison = document.getElementById('views_panier_livraison_' + num_panier);
2718			const bscollapse_views_panier_livraison = new bootstrap.Collapse(mycollapse_views_panier_livraison, {
2719				toggle: false
2720			});
2721			bscollapse_views_panier_livraison.hide();
2722
2723			// await update_labels_info_adresse_livraison()
2724			let promises = [];
2725
2726			promises.push(update_labels_info_adresses("/panier_v3/get_basket_livraison_view"));
2727			promises.push(update_delivery_area_info_adresse_livraison(num_panier));
2728			promises.push(update_form_adresse_livraison());
2729			promises.push(get_recapitulatif_basket_view());
2730
2731			await Promise.all(promises);
2732
2733		}
2734	} catch (error) {
2735		// Gérer les erreurs
2736		logDebug('Erreur lors de la requête :', error);
2737	}
2738}
2739
2740// AUTRE (pts relais Colissimo)
2741async function get_colissimo_pts_relais(collapse, params, maxRetries = 5, retries = 0) {
2742	try {
2743		show_ajax_loader();
2744		const response = await fetch(get_protocol_domain_name() + "/panier_v3/geoloc_relais", {
2745			method: 'POST', headers: {
2746				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
2747			}, body: params,
2748			mode: 'cors',
2749			credentials: 'same-origin'
2750		});
2751
2752		if (response.ok) {
2753			const responseData = await response.text();
2754			collapse.innerHTML = responseData;
2755			form_panier_pts_relais_Colissimo_validate();
2756
2757			// await event_colissimo(params);
2758			// delete_sms_colisimo();
2759		} else {
2760			if (retries < maxRetries) {
2761				retries++;
2762				logDebug("Tentative " + retries + " de " + maxRetries);
2763				// Réessayer la requête
2764				return get_colissimo_pts_relais(params, maxRetries, retries);
2765			} else {
2766				throw new Error('Nombre maximal de tentatives atteint');
2767			}
2768		}
2769	} catch (error) {
2770		logDebug('Error get_colissimo_pts_relais:', error);
2771	} finally {
2772		hide_ajax_loader();
2773	}
2774}
2775
2776function form_panier_pts_relais_Colissimo_validate() {
2777	const form = document.querySelector("#form_panier_pts_relais_Colissimo_validate");
2778	const delivery_area = form.closest('.delivery_area');
2779	if (form) {
2780		form.addEventListener("submit", async function (event) {
2781			event.preventDefault();
2782			const collectPoint = form.querySelector('[name=choix_relais]:checked');
2783			if (collectPoint) {
2784				const csrf_test_name = form.querySelector("[name=csrf_test_name]").value;
2785				const collectPoint_data = {
2786					id: collectPoint.value,
2787					address: form.querySelector(`#${collectPoint.id}_ad`).value,
2788					postal_code: form.querySelector(`#${collectPoint.id}_postal_code`).value,
2789					shop_name: form.querySelector(`#${collectPoint.id}_shop_name`).value,
2790					city: form.querySelector(`#${collectPoint.id}_city`).value,
2791					distance: form.querySelector(`#${collectPoint.id}_distance`).value
2792				};
2793
2794				const id_delivery_mode = encodeURIComponent(delivery_area.querySelector('.choix_pts_relais:checked').id.split('_')[2]);
2795				const num_panier = encodeURIComponent(delivery_area.querySelector('.choix_pts_relais:checked').name.split('_')[3]);
2796
2797				const params = new URLSearchParams();
2798				params.append('csrf_test_name', csrf_test_name);
2799				params.append('collectPoint', JSON.stringify(collectPoint_data));
2800				params.append('id_delivery_mode', id_delivery_mode);
2801				params.append('num_panier', num_panier);
2802
2803				await validate_point_relais(num_panier, params, 'collapse_point_relais_' + id_delivery_mode);
2804
2805			}
2806		});
2807	}
2808}
2809
2810// WIDGET COLISSIMO
2811async function load_widget_colissimo_div(mycollapse_point_relais, id_choix_delivery_mod, maxRetries = 5, retries = 0) {
2812	const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
2813
2814	if (mycollapse_point_relais) {
2815
2816		const paramsDPD = new URLSearchParams();
2817		paramsDPD.append('csrf_test_name', encodeURIComponent(csrf_test_name));
2818		paramsDPD.append('meta_shop_delivery_mod_id', encodeURIComponent(id_choix_delivery_mod));
2819		try {
2820			const response = await fetch(get_protocol_domain_name() + "/panier_v3/get_widget_div", {
2821				method: 'POST', headers: {
2822					'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
2823				}, body: paramsDPD,
2824				mode: 'cors',
2825				credentials: 'same-origin'
2826			});
2827
2828			if (response.ok) {
2829				const data = await response.text();
2830				mycollapse_point_relais.innerHTML = data;
2831			} else {
2832				if (retries < maxRetries) {
2833					retries++;
2834					logDebug("Tentative " + retries + " de " + maxRetries);
2835					// Réessayer la requête
2836					return load_widget_colissimo_div(mycollapse_point_relais, id_choix_delivery_mod, maxRetries, retries);
2837				} else {
2838					throw new Error('Nombre maximal de tentatives atteint');
2839				}
2840			}
2841
2842		} catch (error) {
2843			logDebug('Error:', error);
2844		}
2845	}
2846}
2847
2848async function widget_colissimo(choice, mycollapse_point_relais, id_choix_delivery_mod, csrf_test_name, maxRetries = 5, retries = 0) {
2849	if (document.querySelector("#widget-container_" + id_choix_delivery_mod).innerHTML === "") {
2850		const form_livraison = document.querySelector("#form_adr_liv");
2851
2852		const ad = form_livraison.querySelector("[name=ad]").value;
2853		const cp = form_livraison.querySelector("[name=cp]").value;
2854		const ville = form_livraison.querySelector("[name=ville]").value;
2855		const params = new URLSearchParams();
2856		params.append('csrf_test_name', csrf_test_name);
2857		try {
2858			const response = await fetch(get_protocol_domain_name() + "/panier_v3/colissimo_api_auth", {
2859				method: 'POST', headers: {
2860					'Content-Type': 'application/x-www-form-urlencoded'
2861				}, body: params,
2862				mode: 'cors',
2863				credentials: 'same-origin'
2864			});
2865
2866			if (response.ok) {
2867				const data = await response.text();
2868				if (data) {
2869					jQuery.ajax({
2870						type: "GET",
2871						url: "https://ws.colissimo.fr/widget-point-retrait/resources/js/jquery.plugin.colissimo.min.js",
2872						dataType: "script",
2873						success: function () {
2874							jQuery('#widget-container_' + id_choix_delivery_mod).frameColissimoOpen({
2875								"ceLang": "fr",
2876								"callBackFrame": function (collectPoint) {
2877									updatePointRetraitColissimo(collectPoint, choice);
2878								},
2879								"URLColissimo": "https://ws.colissimo.fr",
2880								"ceCountryList": "FR",
2881								"ceCountry": "FR",
2882								"dyPreparationTime": "1",
2883								"ceAddress": ad,
2884								"ceZipCode": cp,
2885								"ceTown": ville,
2886								"token": data
2887							});
2888						}
2889					});
2890
2891				}
2892			} else {
2893				if (retries < maxRetries) {
2894					retries++;
2895					logDebug("Tentative " + retries + " de " + maxRetries);
2896					// Réessayer la requête
2897					return widget_colissimo(choice, csrf_test_name, maxRetries, retries);
2898				} else {
2899					throw new Error('Nombre maximal de tentatives atteint');
2900				}
2901			}
2902		} catch (error) {
2903			logDebug
2904		}
2905	}
2906}
2907
2908async function updatePointRetraitColissimo(collectPoint, choice) {
2909	const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
2910	const params = new URLSearchParams();
2911	const id_delivery_mode = encodeURIComponent(choice.id.split('_')[2]);
2912	const num_panier = encodeURIComponent(choice.name.split('_')[3]);
2913
2914	params.append('csrf_test_name', csrf_test_name);
2915	params.append('collectPoint', JSON.stringify(collectPoint));
2916	params.append('id_delivery_mode', id_delivery_mode);
2917
2918	try {
2919		const response = await fetch(get_protocol_domain_name() + "/panier_v3/ajout_panier_colissimo", {
2920			method: 'POST', headers: {
2921				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
2922			}, body: params,
2923			mode: 'cors',
2924			credentials: 'same-origin'
2925		});
2926
2927		if (!response.ok) {
2928			throw new Error('Network response was not ok');
2929		}
2930
2931		// await update_form_adresse_livraison();
2932
2933		await update_delivery_area_info_adresse_livraison(num_panier);
2934		button_collapse_delivery_mod();
2935		await get_recapitulatif_basket_view();
2936
2937	} catch (error) {
2938		logDebug('Error updatePointRetraitColissimo:', error);
2939	} finally {
2940
2941	}
2942}
2943
2944// WIDGET MONDIAL RELAY
2945function widget_mondial_relay(id_delivery_mode, maxAttempts = 5, currentAttempt = 1) {
2946	if (currentAttempt > maxAttempts) {
2947		logDebug('Maximum number of attempts reached. Unable to load ParcelShopPicker.');
2948		return;
2949	}
2950
2951	var key = "CC22LZIZ";
2952	if (key !== "") {
2953
2954
2955		var cp = document.querySelector("#cp").value;
2956		var ville = document.querySelector("#ville").value;
2957		var pays = document.querySelector("#pays_livraison").value;
2958		var p = "FR";
2959		switch (pays) {
2960			case 'FRANCE' :
2961				p = "FR";
2962				break;
2963			case 'BELGIQUE' :
2964				p = "BE";
2965				break;
2966			case 'DUTSCHLAND' :
2967				p = "DE";
2968				break;
2969			case 'NEDERLANDS' :
2970				p = "NL";
2971				break;
2972			default:
2973				logDebug("Aucun points relais pour ce pays");
2974		}
2975
2976		jQuery.ajax({
2977			type: "GET",
2978			url: "https://widget.mondialrelay.com/parcelshop-picker/jquery.plugin.mondialrelay.parcelshoppicker.min.js",
2979			dataType: "script",
2980			async: true,
2981			success: function () {
2982				if (document.querySelector(".MR-Widget")) {
2983					jQuery("#Zone_Widget").trigger("MR_SetParams", {
2984						Country: p, City: ville, Postcode: cp, AllowedCountries: p
2985					});
2986					jQuery("#Zone_Widget").trigger("MR_DoSearch", [cp, p]);
2987					jQuery("#Zone_Widget").trigger("MR_RebindMap")
2988				} else {
2989					jQuery("#Zone_Widget").MR_ParcelShopPicker({
2990						Target: "#Target_Widget",
2991						Brand: key,
2992						Country: p,
2993						AllowedCountries: p,
2994						City: ville,
2995						PostCode: cp,
2996						NbResults: 10,
2997						Responsive: true,
2998						MapScrollWheel: true,
2999						OnParcelShopSelected: confirmPointRetraitMondial
3000					});
3001				}
3002
3003				var elem = document.querySelector("#collapse_point_relais_" + id_delivery_mode);
3004				check_adresse_pr(elem);
3005			},
3006			error: function (xhr, status, error) {
3007				logDebug('Error loading ParcelShopPicker:', error);
3008				// Retry the request
3009				widget_mondial_relay(maxAttempts, currentAttempt + 1);
3010			}
3011		});
3012
3013	}
3014}
3015
3016function confirmPointRetraitMondial(collectPoint) {
3017	var collectPointInfos = document.querySelector("#collectPointInfos");
3018	if (collectPointInfos.classList.contains("d-none")) {
3019		collectPointInfos.classList.remove("d-none");
3020		collectPointInfos.classList.add("d-block");
3021	}
3022	jQuery('#confirmCollectPoint').data("collectPoint", collectPoint);
3023	jQuery('#collectPointName').html(collectPoint.Nom);
3024	jQuery('#collectPointAdress').html(collectPoint.Adresse1);
3025	jQuery('#collectPointCity').html(collectPoint.CP + ' - ' + collectPoint.Ville);
3026
3027	var confirmCollectPoint = document.querySelector("#confirmCollectPoint");
3028	if (confirmCollectPoint.classList.contains("d-none")) {
3029		confirmCollectPoint.classList.remove("d-none");
3030		confirmCollectPoint.classList.add("d-block");
3031	}
3032	// shipping_adress_scroll();
3033}
3034
3035// Récupère les points DPD
3036async function fetchPointsRelaisDPD(choice, mycollapse_point_relais, id_choix_pts_relais, exclude_area, maxRetries = 5, retries = 0) {
3037	const form_livraison = document.querySelector("#form_adr_liv");
3038	const csrf_test_name = form_livraison.querySelector("[name=csrf_test_name]").value;
3039	const adresse = form_livraison.querySelector("[name=ad]").value;
3040	const cp = form_livraison.querySelector("[name=cp]").value;
3041	const ville = form_livraison.querySelector("[name=ville]").value;
3042	const pays = form_livraison.querySelector("#pays_livraison").value;
3043
3044	if (mycollapse_point_relais) {
3045		if (!adresse || !cp || !ville || !pays) {
3046			selected_value_error = true;
3047		} else {
3048
3049			const paramsDPD = new URLSearchParams();
3050			paramsDPD.append('csrf_test_name', encodeURIComponent(csrf_test_name));
3051			paramsDPD.append('address', encodeURIComponent(adresse));
3052			paramsDPD.append('code_postal', encodeURIComponent(cp));
3053			paramsDPD.append('city', encodeURIComponent(ville));
3054			paramsDPD.append('pays', encodeURIComponent(pays));
3055
3056			paramsDPD.append('id_pts_relais', encodeURIComponent(id_choix_pts_relais));
3057
3058			try {
3059				const response = await fetch(get_protocol_domain_name() + "/panier_v3/get_points_dpd", {
3060					method: 'POST', headers: {
3061						'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
3062					}, body: paramsDPD,
3063					mode: 'cors',
3064					credentials: 'same-origin'
3065				});
3066
3067				if (response.ok) {
3068					const data = await response.text();
3069					if (exclude_area) {
3070						mycollapse_point_relais.innerHTML = data;
3071						await form_panier_pts_relais_DPD_validate(choice);
3072						submit_choix_relais()
3073
3074					}
3075				} else {
3076					if (retries < maxRetries) {
3077						retries++;
3078						logDebug("Tentative " + retries + " de " + maxRetries);
3079						// Réessayer la requête
3080						return fetchPointsRelaisDPD(choice, id_choix_pts_relais, exclude_area, maxRetries, retries);
3081					} else {
3082						throw new Error('Nombre maximal de tentatives atteint');
3083					}
3084				}
3085
3086			} catch (error) {
3087				logDebug('Error:', error);
3088			}
3089		}
3090	}
3091}
3092
3093async function form_panier_pts_relais_DPD_validate(choice) {
3094	const form = document.querySelector("#form_panier_pts_relais_DPD_validate");
3095	if (form) {
3096		form.addEventListener("submit", async function (event) {
3097			event.preventDefault();
3098			const collectPoint = form.querySelector('[name=choix_relais]:checked');
3099			if (collectPoint) {
3100				const csrf_test_name = form.querySelector("[name=csrf_test_name]").value;
3101				const id_delivery_mode = encodeURIComponent(choice.id.split('_')[2]);
3102				const num_panier = encodeURIComponent(choice.name.split('_')[3]);
3103
3104				const collectPoint_data = {
3105					id: collectPoint.value,
3106					address: form.querySelector(`#${collectPoint.id}_ad`).value,
3107					postal_code: form.querySelector(`#${collectPoint.id}_postal_code`).value,
3108					shop_name: form.querySelector(`#${collectPoint.id}_shop_name`).value,
3109					city: form.querySelector(`#${collectPoint.id}_city`).value,
3110					distance: form.querySelector(`#${collectPoint.id}_distance`).value
3111				};
3112
3113				const params = new URLSearchParams();
3114				params.append('csrf_test_name', csrf_test_name);
3115				params.append('collectPoint', JSON.stringify(collectPoint_data));
3116				params.append('id_delivery_mode', id_delivery_mode);
3117				params.append('num_panier', num_panier);
3118				await validate_point_relais(num_panier, params, 'collapse_point_relais_' + id_delivery_mode);
3119			}
3120		});
3121	}
3122}
3123
3124async function validate_point_relais(num_panier, params, collapse) {
3125	show_ajax_loader();
3126	try {
3127		const response = await fetch(get_protocol_domain_name() + "/panier_v3/ajout_panier_point_relais", {
3128			method: 'POST', headers: {
3129				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
3130			}, body: params,
3131			mode: 'cors',
3132			credentials: 'same-origin'
3133		});
3134
3135		if (!response.ok) {
3136			throw new Error('Network response was not ok');
3137		}
3138
3139		const infos_form = {
3140			"identic": false
3141		};
3142		await update_labels_info_adresses("/panier_v3/get_basket_livraison_view", infos_form)
3143
3144		disabled_inputs_form_adresse_livraison(true);
3145		await update_delivery_area_info_adresse_livraison(num_panier);
3146		button_collapse_delivery_mod();
3147		await get_recapitulatif_basket_view();
3148
3149		removeError("mode_livraison_error");
3150
3151		const mycollapse_views_panier_livraison = document.getElementById('views_panier_livraison_' + num_panier);
3152		const bscollapse_views_panier_livraison = new bootstrap.Collapse(mycollapse_views_panier_livraison, {
3153			toggle: false
3154		});
3155		bscollapse_views_panier_livraison.show();
3156
3157		const mycollapse_point_relais = document.getElementById(collapse);
3158		const bscollapse_point_relais_DPD = new bootstrap.Collapse(mycollapse_point_relais, {
3159			toggle: false
3160		});
3161		bscollapse_point_relais_DPD.hide();
3162
3163	} catch (error) {
3164		logDebug('Error form_panier_pts_relais_validate:', error);
3165	} finally {
3166		hide_ajax_loader();
3167	}
3168}
3169
3170///////////////////////////////////////////////////////////////////////////////
3171
3172
3173
3174function collectErrors() {
3175	const errorsList = document.getElementById("basket_errors_list");
3176	const errors = [];
3177
3178	if (errorsList) {
3179		const errorItems = errorsList.querySelectorAll("li");
3180		errorItems.forEach(item => {
3181			errors[item.id] = item.textContent.trim();
3182		});
3183	}
3184
3185	return errors;
3186}
3187
3188function addError(id, message) {
3189	if (document.getElementById("step_errors")) {
3190		const ul = document.querySelector('#step_errors ul');
3191		const li = document.createElement('li');
3192		li.id = id;
3193		li.textContent = message;
3194		ul.appendChild(li);
3195
3196		// Assurer que le conteneur d'erreurs est visible
3197		document.getElementById('step_errors').classList.remove('d-block');
3198		document.getElementById('step_errors').classList.add('d-block');
3199		document.getElementById('step_errors').classList.remove('d-none');
3200	}
3201}
3202
3203function removeError(id) {
3204	if (document.getElementById("step_errors")) {
3205		const li = document.getElementById(id);
3206		if (li) {
3207			li.remove();
3208
3209			// Si le ul est vide, cacher le conteneur des erreurs
3210			const ul = document.querySelector('#step_errors ul');
3211			if (ul.children.length === 0) {
3212				document.getElementById('step_errors').classList.remove('d-block');
3213				document.getElementById('step_errors').classList.add('d-none');
3214			}
3215		}
3216	}
3217}
3218function removeAllError() {
3219	if (document.getElementById("step_errors")) {
3220		const ul = document.querySelector('#step_errors ul');
3221
3222		// Si le <ul> existe et contient des erreurs, on les supprime toutes
3223		if (ul && ul.children.length > 0) {
3224			while (ul.firstChild) {
3225				ul.firstChild.remove();
3226			}
3227
3228			if (ul.children.length === 0) {
3229				document.getElementById('step_errors').classList.remove('d-block');
3230				document.getElementById('step_errors').classList.add('d-none');
3231			}
3232		}
3233	}
3234}
3235function have_errors() {
3236	let error = false;
3237	if (document.getElementById("step_errors")) {
3238		if (document.getElementById("step_errors").classList.contains("d-block")) {
3239			error = true;
3240		}
3241		return error;
3242	}
3243}
3244
3245async function check_basket_errors() {
3246	const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
3247	const params = new URLSearchParams();
3248	params.append('csrf_test_name', csrf_test_name);
3249
3250	try {
3251		const response = await fetch_with_retries(get_protocol_domain_name() + "/panier_v3/get_basket_errors", {
3252			method: 'POST', headers: {
3253				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
3254			}, body: params,
3255			mode: 'cors',
3256			credentials: 'same-origin'
3257		});
3258
3259
3260		if (response.ok) {
3261			const errors = await response.json();
3262			for (var error in errors) {
3263				addError("adr_errors",errors[error]);
3264			}
3265		}
3266	} catch (error) {
3267		logDebug('Erreur lors de la requête :', error);
3268		throw error; // Rejeter l'erreur pour la gérer à l'extérieur si nécessaire
3269	}
3270}
3271
3272async function get_basket_facturation_option(country, pro = false, maxRetries = 5, retries = 0) {
3273	const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
3274	const params = new URLSearchParams();
3275	params.append('csrf_test_name', csrf_test_name);
3276	if (!country) {
3277		country = document.getElementById("pays_facturation").value;
3278	}
3279	params.append('country', country);
3280	params.append('pro', pro);
3281
3282	try {
3283		const response = await fetch(get_protocol_domain_name() + "/panier_v3/get_basket_facturation_option", {
3284			method: 'POST', headers: {
3285				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
3286			}, body: params,
3287			mode: 'cors',
3288			credentials: 'same-origin'
3289		});
3290
3291
3292		if (response.ok) {
3293			const fields = await response.json();
3294			await update_fields(fields["champ"]);
3295			return fields;
3296		} else {
3297			if (retries < maxRetries) {
3298				retries++;
3299				logDebug("Tentative " + retries + " de " + maxRetries);
3300				// Réessayer la requête
3301				return get_basket_facturation_option(country, pro, maxRetries, retries);
3302			} else {
3303				throw new Error('Nombre maximal de tentatives atteint');
3304			}
3305		}
3306
3307
3308	} catch (error) {
3309		logDebug('Erreur lors de la requête :', error);
3310		throw error; // Rejeter l'erreur pour la gérer à l'extérieur si nécessaire
3311	}
3312}
3313async function form_login(maxRetries = 5, retries = 0) {
3314	const form = document.querySelector('#form_basket_login');
3315	form.addEventListener('submit', async function (event) {
3316		// Vérifie la validité du formulaire avant de procéder
3317		event.preventDefault(); // Empêche l'envoi du formulaire
3318		show_ajax_loader(); // Affiche le loader AJAX
3319		try {
3320			let url = "/panier_v3/form_login";
3321			const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
3322			const infos_form = {
3323				"email": document.querySelector("#email_login").value,
3324			};
3325
3326			if (document.querySelector("#password")) {
3327				infos_form["password"] = document.querySelector("#password").value;
3328				url = "/user/login";
3329				infos_form["login_basket"] = true;
3330			}
3331
3332			const params = new URLSearchParams();
3333			params.append('csrf_test_name', encodeURIComponent(csrf_test_name)); // Encode le CSRF
3334			Object.entries(infos_form).forEach(([key, value]) => {
3335				params.append(key, encodeURIComponent(value)); // Encode les valeurs du formulaire
3336			});
3337
3338			const response = await fetch(get_protocol_domain_name() + url, {
3339				method: 'POST', headers: {
3340					'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
3341				}, body: params,
3342				mode: 'cors',
3343				credentials: 'same-origin'
3344			});
3345
3346
3347			if (response.ok) {
3348				const data = await response.json();
3349				if (data.status === 'valid') {
3350					if (data.view) {
3351						// Remplace le contenu du panier par la nouvelle vue
3352						document.getElementById("view_step_basket").innerHTML = data.view;
3353						await form_login(); // Réattache le listener pour le formulaire si nécessaire
3354						passwordToggle();
3355
3356					} else if (data.redirect) {
3357						// Redirection vers la bonne page
3358						window.location.href = data.redirect;
3359					}
3360				} else if (data.status === 'invalid') {
3361					// Afficher l'erreur lorsque le mot de passe est incorrect
3362					const passwordField = document.querySelector("#password");
3363					field_error(passwordField, true, data.message); // Utilisation de la fonction `field_error`
3364				}
3365			} else {
3366
3367				if (retries < maxRetries) {
3368					retries++;
3369					logDebug("Tentative " + retries + " de " + maxRetries);
3370					// Réessayer la requête
3371					return form_login(maxRetries, retries);
3372				} else {
3373					throw new Error('Nombre maximal de tentatives atteint');
3374				}
3375			}
3376		} catch (error) {
3377			logDebug('Erreur lors de la requête :', error);
3378		} finally {
3379			hide_ajax_loader(); // Cache le loader AJAX
3380		}
3381	});
3382}
3383function save_basket() {
3384	if (document.querySelector("#form_basket_save")) {
3385		document.querySelector("#form_basket_save").addEventListener("submit", async function (event) {
3386			event.preventDefault();
3387			show_ajax_loader();
3388			validate_form(this);
3389			try {
3390				const csrf_test_name = this.querySelector("[name=csrf_test_name]").value;
3391				const infos_form = {
3392					"type": this.querySelector("[name=basket_save]").value,
3393				};
3394
3395				const params = new URLSearchParams();
3396				params.append('csrf_test_name', csrf_test_name);
3397				Object.entries(infos_form).forEach(([key, value]) => {
3398					params.append(key, value);
3399				});
3400
3401				const response = await fetch(get_protocol_domain_name() + "/panier_v3/save_basket", {
3402					method: 'POST', headers: {
3403						'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
3404					}, body: params,
3405					mode: 'cors',
3406					credentials: 'same-origin'
3407				});
3408
3409				if (response.ok) {
3410					const data = await response.text();
3411					if (data.includes('error')) {
3412						logDebug('Erreur lors de la sauvegarde du panier:', data);
3413					} else {
3414						window.location.href = data; // Redirection vers la confirmation
3415					}
3416				} else {
3417					throw new Error('Response not OK');
3418				}
3419			} catch (error) {
3420				logDebug('Erreur lors de la requête :', error);
3421			} finally {
3422				// hide_ajax_loader();
3423			}
3424		});
3425	}
3426}
3427
3428function transform_devis() {
3429	// Récupérer tous les formulaires avec la classe "form_transform_devis"
3430	const forms = document.querySelectorAll(".form_transform_devis");
3431	if (forms.length > 0) {
3432		forms.forEach(function (form) {
3433			form.addEventListener("submit", async function (event) {
3434				event.preventDefault();
3435
3436				const num_panier = this.getAttribute("id").split("_").pop(); // Extraire le numéro de panier depuis l'id
3437				const modalElement = document.getElementById(`modal_devis_to_commande_${num_panier}`);
3438				const closeButton = document.getElementById(`button_close_devis_modal_${num_panier}`);
3439				const validationDiv = document.getElementById(`validation_div_devis_to_commande_${num_panier}`);
3440				// Initialiser le modal avec l'API Bootstrap
3441				const modal = new bootstrap.Modal(modalElement, {
3442					backdrop: 'static', // Empêche la fermeture en cliquant à l'extérieur
3443					keyboard: false,   // Empêche la fermeture avec la touche Échap
3444				});
3445
3446				modal.show(); // Affiche le modal
3447
3448				if (closeButton) {
3449					closeButton.style.display = "none";
3450				}
3451
3452				const csrf_test_name = this.querySelector("[name=csrf_test_name]").value;
3453				const num_devis = this.querySelector("[name=num_devis]").value;
3454
3455				const params = new URLSearchParams();
3456				params.append("csrf_test_name", csrf_test_name);
3457				if (num_devis !== undefined) {
3458					params.append("num_devis", num_devis);
3459				}
3460				try {
3461
3462					// Effectuer la requête fetch
3463					const response = await fetch(get_protocol_domain_name() + "/panier_v3/transform_devis", {
3464						method: "POST", headers: {
3465							"Content-Type": "application/x-www-form-urlencoded", "X-Requested-With": "XMLHttpRequest",
3466						}, body: params.toString(),
3467					});
3468
3469					if (response.ok) {
3470						const data = await response.json();
3471
3472						if (data.old || !data.success) {
3473							if (closeButton) closeButton.style.display = "block";
3474							if (validationDiv) validationDiv.innerHTML = data.view;
3475						} else {
3476							if (validationDiv) {
3477								setTimeout(() => {
3478									validationDiv.innerHTML = data.view;
3479								}, 1000);
3480							}
3481							setTimeout(() => {
3482								window.location = data.link;
3483							}, 3000);
3484						}
3485					} else {
3486						if (validationDiv) {
3487							setTimeout(() => {
3488								validationDiv.innerHTML = data.view;
3489							}, 1000);
3490						}
3491						setTimeout(() => {
3492							window.location = data.link;
3493						}, 3000);
3494					}
3495				} catch (error) {
3496					logDebug("Erreur lors de la requête :", error);
3497				} finally {
3498					setTimeout(() => {
3499						modal.hide(); // Fermer le modal via l'API Bootstrap
3500					}, 4000);
3501				}
3502			});
3503		});
3504	}
3505}
3506function delete_devis() {
3507	const delete_button = document.querySelectorAll(".btn-delete-devis");
3508	if (delete_button.length > 0) {
3509		document.querySelectorAll("[id^='confirmDeleteBtn_']").forEach(function (confirmButton) {
3510			confirmButton.addEventListener("click", async function () {
3511				show_ajax_loader();
3512				const num_panier = this.dataset.panierId; // Extraire le numéro de panier depuis l'attribut data-panier-id du bouton
3513				const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
3514				const confirmModalId = `confirmDeleteModal_${num_panier}`;
3515				const confirmModal = document.getElementById(confirmModalId);
3516				const loadingModalId = `loadingDeleteModal_${num_panier}`;
3517				const loadingModal = new bootstrap.Modal(document.getElementById(loadingModalId));
3518
3519				// Fermer la modal de confirmation avant d'ouvrir la modal de "Suppression en cours"
3520				const bootstrapConfirmModal = bootstrap.Modal.getInstance(confirmModal);
3521				bootstrapConfirmModal.hide();
3522
3523
3524				try {
3525					const params = new URLSearchParams();
3526					params.append("csrf_test_name", csrf_test_name);
3527					params.append("num_devis", num_panier);
3528
3529					const response = await fetch(get_protocol_domain_name() + "/panier_v3/delete_devis", {
3530						method: "POST",
3531						headers: {
3532							"Content-Type": "application/x-www-form-urlencoded",
3533							"X-Requested-With": "XMLHttpRequest",
3534						},
3535						body: params.toString(),
3536					});
3537
3538					if (response.ok) {
3539						const data = await response.json();
3540						if (data.success) {
3541							const panierElement = document.querySelector(`#order_detail_${num_panier}`);
3542							if (panierElement) {
3543								const cardElement = panierElement.closest(".card");
3544								if (cardElement) {
3545									const allOrderDetails = cardElement.querySelectorAll(".JS_order_detail");
3546
3547									if (allOrderDetails.length === 1 && allOrderDetails[0] === panierElement) {
3548										// Si c'est le seul, on supprime toute la carte
3549										cardElement.remove();
3550									} else {
3551										// Si ce n’est PAS le seul JS_order_detail
3552										const allOrderDetailsLeft = Array.from(allOrderDetails).filter(el => el !== panierElement);
3553
3554										if (allOrderDetailsLeft.length === 1) {
3555											// Après suppression, il ne restera qu’un seul JS_order_detail,
3556											// donc on peut retirer les JS_total_subbasket
3557											const totalSubbaskets = cardElement.querySelectorAll(".JS_total_subbasket");
3558											totalSubbaskets.forEach(el => el.remove());
3559										}
3560
3561										// Ensuite on supprime juste le panier visé
3562										panierElement.remove();
3563									}
3564								}
3565							}
3566
3567						} else {
3568							logDebug("Erreur serveur :", data.message);
3569						}
3570					} else {
3571						logDebug("Erreur réseau :", response.status);
3572					}
3573				} catch (error) {
3574					logDebug("Erreur lors de la requête :", error);
3575				} finally {
3576					loadingModal.hide();
3577					hide_ajax_loader();
3578				}
3579			});
3580		});
3581	}
3582}
3583
3584if (document.querySelector("#basket_form_vehicule")) {
3585	// Initialisation de l'affichage au chargement de la page
3586	collapse_elements_specific("vehicle_recap", "vehicle_info_form");
3587}
3588
3589function collapse_elements_specific(recapSectionLibellle, formSectionLibelle) {
3590	const recapSection = document.getElementById(recapSectionLibellle); // Section récap
3591	const formSection = document.getElementById(formSectionLibelle); // Section formulaire
3592	const editButton = document.querySelector('.btn-secondary'); // Bouton d'édition
3593
3594	// Ajouter la classe collapse_specific pour gérer les transitions sur recapSection
3595	recapSection.classList.add('collapse_specific');
3596
3597	// Fonction pour afficher/masquer les sections avec transition fluide
3598	const toggleDisplayBasketFormVehicule = () => {
3599		if (formSection.classList.contains('show')) {
3600			// Formulaire est ouvert, cacher récap avec animation
3601			recapSection.classList.add('hide'); // Ajout d'une classe pour masquer avec transition
3602			recapSection.style.display = 'none'; // S'assurer que c'est caché
3603		} else {
3604			// Formulaire est fermé, afficher récap avec animation
3605			recapSection.classList.remove('hide'); // Retirer la classe qui masque
3606			recapSection.style.display = 'flex'; // S'assurer que c'est visible
3607		}
3608	};
3609
3610	// Gestion des événements de collapse Bootstrap
3611	formSection.addEventListener('shown.bs.collapse', function () {
3612		recapSection.classList.add('hide'); // Cache le récap avec transition quand le formulaire est montré
3613		recapSection.style.display = 'none';
3614	});
3615
3616	formSection.addEventListener('hidden.bs.collapse', function () {
3617		recapSection.classList.remove('hide'); // Montre le récap avec transition quand le formulaire est caché
3618		recapSection.style.display = 'flex';
3619	});
3620
3621	// Gestion des clics sur le bouton d'édition
3622	editButton.addEventListener('click', function () {
3623		// Même gestion que pour le titre
3624		if (formSection.classList.contains('show')) {
3625			formSection.classList.remove('show');
3626			recapSection.classList.remove('hide');
3627		} else {
3628			formSection.classList.add('show');
3629			recapSection.classList.add('hide');
3630		}
3631	});
3632
3633	toggleDisplayBasketFormVehicule();
3634
3635
3636
3637}
3638
3639let paymentLocked = false;
3640
3641function collapse_elements_payment() {
3642	const inputs = document.querySelectorAll('input[name="choix_payment"]');
3643
3644	inputs.forEach(input => {
3645		input.addEventListener("click", function (e) {
3646			if (paymentLocked) {
3647				e.preventDefault();
3648				e.stopImmediatePropagation();
3649				return false;
3650			}
3651
3652			paymentLocked = true;
3653
3654			// Même logique qu'avant...
3655			if (this.checked && this.dataset.selected === "true") {
3656				this.checked = false;
3657				this.dataset.selected = "false";
3658
3659				document.querySelectorAll('.collapse_payments').forEach(collapse => {
3660					let bsCollapse_off = bootstrap.Collapse.getOrCreateInstance(collapse, {
3661						toggle: false
3662					});
3663					bsCollapse_off.hide();
3664				});
3665			} else {
3666				inputs.forEach(i => i.dataset.selected = "false");
3667				this.dataset.selected = "true";
3668
3669				document.querySelectorAll('.collapse_payments').forEach(collapse => {
3670					let bsCollapse_off = bootstrap.Collapse.getOrCreateInstance(collapse, {
3671						toggle: false
3672					});
3673					bsCollapse_off.hide();
3674				});
3675
3676				let selectedCollapse = document.getElementById("collapse_payment_" + this.value);
3677				if (selectedCollapse) {
3678					let bsCollapse = bootstrap.Collapse.getOrCreateInstance(selectedCollapse);
3679					bsCollapse.show();
3680				}
3681			}
3682
3683			// Déverrouiller après la transition
3684			setTimeout(() => {
3685				paymentLocked = false;
3686			}, 400);
3687		});
3688	});
3689}
3690
3691async function getBasketInformations(maxRetries = 5, retries = 0) {
3692	try {
3693		const response = await fetch(get_protocol_domain_name() + "/panier_v3/get_basket_informations", {
3694			method: "GET",
3695			headers: {
3696				"X-Requested-With": "XMLHttpRequest"
3697			},
3698			mode: "cors",
3699			credentials: "same-origin"
3700		});
3701
3702		if (response.ok) {
3703			const modalContent = await response.text(); // Récupération du HTML
3704			document.querySelector("#panier_modal").innerHTML = modalContent;
3705			// Affichage de la modale Bootstrap
3706
3707			if (modalContent) {
3708				let basketModal = new bootstrap.Modal(document.getElementById("basket_modal_information"));
3709				basketModal.show();
3710			}
3711		} else {
3712			if (retries < maxRetries) {
3713				retries++;
3714				logDebug(`Tentative ${retries} de ${maxRetries}`);
3715				return getBasketInformations(maxRetries, retries); // On retente la requête
3716			} else {
3717				throw new Error('Nombre maximal de tentatives atteint');
3718			}
3719		}
3720	} catch (error) {
3721		logDebug('Erreur dans getBasketInformations:', error);
3722
3723		if (retries < maxRetries) {
3724			retries++;
3725			logDebug(`Tentative ${retries} de ${maxRetries}`);
3726			return getBasketInformations(maxRetries, retries); // On retente la requête
3727		} else {
3728			console.error("Échec après plusieurs tentatives.");
3729		}
3730	}
3731}
3732
3733async function set_transaction_on_progress() {
3734	document.querySelector("#form_card_payment").addEventListener("submit", async function() {
3735		await transaction_on_progress();
3736	});
3737}
3738
3739async function transaction_on_progress() {
3740	const csrf_test_name = document.querySelector("[name=csrf_test_name]").value;
3741	const params = new URLSearchParams();
3742	params.append('csrf_test_name', csrf_test_name);
3743
3744	try {
3745		await fetchWithRetries(get_protocol_domain_name() + "/panier_v3/set_transaction_on_progress", {
3746			method: 'POST', headers: {
3747				'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest'
3748			}, body: params,
3749			mode: 'cors',
3750			credentials: 'same-origin'
3751		});
3752	} catch (error) {
3753		// Gérer les erreurs
3754		logDebug('Erreur lors de la requête :', error);
3755	}
3756}
3757function check_transaction_on_progress() {
3758	document.querySelector("#form_card_payment").addEventListener("submit", async function(event) {
3759		event.preventDefault();
3760
3761		const form = this;
3762		const csrf_test_name = form.querySelector("[name=csrf_test_name]").value;
3763		const params = new URLSearchParams();
3764		params.append('csrf_test_name', csrf_test_name);
3765
3766		try {
3767			const response = await fetchWithRetries(get_protocol_domain_name() + "/panier_v3/check_transaction_on_progress", {
3768				method: 'POST',
3769				headers: {
3770					'Content-Type': 'application/x-www-form-urlencoded',
3771					'X-Requested-With': 'XMLHttpRequest'
3772				},
3773				body: params.toString(),
3774				mode: 'cors',
3775				credentials: 'same-origin'
3776			});
3777
3778			if (response.ok) {
3779				const data = await response.json();
3780				if (data.status === "ok") {
3781					form.submit();
3782				} else {
3783					if (data.redirect_url) {
3784						window.location.href = data.redirect_url;
3785					} else {
3786						window.location.href = "/" + await trad('_ROUTE_PANIER_AFFICHER')
3787					}
3788				}
3789			}
3790		} catch (error) {
3791			logDebug('Erreur lors de la requête :', error);
3792		}
3793	});
3794}
3795
3796
3797

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.