EN

  |  ES

/Guía Rápida SDKs /Web push /Javascript

SDK de Javascript

Guía avanzada para configurar el SDK de Javascript


Tabla de contenidos



1. Propiedades configurables


En esta sección encontrarás una serie de funcionalidades más avanzadas y que requieren de un desarrollo más complejo. Aconsejamos que sea un desarrollador el encargado de esta configuración.


1.1. Activar las notificaciones geolocalizadas


El SDK de indigitall puede gestionar la localización del usuario. Esto te permite usar los filtros de localización en la pantalla de enviar campaña push (Campañas>Push>Nueva campaña push>Filtros>Filtros geográficos)


Location path on console

Una vez hayamos habilitado esta funcionalidad, el usuario final tendrá que dar su consentimiento al permiso de localización y habilitar los servicios de localización, para que la aplicación obtenga la ubicación exacta del usuario.


Para poder usar la funcionalidad de la localización a través del SDK de indigitall es necesario añadir el método requestLoation a la configuración inicial.


Puedes consultar el fragmento de código más abajo.

<script
  src="/indigitall/sdk.min.js"
  onload="indigitall.init({
    ...
    requestLocation: true
    ...
  })"
  async>
</script>


Opciones que debes tener en cuenta


Es necesario estar al tanto de los cambios de localización del usuario para así poderlo guardar en la herramienta de indigitall.


Para verificar si el dispositivo ha cambiado su ubicación, se debe agregar el callback onLocationUpdated a la configuración inicial para así poder escuchar estos cambios de localización en ese método.


Puedes consultar el extracto de código más abajo.


<script>
  function onLocationUpdated(location){
    console.log("Location\n \t - Latitude:"+location.coords.latitude+"\n \t - Longitude: "+ location.coords.longitude);
  }
</script>

<script
  src="/indigitall/sdk.min.js"
  onload="indigitall.init({
    ...
    onLocationUpdated: onLocationUpdated
    ...
  })"
  async>
</script>


1.2. Set Log Debug


indigitall permite a los desarrolladores poder acceder a toda la información que nos brinda el log.


Si la variable setDebugLog está a falso, ningún log será mostrado. Por otra parte, si esta variable es verdadera por el log aparecerán los mensajes correspondientes al nivel de advertencia de errores al que nos hayamos suscrito.


Puedes consultar el extracto de código más abajo.


<script
  src="/indigitall/sdk.min.js"
  onload="indigitall.init({
    ...
    setDebugLog: false,
    ...
  })"
  async>
</script>


1.3. Asociar el dispositivo a un usuario


Puedes asociar tu propio ID a cada dispositivo. De esta forma te será más sencillo e intuitivo trabajar con nuestra herramienta. Por ejemplo:


Esta opción será para actualizar la información del dispositivo así que llamar al método DeviceCallback nos retornará un dispositivo si esta operación fue exitosa. Para ello, necesitas añadir el siguiente código:


// Remember to replace with your external code
indigitall.setExternalCode("YOUR_EXTERNAL_CODE", (device) => {
  //DO SOMETHING
  }, (error) => {
    //LOG ERROR
  });


No te preocupes por nada. Tus IDs se cifran de forma irreversible en el propio teléfono y se mandan de forma segura a nuestros servidores. Ni siquiera el equipo de indigitall puede conocer esta información.


2. Callbacks que ofrece el SDK


Nuestro SDK ofrece diversos callbacks que te ayudan tener mayor control del flujo de ejecución y a implementar comportamientos personalizados.


Esto es un fragmento de código para usar un callback que se encarge de hacer la inicialización de indigitall. Es necesario añadir el indigitall.init dentro del método onDigitallLoaded y cargarlo en el script.


<script>
  function onNewUserRegistered(device){}

  function onIndigitallInitialized(permissions,device){}

  function onLocationUpdated(location){}

  function onError(error){}

  function requestPushPermission(permission){}

  function requestLocationPermission(permission){}

  // Remember to replace with your appKey
  function onIndigitallLoaded(){
    indigitall.init({
      appKey:'YOUR_APPKEY',
      workerPath:'./ROOT_FOLDER/worker.min.js',
      requestLocation: true,
      onInitialized: onIndigitallInitialized,
      requestPushPermission: requestPushPermission,
      onNewUserRegistered: onNewUserRegistered,
      requestLocationPermission: requestLocationPermission,
      onLocationUpdated: onLocationUpdated,
      onError: onError            
    });
  }
