Distribución farma - mundofarmaceutico
En movimiento
Machine Learning, la tecnología que está revolucionando la distribución farmacéutica
El aprendizaje automático permite analizar grandes volúmenes de datos para anticipar la demanda de medicamentos y optimizar la logística farmacéutica.
¿Cuál es el valor de la distribución farmacéutica de gama completa en la protección de la salud pública?
A través de las farmacias comunitarias, la distribución mayorista garantiza el acceso a la población de todos los medicamentos y productos sanitarios.
Machine Learning, la tecnología que está revolucionando la distribución farmacéutica
El aprendizaje automático permite analizar grandes volúmenes de datos para anticipar la demanda de medicamentos y optimizar la logística farmacéutica.
¿Cuál es el valor de la distribución farmacéutica de gama completa en la protección de la salud pública?
A través de las farmacias comunitarias, la distribución mayorista garantiza el acceso a la población de todos los medicamentos y productos sanitarios.
Blockchain o cómo conseguir una distribución farmacéutica más segura y transparente
Esta tecnología se sigue extendiendo en el sector gracias a los beneficios que presenta; entre otros, destaca la mayor seguridad para el paciente y un mejor cumplimiento normativo.
La colaboración, fundamental para garantizar la seguridad de la cadena de suministro de medicamentos frente a crisis
PharmaSupply 2025, organizada por la GIRP, apuntó a la necesidad de cooperar en todos los niveles: planificación conjunta, ciberseguridad y regulación armonizada.
The following has evaluated to null or missing:
==> renderer.getArticle [in template "20155#20195#187080686" at line 14, column 59]
----
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 journalArticle = renderer.get... [in template "20155#20195#187080686" at line 14, column 33]
----
1<#if entries?has_content>
2 <#assign journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
3
4 <#assign listaContenidos = [] />
5 <#assign listaRenderersContenidos = [] />
6 <#assign portletDisplay = themeDisplay.getPortletDisplay() />
7 <#assign portletId = portletDisplay.getId() />
8 <#assign templateKey = "110969" />
9
10 <div class="slickCarousel${portletId} CuadriculaWidth carouselCards">
11 <#list entries as curEntry>
12 <#assign renderer = curEntry.getAssetRenderer() />
13 <#assign className = renderer.getClassName() />
14 <#assign journalArticle = renderer.getArticle() />
15 <#assign listaContenidos = listaContenidos + [journalArticle] />
16 <#assign listaRenderersContenidos = listaRenderersContenidos + [renderer] />
17 </#list>
18
19 <#list listaContenidos as contenido>
20 <div class="slick-carousel-item">
21 ${journalArticleLocalService.getArticleContent(contenido, templateKey, "VIEW", locale.toString(), null, themeDisplay)}
22 </div>
23 </#list>
24 </div>
25
26 <script type="text/javascript">
27 $(document).ready(function(){
28 $(".slickCarousel${portletId}").slick({
29 dots: false,
30 infinite: true,
31 speed: 300,
32 slidesToShow: 3,
33 prevArrow: '<button type="button" data-role="none" class="slick-prev" aria-label="Previous" tabindex="0" role="button"><svg width="18" height="33" viewBox="0 0 18 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M16.3058 30.5373C16.7469 31.0237 16.7027 31.7689 16.2071 32.2017C15.7665 32.5865 15.1176 32.595 14.669 32.2505L14.511 32.1049L1.30393 17.5431C0.953945 17.1573 0.905707 16.6011 1.16181 16.1682L1.29022 15.991L14.4973 0.910537C14.9297 0.416751 15.6882 0.360467 16.1914 0.784824C16.6387 1.16203 16.7337 1.79203 16.4456 2.27418L16.3195 2.44727L3.79855 16.745L16.3058 30.5373Z" fill="#183657" stroke="#183657"/></svg></button>',
34 nextArrow: '<button type="button" data-role="none" class="slick-next" aria-label="Next" tabindex="0" role="button"><svg width="16" height="33" viewBox="0 0 16 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M14.8499 16.0019C15.1587 16.3905 15.1933 16.9358 14.9558 17.3592L14.8373 17.5324L2.85008 32.0941C2.44541 32.5857 1.73961 32.6381 1.27364 32.2112C0.859439 31.8317 0.774151 31.2012 1.04453 30.7206L1.16264 30.5481L12.5252 16.745L1.1501 2.4364C0.797606 1.99294 0.807338 1.35616 1.14598 0.926309L1.28833 0.775596C1.70868 0.403731 2.3123 0.413998 2.71976 0.771254L2.86262 0.921421L14.8499 16.0019Z" fill="#183657" stroke="#183657"/></svg></button>',
35
36 responsive: [
37 {
38 breakpoint: 600,
39 settings: {
40 slidesToShow: 2,
41 slidesToScroll: 1,
42 arrows: false,
43 dots: true,
44 }
45 },
46 {
47 breakpoint: 480,
48 settings: {
49 slidesToShow: 1,
50 slidesToScroll: 1,
51 arrows: false,
52 dots: true,
53 }
54 }
55 ]
56 });
57 });
58 </script>
59 </#if>
The following has evaluated to null or missing:
==> renderer.getArticle [in template "20155#20195#187080686" at line 14, column 59]
----
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 journalArticle = renderer.get... [in template "20155#20195#187080686" at line 14, column 33]
----
1<#if entries?has_content>
2 <#assign journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
3
4 <#assign listaContenidos = [] />
5 <#assign listaRenderersContenidos = [] />
6 <#assign portletDisplay = themeDisplay.getPortletDisplay() />
7 <#assign portletId = portletDisplay.getId() />
8 <#assign templateKey = "110969" />
9
10 <div class="slickCarousel${portletId} CuadriculaWidth carouselCards">
11 <#list entries as curEntry>
12 <#assign renderer = curEntry.getAssetRenderer() />
13 <#assign className = renderer.getClassName() />
14 <#assign journalArticle = renderer.getArticle() />
15 <#assign listaContenidos = listaContenidos + [journalArticle] />
16 <#assign listaRenderersContenidos = listaRenderersContenidos + [renderer] />
17 </#list>
18
19 <#list listaContenidos as contenido>
20 <div class="slick-carousel-item">
21 ${journalArticleLocalService.getArticleContent(contenido, templateKey, "VIEW", locale.toString(), null, themeDisplay)}
22 </div>
23 </#list>
24 </div>
25
26 <script type="text/javascript">
27 $(document).ready(function(){
28 $(".slickCarousel${portletId}").slick({
29 dots: false,
30 infinite: true,
31 speed: 300,
32 slidesToShow: 3,
33 prevArrow: '<button type="button" data-role="none" class="slick-prev" aria-label="Previous" tabindex="0" role="button"><svg width="18" height="33" viewBox="0 0 18 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M16.3058 30.5373C16.7469 31.0237 16.7027 31.7689 16.2071 32.2017C15.7665 32.5865 15.1176 32.595 14.669 32.2505L14.511 32.1049L1.30393 17.5431C0.953945 17.1573 0.905707 16.6011 1.16181 16.1682L1.29022 15.991L14.4973 0.910537C14.9297 0.416751 15.6882 0.360467 16.1914 0.784824C16.6387 1.16203 16.7337 1.79203 16.4456 2.27418L16.3195 2.44727L3.79855 16.745L16.3058 30.5373Z" fill="#183657" stroke="#183657"/></svg></button>',
34 nextArrow: '<button type="button" data-role="none" class="slick-next" aria-label="Next" tabindex="0" role="button"><svg width="16" height="33" viewBox="0 0 16 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M14.8499 16.0019C15.1587 16.3905 15.1933 16.9358 14.9558 17.3592L14.8373 17.5324L2.85008 32.0941C2.44541 32.5857 1.73961 32.6381 1.27364 32.2112C0.859439 31.8317 0.774151 31.2012 1.04453 30.7206L1.16264 30.5481L12.5252 16.745L1.1501 2.4364C0.797606 1.99294 0.807338 1.35616 1.14598 0.926309L1.28833 0.775596C1.70868 0.403731 2.3123 0.413998 2.71976 0.771254L2.86262 0.921421L14.8499 16.0019Z" fill="#183657" stroke="#183657"/></svg></button>',
35
36 responsive: [
37 {
38 breakpoint: 600,
39 settings: {
40 slidesToShow: 2,
41 slidesToScroll: 1,
42 arrows: false,
43 dots: true,
44 }
45 },
46 {
47 breakpoint: 480,
48 settings: {
49 slidesToShow: 1,
50 slidesToScroll: 1,
51 arrows: false,
52 dots: true,
53 }
54 }
55 ]
56 });
57 });
58 </script>
59 </#if>
The following has evaluated to null or missing:
==> renderer.getArticle [in template "20155#20195#187080686" at line 14, column 59]
----
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 journalArticle = renderer.get... [in template "20155#20195#187080686" at line 14, column 33]
----
1<#if entries?has_content>
2 <#assign journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
3
4 <#assign listaContenidos = [] />
5 <#assign listaRenderersContenidos = [] />
6 <#assign portletDisplay = themeDisplay.getPortletDisplay() />
7 <#assign portletId = portletDisplay.getId() />
8 <#assign templateKey = "110969" />
9
10 <div class="slickCarousel${portletId} CuadriculaWidth carouselCards">
11 <#list entries as curEntry>
12 <#assign renderer = curEntry.getAssetRenderer() />
13 <#assign className = renderer.getClassName() />
14 <#assign journalArticle = renderer.getArticle() />
15 <#assign listaContenidos = listaContenidos + [journalArticle] />
16 <#assign listaRenderersContenidos = listaRenderersContenidos + [renderer] />
17 </#list>
18
19 <#list listaContenidos as contenido>
20 <div class="slick-carousel-item">
21 ${journalArticleLocalService.getArticleContent(contenido, templateKey, "VIEW", locale.toString(), null, themeDisplay)}
22 </div>
23 </#list>
24 </div>
25
26 <script type="text/javascript">
27 $(document).ready(function(){
28 $(".slickCarousel${portletId}").slick({
29 dots: false,
30 infinite: true,
31 speed: 300,
32 slidesToShow: 3,
33 prevArrow: '<button type="button" data-role="none" class="slick-prev" aria-label="Previous" tabindex="0" role="button"><svg width="18" height="33" viewBox="0 0 18 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M16.3058 30.5373C16.7469 31.0237 16.7027 31.7689 16.2071 32.2017C15.7665 32.5865 15.1176 32.595 14.669 32.2505L14.511 32.1049L1.30393 17.5431C0.953945 17.1573 0.905707 16.6011 1.16181 16.1682L1.29022 15.991L14.4973 0.910537C14.9297 0.416751 15.6882 0.360467 16.1914 0.784824C16.6387 1.16203 16.7337 1.79203 16.4456 2.27418L16.3195 2.44727L3.79855 16.745L16.3058 30.5373Z" fill="#183657" stroke="#183657"/></svg></button>',
34 nextArrow: '<button type="button" data-role="none" class="slick-next" aria-label="Next" tabindex="0" role="button"><svg width="16" height="33" viewBox="0 0 16 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M14.8499 16.0019C15.1587 16.3905 15.1933 16.9358 14.9558 17.3592L14.8373 17.5324L2.85008 32.0941C2.44541 32.5857 1.73961 32.6381 1.27364 32.2112C0.859439 31.8317 0.774151 31.2012 1.04453 30.7206L1.16264 30.5481L12.5252 16.745L1.1501 2.4364C0.797606 1.99294 0.807338 1.35616 1.14598 0.926309L1.28833 0.775596C1.70868 0.403731 2.3123 0.413998 2.71976 0.771254L2.86262 0.921421L14.8499 16.0019Z" fill="#183657" stroke="#183657"/></svg></button>',
35
36 responsive: [
37 {
38 breakpoint: 600,
39 settings: {
40 slidesToShow: 2,
41 slidesToScroll: 1,
42 arrows: false,
43 dots: true,
44 }
45 },
46 {
47 breakpoint: 480,
48 settings: {
49 slidesToShow: 1,
50 slidesToScroll: 1,
51 arrows: false,
52 dots: true,
53 }
54 }
55 ]
56 });
57 });
58 </script>
59 </#if>
The following has evaluated to null or missing:
==> renderer.getArticle [in template "20155#20195#187080686" at line 14, column 59]
----
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 journalArticle = renderer.get... [in template "20155#20195#187080686" at line 14, column 33]
----
1<#if entries?has_content>
2 <#assign journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
3
4 <#assign listaContenidos = [] />
5 <#assign listaRenderersContenidos = [] />
6 <#assign portletDisplay = themeDisplay.getPortletDisplay() />
7 <#assign portletId = portletDisplay.getId() />
8 <#assign templateKey = "110969" />
9
10 <div class="slickCarousel${portletId} CuadriculaWidth carouselCards">
11 <#list entries as curEntry>
12 <#assign renderer = curEntry.getAssetRenderer() />
13 <#assign className = renderer.getClassName() />
14 <#assign journalArticle = renderer.getArticle() />
15 <#assign listaContenidos = listaContenidos + [journalArticle] />
16 <#assign listaRenderersContenidos = listaRenderersContenidos + [renderer] />
17 </#list>
18
19 <#list listaContenidos as contenido>
20 <div class="slick-carousel-item">
21 ${journalArticleLocalService.getArticleContent(contenido, templateKey, "VIEW", locale.toString(), null, themeDisplay)}
22 </div>
23 </#list>
24 </div>
25
26 <script type="text/javascript">
27 $(document).ready(function(){
28 $(".slickCarousel${portletId}").slick({
29 dots: false,
30 infinite: true,
31 speed: 300,
32 slidesToShow: 3,
33 prevArrow: '<button type="button" data-role="none" class="slick-prev" aria-label="Previous" tabindex="0" role="button"><svg width="18" height="33" viewBox="0 0 18 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M16.3058 30.5373C16.7469 31.0237 16.7027 31.7689 16.2071 32.2017C15.7665 32.5865 15.1176 32.595 14.669 32.2505L14.511 32.1049L1.30393 17.5431C0.953945 17.1573 0.905707 16.6011 1.16181 16.1682L1.29022 15.991L14.4973 0.910537C14.9297 0.416751 15.6882 0.360467 16.1914 0.784824C16.6387 1.16203 16.7337 1.79203 16.4456 2.27418L16.3195 2.44727L3.79855 16.745L16.3058 30.5373Z" fill="#183657" stroke="#183657"/></svg></button>',
34 nextArrow: '<button type="button" data-role="none" class="slick-next" aria-label="Next" tabindex="0" role="button"><svg width="16" height="33" viewBox="0 0 16 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M14.8499 16.0019C15.1587 16.3905 15.1933 16.9358 14.9558 17.3592L14.8373 17.5324L2.85008 32.0941C2.44541 32.5857 1.73961 32.6381 1.27364 32.2112C0.859439 31.8317 0.774151 31.2012 1.04453 30.7206L1.16264 30.5481L12.5252 16.745L1.1501 2.4364C0.797606 1.99294 0.807338 1.35616 1.14598 0.926309L1.28833 0.775596C1.70868 0.403731 2.3123 0.413998 2.71976 0.771254L2.86262 0.921421L14.8499 16.0019Z" fill="#183657" stroke="#183657"/></svg></button>',
35
36 responsive: [
37 {
38 breakpoint: 600,
39 settings: {
40 slidesToShow: 2,
41 slidesToScroll: 1,
42 arrows: false,
43 dots: true,
44 }
45 },
46 {
47 breakpoint: 480,
48 settings: {
49 slidesToShow: 1,
50 slidesToScroll: 1,
51 arrows: false,
52 dots: true,
53 }
54 }
55 ]
56 });
57 });
58 </script>
59 </#if>
Java method "com.sun.proxy.$Proxy1136.getDDMStructure(long)" threw an exception when invoked on com.sun.proxy.$Proxy1136 object "com.liferay.dynamic.data.mapping.service.impl.DDMStructureLocalServiceImpl@59a246b3"; see cause exception in the Java stack trace.
----
FTL stack trace ("~" means nesting-related):
- Failed at: #assign structure = ddmStructureLocal... [in template "20155#20195#187096557" at line 527, column 1]
----
1<script src="https://maps.google.com/maps/api/js?v=3&libraries=geometry,places&key=AIzaSyCY8E-ymOZcQVzPlN0WREHafmMkAQmsHhY" async defer></script>
2
3<script type="text/javascript">
4
5
6
7 window.onload = function() {
8 // Se cargan las oficinas
9 initLoad();
10 loadCentros();
11 };
12
13 $( document ).ready(function() {
14 //console.log("cambia windows");
15 initLoad();
16 loadCentros();
17 });
18
19 $( window ).resize(function() {
20 //console.log("cambia windows");
21 initLoad();
22 });
23
24 // Variable que guarda los datos de los centros
25 var centros = [];
26
27 // Variable que guarda el html de los resultados encontrados
28 var side_bar_html = "";
29
30 // Array para guardar todos los marcadores
31 var gmarkers = [];
32 var gmarkersshow = [];
33
34 // Variables globales
35 var map;
36 var circle = null;
37 var geocoder;
38 var busquedaRealizada = false;
39 var marker_you;
40 var userMarker;
41 var directionsService;
42 var directionsDisplay;
43 var infowindow;
44 var defaultCoordinates = {lat: 40.4168508 ,lng:-3.7031067};
45
46 // Variable global para saber si se tiene o no geolocalizacion
47 var geoActive = true;
48
49 //Variable para guardar objeto scrollbar
50 var scrollbar;
51
52 //Genera arrays de centros
53 function addCentros (contador,nombre,direccion,latitud,longitud,enlace,telefono){
54 var entryLocation = [nombre,direccion,latitud,longitud,enlace,telefono];
55 centros[contador] = entryLocation;
56 }
57
58 //Funcion que muestra error por consola si no se puede utilizar la geolocalizacion del usuario
59 function showError() {
60 //console.log("Location can't be found");
61 geoActive = false;
62
63 if(directionsService == null || directionsService == "undefined"){
64 directionsService = new google.maps.DirectionsService();
65 }
66 if(directionsDisplay == null || directionsDisplay == "undefined"){
67 directionsDisplay = new google.maps.DirectionsRenderer();
68 }
69 if(infowindow == null || infowindow == "undefined"){
70 infowindow = new google.maps.InfoWindow({
71 size: new google.maps.Size(150,50)
72 });
73 }
74 map = new google.maps.Map(document.getElementById("map_canvas"), {
75 zoom: 8,
76 center: {lat: 40.4169473, lng: -3.7079059}
77
78 });
79
80 // Crea evento para sacar infoWindows
81 google.maps.event.addListener(map, 'click', function() {
82 infowindow.close();
83 });
84
85 // Funcion autocompletar para el campo de texto
86 var autocomplete = new google.maps.places.Autocomplete(document.getElementById('address'));
87 autocomplete.bindTo('bounds', map);
88
89 searchRadius(defaultCoordinates);
90
91 // Se hace focus en el campo de texto de la direccion una vez que todo este cargado
92 $(".js_input_dir").select();
93 }
94
95 // Funcion para crear marcadores
96 function createMarker(latlng, name, html_infow, html_res, indice) {
97 // Contenido del infoWindow
98 var contentString = html_infow;
99
100 // Marcador
101 var marker = new google.maps.Marker({
102 icon: '/o/mundo-farmaceutico-theme/images/icons/ovalado_rojo.png',
103 position: latlng,
104 title: name,
105 // zIndex: Math.round(latlng.lat()*-100000)<<5,
106 zIndex: Math.round(latlng.lat*-100000)<<5,
107 info: html_res,
108 ind: indice
109 });
110
111 // Evento para lanzar la infoWdindows al hacer click sobre el marcador
112 google.maps.event.addListener(marker, 'click', function() {
113 infowindow.setContent(contentString);
114 infowindow.open(map,marker);
115 });
116
117 // Guarda el marcador en el array global
118 gmarkers.push(marker);
119 }
120
121 // Funcion initLoad
122 function initLoad(){
123 //console.log("Entramos en la funcion del callback");
124 // INICIALIZACION
125 geocoder = new google.maps.Geocoder();
126 if (navigator.geolocation) {
127 var options = {
128 enableHighAccuracy: true,
129 maximumAge: 0
130 }
131 navigator.geolocation.getCurrentPosition(initializeMaps, showError, options);
132 }
133 else {
134 //console.log("El navegador no soporta geolocalización");
135 }
136 // FIN INICIALIZACION
137 }
138
139 // Funcion ejecutada al CARGAR LA PáGINA
140 function initializeMaps(userPosition) {
141 // Define las opciones del mapa
142 userMarker = userPosition;
143
144 var myOptions = {
145 zoom: 8,
146 center: new google.maps.LatLng(userPosition.coords.latitude, userPosition.coords.longitude),
147 mapTypeControl: true,
148 mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU},
149 navigationControl: true,
150 mapTypeId: google.maps.MapTypeId.ROADMAP
151 };
152
153 // Define el mapa
154 map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
155
156 // Crea evento para sacar infoWindows
157 google.maps.event.addListener(map, 'click', function() {
158 infowindow.close();
159 });
160
161 if(directionsService == null || directionsService == "undefined"){
162 directionsService = new google.maps.DirectionsService();
163 }
164 if(directionsDisplay == null || directionsDisplay == "undefined"){
165 directionsDisplay = new google.maps.DirectionsRenderer();
166 }
167 if(infowindow == null || infowindow == "undefined"){
168 infowindow = new google.maps.InfoWindow({
169 size: new google.maps.Size(150,50)
170 });
171 }
172
173 // Funcion autocompletar para el campo de texto
174 var autocomplete = new google.maps.places.Autocomplete(document.getElementById('address'));
175 autocomplete.bindTo('bounds', map);
176
177 //se crea el marcador de posición del usuario
178 //marcador = new google.maps.Marker({
179 // position: new google.maps.LatLng(userPosition.coords.latitude, userPosition.coords.longitude),
180 // icon: 'http://opendatacon.org/wp-content/uploads/2016/05/Farm-Fresh_star.png',
181 // title: "Usted está aquí",
182 // map: map
183 //});
184
185 searchRadius();
186
187 // Se hace focus en el campo de texto de la direccion una vez que todo este cargado
188 $(".js_input_dir").select();
189 }
190
191 function searchRadius(coordinates){
192 //se saca la dirección del usuario según sus coordenadas (si no se encuentra se fija la puerta de sol como punto de partida)
193 var userPosic = 'Plaza Puerta del Sol, 28013 Madrid';
194 var latlng;
195
196 if(coordinates != null){
197 latlng = coordinates;
198 }else{
199 var input = (userMarker.coords.latitude+","+userMarker.coords.longitude);
200 var latlngStr = input.split(',', 2);
201 latlng = {lat: parseFloat(latlngStr[0]), lng: parseFloat(latlngStr[1])};
202 }
203
204 geocoder.geocode({'location': latlng}, function(results, status) {
205 if (status === google.maps.GeocoderStatus.OK) {
206 //console.log(results[0].formatted_address);
207 if (results[0]) {
208 userPosic = results[0].formatted_address;
209 } else {
210 window.alert('No results found');
211 }
212 } else {
213 window.alert('Geocoder failed due to: ' + status);
214 }
215
216 //se buscan los centros que estón a menos de 6km del usuario
217 var searchAddress = userPosic;
218 var radVal = 6;
219 var radius = 600000;
220 $(".rad_err_msg").hide();
221 if(searchAddress != null && searchAddress != ""){
222 // Ejecutamos con timeOut de 200ms para evitar el queryLimit de google
223 setTimeout(function(){
224 $(".div_lista").fadeIn();
225 exe_code_address(searchAddress, radius);
226 }, 200);
227 }
228 });
229
230 }
231
232 // Funcion para procesar los centros
233 function loadCentros(){
234 // Para cada centro se genera un marcador y una infoWindow
235 for(var i = 0; i < centros.length; i++){
236 var centroName = centros[i][0];
237 var centroAddress = centros[i][1];
238 var centroLatitud = centros[i][2];
239 var centroLongitud = centros[i][3];
240 var enlaceAWeb = centros[i][4];
241 var centroTlf = centros[i][5];
242
243 var latlng = {lat: parseFloat(centroLatitud), lng: parseFloat(centroLongitud)};
244
245 var urlCentro = "";
246 if("" != enlaceAWeb && null != enlaceAWeb){
247 urlCentro = '<div class="center_url">'+
248 '<a class="btn btn-primary" href="'+ enlaceAWeb +'" target="_blank"> Sitio web </a>'+
249 '</div>';
250 }
251
252 var html_inf =
253 '<div id="content_gmap">'+
254 '<div class="center_data_wrapper" onclick="javascript:myclick({index})">'+
255 '<div class="evo-form__text-info office_data">'+
256 '<p class="center_title">'+centroName+'</p>'+
257 '<p class="center_address">'+centroAddress+'</p>'+
258 '<p class="center_tlf">'+centroTlf+'</p>'+
259 '</div>'+
260 '</div>'+
261 //'<div class="howToGo">'+
262 // '<a class="btn btn-primary" href="javascript:void(0);" onclick="arriveTo(\'' + centroAddress + '\');"> Cómo llegar </a>'+
263 //'</div>'+
264 urlCentro +
265 '</div>';
266
267 var html_res =
268 '<div id="content_gmap">'+
269 '<div class="center_data_wrapper" onclick="javascript:myclick({index})">'+
270 '<div class="center_data">'+
271 '<p class="center_title">'+centroName+'</p>'+
272 '<p class="center_address">'+centroAddress+'</p>'+
273 '<p class="center_tlf">'+centroTlf+'</p>'+
274 '</div>'+
275 '</div>'+
276 //'<div class="howToGo">'+
277 // '<a class="btn btn-primary" href="javascript:void(0);" onclick="arriveTo(\'' + centroAddress + '\');"> Cómo llegar </a>'+
278 //'</div>'+
279 urlCentro +
280 '</div>';
281 //Se crea el marcador en las coordenadas de los centros
282 var marker = createMarker(latlng, centroName, html_inf, html_res, i);
283 }
284 }
285
286
287 var marcador;
288 // Funcion para atender la direccion introducida en el formulario
289 function codeAddress() {
290 //se crea el marcador de posición del usuario con datos por defecto
291 var latitude = defaultCoordinates.lat;
292 var longitude = defaultCoordinates.lng;
293
294 if(userMarker != undefined){
295 latitude = userMarker.coords.latitude;
296 longitude = userMarker.coords.longitude;
297 }
298
299 marcador = new google.maps.Marker({
300 position: new google.maps.LatLng(latitude, longitude),
301 icon: "/o/mundo-farmaceutico-theme/images/icons/pin-position.png",
302 title: "Usted está aquí",
303 map: map
304 });
305
306 //Se resetea el "como llegar",las indicaciones y se cierran la infowindow que hubiese abierta
307 if(directionsDisplay != null){
308 directionsDisplay.setMap(null);
309 }
310 $("#map_indications").html("");
311
312 if(infowindow)infowindow.close();
313 var searchAddress = $("#address").val();
314 var radVal = $("#radius").val();
315 var radius = parseInt($("#radius").val(), 10)*1000;
316
317 if(radVal > 0 && radVal <= 500){
318 $(".rad_err_msg").hide();
319 if(searchAddress != null && searchAddress != ""){
320 // Ejecutamos con timeOut de 200ms para evitar el queryLimit de google
321 setTimeout(function(){
322 $(".div_lista").fadeIn();
323 exe_code_address(searchAddress, radius);
324 }, 200);
325 }
326 }else{
327 $(".rad_err_msg").show();
328 }
329 }
330
331 function exe_code_address(searchAddress, radius){
332 // Flag de busqueda realizada para evento del input de radio
333 busquedaRealizada = true;
334
335 // El marcador de la posicion buscada se reinicia en cada busqueda
336 if(marker_you != null){
337 marker_you.setMap(null);
338 }
339
340 // Se situa un marcador en el mapa con los datos recogidos
341 geocoder.geocode({ 'address': searchAddress}, function(results, status) {
342 if (status == google.maps.GeocoderStatus.OK) {
343 map.setCenter(results[0].geometry.location);
344 map.setZoom(8);
345 var searchCenter = results[0].geometry.location;
346 /*
347 var searchAddressComponents = results[0].address_components;
348 var searchPostalCode = "";
349 var searchCity = "";
350
351 $.each(searchAddressComponents, function(){
352 if(this.types[0]=="postal_code"){
353 searchPostalCode=this.short_name;
354 } else if (this.types[0]=="locality"){
355 searchCity = this.short_name;
356 }
357 });
358
359 // Codigo para enviar a analytics . si hay psotal code se enva CP, si no city
360 var titleBusqueda=searchPostalCode;
361 if (titleBusqueda == ""){
362 titleBusqueda=searchCity;
363 }
364 ga('send', 'event', 'tCuida', 'busqueda_farmacias', titleBusqueda,{ 'dimension1': 'tCuida' });
365 */
366 //......
367
368 marker_you = new google.maps.Marker({
369 map: map,
370 position: results[0].geometry.location,
371 icon: "/o/mundo-farmaceutico-theme/images/icons/pin-position.png",
372 });
373
374 // Se crea un circulo con el radio provisto en el formulario
375 if (circle) circle.setMap(null);
376 circle = new google.maps.Circle({
377 center:searchCenter,
378 radius: radius,
379 fillColor: "#999",
380 strokeWeight: 1,
381 fillOpacity: 0.2,
382 map: map
383 });
384
385 // Se reinicia la lista de resultados
386 side_bar_html = "";
387 gmarkersshow = [];
388
389 var bounds = new google.maps.LatLngBounds();
390 var foundMarkers = 0;
391
392 //Añadimos el marker del sitio buscado al bounds
393 bounds.extend(marker_you.getPosition());
394
395 // Se pintan en la lista todos los resultados
396 for(var i = 0; i < gmarkers.length; i++){
397 if (google.maps.geometry.spherical.computeDistanceBetween(gmarkers[i].getPosition(),searchCenter) < radius) {
398 bounds.extend(gmarkers[i].getPosition()); //Se anade la posicion de todos los markers para expandir la vista y que salgan todos en el mapa
399 gmarkers[i].setMap(map);
400 var distanceToCenter = google.maps.geometry.spherical.computeDistanceBetween(gmarkers[i].getPosition(),searchCenter);
401 gmarkersshow.push({marker: gmarkers[i], dist: distanceToCenter});
402 foundMarkers++;
403 }else{
404 gmarkers[i].setMap(null);
405 }
406 }
407
408 // Se ordena el array de maracadores visibles por distancia
409 gmarkersshow = gmarkersshow.sort(function(a,b){return a.dist - b.dist;});
410
411 // Se pintan en la lista todos los resultados ordenados por distancia
412 var distance;
413 side_bar_html +='<div class="info_container">';
414 for(var i = 0; i < gmarkersshow.length; i++){
415 distance = round((gmarkersshow[i].dist / 1000), 2);
416 side_bar_html += '<div class="info_fcia_side_bar div_side_bar_' + i + '">';
417 side_bar_html += '<div class="info_fcia_distance"><span class="text-base">' + distance + ' km.</span></div>';
418 side_bar_html += (gmarkersshow[i].marker.info).replace("{index}", i);
419 side_bar_html += '</div>';
420 }
421 side_bar_html +='</div>';
422 // Si hay resultados que cumplan el criterio del radio, se anaden a la lista
423 if(foundMarkers > 0){
424 if(foundMarkers == 1){
425 side_bar_html = "<div class=\"titulosidebar\"><p class=\"title_results_gmaps\"><strong>" + foundMarkers + "</strong> resultado encontrado:</p></div>" + side_bar_html;
426 }else{
427 side_bar_html = "<div class=\"titulosidebar\"><p class=\"title_results_gmaps\"><strong>" + foundMarkers + "</strong> resultados encontrados:</p></div>" + side_bar_html;
428 }
429 }else{
430 side_bar_html = "<div class=\"p_aviso_side_bar\"><p class=\"evo-form__text-info js_result_no_found\">No se han encontrado resultados. Por favor, busca en otro lugar o amplía el radio de búsqueda.</p></div>";
431 }
432
433 // Coloca la lista en el sitio que le corresponde
434 document.getElementById("side_bar").innerHTML = side_bar_html;
435 if (foundMarkers > 0) {
436 map.fitBounds(bounds);
437 } else{
438 map.fitBounds(circle.getBounds());
439 }
440 }
441 $(".info_container").mCustomScrollbar({
442 axis:"y"
443 });
444 });
445 }
446
447 // Metodo para redondear a los decimales
448 function round(value, decimals) {
449 return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
450 }
451
452 // Evento para lanzar la infoWindow al clickar sobre el marcador
453 function myclick(i) {
454 google.maps.event.trigger(gmarkersshow[i].marker, "click");
455 }
456
457 //Funcion para utilizar la api de google maps de "cómo llegar"
458 function arriveTo(address) {
459 var request;
460
461 //eliminamos el marcador de la posición del usuario si se muestra
462 if (marcador != null && marcador!=""){
463 marcador.setMap(null);
464 }
465
466 //se saca la dirección del usuario según sus coordenadas (si no se encuentra se fija la puerta de sol como punto de partida)
467 var userPosic = 'Plaza Puerta del Sol, 28013 Madrid';
468 var latlng;
469
470 if(userMarker == null){
471 latlng = defaultCoordinates;
472 }else{
473 var input = (userMarker.coords.latitude+","+userMarker.coords.longitude);
474 var latlngStr = input.split(',', 2);
475 latlng = {lat: parseFloat(latlngStr[0]), lng: parseFloat(latlngStr[1])};
476 }
477
478 geocoder.geocode({'location': latlng}, function(results, status) {
479 if (status === google.maps.GeocoderStatus.OK) {
480 if (results[0]) {
481 userPosic = results[0].formatted_address;
482 } else {
483 window.alert('No results found');
484 }
485 } else {
486 window.alert('Geocoder failed due to: ' + status);
487 }
488
489 if(geoActive){
490 request = {
491 //origin: new google.maps.LatLng(userMarker.coords.latitude, userMarker.coords.longitude),
492 origin: userPosic,
493 destination: address,
494 travelMode: google.maps.TravelMode.DRIVING,
495 unitSystem: google.maps.UnitSystem.METRIC,
496 provideRouteAlternatives: true
497 };
498 }else{
499 request = {
500 origin: userPosic,
501 destination: address,
502 travelMode: google.maps.TravelMode.DRIVING,
503 unitSystem: google.maps.UnitSystem.METRIC,
504 provideRouteAlternatives: true
505 };
506 }
507
508 directionsService.route(request, function(results, status) {
509 if (status == google.maps.DirectionsStatus.OK) {
510 if (circle) circle.setMap(null);
511 if(infowindow)infowindow.close();
512 directionsDisplay.setMap(map);
513 directionsDisplay.setPanel($("#map_indications").get(0));
514 directionsDisplay.setDirections(results);
515 } else {
516 //console.log("No existen rutas entre ambos puntos");
517 }
518 });
519 });
520 }
521</script>
522
523<#assign groupId = themeDisplay.getScopeGroupId()/>
524<#assign journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService")>
525<#assign ddmStructureLocalService = serviceLocator.findService("com.liferay.dynamic.data.mapping.service.DDMStructureLocalService")>
526<#assign structureID = 62817/>
527<#assign structure = ddmStructureLocalService.getDDMStructure(structureID)/>
528<#assign articulos = journalArticleLocalService.getStructureArticles(groupId, structure.getStructureKey())/>
529
530<#if articulos?has_content>
531 <#assign contador = 0 />
532 <#list articulos as entry>
533 <#assign docXml = saxReaderUtil.read(entry.getContent()) />
534 <#assign nombre = docXml.valueOf("//dynamic-element[@name='CampoDeTexto47225641']/dynamic-content/text()") />
535 <#assign direccion = docXml.valueOf("//dynamic-element[@name='CampoDeTexto93009852']/dynamic-content/text()") />
536 <#assign latitud = docXml.valueOf("//dynamic-element[@name='CampoDeTexto23083285']/dynamic-content/text()") />
537 <#assign longitud = docXml.valueOf("//dynamic-element[@name='CampoDeTexto36625583']/dynamic-content/text()") />
538 <#assign enlace = docXml.valueOf("//dynamic-element[@name='CampoDeTexto81864542']/dynamic-content/text()") />
539 <#assign telefono = docXml.valueOf("//dynamic-element[@name='CampoDeTexto87251178']/dynamic-content/text()") />
540 <script>
541 addCentros('${contador}','${nombre}','${direccion}','${latitud}','${longitud}','${enlace}','${telefono}');
542 </script>
543 <#assign contador = contador + 1 />
544 </#list>
545</#if>
546
547<div class="tc-map">
548 <div class="tc-map-search-ctn">
549 <div class="wrapper-ajust">
550 <form class="form-inline form-map">
551 <div class="tc-form-control Direction">
552 <label class="tc-map-label Direction__label" for="address"><span class="text-base">Dirección, CP o Provincia:</span></label>
553 <input class="Direction__input field form-control error-field" name="address" id="address" type="textbox" placeholder="Ej.: Calle Santa Engracia 31, 28010 Madrid"></input>
554 </div>
555 <div class="tc-form-control Radio">
556 <label class="Radio__label tc-map-label" for="radius"><span class="text-base">Radio de búsqueda:</span></label>
557 <input class="Radio__input field form-control error-field field-small" name="radius" id="radius" type="number" min="1" step="1" value="50" placeholder="50"></input>
558 <span class="Radio__km tc-map-text-desc">Km.</span>
559 </div>
560 <button type="button" class="btnSearch btn btn-ico btn-primary" onclick="codeAddress();">
561 <i class="btnSearch--icon icon-search"></i><span class="btnSearch--text">Buscar</span>
562 </button>
563 <span class="rad_err_msg">El radio debe estar comprendido entre 1 km y 500 km.</span>
564 </form>
565 </div>
566 </div>
567 <div class="wrapper-ajust">
568 <div class="tc-map-container">
569 <div id="map_canvas" class="tc-map-show"></div>
570 <div class="div_lista">
571 <div id="side_bar" class="side_bar">
572 <div class="p_aviso_side_bar">
573 <p class="evo-form__text-info">Realice una búsqueda para mostrar un listado de resultados.</p>
574 </div>
575 </div>
576 </div>
577 <div class="MoreOption">
578 <button class="MoreOption__button" onclick="buttonUbicaciones()">
579 Ver todas las ubicaciones
580 <svg width="13" height="10" viewBox="0 0 13 10" fill="none" xmlns="http://www.w3.org/2000/svg">
581 <path d="M6.83301 1L10.833 5L6.83301 9" stroke="#183657" stroke-width="2" stroke-linecap="round"/>
582 <path d="M10.1663 5H2.83301" stroke="#183657" stroke-width="2"/>
583 <path d="M1.49984 5.0026C1.49984 4.63441 1.20136 4.33594 0.833171 4.33594C0.464981 4.33594 0.166504 4.63441 0.166504 5.0026C0.166504 5.37079 0.464981 5.66927 0.833171 5.66927C1.20136 5.66927 1.49984 5.37079 1.49984 5.0026Z" fill="#183657"/>
584 </svg>
585 </button>
586 </div>
587 </div>
588 <div id="map_indications" class="tc-map-indications"></div>
589 </div>
590</div>