Mapas en Business central

Ya conocemos la funcionalidad incluida en las fichas del cliente de Mostrar en el mapa

Si hemos configurado algún servicio de mapas como Bing o Google Maps, al pulsar ese enlace nos abre una nueva ventana con un mapa indicando esa dirección.

Bien, pero ¿y si necesitamos integrar un mapa en Business central en una página y por ejemplo, mostrar una serie de marcadores con unas coordenadas almacenadas en alguna tabla?

Mapa en Business central

Supongamos que un cliente que es una inmobiliaria dispone de varios inmuebles en una o varias ciudades y nos solicita una página en la que poder ver sus inmuebles junto con alguna información, por ejemplo, precio de venta o alquiler.

Para lograr esto vamos a recurrir a un addin que vamos a crear apoyándonos en una librería de javascript llamada Leaflet
Esta librería nos permite mostrar un mapa totalmente manipulable, en cuanto que permite hacer zoom, desplazarse, etc. además de añadir los marcadores que deseemos y otras cuantas posibilidades más.

Supongamos que los inmuebles de nuestro cliente son sus productos, por lo que vamos a extender la tabla Item añadiendo 4 nuevos campo:
  • Longitud
  • Latitud
  • Mostrar en el mapa
  • Descripción en mapa
tableextension 50300 ItemExt extends item
{
    fields
    {
        field(50000; Longitude; Text[20])
        {
            Caption = 'Longitud';
            DataClassification = ToBeClassified;
        }
        field(50001; Latitude; Text[20])
        {
            Caption = 'Latitud';
            DataClassification = ToBeClassified;
        }
        field(50002; "Show in map"; Boolean)
        {
            Caption = 'Mostrar en mapa';
            DataClassification = ToBeClassified;
        }
        field(50003; "Map description"; Text[150])
        {
            Caption = 'Descripción en mapa';
            DataClassification = ToBeClassified;
        }
    }
}

Para mostrar estos nuevos campos añadiremos un nuevo grupo al final de la ficha de los productos y en la lista de los productos para poder gestionarlos con más facilidad:
pageextension 50301 ItemListExt extends "Item List"
{
    layout
    {
        addlast(Control1)
        {
            field(Longitude;Rec.Longitude)
            {}
            field(Latitude;Rec.Latitude)
            {}
            field("Map description";Rec."Map description")
            {}
            field("Show in map";Rec."Show in map")
            {}
        }
    }
}

pageextension 50302 ItemCardExt extends "Item Card"
{
    layout
    {
        addlast(content)
        {
            group(Map)
            {
                field(Longitude; Rec.Longitude)
                { }
                field(Latitude; Rec.Latitude)
                { }
                field("Map description"; Rec."Map description")
                { }
                field("Show in map"; Rec."Show in map")
                { }
            }
        }
    }
}

A continuación crearemos nuestro control o addin. Creamos un fichero con extensión AL en una nueva carpeta llamada Addin y lo definimos de esta manera:

controladdin MyMap
{
    RequestedHeight = 500;
    RequestedWidth = 350;
    MinimumHeight = 500;
    VerticalStretch = true;
    VerticalShrink = true;
    HorizontalStretch = true;
    HorizontalShrink = true;

    StartupScript = './Addin/startup.js';    
    Scripts = 'https://unpkg.com/leaflet@1.6.0/dist/leaflet.js';
    StyleSheets = 'https://unpkg.com/leaflet@1.6.0/dist/leaflet.css';

    event OnStartup();    

    procedure PassCoords(data: JsonArray);
}

Como podemos observar, el addin utiliza como apoyo la librería leaflet versión 1.6.0 junto con su hoja de estilos.

Le damos una altura de 500 pixeles y una anchura de 350. Al indicarle stretch y shrink según redimensionemos la página, el control se ajustará al tamaño disponible.

Por último disponemos del evento OnStartup y de la función PassCoords. Esta última será la que utilizaremos para pasarle las coordenadas a mostrar en el mapa.

Ahora creamos un fichero en la carpeta Addin llamado startup.js con este contenido:

Microsoft.Dynamics.NAV.InvokeExtensibilityMethod('OnStartup')

// Where you want to render the map.
var element = document.getElementById('controlAddIn');

// Height has to be set. You can do this in CSS too.
element.style = 'height:500px;';

// Create Leaflet map on map element.
var map = L.map(element);

// Add OSM tile layer to the Leaflet map.
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

// Target's GPS coordinates.
var target = L.latLng('43.3674914', '-8.4043295');