</script>

<script src="./ROOT_FOLDER/sdk.min.js" onload="onIndigitallLoaded()" ></script>


 2.1. SDK inicializado


El método onIndigitallInitialized se ejecutará cuando el SDK termine de inicializarse y el dispositivo esté preparado para recibir notificaciones de indigitall.


Recibe como parámetro:


A continuación te mostramos un ejemplo que imprime logs sobre el estado de los permisos y la información del dispositivo.


<script>
  function onIndigitallInitialized(permissions,device){
    console.log("Push Permission: ",permissions.push)
    console.log("Location Permission: ",permissions.location)
    console.log("Device: ", device)
  }
</script>

<script
  src="/indigitall/sdk.min.js"
  onload="indigitall.init({
    ...
    onInitialized: onIndigitallInitialized
    ...
  })"
  async>
</script>


 2.2. Nuevo dispositivo registrado


Para comprobar que un usuario se ha registrado, se necesita asociar el callback onNewUserRegistered en la configuración inicial.


Se puede consultar el extracto de código con la implementación más abajo:


<script>
  function onNewUserRegistered(device){
    console.log("Device onNewUserRegistered: ",device)
  }
</script>

<script
  src="/indigitall/sdk.min.js"
  onload="indigitall.init({
    ...
    onNewUserRegistered: onNewUserRegistered
    ...
  })"
  async>
</script>


 2.3. Se ha producido un error



Se pueden producir comportamientos inesperados dentro todo el flujo del SDK.
To check the error logs, you need add 'onError' callback to initial configuration. Para verificar los registros de errores en el log, se debe agregar el callback onError para la configuración inicial.


<script>
  function onError(error){
    console.log(error);
  }
</script>

<script
  src="/indigitall/sdk.min.js"
  onload="indigitall.init({
    ...
    onError: onError
    ...
  })"
  async>
</script>


 2.4. Solicitar el permiso de las notificaciones push


Mediante estos permisos las aplicaciones serán capaces de mostrar las notificaciones que les envíe la herramienta de indigitall.


Para solicitar el estado de los permisos para las notificaciones push se debe añadir el callback requestPushPermission a la configuración inicial.


Este método no funciona on _Edge_ y _Safari_ porque estos navegadores no implementan la API de Permisos


Puedes consultar el código de ejemplo más abajo:


<script>
  function requestPushPermission(permission){
    console.log("RequestPushPermission: "+permission.state);
  }
</script>

<script
  src="/indigitall/sdk.min.js"
  onload="indigitall.init({
    ...
    requestPushPermission: requestPushPermission
    ...
  })"
  async>
</script>


 2.5. Solicitar el permiso de localización


Mediante estos permisos las aplicaciones serán capaces de solicitar a los dispositivo la localización del usuario.


Para solicitar el estado de los permisos de localización se debe añadir el callback requestLocationPermission a la configuración inicial.


This method does not work on Edge and Safari because the browsers does not implement the Permission API


Puedes consultar el código de ejemplo más abajo:


<script>
  function requestLocationPermission(permission){
    console.log("RequestLocationPermission: "+permission.state);
  }
</script>

<script
  src="/indigitall/sdk.min.js"
  onload="indigitall.init({
    ...
    requestLocationPermission: requestLocationPermission
    ...
  })"
  async>
</script>


3. Administrar dispositivo


Esta sección describe las diferentes acciones que se podrían realizar en un dispositivo indigitall. El modelo de dispositivo tendría esta estructura:


device = {
  deviceId: "string",
  pushToken: "string",
  browserPublicKey: "string",
  browserPrivateKey: "string",
  platform: "string",
  version: "string",
  productName: "string",
  productVersion: "string",
  browserName: "string",
  browserVersion: "string",
  osName: "string",
  osVersion: "string",
  deviceType: "string",
  enabled: "boolean",
  externalCode: "string"
};


3.1. Consultar información y estado del dispositivo


Puedes usar el método deviceGet para obtener la información que ha registrado el SDK en referencia al dispositivo.


Debes instanciar un objeto DeviceCallback y pasarlo como segundo parámetro del método deviceGet. Este callback recibirá como parámetro el objeto device que contiene toda la información asociada al dispositivo.


