Une erreur s'est produite lors du traitement du modèle.
The following has evaluated to null or missing:
==> mlxPhoneUtilService [in template "20101#20128#SEARCH-BAR-V3-STR-DEFAULT-TEMPLATE" at line 4, column 21]
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
- Failed at: #assign telValue = mlxPhoneUtilServic... [in template "20101#20128#SEARCH-BAR-V3-STR-DEFAULT-TEMPLATE" at line 4, column 1]
----
1<#assign cdn = (mlxUrlUtilService.getCdn(scopeGroupId))!"" />
2<#assign countryCode = (mlxExpandoService.getExpandoValueForClass("com.liferay.portal.kernel.model.Group","country-code", scopeGroupId).getString())!"" />
3
4<#assign telValue = mlxPhoneUtilService.getTelephone(mlxServiceContext)!"" />
5<#assign telDash = telValue?replace(" - ", " ")?replace(" ", "-")?replace("(", "")?replace(")", "") />
6<#assign telAlt = languageUtil.get(locale, "mlx.theme.menu.telephone") />
7<#assign openingHours = (mlxExpandoService.getExpandoValueForClass("com.liferay.portal.kernel.model.Group","opening-hours", scopeGroupId).getString())!"" />
8
9
10<#assign styleCss = "opacity: 0; pointer-events: none;" />
11
12
13<div class="corporate--header-contact">
14 <a href="tel:${telDash}" rel="nofollow" class="corporate--header-contact--button phone" id="working-time-phone" style="${styleCss}">
15 ${corporate.img(cdn + '/o/corporate-theme/theme-images/00_menu_ico_phone_orange.svg', false, 'class="corporate--header-contact--button-image"')}
16 <span>${telValue}</span>
17 </a>
18
19 <#assign contactMasterId=46017 />
20 <#assign contactLayout=(mlxMastersHelperService.getLayoutByMasterAndGroup(contactMasterId,scopeGroupId)!"") />
21 <#assign contactLabel = languageUtil.get(locale, "mlx.theme.menu.contact") />
22 <#assign contactLogo = themeDisplay.getPathThemeImages() + "/icons/00_menu_ico_mail_white.svg" />
23 <#if contactLayout?has_content>
24 <#assign contactUrl = contactLayout.getFriendlyURL() />
25 <a href="${contactUrl}?cta_origin=CTA_header" class="corporate--header-contact--button mail" title="${contactLabel}" data-gtm-event="click" data-gtm-event-label="/Contact" data-gtm-event-click-category="[currentPage]_Header_Contact">
26 ${corporate.img(cdn + '/o/corporate-theme/theme-images/00_menu_ico_mail_white.svg', false, 'alt="${contactLabel}"', 'title="${contactLabel}"', 'class="corporate--header-contact--button-image"')}
27 <span>${contactLabel}</span>
28 </a>
29 </#if>
30</div>
31
32<script>
33document.addEventListener("DOMContentLoaded", async () => {
34 try {
35 const workingTimeElement = document.getElementById('working-time-phone');
36 if (!workingTimeElement) return;
37
38 // 🔹 Llamada segura a una API interna autenticada
39 const url = new URL(window.location.origin + '/o/corporate-publics-rest-services/v1.0/telephone');
40 const response = await fetch(
41 url,
42 {
43 method: 'GET',
44 headers: {
45 'Accept': 'application/json',
46 'x-csrf-token': Liferay.authToken // 👈 Token necesario para evitar 403 Forbidden
47 },
48 credentials: 'include' // 👈 Envia las cookies de sesión del usuario
49 }
50 );
51
52 if (!response.ok) {
53 console.error('Error al llamar a la API:', response.status, response.statusText);
54 return;
55 }
56
57 const obj = await response.json();
58
59 if (obj && obj.telephone) {
60 const tel = obj.telephone;
61 workingTimeElement.setAttribute('href', 'tel:' + tel.replace(/[^\d+]+/g, ''));
62 workingTimeElement.querySelector('span').textContent = tel;
63 }
64
65 // Fade-in effect
66 workingTimeElement.style.transition = 'all 0.4s ease-out';
67 workingTimeElement.style.opacity = '1';
68 workingTimeElement.style.pointerEvents = 'auto';
69 } catch (error) {
70 console.error('Error al obtener el teléfono:', error);
71 }
72});
73</script>
Nous aidons les entreprises à planifier correctement le volume de leurs stocks pour configurer l'ensemble des produits les plus appropriés dans l’entrepôt, conformément à leur stratégie de stockage et au service client.
Nous proposons des outils logiciels pour situer le stock des différents produits de manière stratégique dans l'entrepôt, en tenant compte de leurs caractéristiques et des besoins de l'entreprise.
- Plan de la chaleur de votre entrepôt pour diagnostiquer les produits mal positionnés.
- Affinité de produits.
- Slotting de produits pour améliorer les temps de préparation sur la base de vos données historiques.