map.setView(target, 14);

  map.on('click', function(e){
    var coord = e.latlng;
    var lat = coord.lat;
    var lng = coord.lng;
    Microsoft.Dynamics.NAV.InvokeExtensibilityMethod('SendCoords',[lat.toString(),lng.toString()]);        
    });

   
 window.PassCoords =function(data) {
    for (var position of data) {  
        console.log(position);
        var myLatLng = new L.latLng(position.lat,position.lng);
        var lat = myLatLng.lat.toPrecision(8);
        var lon = myLatLng.lng.toPrecision(8);
        marker = new L.marker(myLatLng).addTo(map).bindPopup(position.BcText).openPopup();

       
        let isClicked = false

        marker.on({
            mouseover: function() {
                if(!isClicked) {
                    this.openPopup()
                }
            },
            mouseout: function() {
                if(!isClicked) {
                    this.closePopup()
                }
            },
            click: function() {
                isClicked = true
                this.openPopup()
            }
        })

        map.on ({
            click: function() {
                isClicked = false
            },
            popupclose: function () {
                isClicked = false
            }
        })
    };
};

Este código recoge el iFrame que presente el addin al iniciarse (controlAddIn) e incorpora ahí nuestro mapa.
Vemos unas coordenadas que es donde centramos el mapa, en este caso he elegido La Coruña, pero sería muy sencillo pasar desde Business central las coordenadas en las que centrar el mapa.
Y por último vemos la función PassCoords que recoge el Json en el que hemos pasado las coordenadas de los puntos a mostrar así como el texto a mostrar en un popup en cada uno de los marcadores y se ha añadido una funcionalidad Click que enviará las coordenadas en las que hemos pinchado a Business central para poder recoger coordenadas en productos que nos dispongan de ellas, por ejemplo, o modificar las coordenadas de productos que si dispongan de ellas.

Y por último la página donde mostraremos el mapa en cuestión y en la que mostraremos los productos para poder añadir coordenadas en aquellos en los que necesitemos:

page 50300 MyMap
{
    ApplicationArea = All;
    Caption = 'My Map';
    PageType = List;
    SourceTable = Item;
    UsageCategory = Lists;

    layout
    {
        area(content)
        {
            repeater(General)
            {
                field("No."; Rec."No.")
                {
                }
                field(Description; Rec.Description)
                {
                }
                field("Unit Price"; Rec."Unit Price")
                {
                }
                field(Longitude; Rec.Longitude)
                {
                }
                field(Latitude; Rec.Latitude)
                {
                }
                field("Show in map"; Rec."Show in map")
                {
                }
                field("Map description"; Rec."Map description")
                {
                }
            }
            group(Mapa)
            {
                usercontrol(MyMap; MyMap)
                {
                    ApplicationArea = All;
                    trigger OnStartup()
                    begin
                        CurrPage.MyMap.PassCoords(JArray);
                    end;

                    trigger SendCoords(latitude: Text; longitude: Text)
                    var
                        Msg001: Label 'El inmueble %1 ya tiene coordenadas ¿desea sustituirlas?';
                    begin
                        if (Rec.Latitude <> '') or (Rec.Longitude <> '') then
                            if not Confirm(StrSubstNo(Msg001, Rec.Description)) then exit;
                        Rec.Latitude := latitude;
                        Rec.Longitude := longitude;
                        Rec.Modify(false);
                    end;
                }
            }
        }
    }

    trigger OnAfterGetRecord()
    var
        JObject: JsonObject;
    begin
        if (Rec.Longitude <> '') and (Rec.Latitude <> '') and (Rec."Show in map") then begin
            Clear(JObject);
            JObject.Add('lat', Rec.Latitude);
            JObject.Add('lng', Rec.Longitude);
            JObject.Add('BcText', Rec."Map description");
            JArray.Add(JObject);
        end;
    end;

    var
        JArray: JsonArray;
}


Al cargar la página, una vez se comprueba que el addin ha sido cargado generamos el Json con las coordenadas y los textos a mostrar en cada inmueble.
La página consta de un repeater o lista en la que se muestran los productos, debajo aparece nuestro control que al cargarse se le envían las coordenadas en un Json que hemos ido preparando según cargábamos la página y en le que se incluyen logitud, latitud y texto a mostrar de aquellos productos que tengan ambas coordenadas rellenas y activado el check de mostrar en el mapa.
Por último si en el control se hace click en algún sitio, nos devuelve las coordenadas del punto en el que hemos pinchado y podemos usarlo para rellenar coordenadas del producto en el que nos hayamos posicionados.

OJO: El control no puede llamarse Map ya que genera un error interno al compilar y debe llamarse de otra manera, en mi primera versión se llamaba Map y generaba un error al compilar de tipo AL0511


Vamos a ver el control en funcionamiento:


Sin haber iniciado coordenadas en ningún producto.
Recordemos que sólo con pulsar en el mapa nos devolverá coordenadas para el producto seleccionado.

Una vez que hemos rellenado unas cuantas coordenadas y hemos definido textos al mostrar en cada uno de ellos. El texto se muestra al pulsar en el marcador o al pasar el ratón por encima.


Espero que os sea de utilidad.

Como siempre dejo el código fuente en github.

Publicar un comentario

Añade comentario (0)

Artículo Anterior Artículo Siguiente