indigitall.deviceGet((device) => {
  // success function
  console.log(device);
},() => {
  // error function
});


3.2. Habilitar / deshabilitar el dispositivo


Puedes elegir deshabilitar el dispositivo para bloquear la recepción de notificaciones. Es un método muy útil para:


Para ello, dispones de los métodos deviceEnable y deviceDisable.


Debes instanciar un onjeto DeviceCallback y pasarlo como segundo parámetro. Este callback recibirá como parámetro el objeto device que contiene toda la información asociada al dispositivo.


indigitall.deviceEnable((device) => {
  // success function
  console.log(device);
},() => {
  // error function
});

indigitall.deviceDisable((device) => {
  // success function
  console.log(device);
},() => {
  // error function
});


3.3. Ejemplo de uso del dispositivo


Vamos a ver la implementación para verificar el estado del dispositivo donde se está ejecutando la aplicación. Llevaremos a cabo las operaciones de: verificar el estado del dispositivo, habilitar el estado del dispositivo y deshabilitar el dispositivo.
Antes que nada necesitamos crear una vista en HTML. Lo haremos de la siguiente manera:


<div id="notifications-manager">
  <p>Notifications:</p>
  <!-- Rounded switch -->
  <label class="switch">
    <input type="checkbox">
    <span class="slider round"></span>
  </label>
</div>


Tras esto, añadiremos los estilos para la vista dentro del CSS:


/* The switch - the box around the slider */
.switch {
  position: relative;
  display: inline-block;
  width: 60px;
  height: 34px;
}

/* Hide default HTML checkbox */
.switch input {display:none;}

/* The slider */
.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #ccc;
  -webkit-transition: .4s;
  transition: .4s;
}

.slider:before {
  position: absolute;
  content: "";
  height: 26px;
  width: 26px;
  left: 4px;
  bottom: 4px;
  background-color: white;
  -webkit-transition: .4s;
  transition: .4s;
}

input:checked + .slider {
  background-color: #2196F3;
}

input:focus + .slider {
  box-shadow: 0 0 1px #2196F3;
}

input:checked + .slider:before {
  -webkit-transform: translateX(26px);
  -ms-transform: translateX(26px);
  transform: translateX(26px);
}

/* Rounded sliders */
.slider.round {
  border-radius: 34px;
}

.slider.round:before {
  border-radius: 50%;
}


Y para finalizar definiremos los eventos indicados anteriormente en la guía en Javascript con jQuery.


$(() => {
  indigitall.deviceGet((device) => {
    if (device && device.enabled === true) {
      $('.switch input[type=checkbox]')[0].checked = true;
    } else {
      $('.switch input[type=checkbox]')[0].checked = false;
    }
  });

  $('.switch span.slider').click(() => {
    if ($('.switch input[type=checkbox]')[0].checked === true) {
      indigitall.deviceDisable((device) => {
        console.log ('device disabled');
      })
    } else {
      indigitall.deviceEnable((device) => {
        console.log ('device enabled');
      })
    }
  });
});


4. Grupos de interés


Nuestro SDK te permite clasificar a los usuarios en diferentes grupos personalizables. Esto es muy útil para:


Recuerda que primero debes definir los grupos con los que quieres trabajar en la consola de indigitall (Herramientas > Grupos de interés). Consulta nuestro manual de usuario para más info.


El objeto Topic o grupo de interés tiene esta estructura:

topics = [{
  code: "string",
    name: "string",
    subscribed: "boolean",
    visible: "boolean",
    parentCode: "string"
},
{
  ...
}];


4.1. Listar grupos


Usa el método topicsList para obtener la lista de grupos que están configurados en tu proyecto de indigitall. El callback de este método recibe como parámetro un array de Topics, que contiene la información de todos los grupos disponibles, además de un flag que indica si el usuario está incluido en alguno de ellos.


indigitall.topicsList((topics) => {
  // success function
  console.log(topics);
}, () => {
  // error function
});


4.2. Gestionar suscripción


El actual dispositivo podría ser suscrito a varios temas. Si la operación ha sido satisfactoria, este método retonar un array de objetos Topic.


Para gestionar la suscripción del dispositivo a uno o varios grupos, existen dos métodos: topicsSubscribe y topicsUnsubscribe.

