Dentro de la colección de herramientas y servicios que utilizamos tanto en el estudio como en algunos de los productos propios que hemos creado, Google App Scripts es una de nuestras favoritas. Esta herramienta nos permite automatizar tareas y procesos recurrentes de forma gratuita interactuando con servicios de Google como Google Sheets, Docs, Drive etc.

Empezando con Google Apps Script

Para crear nuestro primer script podemos hacerlo accediendo a la página de Google Apps Script. Esta es la página principal de la herramienta donde veremos todos los scripts creados, los logs de las ejecuciones y los activadores asociados.

Dashboard de Google Apps Script

También podemos crear un script directamente desde la herramienta de Google a la que queremos asociarlo, en el caso de Spreadsheet podemos hacerlo pulsando en Herramientas → Editor de secuencia de comandos.

Ejecutar Google Apps Script desde Sheets

Esto nos abrirá un entorno de desarrollo en la nube donde directamente se puede escribir y ejecutar el código del script.

Consola de Google Apps Script

Ahora que ya sabemos cómo crear un script vamos a aprender mediante dos ejemplos las funcionalidades básicas que nos van a permitir empezar a crear procesos automáticos.

Script para actualizar las divisas en Billbot

El primer ejemplo que vamos a ver es un script que utilizamos para obtener y dar formato al listado de Divisas que utilizamos en la aplicación de Billbot que creamos en el estudio.

La primera necesidad que tenemos que resolver es cómo hacer una petición a una API desde el script. Para ello será necesario utilizar la clase UrlFetchApp que nos va a permitir este tipo de operaciones y es una de las mecánicas más útiles que tienen los AppScripts.

En nuestro caso, no solo necesitamos hacer una petición sino múltiples, dada la estructura de los datos que nos devuelve la API. Para ello utilizaremos el método fetchAll que nos permite hacer múltiples peticiones a la vez.

Esto traducido a código sería lo siguiente:

function myFunction() {
  var API = 'API_URL';
  var EUR = API + '&base=EUR';
  var USD = API + '&base=USD';
  var GBP = API + '&base=GBP';
  var CAD = API + '&base=CAD';
  var AUD = API + '&base=AUD';
  var CHF = API + '&base=CHF';
  var MXN = API + '&base=MXN';
  var RUB = API + '&base=RUB';
  var INR = API + '&base=INR';
  var BRL = API + '&base=BRL';
  var DKK = API + '&base=DKK';
  var SEK = API + '&base=SEK';
  var NOK = API + '&base=NOK';
  var HRK = API + '&base=HRK';
  var NZD = API + '&base=NZD';
  var CZK = API + '&base=CZK';
  var JPY = API + '&base=JPY';
  var PLN = API + '&base=PLN';
  var RON = API + '&base=RON';
  var THB = API + '&base=THB';
  var AED = API + '&base=AED';
  var HKD = API + '&base=HKD';
  var HUF = API + '&base=HUF';
  var ILS = API + '&base=ILS';
  var SGD = API + '&base=SGD';
  var TRY = API + '&base=TRY';
  var ZAR = API + '&base=ZAR';
  var SAR = API + '&base=SAR';
  var BGN = API + '&base=BGN';
  var QAR = API + '&base=QAR';
  var ISK = API + '&base=ISK';
  var MAD = API + '&base=MAD';
  var RSD = API + '&base=RSD';
  var ARS = API + '&base=ARS';
  var BHD = API + '&base=BHD';
  var BOB = API + '&base=BOB';
  var CLP = API + '&base=CLP';
  var CNY = API + '&base=CNY';
  var COP = API + '&base=COP';
  var EGP = API + '&base=EGP';
  var IDR = API + '&base=IDR';
  var KRW = API + '&base=KRW';
  var PEN = API + '&base=PEN';
  var PHP = API + '&base=PHP';
  var UAH = API + '&base=UAH';
  var UYU = API + '&base=UYU';
  var GTQ = API + '&base=GTQ';
  var PYG = API + '&base=PYG';

  var response = UrlFetchApp.fetchAll([
    EUR,
    USD,
    GBP,
    CAD,
    AUD,
    CHF,
    MXN,
    RUB,
    INR,
    BRL,
    DKK,
    SEK,
    NOK,
    HRK,
    NZD,
    CZK,
    JPY,
    PLN,
    RON,
    THB,
    AED,
    HKD,
    HUF,
    ILS,
    SGD,
    TRY,
    ZAR,
    SAR,
    BGN,
    QAR,
    ISK,
    MAD,
    RSD,
    ARS,
    BHD,
    BOB,
    CLP,
    CNY,
    COP,
    EGP,
    IDR,
    KRW,
    PEN,
    PHP,
    UAH,
    UYU,
    GTQ,
    PYG,
  ]);

	Logger.log(response);
}

