UNE-EN 300910 V7.3.1
Sistema de telecomunicaciones digitales celulares (Fase 2+) (GSM). Recepción y transmisión vía radio (GSM 05.05 versión 7.3.1 Edición 1998) (Ratificada por AENOR en marzo de 2006.)
| Edition date: |
2006-03-01
In Force
|
|---|---|
| Ratification date: | 2006-03-01 |
| ICS: | 33.060.20-Receiving and transmitting equipment, 33.060.01-Radiocommunications in general |
| CTN: | CTN 133 - Telecomunicaciones |
|
International Equivalence |
Identic EN 300910 V7.3.1 |
Please enter a valid video URL.
The URL can point to any video file or a Youtube video.
The book in the author's words
Ultricies magna feugiat malesuada sociosqu varius vivamus cubilia parturient, himenaeos vitae vehicula nam placerat netus urna platea, nostra rutrum felis mattis penatibus velit quisque.
ButtonStandards cited
The following has evaluated to null or missing:
==> product.productId [in template "34352066712900#33336#null" at line 21, column 22]
----
Tip: It's the step after the last dot that caused this error, not those before it.
----
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 productId = product.productId [in template "34352066712900#33336#null" at line 21, column 1]
----
1<#setting url_escaping_charset="UTF-8">
2<meta name="viewport" content="width=device-width, initial-scale=1">
3
4
5<#-- Variables -->
6<#assign isDebug = false>
7<#assign executeScriptsAndStyles = false>
8<#assign executeHTML = false>
9
10<#assign channelResponse = restClient.get("/headless-commerce-delivery-catalog/v1.0/channels?filter=name eq 'Aenor Tienda'")>
11<#assign channel = channelResponse.items[0]>
12<#assign channelId = channel.id>
13<#assign product = getProduct(channelId, CPDefinition_cProductId.getData()) />
14<#assign siteGroup = themeDisplay.getSiteGroup() />
15<#assign currentLocale = themeDisplay.getLocale()>
16<#assign currentLanguage = currentLocale?substring(0,2)>
17<#assign LANG_ENTRIES = getListTypeEntriesByERC("IDIOMAS_NORMAS_PICKLIST")>
18
19<#-- Product data -->
20<#assign displayDateProduct = CPDefinition_displayDate.getData() />
21<#assign productId = product.productId />
22<#assign cpDefinitionId = product.id />
23
24<#assign categoriesProduct = getProductCategories(channelId, productId) />
25<#assign hasProductCategoriaTipoEntidadLibro = isVocabularyNameIntoCategories(categoriesProduct, 'entity type', 'libro') />
26<#assign hasProductCategoriaTipoEntidadNorma = isVocabularyNameIntoCategories(categoriesProduct, 'entity type', 'norma') />
27<#assign hasProductCategoriaTipoEntidadColeccionTematica = isVocabularyNameIntoCategories(categoriesProduct, 'entity type', 'coleccion tematica') />
28<#assign bookInfoProduct = getBookInfoProduct(cpDefinitionId) />
29
30<#-- Standard/Norma data -->
31 <#assign standardRelationsProduct = getStandardRelationsProduct(cpDefinitionId, "Reference") />
32
33
34
35
36<#-- Functions -->
37<#function getProduct channelId productId>
38 <#return restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products/${productId}")>
39</#function>
40
41
42<#function getBookInfoProduct cpDefinitionId>
43 <#assign response = restClient.get("/c/bookinfos/?filter=r_bookInfo_CPDefinitionId eq '${cpDefinitionId}'")!{} />
44 <#assign items = response.items![] />
45 <#return (items?size > 0)?then(items[0], {}) />
46</#function>
47
48
49<#function getProductCategories channelId productId>
50 <#return restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products/${productId}/categories?sort=vocabulary").items>
51</#function>
52
53
54<#function isVocabularyNameIntoCategories categories vocabulary name>
55 <#assign found = false />
56
57 <#if categories?has_content && vocabulary?has_content && name?has_content>
58
59 <#assign vocabNorm = normalize(vocabulary) />
60 <#assign nameNorm = normalize(name) />
61
62 <#list categories as category>
63 <#if !found>
64 <#assign catVocabNorm = normalize(category.vocabulary) />
65 <#assign catNameNorm = normalize(category.name) />
66
67 <#if catVocabNorm == vocabNorm && catNameNorm == nameNorm>
68 <#assign found = true />
69 </#if>
70 </#if>
71 </#list>
72
73 </#if>
74
75 <#return found>
76</#function>
77
78
79<#function normalize text onlyAccents = false>
80 <#-- proteger null -->
81 <#if !text?has_content>
82 <#return "">
83 </#if>
84
85 <#assign t = text />
86
87 <#-- quitar acentos -->
88 <#assign t = t
89 ?replace("á","a")?replace("é","e")?replace("í","i")
90 ?replace("ó","o")?replace("ú","u")?replace("ü","u")
91 ?replace("ñ","n")
92 ?replace("Á","A")?replace("É","E")?replace("Í","I")
93 ?replace("Ó","O")?replace("Ú","U")?replace("Ü","U")
94 ?replace("Ñ","N")
95 />
96
97 <#-- si NO es solo acentos, normalización completa -->
98 <#if !onlyAccents>
99 <#assign t = t?lower_case />
100 <#assign t = t?trim />
101 <#assign t = t?replace("\\s+", " ", "r") />
102 </#if>
103
104 <#return t>
105</#function>
106
107
108<#function getProductByERC erc>
109 <#-- TODO: estamos usando el endpoint del product admin, hay que usar la del Product de Liferay NO admin: headless-commerce-delivery-catalog -->
110 <#-- <#return restClient.get("/headless-commerce-admin-catalog/v1.0/products/by-externalReferenceCode/${erc}")> -->
111 <#assign response = restClient.get("/headless-commerce-admin-catalog/v1.0/products/by-externalReferenceCode/${erc}")>
112 <#-- Si el producto no existe o tiene status NOT_FOUND, devolvemos string vacío -->
113 <#if response?? && response.status?? && response.status == "NOT_FOUND">
114 <#return {}>
115 <#elseif !response??>
116 <#return {}>
117 <#else>
118 <#return response>
119 </#if>
120</#function>
121
122
123<#function getProductSpecifications channelId productId>
124 <#return restClient.get(
125 "/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products/${productId}/product-specifications?sort"
126 ).items>
127</#function>
128
129
130<#function getCurrentStateDate specifications>
131 <#list specifications as specification>
132 <#if specification.specificationKey == 'current-state-date'>
133 <#return specification.value>
134 </#if>
135 </#list>
136 <#return "">
137</#function>
138
139
140<#function getStatus categories>
141 <#list categories as category>
142 <#if category.vocabulary == 'status'>
143 <#return category.title>
144 </#if>
145 </#list>
146 <#return "">
147</#function>
148
149
150<#function getOrganism categories>
151 <#list categories as category>
152 <#if category.vocabulary == 'organismos'>
153 <#return category.name>
154 </#if>
155 </#list>
156 <#return "">
157</#function>
158
159
160<#function getNormasDetails productId>
161 <#return restClient.get(
162 "/c/standards/?filter=r_standards_CPDefinitionId eq '${productId}'"
163 ).items>
164</#function>
165
166
167<#function getListTypeEntriesByERC erc>
168 <#attempt>
169 <#return restClient.get(
170 "/headless-admin-list-type/v1.0/list-type-definitions/by-external-reference-code/${erc}/list-type-entries?fields=key,name&sort"
171 ).items>
172 <#recover>
173 <#return []>
174 </#attempt>
175</#function>
176
177
178<#function langLiteral key>
179 <#assign k = (key!"")?upper_case>
180 <#list LANG_ENTRIES as e>
181 <#if (e.key!"")?upper_case == k>
182 <#return e.name!"">
183 </#if>
184 </#list>
185 <#return key!"" >
186</#function>
187
188
189<#function getURLsOfProduct product baseURL="" siteFriendlyURL="" languageFieldName="language" urlFieldName="url">
190 <#-- Inicializamos un array vacío -->
191 <#assign urlsArray = []>
192
193 <#-- Validamos que product y product.urls existan -->
194 <#if product?? && product.urls??>
195 <#-- Iteramos sobre los idiomas -->
196 <#list product.urls?keys as lang>
197 <#assign urlValue = product.urls[lang] />
198 <#if urlValue?? && urlValue?has_content>
199 <#-- Aseguramos que la URL empiece con "/p/" -->
200 <#assign cleanUrl = urlValue?starts_with("/")?then(urlValue, "/p/" + urlValue) />
201
202 <#-- Generamos la URL completa -->
203 <#-- Si baseURL tiene contenido, construimos URL completa -->
204 <#if baseURL?? && baseURL?has_content>
205
206 <#-- Aseguramos que el slug empiece con /p/ -->
207 <#assign cleanUrl = urlValue?starts_with("/")?then(urlValue, "/p/" + urlValue) />
208
209 <#-- Tomamos las dos primeras letras del idioma para el prefijo -->
210 <#assign langPrefix = lang?substring(0,2)>
211
212 <#-- Construimos la URL completa -->
213 <#if siteFriendlyURL?? && siteFriendlyURL?has_content>
214 <#assign fullUrl = baseURL + "/" + langPrefix + siteFriendlyURL + cleanUrl>
215 <#else>
216 <#assign fullUrl = baseURL + "/" + langPrefix + cleanUrl>
217 </#if>
218
219 <#else>
220 <#assign fullUrl = cleanUrl>
221 </#if>
222
223 <#-- Creamos el objeto language+url -->
224 <#assign newItem = {(languageFieldName): lang, (urlFieldName): fullUrl} />
225
226 <#-- Lo agregamos al array -->
227 <#assign urlsArray = urlsArray + [newItem] />
228 </#if>
229 </#list>
230 </#if>
231
232 <#return urlsArray>
233</#function>
234
235
236<#function getStandardRelationsProduct cpDefinitionId type=""
237 ercProductFieldName="ercProduct" defaultLang = "es_ES" urlProductCurrentLanguageFieldName="urlProductCurrentLanguage" urlsProductByLangFieldName="urlsProductByLang"
238 languageFieldName="language" urlFieldName="url" sort="type">
239
240 <#assign result = [] />
241 <#assign typeFilter = "" />
242
243 <#if type?? && type?has_content>
244 <#assign typeFilter = " and type eq '${type}'" />
245 </#if>
246
247 <#-- Obtener relaciones desde la API -->
248 <#-- Construcción final del endpoint -->
249 <#assign restUrl = "/c/standardrelationses/?filter=r_standardRelations_CPDefinitionId eq '${cpDefinitionId}'${typeFilter}&sort=${sort}" />
250 <#-- Llamada al servicio -->
251 <#assign standardRelations = restClient.get(restUrl).items />
252
253 <#-- Iterar sobre cada relación -->
254 <#list standardRelations as standardRelationProduct>
255
256 <#-- Crear ERC del producto relacionado -->
257 <#assign ercProduct = (standardRelationProduct.relatedOrganismStandardName!"relatedOrganismStandardName") + "-" + (standardRelationProduct.relatedStandardId!"relatedStandardId") />
258
259 <#-- Obtener el producto por ERC -->
260 <#assign productByERC = getProductByERC(ercProduct) />
261 <#assign findProductByERC = (productByERC?? && productByERC?has_content)>
262
263 <#-- Obtener URLs del producto -->
264 <#assign baseURL = themeDisplay.getPortalURL()>
265 <#assign siteFriendlyURL = "/web" + siteGroup.getFriendlyURL()>
266 <#assign urlsProductByLang = getURLsOfProduct(productByERC, baseURL, siteFriendlyURL, languageFieldName, urlFieldName) />
267
268 <#-- Obtenemos URLs del producto default y current language -->
269 <#assign selectedURLCurrent = "">
270 <#assign selectedURLDefault = "">
271 <#list urlsProductByLang as item>
272 <#-- URL del idioma actual -->
273 <#if item.language == currentLocale && selectedURLCurrent == "">
274 <#assign selectedURLCurrent = item.url>
275 </#if>
276
277 <#-- URL del idioma por defecto -->
278 <#if item.language == defaultLang && selectedURLDefault == "">
279 <#assign selectedURLDefault = item.url>
280 </#if>
281
282 <#-- Salimos si ya tenemos ambas -->
283 <#if selectedURLCurrent != "" && selectedURLDefault != "">
284 <#break>
285 </#if>
286 </#list>
287
288 <#-- Usamos el idioma actual si existe, sino el por defecto -->
289 <#if selectedURLCurrent != "">
290 <#assign urlCurrentLanguage = selectedURLCurrent>
291 <#else>
292 <#assign urlCurrentLanguage = selectedURLDefault>
293 </#if>
294
295 <#-- Combinar todos los datos del objeto original + nuevos campos -->
296 <#assign resultItem = standardRelationProduct + {
297 (ercProductFieldName): ercProduct,
298 (urlProductCurrentLanguageFieldName): urlCurrentLanguage,
299 (urlsProductByLangFieldName): urlsProductByLang,
300 ("findProductByERC"): findProductByERC
301 } />
302
303 <#-- Añadir al array final -->
304 <#assign result = result + [resultItem] />
305 </#list>
306
307 <#return result>
308</#function>
309
310
311<#macro printObject obj>
312 <#-- Permite hacer un output de un array de objetos o un objeto que se pasa como parámetro -->
313 <#if obj?is_hash>
314 {
315 <#list obj?keys as k>
316 "${k}":
317 <#assign value = obj[k]>
318 <#if value?is_hash || value?is_sequence>
319 <@printObject obj=value/>
320 <#elseif value?is_boolean>
321 ${value?c}
322 <#elseif value?is_number>
323 ${value}
324 <#elseif value?has_content>
325 "${value?string}"
326 <#else>
327 null
328 </#if>
329 <#if k_has_next>, </#if>
330 </#list>
331 }
332 <#elseif obj?is_sequence>
333 [
334 <#list obj as item>
335 <@printObject obj=item/>
336 <#if item_has_next>, </#if>
337 </#list>
338 ]
339 <#elseif obj?is_boolean>
340 ${obj?c}
341 <#elseif obj?is_number>
342 ${obj}
343 <#elseif obj?has_content>
344 "${obj?string}"
345 <#else>
346 null
347 </#if>
348</#macro>
349
350
351<#macro renderDebugProduct isDebug product hasProductCategoriaTipoEntidadLibro hasProductCategoriaTipoEntidadNorma standardRelationsProduct>
352
353 <#if product??>
354 <#assign productId = product.productId!"" />
355 <#assign cpDefinitionId = product.id!"" />
356 </#if>
357
358 <#if themeDisplay??>
359 <#assign siteGroup = themeDisplay.getSiteGroup() />
360 </#if>
361
362 <#if isDebug>
363
364 <h2>Información del Producto</h2>
365 <ul>
366 <li><strong>Nombre:</strong> ${product.name}</li>
367 <li><strong>Descripción:</strong> ${product.description?default("Sin descripción")}</li>
368 <li><strong>External Reference Code:</strong> ${product.externalReferenceCode?default("No disponible")}</li>
369 <li><strong>Product ID (Field: product.productId):</strong> ${productId}</li>
370 <li><strong>CPDefinition ID (Field: product.id):</strong> ${cpDefinitionId}</li>
371 <li><strong>ClassNameId de com.liferay.commerce.product.model.CPDefinition:</strong> 30025</li>
372
373 <li>
374 <strong>URL del producto:</strong>
375 ${siteGroup.getDisplayURL(themeDisplay)}/e/{friendlyURL_display_page_template}/30025/{cpDefinitionId}
376 <b>por ejemplo:</b>
377 ${siteGroup.getDisplayURL(themeDisplay)}/e/producto-tienda/30025/${cpDefinitionId}
378 </li>
379
380 <li><strong>Tiene Categoria [Tipo entidad > Libro]:</strong> ${hasProductCategoriaTipoEntidadLibro?string}</li>
381 <li><strong>Tiene Categoria [Tipo entidad > Norma]:</strong> ${hasProductCategoriaTipoEntidadNorma?string}</li>
382 </ul>
383
384 <hr>
385
386 <h2>Standard/Norma Relations del Producto</h2>
387 <p style="margin-left: 20px;">
388 - Información complementaria relacionada al producto en la entidad "StandardRelations" (relación 1:N).<br>
389 </p>
390
391 <#if standardRelationsProduct?has_content>
392
393 <#list standardRelationsProduct as standardRelationProduct>
394 <li>
395 <strong>
396 Standard/Norma Relation #${standardRelationProduct_index + 1}
397 de ${standardRelationsProduct?size}
398 </strong>
399
400 <ul>
401 <li><strong>id:</strong> ${standardRelationProduct.id}</li>
402 <li><strong>externalReferenceCode:</strong> ${standardRelationProduct.externalReferenceCode}</li>
403 <li><strong>relatedOrganismStandardName:</strong> ${standardRelationProduct.relatedOrganismStandardName!""}</li>
404 <li><strong>r_standardRelations_CPDefinitionERC:</strong> ${standardRelationProduct.r_standardRelations_CPDefinitionERC}</li>
405 <li><strong>r_standardRelations_CPDefinitionId:</strong> ${standardRelationProduct.r_standardRelations_CPDefinitionId}</li>
406 <li><strong>standardRelationsERC:</strong> ${standardRelationProduct.standardRelationsERC}</li>
407 <li><strong>relatedStandardId:</strong> ${standardRelationProduct.relatedStandardId}</li>
408 <li><strong>type:</strong> ${standardRelationProduct.type}</li>
409 <li><strong>relatedStandardName:</strong> ${standardRelationProduct.relatedStandardName!""}</li>
410 <li><strong>ERC del producto relacionado:</strong> ${standardRelationProduct.ercProduct}</li>
411 <li><strong>Encontrado producto relacionado byERC (Field: findProductByERC):</strong> ${standardRelationProduct.findProductByERC?string("sí","no")}</li>
412 <li>
413 <strong>URL del producto del actual idioma (Field: urlProductCurrentLanguage):</strong>
414 ${standardRelationProduct.urlProductCurrentLanguage?has_content?then(standardRelationProduct.urlProductCurrentLanguage, "No find")}
415 </li>
416 <li>
417 <strong>URLs del producto relacionado (Field: urlsProductByLang.language / urlsProductByLang.url):</strong>
418 <#if standardRelationProduct.urlsProductByLang?? && standardRelationProduct.urlsProductByLang?has_content>
419 <#list standardRelationProduct.urlsProductByLang as item>
420 ${item.language} - ${item.url}<#if item_has_next>, </#if>
421 </#list>
422 <#else>
423 No find
424 </#if>
425 </li>
426 <li>
427 <div class="">
428 <p><strong>Print standardRelationProduct:</strong></p>
429 <div class="print-object-json-content mb-3" style="max-height:200px; overflow:auto; border:1px solid #ccc; padding:5px; cursor:pointer;"
430 onclick="const r=document.createRange(); r.selectNodeContents(this); const s=window.getSelection(); s.removeAllRanges(); s.addRange(r);">
431 <@printObject standardRelationProduct />
432 </div>
433 </div>
434 </li>
435 </ul>
436 </li>
437 </#list>
438
439 <#else>
440 <p>Sin registros relacionados en la relación Product → StandardRelations (1:N).</p>
441 </#if>
442
443 </#if>
444
445</#macro>
446
447
448<#macro standardsScriptsAndStyles>
449 <script>
450 (function($){
451
452 function euros(v){
453 var n = Number(v) || 0;
454 return n.toLocaleString('es-ES', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' €';
455 }
456 function uniq(a){ return Array.from(new Set(a)); }
457
458 function fill($sel, values, textFn){
459 var keep = $sel.val();
460 $sel.empty();
461 values.forEach(function(v){
462 $sel.append($('<option>', { value: v, text: textFn ? textFn(v) : v }));
463 });
464 if(keep && values.indexOf(keep) !== -1){ $sel.val(keep); }
465 else if(values.length){ $sel.val(values[0]); }
466 }
467
468 function relabel($sel, textFn){
469 $sel.find('option').each(function(){
470 var v = $(this).attr('value');
471 $(this).text(textFn ? textFn(v) : v);
472 });
473 }
474
475 function initCard($card){
476 var dataNode = $card.find('script.normas-data')[0];
477 if(!dataNode) return;
478 var data = [];
479 try { data = JSON.parse(dataNode.textContent); } catch(e) { data = []; }
480 if(!data.length) return;
481
482 var mapNode = $card.find('script.lang-map')[0];
483 var langMap = {};
484 try { if(mapNode) langMap = JSON.parse(mapNode.textContent); } catch(e) { langMap = {}; }
485
486 var $lang = $card.find('.select-language');
487 var $fmt = $card.find('.select-format');
488 var $price = $card.find('.price-ae');
489
490 function toUC(s){ return (s||'').toString().toUpperCase(); }
491 function labelOf(lang){ return langMap[toUC(lang)] || lang; }
492 function formatsFor(lang){
493 return uniq(data.filter(function(d){ return d.language === lang; }).map(function(d){ return d.format; }));
494 }
495 function languagesFor(fmt){
496 return uniq(data.filter(function(d){ return d.format === fmt; }).map(function(d){ return d.language; }));
497 }
498 function priceOf(lang, fmt){
499 var m = data.find(function(d){ return d.language === lang && d.format === fmt; });
500 return m ? Number(m.price) || 0 : 0;
501 }
502
503 function onLanguageChange(){
504 var lang = $lang.val();
505 var fmts = formatsFor(lang);
506 fill($fmt, fmts, null);
507 $price.text(euros(priceOf(lang, $fmt.val())));
508 }
509 function onFormatChange(){
510 var fmt = $fmt.val();
511 var langs = languagesFor(fmt);
512 fill($lang, langs, labelOf);
513 $price.text(euros(priceOf($lang.val(), fmt)));
514 }
515
516 var l0 = $lang.val();
517 var f0 = $fmt.val();
518 if(!data.find(function(d){ return d.language === l0 && d.format === f0; })){
519 onLanguageChange();
520 } else {
521 $price.text(euros(priceOf(l0, f0)));
522 }
523 relabel($lang, labelOf);
524
525 $lang.off('change.ae').on('change.ae', onLanguageChange);
526 $fmt.off('change.ae').on('change.ae', onFormatChange);
527
528 async function onAdd(e){
529 e.preventDefault();
530 var entryType = ($card.data('entrytype') || 'Norma');
531 var code = ($card.data('code') || '').toString();
532 var codIdioma = ($lang.val() || '').toString();
533 var codFormato = ($fmt.val() || '').toString();
534 if (!code) code = ($card.find('.title-standard').text() || '').trim();
535
536 await window.ecomGlobalScripts.functions.addToCart({
537 entryType: entryType,
538 code: code,
539 codIdioma: codIdioma,
540 codFormato: codFormato,
541 price: Number(priceOf(codIdioma, codFormato)) || 0,
542 name: ($card.data('title') || '').toString(),
543 amount: 1
544 });
545 }
546
547 $card.find('.standard-button').off('click.ae').on('click.ae', onAdd);
548 }
549
550 function adjustHeights(){
551 if($(window).width() > 766.98){
552 var hT = 0, hD = 0;
553 $('.standards-section .title-standard').css('height', 'auto').each(function(){ hT = Math.max(hT, $(this).outerHeight()); });
554 $('.standards-section .description-text').css('height', 'auto').each(function(){ hD = Math.max(hD, $(this).outerHeight()); });
555 $('.standards-section .title-standard').height(hT);
556 $('.standards-section .description-text').height(hD);
557 } else {
558 $('.standards-section .title-standard, .standards-section .description-text').css('height', 'auto');
559 }
560 }
561
562 $(function(){
563 $('.standards-section .item-standard').each(function(){ initCard($(this)); });
564
565 var $owl = $('.standards-section .standards-container');
566
567 if ($owl.length && !$owl.hasClass('owl-loaded') && !$owl.data('owl.carousel')) {
568 $owl.owlCarousel({
569 nav: true,
570 navText: [
571 '<i class="fa-solid fa-chevron-left" aria-hidden="true"></i>',
572 '<i class="fa-solid fa-chevron-right" aria-hidden="true"></i>'
573 ],
574 loop: false,
575 dots: false,
576 pagination: false,
577 margin: 25,
578 autoHeight: false,
579 responsive: {
580 0: { items: 1, mouseDrag: true, touchDrag: true },
581 500: { items: 1, mouseDrag: true, touchDrag: true },
582 767: { items: 2, mouseDrag: true, touchDrag: true },
583 1000:{ items: 3, mouseDrag: true, touchDrag: true },
584 1200:{ items: 4, mouseDrag: true, touchDrag: true }
585 }
586 });
587
588 $owl.off('initialized.owl.carousel refreshed.owl.carousel resized.owl.carousel translated.owl.carousel')
589 .on('initialized.owl.carousel refreshed.owl.carousel resized.owl.carousel translated.owl.carousel', adjustHeights);
590 }
591
592 adjustHeights();
593 $(window).off('resize.standards').on('resize.standards', adjustHeights);
594 });
595 })(jQuery);
596 </script>
597
598 <style>
599
600 #ecom-norma-detail-normas-referenced .standards-section .standards-container {
601 display: flex;
602 flex-wrap: nowrap;
603 gap: 20px 0;
604 }
605 #ecom-norma-detail-normas-referenced .standards-section .standards-container:not(.owl-drag) .owl-stage {
606 cursor: auto;
607 }
608 #ecom-norma-detail-normas-referenced .standards-section .item-standard {
609 position: relative;
610 border: 1px solid #e0e0e0;
611 padding: 20px 14px 21px;
612 border-radius: 4px;
613 background: #fff;
614 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
615 display: flex;
616 flex-direction: column;
617 justify-content: space-between;
618 }
619 #ecom-norma-detail-normas-referenced .standards-section .title-standard {
620 font-family: SohoGothicPro-Regular;
621 font-size: 16px;
622 font-weight: bold;
623 color: #1a4b94;
624 margin-top: 10px;
625 margin-bottom: 10px;
626 }
627 #ecom-norma-detail-normas-referenced .standards-section .description-text {
628 margin-top: 10px;
629 margin-bottom: 12px;
630 font-family: SohoGothicPro-Regular;
631 font-size: 13px;
632 text-align: left;
633 color: #333;
634 }
635 #ecom-norma-detail-normas-referenced .standards-section .price-container {
636 display: flex;
637 flex-direction: column;
638 text-align: left;
639 letter-spacing: -0.02em;
640 }
641 #ecom-norma-detail-normas-referenced .standards-section .price-container .price-text {
642 font-family: SohoGothicPro-Regular;
643 font-size: 12px;
644 font-weight: 400;
645 line-height: 13.2px;
646 color: #000;
647 }
648 #ecom-norma-detail-normas-referenced .standards-section .price-container .price {
649 font-size: 20px;
650 font-weight: bold;
651 margin-bottom: 10px;
652 color: #1a4b94;
653 }
654 #ecom-norma-detail-normas-referenced .standards-section .info-container {
655 display: flex;
656 }
657 @media (min-width: 500px) and (max-width: 767px) {
658 #ecom-norma-detail-normas-referenced .standards-section .info-container {
659 flex-direction: column;
660 justify-content: end;
661 align-items: start;
662 }
663 }
664 #ecom-norma-detail-normas-referenced .standards-section .info-container .standard-mode img,
665 #ecom-norma-detail-normas-referenced .standards-section .info-container .standard-date img,
666 #ecom-norma-detail-normas-referenced .standards-section .info-container .standard-mode picture,
667 #ecom-norma-detail-normas-referenced .standards-section .info-container .standard-date picture {
668 width: 16px;
669 }
670 #ecom-norma-detail-normas-referenced .standards-section .info-container .standard-mode {
671 margin-right: 16px;
672 }
673 #ecom-norma-detail-normas-referenced .standards-section .standard-button {
674 padding: 17px;
675 width: 100%;
676 text-align: center;
677 display: block;
678 background-color: var(--brand-color-1, #1f57a3);
679 color: #fff;
680 text-transform: uppercase;
681 font-family: SohoStd-Medium;
682 font-size: 14px;
683 font-weight: 500;
684 line-height: 14px;
685 border: none;
686 text-align: center;
687 cursor: pointer;
688 }
689 #ecom-norma-detail-normas-referenced .standards-section .standard-button:disabled,
690 #ecom-norma-detail-normas-referenced .standards-section .standard-button[disabled],
691 #ecom-norma-detail-normas-referenced .standards-section .standard-button.disabled,
692 #ecom-norma-detail-normas-referenced .standards-section .standard-button.ecom-btn-loading {
693 opacity: .6;
694 pointer-events: none;
695 filter: brightness(0.85);
696 }
697 #ecom-norma-detail-normas-referenced .standards-section .standard-button:active {
698 filter: brightness(0.85);
699 }
700
701 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next {
702 width: 50px;
703 border: 1px solid #c3c3c3;
704 border-radius: 0;
705 height: 50px;
706 font-size: 30px;
707 }
708 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next:focus {
709 outline: 0;
710 }
711 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-prev {
712 width: 50px;
713 border: 1px solid #c3c3c3;
714 border-radius: 0;
715 height: 50px;
716 font-size: 30px;
717 }
718 #ecom-norma-detail-normas-referenced .standards-section .owl-dots {
719 display: flex;
720 justify-content: center;
721 margin-top: 30px;
722 }
723 #ecom-norma-detail-normas-referenced .standards-section button.owl-dot {
724 width: 15px;
725 height: 15px;
726 background: transparent;
727 margin: 10px;
728 border: 1px solid var(--brand-color-2, #6a9bd3);
729 background-color: var(--brand-color-2, #6a9bd3);
730 }
731 #ecom-norma-detail-normas-referenced .standards-section button.owl-dot:focus-visible {
732 outline: solid;
733 }
734 #ecom-norma-detail-normas-referenced .standards-section .owl-dot button {
735 color: white;
736 }
737 #ecom-norma-detail-normas-referenced .standards-section .pagi-btn {
738 font-family: "SohoGothicPro-Regular";
739 font-size: 16px;
740 font-weight: 400;
741 line-height: 24px;
742 position: relative;
743 width: 100%;
744 background: transparent !important;
745 border: none !important;
746 cursor: pointer;
747 padding: 32px 10px;
748 }
749 #ecom-norma-detail-normas-referenced .standards-section .owl-dot.active {
750 background: var(--brand-color-3, #29337f);
751 border: 1px solid var(--brand-color-3, #29337f);
752 }
753 #ecom-norma-detail-normas-referenced .standards-section .owl-dot.active .pagi-btn {
754 color: white;
755 font-family: "SohoStd-Medium";
756 font-size: 16px;
757 font-weight: 500;
758 line-height: 24px;
759 }
760 #ecom-norma-detail-normas-referenced .standards-section .owl-dot.active .pagi-btn::before {
761 border-bottom: 28px solid var(--brand-color-2, #6a9bd3);
762 border-left: 15px solid transparent;
763 border-right: 15px solid transparent;
764 width: 0;
765 height: 0;
766 content: "";
767 position: absolute;
768 bottom: 84px;
769 left: 45%;
770 }
771 @media (min-width: 992px) {
772 #ecom-norma-detail-normas-referenced .standards-section .owl-navigation-mobile {
773 display: none;
774 }
775 }
776 #ecom-norma-detail-normas-referenced .standards-section .owl-navigation-mobile .owl-navigation-mobile-box {
777 background: linear-gradient(0deg, var(--brand-color-2, #6a9bd3) 4.9%, var(--brand-color-1, #1f57a3) 110.78%);
778 padding: 28px;
779 }
780 #ecom-norma-detail-normas-referenced .standards-section .owl-navigation-mobile .owl-navigation-mobile-box p {
781 color: white;
782 font-family: "SohoStd-Medium";
783 font-size: 14px;
784 font-weight: 500;
785 line-height: 18px;
786 margin-bottom: 0;
787 }
788 #ecom-norma-detail-normas-referenced .standards-section .owl-navigation-mobile .owl-navigation-mobile-box::before {
789 border-bottom: 28px solid var(--brand-color-1, #1f57a3);
790 border-left: 15px solid transparent;
791 border-right: 15px solid transparent;
792 width: 0;
793 height: 0;
794 content: "";
795 position: absolute;
796 bottom: 72px;
797 z-index: 1;
798 margin-left: -14px;
799 }
800 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav {
801 position: absolute;
802 top: 40%;
803 left: 0;
804 right: 0;
805 }
806 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-prev,
807 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next {
808 position: absolute;
809 background: none;
810 border: 2px solid #fff;
811 z-index: 100;
812 }
813 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-prev.disabled,
814 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next.disabled {
815 opacity: 0.5;
816 }
817 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-prev {
818 background: var(--brand-color-3, #29337f);
819 padding: 16px !important;
820 left: -25px;
821 }
822 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-prev i {
823 color: white;
824 position: absolute;
825 top: 17px;
826 left: 19px;
827 font-size: 13px;
828 }
829 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next {
830 background: var(--brand-color-3, #29337f);
831 padding: 16px !important;
832 right: -25px;
833 }
834 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next i {
835 color: white;
836 position: absolute;
837 top: 17px;
838 left: 19px;
839 font-size: 13px;
840 }
841 @media (max-width: 991px) {
842 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-prev { left: -55px; }
843 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next { right: -55px; }
844 }
845 @media (max-width: 868px) {
846 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-prev { left: -25px; }
847 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next { right: -25px; }
848 }
849 @media (max-width: 767px) {
850 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-prev { left: -60px; }
851 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next { right: -60px; }
852 }
853 @media (max-width: 668px) {
854 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav { top: 103%; }
855 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-prev { left: 40%; }
856 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next { right: 40%; }
857 }
858 @media (max-width: 575px) {
859 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-prev { left: 35%; }
860 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next { right: 35%; }
861 }
862 @media (max-width: 400px) {
863 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-prev { left: 32%; }
864 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next { right: 32%; }
865 }
866 @media (min-width: 300px) {
867 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-stage-outer {
868 overflow: visible;
869 }
870 }
871 @media (min-width: 1100px) {
872 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-prev { left: -55px; }
873 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next { right: -55px; }
874 }
875 @media (min-width: 1200px) {
876 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-prev { left: -25px; }
877 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next { right: -25px; }
878 }
879 @media (min-width: 1330px) {
880 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-prev { left: -75px; }
881 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-nav .owl-next { right: -75px; }
882 }
883
884 #ecom-norma-detail-normas-referenced .standards-section .owl-item {
885 display: flex;
886 flex-direction: column;
887 justify-content: stretch;
888 }
889 .status-standard {
890 margin-right: 10px;
891 color: white;
892 font-size: 10px;
893 padding: 2px 6px;
894 border-radius: 3px;
895 font-weight: bold;
896 }
897 .date-standard {
898 font-size: 12px;
899 color: #666;
900 }
901 #ecom-norma-detail-normas-referenced .standards-section .tag-standard {
902 position: absolute;
903 background-color: #6a9bd3;
904 top: -10px;
905 left: 16px;
906 padding: 4px 10px;
907 border-radius: 4px;
908 color: #fff;
909 font-weight: bold;
910 font-size: 12px;
911 z-index: 5;
912 }
913 #ecom-norma-detail-normas-referenced .standards-section .status-box {
914 text-transform: uppercase;
915 align-items: center;
916 display: flex;
917 flex-wrap: wrap;
918 margin: 0 0 10px;
919 gap: 4px 0;
920 }
921 #ecom-norma-detail-normas-referenced .standards-section .status-box .status-standard.red-tag {
922 background-color: var(--ae-450, #D44436);
923 border: 1px solid var(--ae-450, #D44436);
924 color: #fff;
925 }
926 #ecom-norma-detail-normas-referenced .standards-section .status-box .status-standard.green-tag {
927 background-color: #138636;
928 border: 1px solid #138636;
929 color: #fff;
930 }
931 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-stage-outer {
932 overflow-x: hidden;
933 overflow-y: visible;
934 }
935 #ecom-norma-detail-normas-referenced .standards-section .owl-carousel .owl-stage-outer .owl-stage {
936 overflow: hidden;
937 display: flex;
938 align-items: stretch;
939 padding-left: 0 !important;
940 padding-right: 0 !important;
941 padding-top: 30px;
942 }
943
944 /* select */
945 select .form-control {
946 padding: 15.5px 16px;
947 font-family: "SohoGothicPro-Regular";
948 font-size: 14px;
949 font-weight: 400;
950 line-height: 18px;
951 letter-spacing: 0.5px;
952 text-align: left;
953 border: 1px solid #c2c2c2;
954 height: 50px;
955 width: 100%;
956 color: #66757f;
957 border-radius: 4px;
958 }
959 select.form-control option {
960 font-family: "SohoGothicPro-Regular";
961 font-size: 14px;
962 font-weight: 400;
963 line-height: 18px;
964 letter-spacing: 0.5px;
965 text-align: left;
966 }
967 select.form-control,
968 select.form-control:focus,
969 select.form-control:focus-visible {
970 background-image: url(/documents/d/global/ico-chevron-down);
971 position: relative;
972 background-size: 18px 10px;
973 background-position-x: 95%;
974 }
975
976 #ecom-norma-detail-normas-referenced .standards-section .options-standard {
977 display: flex;
978 gap: 10px;
979 margin-bottom: 16px;
980 border: none;
981 }
982 #ecom-norma-detail-normas-referenced .standards-section .options-standard .select-language {
983 background-color: #f5f5f5;
984 flex: 2;
985 font-size: 13px;
986 }
987 #ecom-norma-detail-normas-referenced .standards-section .options-standard .select-format {
988 background-color: #f5f5f5;
989 flex: 1;
990 font-size: 13px;
991 }
992 </style>
993
994</#macro>
995
996<#-- Estilos mínimos siempre activos (spinner/disabled) -->
997<style>
998#ecom-norma-detail-normas-referenced .standard-button.ecom-btn-loading,
999#ecom-norma-detail-normas-referenced .standard-button:disabled,
1000#ecom-norma-detail-normas-referenced .standard-button[disabled],
1001#ecom-norma-detail-normas-referenced .standard-button.disabled {
1002 opacity: .6 !important;
1003 pointer-events: none;
1004 filter: brightness(0.85);
1005}
1006#ecom-norma-detail-normas-referenced .standard-button:active {
1007 filter: brightness(0.85);
1008}
1009#ecom-norma-detail-normas-referenced .standard-button:hover,
1010#ecom-norma-detail-normas-referenced .standard-button:focus,
1011#ecom-norma-detail-normas-referenced .standard-button:focus-visible {
1012 outline: 2px solid var(--brand-color-2, #6a9bd3);
1013 outline-offset: 2px;
1014 box-shadow: 0 0 0 3px rgba(106, 155, 211, 0.35);
1015}
1016</style>
1017
1018<#-- HTML -->
1019<#if hasProductCategoriaTipoEntidadNorma>
1020 <div id="ecom-norma-detail-normas-referenced" class="ecom-norma">
1021
1022 <#if isDebug>
1023 <@renderDebugProduct
1024 isDebug=isDebug
1025 product=product
1026 hasProductCategoriaTipoEntidadLibro=hasProductCategoriaTipoEntidadLibro
1027 hasProductCategoriaTipoEntidadNorma=hasProductCategoriaTipoEntidadNorma
1028 standardRelationsProduct=standardRelationsProduct
1029 />
1030 </#if>
1031
1032 <#if executeScriptsAndStyles>
1033 <@standardsScriptsAndStyles />
1034 </#if>
1035
1036
1037 <#-- HTML -->
1038 <section class="standards-section">
1039 <div class="container m-1 p-1">
1040 <div class="row d-flex">
1041 <div class="col-12 standards-container add-items-standard-referenced-html owl-carousel owl-theme">
1042 <#--
1043 El contenido se agrega por JS desde: [dxp-ecom-portal/misc/fragments/Collection Tienda/ECOM-Global_functions/index.js]
1044 - Usando: [
1045 eventListeners ["DOMContentLoaded", "endNavigate"] > function _DOMContentLoaded > await _generateHTMLECOMNormaDetailNormasReferenced(productERC);
1046 ]
1047 - Desde el function [_generateHTMLECOMNormaDetailNormasReferenced] se llama internamente a [await window.ecomNormaReferencedScript.init()]
1048 que se encuentra definido en [dxp-ecom-portal/misc/adt/tienda/Detalle producto/ECOM-Norma-Scripts.ftl].
1049 - Usando el class [#ecom-norma-detail-normas-referenced .add-items-standard-referenced-html]
1050 -->
1051 <#if executeHTML && standardRelationsProduct?has_content>
1052 <#list standardRelationsProduct as standardRelationProduct>
1053
1054 <#-- Product data -->
1055 <#assign product = getProductByERC(standardRelationProduct.ercProduct)>
1056
1057 <#if isDebug>
1058 <!--
1059 <div class="">
1060 <p><strong>Print product:</strong></p>
1061 <div class="print-object-json-content mb-3" style="max-height:200px; overflow:auto; border:1px solid #ccc; padding:5px; cursor:pointer;"
1062 onclick="const r=document.createRange(); r.selectNodeContents(this); const s=window.getSelection(); s.removeAllRanges(); s.addRange(r);">
1063 <@printObject product />
1064 </div>
1065 </div>
1066 -->
1067 </#if>
1068
1069 <#if product?? && product?has_content>
1070
1071 <#assign productId = product.productId />
1072 <#assign cpDefinitionId = product.id />
1073 <#assign categoriesProduct = getProductCategories(channelId, productId) />
1074 <#assign hasProductCategoriaTipoEntidadLibro = isVocabularyNameIntoCategories(categoriesProduct, 'entity type', 'Libro') />
1075 <#assign hasProductCategoriaTipoEntidadNorma = isVocabularyNameIntoCategories(categoriesProduct, 'entity type', 'Norma') />
1076 <#assign currentStateDate = getCurrentStateDate(getProductSpecifications(channelId, product.productId))>
1077 <#assign status = getStatus(getProductCategories(channelId, product.productId))>
1078 <#assign organism = getOrganism(getProductCategories(channelId, product.productId))>
1079 <#assign normasDetails = getNormasDetails(product.id)>
1080 <#assign productName = product.name[currentLocale]!"">
1081 <#assign productDescription = product.description[currentLocale]!"">
1082 <#assign productUrl = product.urls[currentLocale]!"">
1083 <#if productUrl?? && productUrl?has_content>
1084 <#assign productUrl = "/p/" + productUrl>
1085 </#if>
1086
1087 <#assign languages = []>
1088 <#list normasDetails as n>
1089 <#if n.language?? && n.language?has_content && !languages?seq_contains(n.language)>
1090 <#assign languages = languages + [n.language]>
1091 </#if>
1092 </#list>
1093
1094 <#assign defaultLang = "">
1095 <#assign defaultFmt = "">
1096 <#assign defaultPrice = 0>
1097 <#if normasDetails?has_content>
1098 <#assign defaultLang = (normasDetails[0].language!"")>
1099 <#assign defaultFmt = (normasDetails[0].format!"")>
1100 <#assign defaultPrice = (normasDetails[0].price!'0')?number>
1101 </#if>
1102
1103 <#assign formatsForDefault = []>
1104 <#list normasDetails?filter(nd -> (nd.language!"") == defaultLang) as nd>
1105 <#if nd.format?? && nd.format?has_content && !formatsForDefault?seq_contains(nd.format)>
1106 <#assign formatsForDefault = formatsForDefault + [nd.format]>
1107 </#if>
1108 </#list>
1109 <#if formatsForDefault?has_content && !formatsForDefault?seq_contains(defaultFmt)>
1110 <#assign defaultFmt = formatsForDefault[0]>
1111 </#if>
1112 <#list normasDetails as nd>
1113 <#if (nd.language!"") == defaultLang && (nd.format!"") == defaultFmt>
1114 <#assign defaultPrice = (nd.price!'0')?number>
1115 </#if>
1116 </#list>
1117
1118 <div class="item-standard add-item-standard-referenced-html"
1119 data-category-type-entity="${
1120 hasProductCategoriaTipoEntidadLibro?then(
1121 'book',
1122 hasProductCategoriaTipoEntidadNorma?then(
1123 'standard',
1124 hasProductCategoriaTipoEntidadColeccionTematica?then(
1125 'collection-thematic',
1126 'other'
1127 )
1128 )
1129 )
1130 }"
1131 data-index="${standardRelationProduct_index + 1}"
1132 data-standard-relation-type="${standardRelationProduct.type}"
1133 data-index-total="${standardRelationsProduct?size}"
1134 data-productid="${product.id?html}"
1135 data-title="${productName?html}"
1136 data-entrytype="Norma"
1137 data-code="${(product.externalReferenceCode!product.getCProductId())?html}">
1138 <#if organism?? && organism?has_content>
1139 <div class="tag-standard">${organism}</div>
1140 </#if>
1141
1142 <div class="info-standard">
1143 <#if productUrl?? && productUrl?has_content>
1144 <a href="${productUrl}" data-senna-off="true">
1145 <h3 class="title-standard">${productName}</h3>
1146 </a>
1147 </#if>
1148
1149 <div class="status-box">
1150
1151 <#if status?? && status?has_content>
1152 <#assign statusTagClass = ''>
1153
1154 <#if status?trim?upper_case == 'EN VIGOR'>
1155 <#assign statusTagClass = 'green-tag'>
1156 <#elseif status?trim?upper_case == 'ANULADA'>
1157 <#assign statusTagClass = 'red-tag'>
1158 <#elseif status?trim?upper_case == 'PROYECTO'>
1159 <#assign statusTagClass = 'blue-tag'>
1160 </#if>
1161
1162 <#if statusTagClass?? && statusTagClass?has_content>
1163 <#assign statusTagClass = "status-standard " + statusTagClass>
1164 </#if>
1165
1166 <div class="badge ${statusTagClass}">${status}</div>
1167 </#if>
1168
1169
1170
1171 <#if currentStateDate?? && currentStateDate?has_content>
1172 <span class="date-standard">
1173 ${currentStateDate?date.iso?string('yyyy-MM-dd')}
1174 </span>
1175 </#if>
1176 </div>
1177
1178 <div class="description-text">
1179 ${productDescription}
1180 </div>
1181
1182 <div class="price-container">
1183 <span class="price">
1184 ${(defaultPrice?string["0.00"])?replace(".", ",")} €
1185 </span>
1186 </div>
1187
1188 <div class="options-standard">
1189 <select class="form-control select-language">
1190 <#list languages as l>
1191 <#-- value debe ser acrónimo: ES, EN, etc. -->
1192 <option value="${l?html}" <#if l == defaultLang>selected</#if>>
1193 ${langLiteral(l)?html}
1194 </option>
1195 </#list>
1196 </select>
1197 <select class="form-control select-format">
1198 <#list formatsForDefault as f>
1199 <option value="${f?html}" <#if f == defaultFmt>selected</#if>>
1200 ${f?html}
1201 </option>
1202 </#list>
1203 </select>
1204 </div>
1205
1206 <a class="standard-button disabled" data-senna-off="true">
1207 ${languageUtil.get(locale, "ecom-add_cart")}
1208 </a>
1209 </div>
1210
1211 <script type="application/json" class="normas-data">[
1212 <#list normasDetails as n>
1213 {
1214 "format": "${(n.format!"")?js_string}",
1215 "language": "${(n.language!"")?js_string}",
1216 "price": ${(n.price!'0')?c}
1217 }<#if n_has_next>,</#if>
1218 </#list>
1219 ]</script>
1220
1221 <script type="application/json" class="lang-map">{
1222 <#list languages as l>
1223 "${(l!"")?upper_case?js_string}": "${langLiteral(l)?js_string}"<#if l_has_next>,</#if>
1224 </#list>
1225 }</script>
1226
1227 </div>
1228 </#if>
1229 </#list>
1230 </#if>
1231 </div>
1232 </div>
1233 </div>
1234 </section>
1235
1236 </div>
1237</#if>
1238
1239<#-- Estilos mínimos siempre cargados para estado loading/disabled del botón -->
1240<style>
1241#ecom-norma-detail-normas-referenced .standard-button:disabled,
1242#ecom-norma-detail-normas-referenced .standard-button[disabled],
1243#ecom-norma-detail-normas-referenced .standard-button.disabled,
1244#ecom-norma-detail-normas-referenced .standard-button.ecom-btn-loading {
1245 opacity: .6;
1246 pointer-events: none;
1247 filter: brightness(0.85);
1248}
1249#ecom-norma-detail-normas-referenced .standard-button:active {
1250 filter: brightness(0.85);
1251}
1252</style>
Related books
Related standards
Other thematic collections
- Standards UNE, EN, ISO, IEC, BSI, DIN, ASTM, AFNOR, IEEE, SAE
- In addition, you can request the rules of the rest of the organizations through the e-mail normas@aenor.com
- Technical books on paper and in electronic format (PDF, epub).
The standards can be purchased in PDF, reading or paper. The reading standards are not download files, they can only be viewed in the client area. The standards ordered on paper and some of the books in the catalogue are printed on demand.
Check deadlines in normas@aenor.com.
The license of use is for one user and one device, if you want to reproduce the content of the standard, you must request a license that will have an additional cost. Send us your inquiry here
The AENOR standards and books that appear in the online store can only be purchased exclusively through the website. AENOR does not have a physical store.
Purchase procedure: by clicking on "Buy" the desired products will go to the shopping cart. If there are display problems, the recommended browser is Chrome.
To formalize the purchase you must access the customer area. If you are not registered as a customer, you must fill in a form with the data along with a password and username. This will create the account.
Once the "Customer data" form has been completed, "Order in progress" will be displayed with all the items loaded in the shopping cart, their prices, taxes established in current legislation and shipping costs if applicable.
The prices of the standards and books that appear in the various sections do not include taxes or shipping costs.
AENOR promotional codes consist of alphanumeric characters and can only be applied to online purchases, received through a specific offer and for a limited time. To apply your promotional code, you just have to enter it in step 2 of 4 of the purchase process on the website and click on "apply", after you have identified yourself and chosen the payment methods. Promo codes are not cumulative.
- Credit or debit card (Visa, Mastercard) and PayPal.
- Bank transfer. If you opt for this form of payment, you must first send AENOR a copy of the transfer by email to normas@aenor.com
- The purchase invoice can be downloaded from the customer area, in my previous orders
In the case of clients of companies based abroad, the taxpayer identification number of the corresponding country (for example, in Argentina the CUIT), must be filled in the CIF/NIF - VAT field .
- Direct download via the website in the Customer Area. In the customer area, which can only be accessed with a password and username, the products purchased will be available for a period of fifteen days from the date of purchase, as long as the payment has been accepted. Files in digital format are protected and in no case editable. Before purchasing them, it is important that the license of use is read and accepted as a prior step to purchase.
- Shipping by courier. Products purchased on physical media are shipped by courier. The maximum delivery time in Spanish territory, from the acceptance of the order by AENOR, is:
- Approximately seven working days for all standards purchased through the store in paper format.
- Approximately three days for books purchased through the store. Stocks of paper books are limited and their offer on the website does not imply availability within the indicated period. In the event that the requested book is not available, the customer is notified of the delay in receiving the order, which will be approximately seven working days.
For the rest of the products that are not on the website, check availability and delivery time at normas@aenor.com.
1. For digital products (PDF, Epub), once delivery has been made by direct download via the website in the Customer Area, you will not have the right to exercise your right of withdrawal.
2. For personalised products on paper, once the purchase has been made, you will not have the right to exercise your right of withdrawal.
3. For all other paper products, you have the right to withdraw from the sale within 14 calendar days from the date of purchase. Remember that for the return it is essential that the product is in perfect condition, sealed by the packaging and preserving its original packaging. The customer will be responsible for pickup and shipping costs.
The order invoice includes shipping costs, so there is no amount to pay to the courier. Shipping costs are calculated based on both the final destination of the order and the number of products ordered. They include transport and packaging costs. Shipping costs are subject to periodic revisions. Outlet books will have free shipping costs only if the shipment is made in the Peninsula.
| Destination | Up to three standards and/or publications | From three standards and/or publications |
| Peninsula | 7,31€ | 8,60€ |
| Balearic Islands | 18,04€ | 23,34€ |
| Canary Islands, Ceuta and Melilla | 18,04€ | 23,34€ |
| Europe | 59,17€ | 80,07€ |
| United States and Canada | 70,07€ | 96,94€ |
| Rest of the world | 91,94€ | 115,91€ |
- Purchases made by residents of the Member States of the European Union will be subject to the payment of VAT (value added tax).
-
- In the case of legal persons and natural persons who, acting as entrepreneurs, are domiciled in a Member State of the European Union (except residents in Spain) and have an intra-community NIF/VAT registered in the VIES census, they will be exempt from paying VAT, being an essential condition the sending of this document by email to normas@aenor.com.
- Purchases made in a private capacity (natural person), regardless of where they have their residence, will be subject to the payment of VAT.
- Purchases made by entities in non-EU countries will be exempt from paying VAT, as long as they send the corresponding tax residence document by email to normas@aenor.com.
- The sale operations will be understood to have been carried out at AENOR's registered office: Génova 6, 28004, Madrid – Spain.
The contract for the purchase of products through this Website shall be governed by Spanish law. Any dispute arising out of or in connection with the use of the Website or such contract shall be subject to the exclusive jurisdiction of the Courts and Tribunals of Madrid.
Notwithstanding the foregoing, if you are entering into this contract as a consumer under the terms of Royal Decree 1/2007, nothing in this clause shall affect the rights that may be granted to you as such under applicable law.










