-50% de descuento* Si compras la misma norma UNE en distintos idiomas. * Dto. sobre el pvp inferior.

CEN ISO/TS 22391-7:2018

Plastics piping systems for hot and cold water installations - Polyethylene of raised temperature resistance (PE-RT) - Part 7: Guidance for the assessment of conformity (ISO/TS 22391-7:2018)

Se ha producido un error al procesar la plantilla.
For "." left-hand operand: Expected a hash, but this has evaluated to a string (wrapper: f.t.SimpleScalar):
==> response  [in template "34352066712900#33336#null" at line 65, column 24]

----
FTL stack trace ("~" means nesting-related):
	- Failed at: #if response?? && response.status?? &...  [in template "34352066712900#33336#null" in function "getProductByERC" at line 65, column 5]
----
1<#-- Variables --> 
2<#assign isDebug = false> 
3<#assign channelResponse = restClient.get("/headless-commerce-delivery-catalog/v1.0/channels?filter=name eq 'Aenor Tienda'")> 
4<#assign channel = channelResponse.items[0]> 
5<#assign channelId = channel.id> 
6<#assign product = getProduct(channelId, CPDefinition_cProductId.getData()) /> 
7<#assign siteGroup = themeDisplay.getSiteGroup() /> 
8<#assign currentLocale = themeDisplay.getLocale()> 
9<#assign currentLanguage = currentLocale?substring(0,2)> 
10 
11<#-- Product data --> 
12<#assign displayDateProduct = CPDefinition_displayDate.getData() /> 
13<#assign productId = product.productId /> 
14<#assign cpDefinitionId = product.id /> 
15 
16<#assign categoriesProduct = getProductCategories(channelId, productId) /> 
17<#assign hasProductCategoriaTipoEntidadLibro = isVocabularyNameIntoCategories(categoriesProduct, 'entity type', 'libro') /> 
18<#assign hasProductCategoriaTipoEntidadNorma = isVocabularyNameIntoCategories(categoriesProduct, 'entity type', 'norma') /> 
19<#assign hasProductCategoriaTipoEntidadColeccionTematica = isVocabularyNameIntoCategories(categoriesProduct, 'entity type', 'coleccion tematica') /> 
20<#assign hasProductCategoriaTipoOrganismoSAE = isVocabularyNameIntoCategories(categoriesProduct, 'organismos', 'SAE') /> 
21<#assign hasProductCategoriaTipoOrganismoASTM = isVocabularyNameIntoCategories(categoriesProduct, 'organismos', 'ASTM') /> 
22 
23<#assign categoryProductInfoTematica = getCategoriesByVocabularyAsString(categoriesProduct, "temáticas", " / ", "title") /> 
24<#assign categoryProductInfoStatus = getCategoriesByVocabularyAsString(categoriesProduct, "status", " / ", "title") /> 
25 
26<#-- Standard Warning --> 
27<#assign standardWarning = getStandardWarning(product.externalReferenceCode) /> 
28 
29<#-- PickList de languages --> 
30<#assign ercOfListTypeEntryLanguages = 'IDIOMAS_NORMAS_PICKLIST' /> 
31<#assign languageEntries = getListTypeEntriesByERC(ercOfListTypeEntryLanguages) /> 
32 
33<#-- Specifications/Specifications language --> 
34<#assign specificationsLanguagesProduct = getSpecificationsProduct(channelId, productId, 'specificationKey', 'standard-languages') /> 
35<#assign filteredSpecificationsLanguagesProductTemp = filterOutItems(specificationsLanguagesProduct, 'value', ['BI', 'TR']) /> 
36<#assign filteredSpecificationsLanguagesProduct = addAllMatchingLanguagesByField(filteredSpecificationsLanguagesProductTemp, languageEntries, 'value', 'title') /> 
37 
38<#-- Specifications/Specifications others --> 
39<#assign specificationsCTNProduct = getSpecificationsProduct(channelId, productId, 'specificationKey', 'ctn') /> 
40<#assign specificationsICSProduct = getSpecificationsProduct(channelId, productId, 'specificationKey', 'ics') /> 
41<#assign specificationsCurrentStateDateProduct = getSpecificationsProduct(channelId, productId, 'specificationKey', 'current-state-date') /> 
42 
43<#-- Standard/Norma data --> 
44<#assign standardRelationsProduct = getStandardRelationsProduct(cpDefinitionId) /> 
45<#assign standardInfoProduct = getStandardInfoProduct(cpDefinitionId) /> 
46 
47<#assign ercOfListTypeEntryTipoRelacionesNormasSections = 'TIPO_RELACIONES_NORMAS-SECTIONS' /> 
48<#assign tipoRelacionesNormasSectionsEntries = getListTypeEntriesByERC(ercOfListTypeEntryTipoRelacionesNormasSections) /> 
49<#assign ercOfListTypeEntryTipoRelacionesNormasTypes = 'TIPO_RELACIONES_NORMAS-TYPE' /> 
50<#assign tipoRelacionesNormasTypesEntries = getListTypeEntriesByERC(ercOfListTypeEntryTipoRelacionesNormasTypes) /> 
51<#assign standardRelationsTypesProduct = getStandardRelationsTypesProduct(tipoRelacionesNormasSectionsEntries, tipoRelacionesNormasTypesEntries) /> 
52 
53 
54<#-- Functions --> 
55<#function getProduct channelId productId> 
56    <#return restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products/${productId}")> 
57</#function> 
58 
59 
60<#function getProductByERC erc> 
61    <#-- TODO: estamos usando el endpoint del product admin, hay que usar la del Product de Liferay NO admin: headless-commerce-delivery-catalog --> 
62    <#-- <#return restClient.get("/headless-commerce-admin-catalog/v1.0/products/by-externalReferenceCode/${erc}")> --> 
63    <#assign response = restClient.get("/headless-commerce-admin-catalog/v1.0/products/by-externalReferenceCode/${erc}")> 
64    <#-- Si el producto no existe o tiene status NOT_FOUND, devolvemos string vacío --> 
65    <#if response?? && response.status?? && response.status == "NOT_FOUND"> 
66        <#return {}> 
67    <#elseif !response??> 
68        <#return {}> 
69    <#else> 
70        <#return response> 
71    </#if> 
72</#function> 
73 
74 
75<#function getURLsOfProduct product baseURL="" siteFriendlyURL="" languageFieldName="language" urlFieldName="url"> 
76    <#-- Inicializamos un array vacío --> 
77    <#assign urlsArray = []> 
78 
79    <#-- Validamos que product y product.urls existan --> 
80    <#if product?? && product.urls??> 
81        <#-- Iteramos sobre los idiomas --> 
82        <#list product.urls?keys as lang> 
83            <#assign urlValue = product.urls[lang] /> 
84            <#if urlValue?? && urlValue?has_content> 
85                <#-- Aseguramos que la URL empiece con "/p/" --> 
86                <#assign cleanUrl = urlValue?starts_with("/")?then(urlValue, "/p/" + urlValue) /> 
87 
88                <#-- Generamos la URL completa --> 
89                <#-- Si baseURL tiene contenido, construimos URL completa --> 
90                <#if baseURL?? && baseURL?has_content> 
91 
92                    <#-- Aseguramos que el slug empiece con /p/ --> 
93                    <#assign cleanUrl = urlValue?starts_with("/")?then(urlValue, "/p/" + urlValue) /> 
94 
95                    <#-- Tomamos las dos primeras letras del idioma para el prefijo --> 
96                    <#assign langPrefix = lang?substring(0,2)> 
97 
98                    <#-- Construimos la URL completa --> 
99                    <#if siteFriendlyURL?? && siteFriendlyURL?has_content> 
100                        <#assign fullUrl = baseURL + "/" + langPrefix + siteFriendlyURL + cleanUrl> 
101                    <#else> 
102                        <#assign fullUrl = baseURL + "/" + langPrefix + cleanUrl> 
103                    </#if> 
104 
105                <#else> 
106                    <#assign fullUrl = cleanUrl> 
107                </#if> 
108 
109                <#-- Creamos el objeto language+url --> 
110                <#assign newItem = {(languageFieldName): lang, (urlFieldName): fullUrl} /> 
111 
112                <#-- Lo agregamos al array --> 
113                <#assign urlsArray = urlsArray + [newItem] /> 
114            </#if> 
115        </#list> 
116    </#if> 
117 
118    <#return urlsArray> 
119</#function> 
120 
121 
122<#function getProductCategories channelId productId> 
123    <#return restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products/${productId}/categories?sort=vocabulary").items> 
124</#function> 
125 
126 
127<#function getSpecificationsProduct channelId productId field="" value=""> 
128    <#assign response = restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products/${productId}/product-specifications?pageSize=100&sort")> 
129    <#assign items = response.items> 
130 
131    <#-- Si se pasa campo y valor, filtrar --> 
132    <#if field?has_content && value?has_content> 
133        <#assign items = items?filter(item -> 
134            (item[field]??) && (item[field]?string?lower_case == value?lower_case) 
135        )> 
136    </#if> 
137 
138    <#return items> 
139</#function> 
140 
141 
142<#function filterOutItems items field valuesToExclude> 
143    <#-- Si el array o los valores no existen, devolver items sin cambios --> 
144    <#if !items?? || !valuesToExclude??> 
145        <#return items> 
146    </#if> 
147 
148    <#-- Filtramos: solo mantener los items cuyo campo no esté en la lista --> 
149    <#assign filteredItems = items?filter(item -> 
150        !(item[field]?? && (valuesToExclude?seq_contains(item[field]?string))) 
151    )> 
152 
153    <#return filteredItems> 
154</#function> 
155 
156 
157<#function addAllMatchingLanguagesByField specificationsLanguagesProduct languageEntries specValueField newSpecField> 
158 
159    <#if specificationsLanguagesProduct?? && languageEntries?? && specValueField?? && newSpecField??> 
160 
161        <#-- Creamos una copia para no modificar el original directamente --> 
162        <#local updatedSpecs = []> 
163 
164        <#list specificationsLanguagesProduct as spec> 
165            <#-- Valor por el que buscamos coincidencia (puede venir vacío) --> 
166            <#local keyValue = (spec[specValueField]!"")?string> 
167 
168            <#-- Buscar coincidencia sin lanzar error si no existe (idioma nuevo no contemplado) --> 
169            <#local match = {}> 
170            <#list languageEntries as entry> 
171                <#if (entry.key!"")?string == keyValue> 
172                    <#local match = entry> 
173                    <#break> 
174                </#if> 
175            </#list> 
176 
177            <#-- Crear una copia del objeto actual --> 
178            <#local newSpec = spec> 
179 
180            <#-- Si hay match con nombre válido usamos su nombre; si no, usamos el código del idioma como fallback --> 
181            <#if match?has_content && match.name?? && match.name?has_content> 
182                <#local newSpec = newSpec + { (newSpecField): match.name }> 
183            <#elseif keyValue?has_content> 
184                <#local newSpec = newSpec + { (newSpecField): keyValue }> 
185            </#if> 
186 
187            <#-- Añadir al array final --> 
188            <#local updatedSpecs = updatedSpecs + [newSpec]> 
189        </#list> 
190 
191        <#return updatedSpecs> 
192    <#else> 
193        <#return specificationsLanguagesProduct> 
194    </#if> 
195</#function> 
196 
197 
198<#function getListTypeEntriesByERC erc fields="key,name,externalReferenceCode,name_i18n" sort="key" pageSize="1000"> 
199    <#attempt> 
200        <#return restClient.get( 
201            "/headless-admin-list-type/v1.0/list-type-definitions/by-external-reference-code/${erc}/list-type-entries?fields=${fields}&sort=${sort}&pageSize=${pageSize}" 
202        ).items> 
203    <#recover> 
204        <#return []> 
205    </#attempt> 
206</#function> 
207 
208 
209<#function getStandardRelationsProduct cpDefinitionId 
210    ercProductFieldName="ercProduct" defaultLang = "es_ES" urlProductCurrentLanguageFieldName="urlProductCurrentLanguage" urlsProductByLangFieldName="urlsProductByLang" 
211    languageFieldName="language" urlFieldName="url" sort="type"> 
212 
213    <#assign result = [] /> 
214 
215    <#-- Obtener relaciones desde la API --> 
216    <#assign standardRelations = restClient.get("/c/standardrelationses/?filter=r_standardRelations_CPDefinitionId eq '${cpDefinitionId}'&sort=${sort}").items /> 
217 
218    <#-- Iterar sobre cada relación --> 
219    <#list standardRelations as standardRelationProduct> 
220 
221        <#-- Crear ERC del producto relacionado --> 
222        <#assign ercProduct = (standardRelationProduct.relatedOrganismStandardName!"relatedOrganismStandardName") + "-" + (standardRelationProduct.relatedStandardId!"relatedStandardId") /> 
223 
224        <#-- Obtener el producto por ERC --> 
225        <#assign productByERC = getProductByERC(ercProduct) /> 
226        <#assign findProductByERC = (productByERC?? && productByERC?has_content)> 
227 
228        <#-- Obtener URLs del producto --> 
229        <#assign baseURL = themeDisplay.getPortalURL()> 
230        <#assign siteFriendlyURL = "/web" + siteGroup.getFriendlyURL()> 
231        <#assign urlsProductByLang = getURLsOfProduct(productByERC, baseURL, siteFriendlyURL, languageFieldName, urlFieldName) /> 
232 
233        <#-- Obtenemos URLs del producto default y current language --> 
234        <#assign selectedURLCurrent = ""> 
235        <#assign selectedURLDefault = ""> 
236        <#list urlsProductByLang as item> 
237            <#-- URL del idioma actual --> 
238            <#if item.language == currentLocale && selectedURLCurrent == ""> 
239                <#assign selectedURLCurrent = item.url> 
240            </#if> 
241 
242            <#-- URL del idioma por defecto --> 
243            <#if item.language == defaultLang && selectedURLDefault == ""> 
244                <#assign selectedURLDefault = item.url> 
245            </#if> 
246 
247            <#-- Salimos si ya tenemos ambas --> 
248            <#if selectedURLCurrent != "" && selectedURLDefault != ""> 
249                <#break> 
250            </#if> 
251        </#list> 
252 
253        <#-- Usamos el idioma actual si existe, sino el por defecto --> 
254        <#if selectedURLCurrent != ""> 
255            <#assign urlCurrentLanguage = selectedURLCurrent> 
256        <#else> 
257            <#assign urlCurrentLanguage = selectedURLDefault> 
258        </#if> 
259 
260        <#-- Combinar todos los datos del objeto original + nuevos campos --> 
261        <#assign resultItem = standardRelationProduct + { 
262            (ercProductFieldName): ercProduct, 
263            (urlProductCurrentLanguageFieldName): urlCurrentLanguage, 
264            (urlsProductByLangFieldName): urlsProductByLang, 
265            ("findProductByERC"): findProductByERC 
266        } /> 
267 
268        <#-- Añadir al array final --> 
269        <#assign result = result + [resultItem] /> 
270    </#list> 
271 
272    <#return result> 
273</#function> 
274 
275 
276<#function getStandardInfoProduct cpDefinitionId> 
277    <#assign response = restClient.get("/c/standardinfos/?filter=r_standardInfo_CPDefinitionId eq '${cpDefinitionId}'")!{} /> 
278    <#assign items = response.items![] /> 
279    <#return (items?size > 0)?then(items[0], {}) /> 
280</#function> 
281 
282<#function getStandardWarning externalReferenceCode> 
283    <#assign response = restClient.get("/c/standardwarnings/?fields=warningTitle,warningDescription&filter=standardId eq '${externalReferenceCode}' and showWarning eq true")!{} /> 
284    <#assign items = response.items![] /> 
285    <#return (items?size > 0)?then(items[0], {}) /> 
286</#function> 
287 
288<#function getStandardRelationsTypesProduct tipoRelacionesNormasSectionsEntries tipoRelacionesNormasTypesEntries> 
289    <#attempt> 
290 
291        <#-- Obtener los items del endpoint --> 
292        <#assign itemsStandardRelationsTypeProduct = restClient.get("/c/standardrelationtypeses/?pageSize=100").items> 
293 
294        <#-- Crear array vacío para ir acumulando los items enriquecidos --> 
295        <#assign enrichedItemsStandardRelationsTypeProduct = []> 
296 
297        <#assign enrichedItemsStandardRelationsTypeProduct = applyTipoRelacionesNormasEntries( 
298            itemsStandardRelationsTypeProduct, tipoRelacionesNormasSectionsEntries, 
299            "relatedSection", "section" 
300        )> 
301 
302        <#assign enrichedItemsStandardRelationsTypeProduct = applyTipoRelacionesNormasEntries( 
303            enrichedItemsStandardRelationsTypeProduct, tipoRelacionesNormasTypesEntries, 
304            "relatedType", "type" 
305        )> 
306 
307        <#assign enrichedItemsStandardRelationsTypeProduct = addKeysFieldNested( 
308            enrichedItemsStandardRelationsTypeProduct, "section", "name", "sectionName", "all") 
309        > 
310 
311        <#assign enrichedItemsStandardRelationsTypeProduct = addKeysFieldNested( 
312            enrichedItemsStandardRelationsTypeProduct, "section", "key", "sectionKey", "first") 
313        > 
314 
315        <#assign enrichedItemsStandardRelationsTypeProduct = addKeysFieldNested( 
316            enrichedItemsStandardRelationsTypeProduct, "section", "externalReferenceCode", "sectionKeyERC", "first", "relatedSection") 
317        > 
318 
319         <#assign enrichedItemsStandardRelationsTypeProduct = addKeysFieldNested( 
320            enrichedItemsStandardRelationsTypeProduct, "type", "name", "typeName", "all") 
321        > 
322 
323        <#assign enrichedItemsStandardRelationsTypeProduct = addKeysFieldNested( 
324            enrichedItemsStandardRelationsTypeProduct, "type", "key", "typeKey", "all") 
325        > 
326 
327        <#assign enrichedItemsStandardRelationsTypeProduct = addKeysFieldNested( 
328            enrichedItemsStandardRelationsTypeProduct, "type", "externalReferenceCode", "typeKeyERC", "all", "relatedType") 
329        > 
330 
331        <#assign enrichedItemsStandardRelationsTypeProductSorted = sortByField(enrichedItemsStandardRelationsTypeProduct, "section?first.key")> 
332        <#return enrichedItemsStandardRelationsTypeProductSorted> 
333 
334    <#recover> 
335        <#return []> 
336    </#attempt> 
337</#function> 
338 
339 
340<#function applyTipoRelacionesNormasEntries 
341    itemsStandardRelationsTypeProduct tipoRelacionesNormasEntries 
342    relatedEntriesFieldName="relatedEntries" putRelatiedEntriesFieldName="entries" 
343    > 
344 
345    <#assign enrichedItems = []> 
346 
347    <#list itemsStandardRelationsTypeProduct as item> 
348 
349        <#assign relatedEntries = []> 
350 
351        <#list item[putRelatiedEntriesFieldName] as sec> 
352            <#assign matchedEntry = {}> 
353 
354            <#list tipoRelacionesNormasEntries as te> 
355                <#if te.key?string?trim == sec.key?string?trim> 
356                    <#assign matchedEntry = te> 
357                    <#break> 
358                </#if> 
359            </#list> 
360 
361            <#assign relatedEntry = []> 
362            <#if matchedEntry?has_content> 
363                <#assign relatedEntry = [ matchedEntry ]> 
364            </#if> 
365 
366            <#assign relatedItem = sec + { (relatedEntriesFieldName): relatedEntry }> 
367            <#assign relatedEntries = relatedEntries + [ relatedItem ]> 
368 
369        </#list> 
370 
371        <#assign enrichedItem = item + { 
372            (putRelatiedEntriesFieldName): relatedEntries 
373        }> 
374 
375        <#assign enrichedItems = enrichedItems + [ enrichedItem ]> 
376 
377    </#list> 
378 
379    <#return enrichedItems> 
380</#function> 
381 
382 
383<#function sortByField items fieldPath sortFieldName="sortKey" order="asc"> 
384 
385    <#-- Array temporal con el campo auxiliar --> 
386    <#assign prepared = []> 
387 
388    <#list items as e> 
389        <#-- Evaluar el valor del campo dinámico --> 
390        <#assign sortValue = "" /> 
391        <#if fieldPath == "section?first.key"> 
392            <#assign sortValue = (e.section?first.key)!""?lower_case> 
393        <#elseif fieldPath == "section?first.name"> 
394            <#assign sortValue = (e.section?first.name)!""?lower_case> 
395        <#elseif fieldPath == "type?first.key"> 
396            <#assign sortValue = (e.type?first.key)!""?lower_case> 
397        <#else> 
398            <#-- Si el campoPath no está mapeado, usar vacío --> 
399            <#assign sortValue = "" /> 
400        </#if> 
401 
402        <#-- Agregar objeto enriquecido con campo auxiliar --> 
403        <#assign prepared = prepared + [ e + { (sortFieldName): sortValue } ]> 
404    </#list> 
405 
406    <#-- Ordenar --> 
407    <#assign sorted = prepared?sort_by(sortFieldName)> 
408 
409    <#-- Si order = desc, invertir --> 
410    <#if order?lower_case == "desc"> 
411        <#assign sorted = sorted?reverse> 
412    </#if> 
413 
414    <#return sorted> 
415</#function> 
416 
417 
418<#function addKeysFieldNested items arrayField nestedField newFieldName mode="first" subArrayField=""> 
419 
420    <#assign enrichedItems = []> 
421 
422    <#list items as e> 
423        <#assign resultValue = ""> 
424 
425        <#-- Detectamos el array del objeto principal --> 
426        <#assign targetArray = e[arrayField]![]> 
427 
428        <#if targetArray?has_content> 
429            <#if mode == "all"> 
430                <#assign keysList = []> 
431                <#list targetArray as t> 
432                    <#if subArrayField?has_content> 
433                        <#assign subArray = t[subArrayField]![]> 
434                        <#if subArray?has_content> 
435                            <#list subArray as sub> 
436                                <#assign keysList = keysList + [ sub[nestedField]!"" ]> 
437                            </#list> 
438                        </#if> 
439                    <#else> 
440                        <#assign keysList = keysList + [ t[nestedField]!"" ]> 
441                    </#if> 
442                </#list> 
443                <#assign resultValue = keysList?join(", ")> 
444            <#elseif mode == "first"> 
445                <#assign firstItem = targetArray?first> 
446                <#if subArrayField?has_content> 
447                    <#assign subArray = firstItem[subArrayField]![]> 
448                    <#if subArray?has_content> 
449                        <#assign resultValue = subArray?first[nestedField]!"" > 
450                    <#else> 
451                        <#assign resultValue = "" > 
452                    </#if> 
453                <#else> 
454                    <#assign resultValue = firstItem[nestedField]!"" > 
455                </#if> 
456            </#if> 
457        <#else> 
458            <#assign resultValue = ""> 
459        </#if> 
460 
461        <#-- Añadimos el nuevo campo al objeto --> 
462        <#assign enrichedItems = enrichedItems + [ 
463            e + { (newFieldName): resultValue } 
464        ]> 
465    </#list> 
466 
467    <#return enrichedItems> 
468</#function> 
469 
470 
471<#function isVocabularyNameIntoCategories categories vocabulary name> 
472    <#assign found = false /> 
473 
474    <#if categories?has_content && vocabulary?has_content && name?has_content> 
475 
476        <#assign vocabNorm = normalize(vocabulary) /> 
477        <#assign nameNorm  = normalize(name) /> 
478 
479        <#list categories as category> 
480            <#if !found> 
481                <#assign catVocabNorm = normalize(category.vocabulary) /> 
482                <#assign catNameNorm  = normalize(category.name) /> 
483 
484                <#if catVocabNorm == vocabNorm && catNameNorm == nameNorm> 
485                    <#assign found = true /> 
486                </#if> 
487            </#if> 
488        </#list> 
489 
490    </#if> 
491 
492    <#return found> 
493</#function> 
494 
495 
496<#function normalize text onlyAccents = false> 
497    <#-- proteger null --> 
498    <#if !text?has_content> 
499        <#return ""> 
500    </#if> 
501 
502    <#assign t = text /> 
503 
504    <#-- quitar acentos --> 
505    <#assign t = t 
506        ?replace("á","a")?replace("é","e")?replace("í","i") 
507        ?replace("ó","o")?replace("ú","u")?replace("ü","u") 
508        ?replace("ñ","n") 
509        ?replace("Á","A")?replace("É","E")?replace("Í","I") 
510        ?replace("Ó","O")?replace("Ú","U")?replace("Ü","U") 
511        ?replace("Ñ","N") 
512    /> 
513 
514    <#-- si NO es solo acentos, normalización completa --> 
515    <#if !onlyAccents> 
516        <#assign t = t?lower_case /> 
517        <#assign t = t?trim /> 
518        <#assign t = t?replace("\\s+", " ", "r") /> 
519    </#if> 
520 
521    <#return t> 
522</#function> 
523 
524 
525<#function filterStandardRelationsProductsByFieldType standardRelationsProducts types> 
526    <#-- Función para filtrar y obtener elementos por type --> 
527    <#-- Normalizamos types a lista en minúsculas --> 
528    <#if types?is_string> 
529        <#assign typeList = [types?lower_case]> 
530    <#else> 
531        <#assign typeList = types?map(t -> t?lower_case)> 
532    </#if> 
533 
534    <#assign result = []> 
535 
536    <#list standardRelationsProducts as standardRelationsProduct> 
537        <#if standardRelationsProduct.type?? && typeList?seq_contains(standardRelationsProduct.type?lower_case)> 
538            <#assign result += [standardRelationsProduct]> 
539        </#if> 
540    </#list> 
541 
542    <#return result> 
543</#function> 
544 
545 
546<#function excludeStandardRelationsByFieldType standardRelationsProducts types> 
547    <#-- Función para filtrar y quitar elementos por type --> 
548    <#-- Normalizamos types a lista en minúsculas --> 
549    <#if types?is_string> 
550        <#assign typeList = [types?lower_case]> 
551    <#else> 
552        <#assign typeList = types?map(t -> t?lower_case)> 
553    </#if> 
554 
555    <#assign result = []> 
556 
557    <#list standardRelationsProducts as standardRelationsProduct> 
558        <#-- Solo agregamos si el type NO está en la lista --> 
559        <#if !(standardRelationsProduct.type?? && typeList?seq_contains(standardRelationsProduct.type?lower_case))> 
560            <#assign result += [standardRelationsProduct]> 
561        </#if> 
562    </#list> 
563 
564    <#return result> 
565</#function> 
566 
567 
568 
569<#function getStandardRelationsProductsByField 
570    itemStandardRelationsTypeProduct standardRelationsProducts itemStandardRelationsTypeProductField="typeKeyERC" standardRelationsProductField="type"> 
571 
572    <#assign matched = []> 
573 
574    <#-- Verificar que el item tenga el campo indicado --> 
575    <#if itemStandardRelationsTypeProduct[itemStandardRelationsTypeProductField]?? && itemStandardRelationsTypeProduct[itemStandardRelationsTypeProductField]?has_content> 
576 
577        <#-- Normalizamos (minusculas, sin espacios a al principio/final y separamos en lista si hay varios valores) --> 
578        <#assign itemStandardRelationsTypeProductValues = itemStandardRelationsTypeProduct[itemStandardRelationsTypeProductField]?split(",")?map(v -> v?trim?lower_case)> 
579 
580        <#-- Recorrer los productos --> 
581        <#list standardRelationsProducts as standardRelationsProduct> 
582            <#-- Asegurar que el campo del producto existe --> 
583            <#if standardRelationsProduct[standardRelationsProductField]?? && standardRelationsProduct[standardRelationsProductField]?has_content> 
584 
585                <#-- 
586                    - Los elementos de [standardRelationsProducts.type] tienen datos como: REVISED_BY 
587                    - En los PickList, en este caso la picklist [erc: TIPO_RELACIONES_NORMAS], no permite guardar 
588                      keys con "_" por lo que existirá una key: REVISEDBY pero entonces comparamos por su 
589                      campo ERC que si permite "_", entonces tendremos como ERC: REVISED_BY y como key: REVISEDBY. 
590                    - Entonces buscaremos, usando de la picklist, la key (el ERC) del tipo de relación [itemStandardRelationsTypeProduct.typeKeyERC] 
591                      en [standardRelationsProducts.type]. 
592                    - Convertimos el texto a minúsculas y quitamos los espacio del principio/fin. 
593                    - Dentro de [itemStandardRelationsTypeProduct.typeKeyERC] podemos tener 
594                      varios valores, por ejemplo [typeKey: REPLACED_BY, REPLACEDBY]. 
595                --> 
596                <#assign normalizedProdValue = standardRelationsProduct[standardRelationsProductField]?trim?lower_case> 
597 
598                <#-- 
599                    Verificar si coincide alguno de los valores del item StandardRelationsTypeProduct con 
600                    el valor normalizado de standardRelationsProduct 
601                --> 
602                <#if itemStandardRelationsTypeProductValues?seq_contains(normalizedProdValue)> 
603                    <#assign matched = matched + [standardRelationsProduct]> 
604                </#if> 
605            </#if> 
606        </#list> 
607    </#if> 
608 
609    <#return matched> 
610</#function> 
611 
612 
613<#-- Función que retorna los valores de categorías como string, normalizando vocabulario --> 
614<#function getCategoriesByVocabularyAsString categories vocabulary separator=" / " field="name"> 
615    <#assign matchedValues = []> 
616    <#if categories?has_content && vocabulary?has_content> 
617        <#list categories as category> 
618            <#-- Normalizamos tanto el vocabulary de la categoría como el buscado --> 
619            <#if normalize(category.vocabulary, true)?lower_case == normalize(vocabulary, true)?lower_case> 
620                <#if field == "title"> 
621                    <#assign matchedValues += [category.title]> 
622                <#else> 
623                    <#assign matchedValues += [category.name]> 
624                </#if> 
625            </#if> 
626        </#list> 
627    </#if> 
628    <#return matchedValues?join(separator)> 
629</#function> 
630 
631 
632<#function getStatusInfo status class=""> 
633    <#local defaultResult = { 
634        "status": status!"", 
635        "tagClass": "", 
636        "isInForce": false, 
637        "isCancelled": false, 
638        "isProject": false 
639    }> 
640 
641    <#local trimmedStatus = (status!"")?trim> 
642    <#if trimmedStatus == ""> 
643        <#return defaultResult> 
644    </#if> 
645 
646    <#local normalizedStatus = trimmedStatus?upper_case> 
647    <#local tagClass = ""> 
648    <#if class?has_content> 
649        <#local tagClass = class> 
650    </#if> 
651 
652    <#local isInForce = false> 
653    <#local isCancelled = false> 
654    <#local isProject = false> 
655 
656    <#if ["EN VIGOR", "IN FORCE", "EM VIGOR", "IN VIGORE"]?seq_contains(normalizedStatus)> 
657        <#local tagClass = tagClass + " tag-success"> 
658        <#local isInForce = true> 
659    <#elseif ["ANULADA", "CANCELLED", "ANULADA", "ANNULLATA"]?seq_contains(normalizedStatus)> 
660        <#local tagClass = tagClass + " tag-danger"> 
661        <#local isCancelled = true> 
662    <#elseif ["PROYECTO", "PROJECT", "PROJETO", "PROGETTO"]?seq_contains(normalizedStatus)> 
663        <#local tagClass = tagClass + " tag-blue"> 
664        <#local isProject = true> 
665    </#if> 
666 
667    <#return { 
668        "status": status, 
669        "tagClass": tagClass?trim, 
670        "isInForce": isInForce, 
671        "isCancelled": isCancelled, 
672        "isProject": isProject 
673    }> 
674</#function> 
675 
676 
677<#macro printObject obj> 
678    <#-- Permite hacer un output de un array de objetos o un objeto que se pasa como parámetro --> 
679    <#if obj?is_hash> 
680        { 
681        <#list obj?keys as k> 
682            "${k}": 
683            <#assign value = obj[k]> 
684            <#if value?is_hash || value?is_sequence> 
685                <@printObject obj=value/> 
686            <#elseif value?is_boolean> 
687                ${value?c} 
688            <#elseif value?is_number> 
689                ${value} 
690            <#elseif value?has_content> 
691                "${value?string}" 
692            <#else> 
693                null 
694            </#if> 
695            <#if k_has_next>, </#if> 
696        </#list> 
697        } 
698    <#elseif obj?is_sequence> 
699        [ 
700        <#list obj as item> 
701            <@printObject obj=item/> 
702            <#if item_has_next>, </#if> 
703        </#list> 
704        ] 
705    <#elseif obj?is_boolean> 
706        ${obj?c} 
707    <#elseif obj?is_number> 
708        ${obj} 
709    <#elseif obj?has_content> 
710        "${obj?string}" 
711    <#else> 
712        null 
713    </#if> 
714</#macro> 
715 
716 
717<#macro renderStandardRelationsSectionsRows standardRelationsTypesProduct standardRelationsProduct typesToExclude=[] isDebug=false> 
718 
719    <#assign lastSectionKey = ""> 
720    <#assign openRow = false> 
721    <#assign indexCount = 0> 
722 
723    <#assign filteredStandardRelationsProduct = standardRelationsProduct > 
724    <#if typesToExclude?has_content> 
725        <#assign filteredStandardRelationsProduct = excludeStandardRelationsByFieldType(standardRelationsProduct, typesToExclude)> 
726    </#if> 
727 
728    <#list standardRelationsTypesProduct as standardRelationsTypeProduct> 
729 
730        <#assign currentSectionKey = (standardRelationsTypeProduct.sectionKey)!"" /> 
731        <#assign standardRelationsProductsByTypeKey = getStandardRelationsProductsByField(standardRelationsTypeProduct, filteredStandardRelationsProduct)> 
732        <#assign hasElementsStandardRelationsProducts = (standardRelationsProductsByTypeKey?size > 0)> 
733 
734        <#if isDebug || hasElementsStandardRelationsProducts> 
735 
736            <#-- Si la sección cambia, cerramos la fila anterior --> 
737            <#if openRow && currentSectionKey != lastSectionKey> 
738                </td> 
739                </tr> 
740                <#assign openRow = false> 
741            </#if> 
742 
743            <#-- Si es una nueva sección, abrimos una nueva fila --> 
744            <#if !openRow> 
745                <#assign indexCount = 0> 
746                <tr 
747                    data-section-key="${currentSectionKey}" 
748                    data-section-name="${standardRelationsTypeProduct.sectionName}" 
749                    data-sort-key="${standardRelationsTypeProduct.sortKey}"> 
750                    <th> 
751                        <p>${standardRelationsTypeProduct.sectionName}</p> 
752                    </th> 
753                    <td data-section-key="${currentSectionKey}"> 
754                <#assign openRow = true> 
755            </#if> 
756 
757            <#if isDebug> 
758                <div class=""> 
759                    <p><strong>typeKey:</strong> ${standardRelationsTypeProduct.typeKey}</p> 
760                    <p><strong>sectionKey:</strong> ${standardRelationsTypeProduct.sectionKey}</p> 
761                    <p><strong>sectionName:</strong> ${standardRelationsTypeProduct.sectionName}</p> 
762                    <p><strong>sortKey:</strong> ${standardRelationsTypeProduct.sortKey}</p> 
763                    <p><strong>total standardRelationsProductsByTypeKey[${standardRelationsTypeProduct.typeKey}]: </strong> ${standardRelationsProductsByTypeKey?size}</p> 
764 
765                    <p class="mb-0"><strong>standardRelationsTypeProduct:</strong></p> 
766                    <div class="print-object-json-content mb-3" 
767                         style="max-height:200px; overflow:auto; border:1px solid #ccc; padding:5px; cursor:pointer;" 
768                         onclick="const r=document.createRange(); r.selectNodeContents(this); const s=window.getSelection(); s.removeAllRanges(); s.addRange(r);"> 
769                        <@printObject standardRelationsTypeProduct /> 
770                    </div> 
771 
772                    <p class="mb-0"><strong>standardRelationsProductsByTypeKey:</strong></p> 
773                    <div class="print-object-json-content mb-3" 
774                         style="max-height:200px; overflow:auto; border:1px solid #ccc; padding:5px; cursor:pointer;" 
775                         onclick="const r=document.createRange(); r.selectNodeContents(this); const s=window.getSelection(); s.removeAllRanges(); s.addRange(r);"> 
776                        <@printObject standardRelationsProductsByTypeKey /> 
777                    </div> 
778                </div> 
779            </#if> 
780 
781            <#if standardRelationsProductsByTypeKey?has_content> 
782                <#list standardRelationsProductsByTypeKey as standardRelationProductsByTypeKey> 
783                    <#assign indexCount = indexCount + 1> 
784                    <#assign urlProductCurrentLanguage = standardRelationProductsByTypeKey.urlProductCurrentLanguage> 
785 
786                    <p data-section-key="${currentSectionKey}" 
787                        data-type-key="${standardRelationsTypeProduct.typeKey}" data-type-index="${indexCount}"> 
788 
789                        ${standardRelationsTypeProduct.description} 
790 
791                        <#-- 
792                            <#if urlProductCurrentLanguage?? && urlProductCurrentLanguage?has_content> 
793                                <a href="${urlProductCurrentLanguage}" target="_blank"> 
794                                    ${standardRelationProductsByTypeKey.relatedStandardName!""} 
795                                </a> 
796                            <#else> 
797                                <a class="add-link-product-by-erc" data-product-erc="${standardRelationProductsByTypeKey.ercProduct}" href="" target="_blank"> 
798                                    ${standardRelationProductsByTypeKey.relatedStandardName!""} 
799                                </a> 
800                            </#if> 
801                        --> 
802 
803                        <a class="add-link-product-by-erc text-decoration-none text-body" data-product-erc="${standardRelationProductsByTypeKey.ercProduct}" href=""> 
804                            ${standardRelationProductsByTypeKey.relatedStandardName!""} 
805                        </a> 
806 
807                    </p> 
808 
809                </#list> 
810 
811                <#if isDebug> 
812                    <p> 
813                        <strong>Info:</strong>SI hay (<strong>${standardRelationsProductsByTypeKey?size}</strong>) <strong>Standard/Norma Relation</strong> con el type [<strong>typeKey:</strong> ${standardRelationsTypeProduct.typeKey}] 
814                        en la sección [<strong>sectionKey:</strong> ${standardRelationsTypeProduct.sectionKey}] 
815                    </p> 
816                </#if> 
817            <#else> 
818                <#if isDebug> 
819                    <p> 
820                        <strong>Info:</strong>NO hay <strong>Standard/Norma Relation</strong> con el type [<strong>typeKey:</strong> ${standardRelationsTypeProduct.typeKey}] 
821                        en la sección [<strong>sectionKey:</strong> ${standardRelationsTypeProduct.sectionKey}] 
822                    </p> 
823                <#else> 
824                    <p>N/A</p> 
825                </#if> 
826            </#if> 
827 
828            <#-- Separador visual en debug entre elementos standardRelations dentro del mismo section --> 
829            <#if isDebug> 
830                <#-- Separador visual mejorado --> 
831                <div style="margin:10px 0; padding:5px; border-top:2px dashed #007BFF; background-color:#f0f8ff;"></div> 
832            </#if> 
833 
834            <#assign lastSectionKey = currentSectionKey> 
835        </#if> 
836    </#list> 
837 
838    <#-- Cerrar la última fila abierta --> 
839    <#if openRow> 
840        </td> 
841        </tr> 
842    </#if> 
843 
844</#macro> 
845 
846 
847 
848 
849<#-- HTML --> 
850<#if hasProductCategoriaTipoEntidadNorma> 
851    <div id="ecom-norma-detail" class="ecom-norma"> 
852        <div class="tabs-section"> 
853            <div class="tab-content"> 
854 
855                <table> 
856 
857                    <#-- Custom object [StandardWarning] --> 
858                    <#if standardWarning?? && standardWarning?has_content> 
859                        <tr class="alert-row"> 
860                            <th class="alert-label"> 
861                                <#if standardWarning.warningTitle??> 
862                                    <strong>${standardWarning.warningTitle}</strong> 
863                                </#if> 
864                            </th> 
865                            <td class="alert-content"> 
866                                <#if standardWarning.warningDescription??> 
867                                    ${standardWarning.warningDescription} 
868                                </#if> 
869                            </td> 
870                        </tr> 
871                    </#if> 
872 
873                    <#-- Custom object [StandardRelations] > Buscamos si el producto tiene elementos [StandardRelations] con el campo key = ["MOD", "MODIFIED"] --> 
874                    <#assign findStandardRelationsProductsByTypeModified = filterStandardRelationsProductsByFieldType(standardRelationsProduct, ["MOD", "MODIFIED"])> 
875                    <#if findStandardRelationsProductsByTypeModified?has_content> 
876                        <tr class="alert-row"> 
877                            <th class="alert-label"> 
878                                <strong>${languageUtil.get(locale, "ecom-aviso")}</strong>: 
879                            </th> 
880                            <td class="alert-content"> 
881                                ${languageUtil.get(locale, "ecom-aviso_modificaciones_text")} 
882                            </td> 
883                        </tr> 
884                    </#if> 
885 
886                    <#-- Producto tiene [categoria: Organismo] > Si el producto tiene la [categoria: Organismo] = SAE --> 
887                    <#if hasProductCategoriaTipoOrganismoSAE> 
888                        <tr class="alert-row"> 
889                            <th class="alert-label"> 
890                                <span class="text-danger"> 
891                                    <strong>${languageUtil.get(locale, "ecom-aviso_pdf_secure")}</strong>: 
892                                </span> 
893                            </th> 
894                            <td class="alert-content"> 
895                                ${languageUtil.get(locale, "ecom-aviso_pdf_secure_text")} 
896                            </td> 
897                        </tr> 
898                    </#if> 
899 
900                    <#-- Producto tiene [categoria: Organismo] > Si el producto tiene la [categoria: Organismo] = ASTM --> 
901                    <#if hasProductCategoriaTipoOrganismoASTM> 
902                        <tr class="alert-row"> 
903                            <th class="alert-label"> 
904                                <strong>${languageUtil.get(locale, "ecom-aviso_astm")}</strong> 
905                            </th> 
906                            <td class="alert-content"> 
907                                ${languageUtil.get(locale, "ecom-aviso_astm_text")} 
908                            </td> 
909                        </tr> 
910                    </#if>                     
911 
912                    <#-- Categoria producto > Tematicas --> 
913                    <#if categoryProductInfoTematica?has_content> 
914                        <tr> 
915                            <th>${languageUtil.get(locale, "ecom-tematicas")}:</th> 
916                            <td>${categoryProductInfoTematica}</td> 
917                        </tr> 
918                    </#if> 
919 
920                    <#-- Fecha edicion del producto > displayDate del Producto --> 
921                    <#assign statusInfo = getStatusInfo(categoryProductInfoStatus, "badge status-standard")> 
922                    <#if statusInfo?? && !statusInfo.isCancelled> 
923                        <tr> 
924                            <th>${languageUtil.get(locale, "ecom-fecha_edicion")}:</th> 
925                            <td> 
926 
927                                <#-- Comentado provisonalmente hasta cambio en integracion 
928                                <#if displayDateProduct?? && displayDateProduct?has_content> 
929                                  ${displayDateProduct?datetime("d/MM/yy H:mm")?string("yyyy-MM-dd")} 
930                                <#else> 
931                                  - 
932                                </#if> 
933                                --> 
934 
935                                ${specificationsCurrentStateDateProduct 
936                                    ?filter(spec -> spec.value?? 
937                                        && spec.value?has_content 
938                                        && spec.value?length == 8) 
939                                    ?map(spec -> spec.value?date("yyyyMMdd")?string("yyyy-MM-dd")) 
940                                    ?join(", ")} 
941 
942                                <#if categoryProductInfoStatus?? && categoryProductInfoStatus?has_content> 
943                                    <div class="${statusInfo.tagClass}">${statusInfo.status}</div> 
944                                </#if> 
945 
946                            </td> 
947                        </tr> 
948                    </#if> 
949 
950                    <#-- Especificacion del producto > current-state-date (Nos indicaron que es la fecha de anulacion de la ficha) --> 
951                    <#-- Fecha de cancelacion del producto --> 
952                    <#if statusInfo?? && statusInfo.isCancelled> 
953                        <#if specificationsCurrentStateDateProduct?has_content> 
954                            <tr> 
955                                <th>${languageUtil.get(locale, "ecom-cancellationDate")}:</th> 
956                                <td> 
957 
958                                    ${specificationsCurrentStateDateProduct 
959                                        ?filter(spec -> spec.value?? 
960                                            && spec.value?has_content 
961                                            && spec.value?length == 8) 
962                                        ?map(spec -> spec.value?date("yyyyMMdd")?string("yyyy-MM-dd")) 
963                                        ?join(", ")} 
964 
965                                    <div class="${statusInfo.tagClass}">${statusInfo.status}</div> 
966 
967                                </td> 
968                            </tr> 
969                        </#if> 
970                    </#if> 
971 
972                    <#-- Custom object [StandardInfo] > confirmationDate --> 
973                    <#if standardInfoProduct?? && standardInfoProduct.confirmationDate?? 
974                        && standardInfoProduct.confirmationDate?has_content && !standardInfoProduct.confirmationDate?starts_with("0001-01-01")> 
975                        <tr> 
976                            <th>${languageUtil.get(locale, "ecom-confirmationDate")}:</th> 
977                            <td>${standardInfoProduct.confirmationDate?datetime("yyyy-MM-dd'T'HH:mm:ss.SSSX")?string("yyyy-MM-dd")}</td> 
978                        </tr> 
979                    </#if> 
980 
981                    <#-- Custom object [StandardInfo] > correctionDate --> 
982                    <#if standardInfoProduct?? && standardInfoProduct.correctionDate?? 
983                        && standardInfoProduct.correctionDate?has_content && !standardInfoProduct.correctionDate?starts_with("0001-01-01")> 
984                        <tr> 
985                            <th>${languageUtil.get(locale, "ecom-correctionDate")}:</th> 
986                            <td>${standardInfoProduct.correctionDate?datetime("yyyy-MM-dd'T'HH:mm:ss.SSSX")?string("yyyy-MM-dd")}</td> 
987                        </tr> 
988                    </#if> 
989 
990                    <#-- Custom object [StandardInfo] > ratificationDate --> 
991                    <#if standardInfoProduct?? && standardInfoProduct.ratificationDate?? 
992                        && standardInfoProduct.ratificationDate?has_content && !standardInfoProduct.ratificationDate?starts_with("0001-01-01")> 
993                        <tr> 
994                            <th>${languageUtil.get(locale, "ecom-ratificationDate")}:</th> 
995                            <td>${standardInfoProduct.ratificationDate?datetime("yyyy-MM-dd'T'HH:mm:ss.SSSX")?string("yyyy-MM-dd")}</td> 
996                        </tr> 
997                    </#if> 
998 
999                    <#-- Especificacion del producto > standard-languages (se aplica filtro para idiomas combinados) --> 
1000                    <#if filteredSpecificationsLanguagesProduct?has_content> 
1001                        <tr> 
1002                            <th>${languageUtil.get(locale, "ecom-idiomas_disponibles")}:</th> 
1003                            <td>${filteredSpecificationsLanguagesProduct?map(spec -> spec.title)?join(", ")}</td> 
1004                        </tr> 
1005                    </#if> 
1006 
1007                    <#-- Custom object [StandardInfo] > resumen --> 
1008                    <#if standardInfoProduct?? && standardInfoProduct.resumen?has_content> 
1009                        <tr> 
1010                            <th class="th-content">${languageUtil.get(locale, "ecom-resumen")}:</th> 
1011                            <td class="td-content">${htmlUtil.unescape(standardInfoProduct.resumen)}</td> 
1012                        </tr> 
1013                    </#if> 
1014 
1015                    <#-- Product > expando.keywords --> 
1016                    <#if product?? && product.expando?? && product.expando.keywords?has_content> 
1017                        <tr> 
1018                            <th class="th-content">${languageUtil.get(locale, "ecom-keywords")}:</th> 
1019                            <td class="td-content">${product.expando.keywords}</td> 
1020                        </tr> 
1021                    </#if> 
1022 
1023                    <#-- Custom object [StandardInfo] > scope --> 
1024                    <#if standardInfoProduct?? && standardInfoProduct.scope?has_content> 
1025                        <tr> 
1026                            <th class="th-content">${languageUtil.get(locale, "ecom-scope")}:</th> 
1027                            <td class="td-content">${standardInfoProduct.scope}</td> 
1028                        </tr> 
1029                    </#if> 
1030 
1031                    <#-- Especificacion del producto > ics --> 
1032                    <#if specificationsICSProduct?has_content> 
1033                        <tr> 
1034                            <th>${languageUtil.get(locale, "ecom-ics")}:</th> 
1035                            <td> 
1036                                <span class="add-link-parameter" data-parameter="ics" data-url="/normas"> 
1037                                    ${specificationsICSProduct?filter(spec -> spec.value?? && spec.value?has_content)?map(spec -> spec.value)?join(", ")} 
1038                                </span> 
1039                            </td> 
1040                        </tr> 
1041                    </#if> 
1042 
1043                    <#-- Especificacion del producto > ctn --> 
1044                    <#if specificationsCTNProduct?? && specificationsCTNProduct?size gt 0> 
1045                        <tr> 
1046                            <th>${languageUtil.get(locale, "ecom-ctn")}:</th> 
1047                            <td> 
1048                                <span class="add-link-parameter" data-parameter="ctn" data-url="/normas"> 
1049                                    ${specificationsCTNProduct?filter(spec -> spec.value?? && spec.value?has_content)?map(spec -> spec.value)?join(", ")} 
1050                                </span> 
1051                            </td> 
1052                        </tr> 
1053                    </#if> 
1054 
1055                    <#-- Para imprimir el contenido de los Objects --> 
1056                    <#if isDebug> 
1057                        <div class=""> 
1058                            <p><strong>standardRelationsProduct:</strong></p> 
1059                            <div class="print-object-json-content mb-3" style="max-height:200px; overflow:auto; border:1px solid #ccc; padding:5px; cursor:pointer;" 
1060                                 onclick="const r=document.createRange(); r.selectNodeContents(this); const s=window.getSelection(); s.removeAllRanges(); s.addRange(r);"> 
1061                                <@printObject standardRelationsProduct /> 
1062                            </div> 
1063                        </div> 
1064                     </#if> 
1065 
1066                    <@renderStandardRelationsSectionsRows 
1067                        standardRelationsTypesProduct = standardRelationsTypesProduct 
1068                        standardRelationsProduct = standardRelationsProduct 
1069                        typesToExclude = ["REFERENCE"] 
1070                        isDebug = isDebug 
1071                   /> 
1072 
1073                </table> 
1074            </div> 
1075        </div> 
1076    </div> 
1077</#if> 