Para poder ver los resultados de la petición podemos utilizar  Logger.log. Esto sería el equivalente al console.log de JavaScript pero que nos permitirá ver los resultados en el debugger de App Scripts. Para ver los registros podemos pulsar en ctrl + Enter en el teclado o cmd en el caso de mac.

Logs de Google Apps Script

Una vez ya tenemos los datos, el siguiente paso es formatearlos como queremos. Para ello simplemente utilizaremos un reduce de JavaScript y el resultado de este lo convertiremos en un string.

var data = response.reduce(function (previous, current) {
    var currentJson = JSON.parse(current);
    var currencyData = currentJson.rates;
    var currency = currentJson.base;
    var currencyDataWithBase = { ...currencyData, [currency]: 1 };

    return { ...previous, [currency]: currencyDataWithBase };
}, {});

var dataParsed = JSON.stringify(data)

Una vez formateados viene la parte interesante: almacenarlos en la hoja de calculo. Esto nos lo va a permitir la clase SpreadSheetApp. Los métodos esenciales de esta clase son getActive(), que nos permite coger la referencia del fichero al cual está asociada el script, y getSheetByName(), que no permite establecer la referencia de la hoja del fichero asociado.

Una vez tenemos la referencia de la hoja en una variable, podremos utilizar esta para leer y almacenar datos dentro de sus filas y las columnas. Con los métodos getRange y setValue podremos escribir dentro de la celda, y con el método getValue obtendremos el valor que se encuentra en ella.

Concretamente, en nuestro script queremos almacenar todos los datos obtenidos en la primera celda de la hoja de cálculo, esto lo podemos conseguir con estas cuatro líneas de código.

var ratesSpreadSheet = SpreadsheetApp.getActive();
var dbSheet = ratesSpreadSheet.getSheetByName('db');

dbSheet.getRange(1, 1).setValue(dataParsed);
SpreadsheetApp.flush();

El resultado final una vez ejecutado el script es la celda 1,1 de nuestra hoja de cálculo, ahora completada con los datos obtenidos de la API y formateados con nuestras necesidades.

Respuesta de la API en Sheets

Solo haciendo uso de las classes Logger, SpreadSheetApp y UrlFetchApp que acabamos de ver se pueden llegar a crear scripts muy potentes si tenemos algunos conocimientos de JavaScript y algo de creatividad. El siguiente ejemplo es un claro caso de ello, ya que con el uso de estas tres API's creamos un sistema de creación de facturas automáticas para nuestra startup.

Sistema de facturación para partners de Cravy

En Cravy cada semana teníamos que crear las facturas de los restaurantes que eran partners de nuestra plataforma. Inicialmente empezamos creándolas manualmente con una hoja de calculo de Google que convertíamos a pdf. Cuando llegamos a tener más de 10 restaurantes, el proceso era bastante tedioso y podia llegar a suponer un día entero de trabajo.

Cada restaurante tenía dos documentos: la factura con la comisión de nuestro servicio y un justificante con todos los pedidos asociados a esa comisión.

Factura de Cravy en Google Sheets
Justificante de pedidos de Cravy en Google Sheets

Aprovechando que ya teníamos la plantilla hecha y un control total sobre la base de datos y el backend del proyecto, decidimos crear un App Script que se encargara de lo siguiente:

  1. Crear una carpeta con la fecha para almacenar los documentos en Google Drive de forma organizada.
  2. Obtener la información de los pedidos de cada restaurante haciendo una petición al backend.
  3. Crear una copia de las plantillas de Google Sheets para cada restaurante y rellenarlas con la información obtenida de la API.
  4. Almacenar las copias creadas en la carpeta correspondiente y crear una versión en PDF del fichero.

En este artículo nos vamos a centrar en mostrar las opciones más interesantes que nos ofrece la API y no entraremos en detalle de la lógica propia del script, pero si queréis ver el script completo se encuentra en Github.

Creación de la carpeta en Google Drive

Una de las clases que aun no hemos visto es la de DriveApp, que nos permite realizar operaciones en carpetas y ficheros de Google Drive.

En nuestro caso queremos crear una carpeta nueva con la fecha como nombre dentro de una carpeta específica de Google Drive.

  const now = new Date();
  const billDay = new Date(now.setDate(now.getDate() + 1))
    .toISOString()
    .slice(0, 10);