Opcionalmente ambos reciben un objeto TopicsCallback como tercer parámetro, que devolverá el listado de todos los Topic del proyecto.


var topicsCodes = ["001", ...];
indigitall.topicsSubscribe(topicsCodes, (topics) => {
  // success function
  console.log(topics);
}, () => {
  // error function
});

// Recuerda reemplazar con los códigos de tus temas
indigitall.topicsUnsubscribe(topicCodes, (topics) => {
  // success function
  console.log(topics);
}, () => {
  // error function
});


4.3. Casos de uso


Cómo hacer la suscripción/darse de baja de los temas


En este caso nosotros usaremos el ejemplo anterior para extenderlo con este ejemplo concreto.
Primero vamos a añadir esta vista para el archivo HTML:


<div id="notifications-manager">
  ...

  <p>Topics:</p>
  <ul class="topics">
  </ul>
</div>


Después vamos a eliminar el estilo 'ul' por defecto:


...

ul {
  list-style: none;
}


Y al final habrá que añadir este código a tu archivo Javascript:


$(() => {
  ...

  indigitall.topicsList((topics) => {
    topics.forEach((topic) => {
      $("ul.topics").append(`<li><input type="checkbox"
        id="${topic.code}"
        ${topic.subscribed ? 'checked' : ''}/>
        ${topic.name}</li>`)
    });

    $('ul.topics li input[type="checkbox"]').click((e) => {
      if (e.target.checked === true) {
        indigitall.topicsSubscribe([e.target.id]);
      } else {
        indigitall.topicsUnsubscribe([e.target.id])
      }
    })
  });
});


5. Enviar eventos personalizados



Tu app puede mandar información a los servidores de indigitall para identificar las acciones y eventos que suceden en ella. Esto te permite automatizar acciones de retargeting.


Para registrar estos eventos hay que llamar al método sendCustomEvent, pasando como parámetro un ID descriptivo (puedes inventarte el que más te guste) y el set de datos que necesites.


indigitall.sendCustomEvent({
          eventType: "YOUR_CUSTOM_EVENT",
          customData: {}, // add your data
          async: false, // call this event sync/async
        }, (response) => {
          //DO SOMETHING     
        },(error)=>{
          //LOG ERROR
        });


6. Mensajes In-App


Si quieres integrar los mensajes In-App en tu aplicación, puedes hacerlo con varios formatos complementarios:


El modelo del InApp sería el siguiente:


inApp = {
  inAppId: int,
  lastVersionId: int,
  showOnce: boolean,
  properties: {
      action: {
          url: "string",
          type: "string"
      }
  }
  contentUrl: "string",
  renewalTime: "string",
  schema: {
      code: "string",
        width: int,
        height: int
    }
};


6.1. Formato banner


A continuación te contamos como instanciar uno o varios mensajes In-App en formato banner.

Recuerda que primero deberías tenerlos definidos en la consola de indigitall. Consulta nuestro manual de usuario para más info.


6.1.1. Un Único banner


En este primer método se carga una InApp en una página. Para llamarlo, se debe crear un div en su página con el tamaño que ya previamente haya creado en InApp/InWeb Schemes de nuestra consola de indigitall. Como este ejemplo:


<div id="divView" style="width:1250px; height:285px;"></div>


Una vez que se haya creado el código para mostrar la InApp, hay que instanciarla y llamarla en el método showInApp que podemos ver más abajo. Hay que pasarle como parámetros el código de la InApp, el id del div anterior y el callback oportuno para obtener la vista y el código. Este callback nos indicará si se ha cargado correctamente o no y en relación a este resultado haremos una acción u otra.


indigitall.showInApp(divView_code, "divView", (inApp, div)=>{
              // DO SOMETHING
          },(error)=>{
              // Log error message
          });
WebView myWebView = findViewById(R.id.webViewBanner);


6.1.2. Múltiples banner


Si queremos tener varias InApp para ser mostradas en el flujo de los usuarios hay que seguir los siguientes pasos.


Para ello, en primer lugar se debe crear cada vista div en su página. Cada una de ellas debe tener asignado el mismo tamaño que se creó en InApp/inWeb Schemes de nuestra consola de indigitall.


  <div id="divView" style="width:1250px; height:285px;"></div>
  <div id="divViewTwo" style="width:980px; height:150px;" ></div>
  <div id="divViewThree" style="width:150px; height:950px;"></div>