El libro en palabras del autor

Ultricies magna feugiat malesuada sociosqu varius vivamus cubilia parturient, himenaeos vitae vehicula nam placerat netus urna platea, nostra rutrum felis mattis penatibus velit quisque.
Preguntas frecuentes ¿Tienes alguna duda sobre nuestros productos?
  • ​Normas UNE, EN, ISO, IEC, BSI, DIN, ASTM, AFNOR, IEEE, SAE.
  • Además, las normas del resto de organismos las puedes pedir a través del e-mail normas@aenor.com​​
  • Libros técnicos en papel y en soporte electrónico (PDF, epub).

 

Las normas pueden adquirirse en PDF, lectura o papel. Las normas en lectura no son archivos de descarga, solo pueden visualizarse en el área de cliente. Las normas solicitadas en papel y algunos de los libros en catálogo se imprimen bajo demanda. 

 

Consultar plazos en normas@aenor.com​​.

La licencia de uso es para un usuario y un dispositivo, si deseas reproducir el contenido de la norma, debes solicitar una licencia que tendrá un coste adicional. Envíanos tu consulta aquí 
 

Prohibido utilizar normas y otros contenidos protegidos por propiedad intelectual en sistemas de IA. Si está interesado en este tipo de usos, contacte con normas@aenor.com. El incumplimiento supondrá la retirada de la licencia de acceso.