// Creating the day folder to save the bills
  const folderId = DriveApp.getFolderById('FOLDER-ID')
    .createFolder(billDay)
    .getId();

El FOLDER-ID lo podemos encontrar al final del slug de la url si estamos en la carpeta tal y como podemos ver en la imagen.

Folder-id de una carpeta de Google Drive

Crear una copia de las plantillas de Google Sheets para cada restaurante

Para poder crear una hoja de cálculo para cada restaurante lo que hacemos es ejecutar la función para cada uno de los restaurantes de los que disponemos. Esto lo podemos hacer mediante un simple for.

for (var index = 0; index < restaurantsData.length; index++) {
    fillSheetWithBillingData(
      restaurantsData[index],
      billDay,
      firstDay,
      lastDay,
      folderId
    );
  }

Una vez ejecutada la función, esta pide la información del restaurante al backend usando la clase UrlFetchApp igual que hemos visto en el ejemplo de Billbot, y hacemos las operaciones necesarias en JavaScript para obtener los datos en el formato que deseamos.

Cuando tenemos estos datos procedemos a crear la nueva hoja de cálculo, para ello solo nos hace falta implementar las siguientes lineas de código.

//Setting the reference to the original sheets
var billSheet = originalSpreadsheet.getSheetByName('Bill');
var ordersBillSheet = originalSpreadsheet.getSheetByName('OrdersBill');

//Create new restaurant sheet
var newBillSheet = SpreadsheetApp.create(
      'Factura-' + restaurantName + '-' + billDay + ''
    );
var newOrdersBillSheet = SpreadsheetApp.create(
      'Annnexo-' + restaurantName + '-' + billDay + ''
    );

//Copy the parent sheet content to the new created sheets
billSheet.copyTo(newBillSheet);
ordersBillSheet.copyTo(newOrdersBillSheet);

Mediante las funciones create() y copyTo() lo que hacemos es crear dos nuevas hojas de cálculo vacías y después copiar el contenido de la hoja de cálculo que nos sirve como plantilla. Hay que tener en cuenta que esto nos creará los ficheros en la carpeta raíz de nuestro Google Drive, así que en el paso final tendremos que tener eso en cuenta y mover estos ficheros a la carpeta correspondiente y eliminarlos de la raíz.

El siguiente paso del script es rellenar las hojas de cálculo que acabamos de crear con la información obtenida de la API usando los métodos getRange() y setValue() de la clase SpreadsheetApp que hemos visto en el ejemplo anterior.

Almacenar las copias creadas en la carpeta correspondiente y crear una versión en PDF del fichero.

Finalmente, el último paso es almacenar de forma organizada las dos hojas de cálculo creadas y almacenarlas en PDF, para ello solo nos hará falta una pequeña función.

function exportSomeSheets(
  restaurantName,
  folderId,
  newBillSheet,
  newOrdersBillSheet
) {
  // Save the files in to the correspondent folder
  var folder = DriveApp.getFolderById(folderId).createFolder(restaurantName);
  var copyNewBillSheet = DriveApp.getFileById(newBillSheet.getId());
  var copyNewOrdersBillSheet = DriveApp.getFileById(newOrdersBillSheet.getId());

  folder.addFile(copyNewBillSheet);
  folder.addFile(copyNewOrdersBillSheet);
  folder.createFile(copyNewBillSheet);
  folder.createFile(copyNewOrdersBillSheet);

  DriveApp.getRootFolder().removeFile(copyNewBillSheet);
  DriveApp.getRootFolder().removeFile(copyNewOrdersBillSheet);
}

Los pasos que realiza esta función son los siguientes: primero crea una carpeta con el nombre del restaurante dentro de la carpeta con la fecha generada en el paso anterior.

Carpeta de facturas 

A continuación pega las hojas de cálculo del segundo paso dentro de la carpeta con el nombre del restaurante con la función addFile() y con la función createFile() crea la versión en pdf.

Finalmente eliminamos los ficheros de la carpeta raíz para evitar acumularlos, el resultado final es el siguiente.

Contenido de la carpeta de restaurante

Conclusiones

Como podemos ver, con los App Script y nuestra creatividad se pueden llegar a hacer cosas muy potentes que nos ayuden en el día a día de nuestra empresa y nos ahorren cientos de horas a final de mes. Esto son sólo un par de ejemplos que nosotros hemos implementado para automatizar ciertas partes de nuestras operaciones, pero esto mismo se puede aplicar a muchos más casos.

Además, otra de las ventajas de utilizar App Script es que es un servicio completamente gratuito dentro de los límites de la plataforma, por lo que podemos tener cron jobs y otros procesos automáticos a coste cero.