...


Una vez que se han creado todos las vistas, hay que instanciarlos mediante el método showMultipleInApp. Antes de llegar a esta llamada hay que crear un par de arrays. El primero de ellos es la lista de los código InApp mientras que el segundo contendrá los identificadores de los div donde aparecerán las InApp. Cuando se llame al método showMultipleInApp hay que pasarle la lista con los identificadores, la lista con los div y además un callback que será el encargado de indicarnos si la operación ha sido satisfactoria o por el contratio ha ocurrido un error.

let inAppCodeList = [];
inAppCodeList.push("divView_code");
inAppCodeList.push("divView_code_two");
inAppCodeList.push("divView_code_three");
...

let divList = [];
divList.push("divView");
divList.push("divViewTwo");
divList.push("divViewThree");
...

indigitall.showMultipleInApp(inAppCodeList, divList,(inApp, div)=>{
            //DO SOMETHING
        },(error)=>{
             // Log error message
        });



6.2. Formato Popup


Podría darse el caso que se quisiera mostrar una InApp con un PopUp.


Afortunadamente, en Javascript, para crear una InApp como un PopUp no es necesario un nuevo procedimiento para crearlo. Se puede seguir la misma actuación que para mostrar una única InApp.


7. Inbox


7.1. Configuración Inbox


En esta sección encontrarás una serie de funcionalidades más avanzadas y que requieren de un desarrollo más complejo. Aconsejamos que sea un desarrollador el encargado de esta configuración.


7.1.1. Identificación de usuarios


Para poder obtener las notificaciones del Inbox de Indigitall, el usuario debe identificarse. Primero hay que inicializar la SDK de Indigitall para que genere nuestro identificador (deviceId) y poder asociarlo al ID personalizado que asocies a dispositivo, similar a como se explica aquí.


Para realizar las tareas de registro, se usan estos dos métodos:


//Identificación de usuario
indigitall.logIn("YOUR_ID", (device)=>{
     //DO SOMETHING
}, (error)=>{
    //LOG ERROR
});

//Desconexión
indigitall.logOut((device)=>{
    //DO SOMETHING
}, (error)=>{
    //LOG ERROR
});


7.1.2. Generar token de autentificación


En esta sección verás cómo se genera un token de validación para una aplicación que tenga configurado una autentificación con webhook. Para generar dicho token, se necesita añadir el JSON con la configuración.


El token tiene una fecha predeterminada de caducidad, una vez caducado en nuestro sistema, se lanzará un evento llamado getConfigAuth que indicará dicha caducidad y tendrá que generar el token con el JSON de configuración. Para recoger el evento, hay que añadirlo a las llamadas del Inbox e implementarlo de la siguiente manera:


function getAuthConfig(){
    return YOUR_JSON
}


7.2. Funcionalidades principales del Inbox


Una vez hecho el registro del dispositivo correctamente, se puede empezar a realizar las peticiones del Inbox. Hay que tener en cuenta las siguientes características del Inbox, que opcionalmente son configurables.

Esta sección describe las diferentes acciones que se podrían realizar con el Inbox de indigitall. El modelo de Inbox y el de notification tendrían esta estructura:


inbox = {
  lastAccess: "string",
  notifications: [Inboxnotification],
  count: int,
  pageSize: int,
  page: int,
  allNewNotifications: [Inboxnotification],
  totalPages: int
};

notification = {
  id: "string",
  externalId: "string",
  sentAt: {},
  status: "string",
  sendingId: int,
  campaignId: int,
  message: Push,
  read: Boolean
};


7.2.1. Propiedades del Inbox


Las notificaciones del Inbox tendrán los siguiente estados de la clase inboxStatus:



Las notificaciones también vendrán con un estado leído o 'read', para ayudar a diferenciar dichos estados.


Cada notificación vendrá asignada con un sendingId entero y único, para poder diferenciarlos y usarlos para algunas de las funcionalidades.


7.2.2. Obtener las notificaciones


Como se ha explicado anteriormente, para obtener las notificaciones se usa el siguiente método:

indigitall.getInbox({auth: getAuthConfig}, (inbox)=>{
    //DO SOMETHING
}, (error)=>{
    //LOG ERROR
});


7.2.2.1 Siguiente página