Las normas y libros de AENOR que aparecen en la tienda on-line solo se pueden comprar exclusivamente a través de la web: Tienda AENOR. No disponemos de tienda física.

Procedimiento de compra: haciendo clic en “Comprar” los productos deseados irán a la cesta de la compra. Si hubiera problemas de visualización el navegador recomendado es Chrome.

Para formalizar la compra debe Registrarse. En caso de no estar registrado como cliente, deberá Registrarse en la web incluyendo los datos de facturación, una clave y su email como usuario. De este modo, quedará creada la cuenta.

Una vez hecho esto, podrá visualizar su Pedido y su descuento, en caso de haber introducido algún código promocional, con todos los artículos cargados en la cesta de la compra, sus precios, impuestos establecidos en la legislación vigente y gastos de envío si fueran de aplicación.

Los precios de las normas y libros que aparecen en las diversas secciones no incluyen impuestos, ni gastos de envío.

Los códigos promocionales de AENOR constan de caracteres alfanuméricos y solo se podrán aplicar en la compra en web, recibir a través de una oferta específica y durante un tiempo limitado. Para aplicar tu código promocional, solo tienes que introducirlo en el paso 2 de 4 del proceso de compra en la web y clicar en “aplicar”, después de haberte identificado y elegido las formas de pago. Los códigos promocionales no son acumulables.

 

  • Tarjeta de crédito o débito (Visa, Mastercard) y PayPal.
  • ​Transferencia b​ancaria. En caso de optar por esta forma de pago es necesario enviar previamente a AENOR copia de la transferencia por correo electrónico a normas@aenor.com​​​
  • La factura de compra se puede descargar desde el área de cliente, en mis pedidos anteriores

​​En el caso de los ​clientes de empresas con sede ​en el extranjero, el número de identificación del contribuyente del país correspondiente (por ejemplo, en Argentina el CUIT), deberá rellenarse en el campo CIF/NIF - VAT.

  • Podrás acceder al contenido de tu compra haciendo clic en descarga o lectura según el formato seleccionado. En el apartado de "Mis productos" puedes ver todos los artículos que has adquirido; al hacer clic en cualquiera de ellos se abre el entorno de AENORMÁS, donde podrás acceder y consultar todos tus productos. Los archivos en formato digital están protegidos y en ningún caso son editables. Antes de adquirirlos, es importante que la licencia de uso sea leída y aceptada como paso previo a la compra.
  • Envío por mensajería. Los productos comprados en soporte físico se envían por mensajería. El plazo máximo de entrega en el territorio español, desde la aceptación del pedido por parte AENOR es de:
  •  Siete días laborables aproximados para todas las normas compradas a través de la tienda en soporte papel.
  • Tres días laborables aproximados para libros comprados a través de la tienda. Las existencias de los libros en papel son limitadas y su oferta en la web no implica disponibilidad en el plazo indicado. En el caso de no disponer del libro solicitado, se avisa al cliente de la demora en la recepción del pedido que será aproximadamente de siete días laborables. 