Una vez obtenida la instancia Inbox, la usaremos para pedir la siguiente página, que se realizada con el siguiente método, en el caso de que no haya más páginas te lo indicará en el error con el códigoo 410:


inbox.getNextPage((inbox, newNotifications)=>{
    //DO SOMETHING
}, (error)=>{
    if (error == 410){
        //LOG NO HAY MÁS PÁGINAS
    }else{
        //LOG ERROR
    }
});


Ten en cuenta que el callback del Inbox a parte de devolver el Inbox actualizado, devuelve un array que se llama newNotifications, en el que se irán las nuevas notificaciones que añadir al Inbox, para que, en caso de ser necesario, poder utilizar dicho array para moverte entre las páginas sin depender de las llamadas al Inbox.


7.2.3. Obtener la información de una notificación


Para obtener la información de una notificación en particular, hay que hacer la siguiente llamada con el sendingId de cada notificación:


inbox.getInfoFromNotification(SENDING_ID, (notification)=>{
    //DO SOMETHING
},(error)=>{
    //LOG ERROR
});


7.2.4. Editar el estado de una o más notificaciones


Para editar el estado de una o más notificaciones a la vez, se realiza con el siguiente método en el que se deben indicar los sendingIds de las notificaciones a editar y el estado al que se quiere cambiar:

//Modificar una notificación
inbox.modifyStatusFromNotification(SENDING_ID, STATUS,(notification)=>{
    //DO SOMETHING
},(error)=>{
    //LOG ERROR
});

//Modificar masivamente
inbox.massiveEditNotifications(SENDING_IDS,STATUS, ()=>{
    //DO SOMETHING
}, (error)=>{
    //LOG ERROR
});


7.2.5. Contadores de estado de las notificaciones


En este apartado podrás conocer el número de notificaciones que hay en el Inbox según su estado, el modelo es el siguiente:


counter = {
    click: int,
    sent: int,
    deleted: int,
    unread: {
       count: int,
       lastAccess: "string" 
    }
}


Y se reliza con este método:

indigitall.getInboxMessagesCount({auth: getAuthConfig}, (counter)=>{
    //DO SOMETHING
},(error)=>{
    //LOG ERROR 
});


8. Inicialización personalizada


Esta inicialización se puede realizar a través de NPM o archivos locales.


Si tiene otros ServiceWorkers en su sitio web, puede crear un archivo service-worker.js e importar todos sus ServiceWorkers en él. Siga estos pasos para hacerlo:

  1. Cree un archivo en su proyecto raíz con el nombre service-worker.js

  2. Agregue esta de estas líneas a su archivo service-worker.js:


importScripts('/node_modules/indigitall-webpush/worker.min.js');
// Other imports



importScripts('/indigitall/worker.min.js');
// Other imports


Tu proyecto tendrá la siguiente estructura:


/
|   node_modules/
|   |   indigitall-webpush/
|   |   |   index.js
|   |   |   package.json
|   |   |   readme.md
|   |   |   sdk.min.js
|   |   |   worker.min.js
|   |   ...
|   service-worker.js
|   ...



/
|   indigitall/
|   |   sdk.min.js
|   |   worker.min.js
|   service-worker.js
|   ...


Elimine el parámetro workerPath en el método indigitall.init ({... ~~ workerPath: '/indigitall/worker.min.js'~~ ...}).


<!-- Reemplaza este fragmento con tu appKey -->
<script
  src="/indigitall/sdk.min.js"
  onload="indigitall.init({
    appKey:'765b4222-ae48-xxxx-80e2-213c62f337df'
  })"
  async>
</script>


9. Documentación de referencia


Referencia JSdoc


10. Changelog

3.5.0 - 11/2020

Añadido

3.4.1 - 07/2020

Correcciones

3.4.0 - 06/2020

Añadido

3.3.6 - 05/2020

Correciones

3.3.5 - 04/2020

Correciones

3.3.4 - 04/2020

Correciones

3.3.3 - 03/2020

Correciones

3.3.2 - 03/2020

Correciones

3.3.1 - 03/2020

Correciones

3.3.0 - 03/2020

Añadido

[3.2.0] - 01/2020

Correciones

[3.1.3] - 10/2019

Correciones

[3.1.2] - 10/2019

Modificaciones

[3.1.1] - 09/2019

Correciones

[3.1.0] - 08/2019

Añadido