Para el resto de productos que no están en la web, consultar disponibilidad y plazo de entrega en normas@aenor.com.

1. Para los productos digitales (PDF, Epub), una vez realizada la entrega mediante descarga directa a través de la web en el Área de clientes, no tendrás derecho a ejercer tu derecho de desistimiento.

2. Para los productos personalizados en soporte papel, una vez realizada la compra, no tendrás derecho a ejercer tu derecho de desistimiento.

3.  Para el resto de productos en soporte papel, dispones del derecho a desistir de la compraventa en un plazo de 14 días naturales a contar desde la fecha de la compra. Recuerda que para la devolución es imprescindible que el producto se encuentre en perfectas condiciones, precintado por el envoltorio y conservando su embalaje original. El cliente será responsable de la recogida y los gastos de envío.

La factura del pedido incluye los gastos de envío​, por lo que no hay que abonar ningún importe al mensajero. ​Los gastos de envío se calculan en función tanto del destino final del pedido como del número de productos solicitados. Incluyen gastos de transporte y embalaje. Los gastos de envío están sujetos a revisiones periódicas. Los libros outlet tendrán gastos de envío gratuitos solo si el envío se realiza en Península.

​Destino ​Hasta tres normas y/o publicaciones ​A partir de tres normas y/o publicaciones
​Península ​ 7,31€ ​8,60€
​Baleares ​ 18,04€ ​23,34€
​Canarias, Ceuta y Melilla  ​​​18,04€ ​​23,34€
​Europa ​ 59,17€ ​80,07€
​Estados Unidos y Canadá ​ 70,07€ ​96,94€
​Resto del mundo ​ 91,94€ ​115,91€​​

 

  • ​​​​​Las compras realizadas por residentes en los Estados miembros de la Unión Europea estarán sujetas al pago de IVA (impuesto sobre el valor añadido).​
  • ​​
  • ​​En el caso de personas jurídicas y personas físicas que, actuando como empresarios, tengan su domicilio en algún Estado miembro de la Unión Europea (excepto residentes en España) y posean NIF/VAT intracomunitario inscrito en el censo VIES, estarán exentas del pago del IVA, siendo condición imprescindible el envío de dicho documento por correo electrónico a ​normas@aenor.com​​​.
  • Las compras realizadas a título particular (persona física), independientemente de donde tengan su residencia, estarán sujetas al pago del ​IVA.
  • L​as compras realizadas por entidades en países extracomunitarios estarán exentas del pago del IVA, siempre y cuando envíen el correspondiente documento de residencia fiscal por correo electrónico a normas@aenor.com​.
  • Las operaciones de venta se entenderán realizadas en el domicilio social de AENOR: Génova 6, 28004, Madrid – España.​

El contrato de compra de productos a través de este Sitio Web se regirá por la legislación española. Cualquier controversia que surja o guarde relación con el uso del Sitio Web o con dicho contrato será sometida a la jurisdicción exclusiva de los Juzgados y Tribunales de Madrid Capital.

No obstante lo anterior, si estás contratando como consumidor en los términos del Real Decreto 1/2007, nada en la presente cláusula afectará a los derechos que como tal te pudiera reconocer la legislación vigente.