Fundamentos Apps Script👨💻
Contents
Fundamentos Apps Script👨💻¶
Apps Script Powered by: Aula en la nube Apps Script Fundamentos Powered By: Mozart Alberto García de Haro Indice
Basic Module
Añadir ventana de verificación sobre combinar correspondencia
[Crear Barra lateral en Google Sheets](#Crear Barra lateral en Google-sheets)
Installar Google Apps Script¶
Google Apps Script and open it then start scripting. Also get access from Goolge Drive
Crear y abrir documentos en Google DOCS¶
Creacion de un Documento en Blanco en Google Docs
function CrearDcumento() {
DocumentApp.create('Data Analyst')
//Listo Creamos un Docs al Ejecutar la funcion.
}
Para guardar el documento y manipularlo lo debemos guardar en una variable. El objetivo es poder acceder a metodos, a diferetes niveles de profundidad y que el codigo sea legible realemten podemos colocar una cadena de metodos sin afectar el funcionamiento del codigo.
function CrearDcumento() {
var documento = DocumentApp.create('Data Analyst')
var documento_body= documento.getBody()
documento_body.appendParagraph('Escribiendo en Docs Creado desde Apps Script')
//La legibilidad no es la mejor:
documento.getBody().appendParagraph('Text')
}
Escribir sobre un Documento Existente. Los Docs normalmente tienen un Id el cual podemos extraer desde la URL del documento de Google.
function OpenDocumento() {
var documento = DocumentApp.openById('Id')
documento.getBody().appendParagraph('Text')
}
Condiciones¶
function ModificarFormato() {
Logger.log('Imprime Texto en pantalla');
//Buscamos el documento a partir de su Id
//Accedemos al cuerpo del documento, luego al parrafo
//El parrafo un elemento tipo lista y lo accedemos a partir de getText()
var documento = DocumentApp.openById('1S9s6tjqJapx7BL2fnxzsWRwjNmS3UoGgrCINLqYjRMQ');
var parrafo = documento.getBody().getParagraphs();
//If: Si la condicion se cumple usamos setText() para modificar el parrafo[0]
if (parrafo[0].getText() == 'Hola Data Analyst Jr. ') parrafo[0].setText('Soy Data Scientist');
//If/Else: Alineamos a la Izquierda si se encuentra a la derecha y viceversa
if (parrafo[0].isLeftToRight)
parrafo[0].setLeftToRight(false);
else
parrafo[0].setLeftToRight(true);
//If/Else If/Else: Obtiene el numero de espacios despues del parrafo señalado, a partir de ese numero
//modifica la cantidad de espacios si se cumple alguna de la condiciones indicadas.
if (parrafo[0].getSpacingAfter()==null)
parrafo[0].setSpacingAfter(10);
else if (parrafo[0].getSpacingAfter()==10)
parrafo[0].setSpacingAfter(20);
else if (parrafo[0].getSpacingAfter()==20)
parrafo[0].setSpacingAfter(30);
else
parrafo[0].setSpacingAfter(null);
}
Bucle¶
Indice A continuaciones aplicaremos loops en documentos, pero para eso debemos abrir el Documento sobre el que se escribira en la ejecucion del bucle.
Inicializamos
contador
, definimos una condicion a partir de contador e incrementamoscontador++
.En cada ejecucion usamos
appendParagraph()
para escribir sobre el documento.
While Loop
function CrearLoopParagraphs(){
var documento = DocumentApp.openById('1S9s6tjqJapx7BL2fnxzsWRwjNmS3UoGgrCINLqYjRMQ');
var contador = 0;
while(contador<100){
documento.getBody().appendParagraph(contador+' Data Analysis is the Future')
contador++;
}
}
For Loop
function CrearLoopParagraphs(){
var documento = DocumentApp.openById('1S9s6tjqJapx7BL2fnxzsWRwjNmS3UoGgrCINLqYjRMQ');
for(var contador = 0;contador < 100;contador++)
{
documento.getBody().appendParagraph(contador+' Data Analysis is the Future');
}
}
While Loop/Condicional
function ChangeDocThruLoop(){
var documento = DocumentApp.openById('1S9s6tjqJapx7BL2fnxzsWRwjNmS3UoGgrCINLqYjRMQ');
var parrafo = documento.getBody().getParagraphs();
var contador = 0;
while(contador < parrafo.length){
var thisparagraph = parrafo[contador].getText();
//Se modifica el parrafo si la condicion se cumple.
if (thisparagraph =='2 Data Analysis is the Future'){
parrafo[contador].setText('Analysis is the Future');
}
contador++;
}
}
Bucle FOR IN y análisis de atributos¶
Este codigo ademas de usar For In
similar a For Each
utilizar metodos que hacen que un vector se convierta en otro vector y ademas se modifique a partir de sus atributos.
function AnalizarParrafos(){
var doc = DocumentApp.openById('1S9s6tjqJapx7BL2fnxzsWRwjNmS3UoGgrCINLqYjRMQ');
//Acedemos al texto a partir de getParagraphs()
var parrafos = doc.getBody().getParagraphs();
//Inicializamos el tamaño del texto
var size = 10;
//Analizar cada parrafo por separado.
for(var parrafo in parrafos){
//Crear un vector con los attributos del parrafo
var paragraphattrs = parrafos[parrafo].getAttributes();
//Recorrer el vector y validar los condicionales
for(var paragraphattr in paragraphattrs){
//Si este en BOLD entonces retiramos ese atributo
if (paragraphattr == 'BOLD' && paragraphattrs[paragraphattr] == true){
parrafos[parrafo].setAttributes({'BOLD':false});
}
if (paragraphattr == 'FOREGROUD_COLOR' && paragraphattrs[paragraphattr] != null){
parrafos[parrafo].setAttributes({'FOREGROUD_COLOR':'#00ffff','FOND_SIZE':size++});
}
}
}
}
Crear formulario HTML en Google Docs¶
Creamos un formulario usando HTML y luego usamos JavaScript para llamar la funcion de Apps Script y pasarle lo argumentos obtenidos a partir del formulario.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<label>Cuantos Parrafos?</label>
<input type="number" id="cantidad"><br>
<label>Introduce el contenido de Parrafos</label>
<input type="text" id="frase"><br>
<label>Introduce el Color</label>
<input type="color" id="colores"><br>
<label>Fecha</label>
<input type="date" id="fecha"><br>
<button type="button" onclick="GetInfoForm()">Escribir Documento</button>
<script>
function GetInfoForm(){
var texto = document.getElementById('frase').value;
var number = document.getElementById('cantidad').value;
var colores = document.getElementById('colores').value;
var fecha = document.getElementById('fecha').value;
google.script.run.OpenFromJS(texto,number,colores,fecha)
google.script.host.close();
}
</script>
</body>
</html>
Creamos un menu facil de acceder desde Google Docs
function onOpen(){
//createMenu('name_nav_menu') Es el nombre que tendra la nueva opcion del panel
DocumentApp.getUi().createMenu('Options')
//addItem('name_option','name_function') No solo el nombre de la opcion sino que funcion desencadena.
.addItem('Form HTML','OpenForm')
.addToUi();
}
La primera funcion a Ejecutar es aquella que abre el archivo HTML
//La funcion `OpenForm()` abre al formulario y es la funcion desencadenada por el menu de herramientas
function OpenForm(){
//Me permite crear un HTML a partir de un archivo
var html = HtmlService.createHtmlOutputFromFile('index.html')
.setWidth(1000)
.setHeight(700)
//Usado para proteger a los usuarios de HTML malicioso o JS
//y que se ejecuta en un Sandbox que impone restricciones al codigo.
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
DocumentApp.getUi().showModalDialog(html,'Name');
}
Luego de abrir el formulario, el usuario ingresara la informacion y esta sera recolectada a travez de JavaScript para pasar los argumentos a la siguiente funcion.
function OpenFromJS(texto,numero,color,fecha){
var documento = DocumentApp.getActiveDocument();
documento.getBody().clear();
documento.getBody().setAttributes({'FOREGROUND_COLOR':color});
var title = documento.getBody().insertParagraph(0,'Darn Good Title')
title.setHeading(DocumentApp.ParagraphHeading.HEADING1);
for(var contador = 0;contador<numero;contador++){
var paraph = documento.getBody().appendParagraph(texto);
}
documento.addFooter();
var footer = documento.getFooter().appendParagraph('Modified on: '+fecha);
footer.setAlignment(DocumentApp.HorizontalAlignment.RIGHT);
}
Crear tablas personalizadas con formulario HTML¶
En esta seccion se explica como crear una tabla en Google Docs. El usuario indica filas, columnas y que colores debe tener el encabezado y el cuerpo de la tabla. El proceso de ejecucion involucra una interfaz de usuario creada a partir de HTML, CSS y JavaScript la cual se comunica con Apps Script y ejecuta la logica de la creacion de la tabla en este lenguage.
Creamos un menu
Options
en Google Docs con la opcionInsert Table
.
function onOpen(){
DocumentApp.getUi().createMenu('Options')
.addItem('Form HTML','OpenForm')
.addItem('Insert Table','OpenCreateTable')
.addToUi();
}
La opcion
Insert Table
activa la funcionOpenCreateTable()
que se encarga de abrir el archivo HTML.
function OpenCreateTable(){
var html = HtmlService.createHtmlOutputFromFile('table.html')
.setWidth(1000)
.setHeight(700)
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
DocumentApp.getUi().showModalDialog(html,'Este Codigo nos Permite insertar tablas en el Documento');
}
Usamos Bootstrap y le damos estilo al HTML.
<!DOCTYPE html>
<html>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script>
<style>
.contenedor{
display:flex;
text-align:right;
justify-content:space-around;
flex-direction:row;
flex-wrap: wrap;
fond-size:large;
border-radius: 5px;
padding:50px;
margin:40px;
width: 80%;
background-color:rgb(243,247,255);
box-shadow:0px 2px 2px #aaaaaa;
}
.caja{
line-height:50px;
}
</style>
Creamos el formulario en HTML
<head>
<base target="_top">
</head>
<body>
<div class="contenedor">
<div class="caja">
<label>Introduce la cantidad de Filas</label>
<input type="range" id="filas" min="1" max="20" step="1" value="5">
<output class="filas-output"></output><br>
<label>Introduce la cantidad de Columnas</label>
<input type="range" id="columnas" min="1" max="20" step="1" value="5">
<output class="columnas-output"></output><br>
<label>Introduce el Color Enabezado</label>
<input type="color" id="colorE"><br>
<label>Introduce el Color Par</label>
<input type="color" id="colorP"><br>
<label>Introduce el Color Impar</label>
<input type="color" id="colorI"><br>
<center><button type="button" class="btn btn-outline-primary" onclick="CrearTable()">Crear Tabla</button></center>
</div>
</div>
Capturamos los datos del Usuario usando JS
<script>
function CrearTable(){
var rows = document.getElementById('filas').value;
var columns = document.getElementById('columnas').value;
var colorE = document.getElementById('colorE').value;
var colorP = document.getElementById('colorP').value;
var colorI = document.getElementById('colorI').value;
google.script.run.ParamsTable(rows,columns,colorE,colorP,colorI);
google.script.host.close();
}
Esta parte del codigo solo se encarga de mostrar el usuario el valor correspondiente a los
<input>
tiporage
.
//Indica el Id del objeto que se esta consultando
const numRows = document.querySelector('#filas');
//Indica la clase del Objeto donde se va a mostrar el # de rows
const outRows = document.querySelector('.filas-output');
//Se coloca para mostrar el valor inicial addEventListener() no lo muestra a menos que cambie.
outRows.textContent = numRows.value;
//Obtiene y Actualiza constatemente outRows que es igual a numRows.value
numRows.addEventListener('input',function(){outRows.textContent = numRows.value;})
const numCols = document.querySelector('#columnas');
const outCols = document.querySelector('.columnas-output');
outCols.textContent = numCols.value;
numCols.addEventListener('input',function(){outCols.textContent = numCols.value;})
</script>
</body>
</html>
Creamos una funcion en Apps Script que se encarga de crear la tabla segun los parametros indicados por el usuario.
function ParamsTable(rows,columns,colorE,colorP,colorI){
var documento = DocumentApp.getActiveDocument().getBody();
var styleDocP = {};
styleDocP[DocumentApp.Attribute.BACKGROUND_COLOR] = colorP;
var styleDocE = {};
styleDocE[DocumentApp.Attribute.BACKGROUND_COLOR] = colorE;
styleDocE[DocumentApp.Attribute.BOLD] = true
var styleDocI = {};
styleDocI[DocumentApp.Attribute.BACKGROUND_COLOR] = colorI;
var createTable = documento.appendTable();
var fila;
var celda;
for(var i=0;i<rows;i++){
fila = createTable.appendTableRow();
for(var j=0;j<columns;j++){
celda = fila.appendTableCell('Celda '+j)
if (i==0) celda.setAttributes(styleDocE);
else if (i%2 == 0) celda.setAttributes(styleDocP);
else celda.setAttributes(styleDocI);
}
}
}
Combinar correspondencia en Google Docs¶
A continuacion se muestra como podemos crear documentos personalizables a partir de los parametros indicados por el usuario los cuales fueron previamente asignados a una variable la cual se reemplazara en el documento.
Creamos una platilla y colocamos las variables
<<variable>>
.
Creamos el menu de
Google Docs
para que el usuario intereacture con la funcion.
Abrimos el HTML usando
HtmlService.createHtmlOutputFromFile
como se ha hecho anteriormente.
La funcion principal
CreateCertificate()
crea un nuevo Documento y luego reemplaza las variables<<>>
en el texto, asi podemos utilizar la plantilla un numero ilimitado de veces y crear tantos documentos como queramos.
function CreateCertificate(curso,plataforma,funcion){
var idCurrentDoc = DocumentApp.getActiveDocument().getId();
var currentDoc = DriveApp.getFileById(idCurrentDoc)
//Creamos un nuevo documento, si no lo hacemos perderemos la plantilla
var newDoc= currentDoc.makeCopy('Curso: '+curso)
var documento = DocumentApp.openById(newDoc.getId());
//Obtenemos la fecha en la que se creo el Certificado
var date = new Date();
var mes = date.getMonth();
var day = date.getDate();
var year = date.getFullYear();
//La funcion switch pemite reemplazar el mes numerico a tipo texto
switch(mes){
case 0: mes = 'Enero'; break;
case 1: mes = 'Febrero'; break;
case 2: mes = 'Marzo'; break;
case 3: mes = 'Abril'; break;
case 4: mes = 'Mayo'; break;
case 5: mes = 'Junio'; break;
case 6: mes = 'Julio'; break;
case 7: mes = 'Agosto'; break;
case 8: mes = 'Septiembre'; break;
case 9: mes = 'Octubre'; break;
case 10: mes = 'Noviembre'; break;
case 11: mes = 'Diciembre'; break;
}
//Reemplazamos las variables <<>> en el texto por aquellas ingresadas por el usuario.
var certyDate = 'Certificado Emitido el dia '+day+' de '+mes+' de '+year;
documento.getBody().replaceText('<<curso>>',curso);
documento.getBody().replaceText('<<plataforma>>',plataforma);
documento.getBody().replaceText('<<funcion>>',funcion);
documento.getBody().replaceText('<<fecha>>',certyDate);
}
Combinar correspondencia múltiple¶
Indice
A diferencia del codigo anterior(HTML Form) ahora utilizamos Google Sheets para crear varios documentos.
Como no usamos HTML no necesitamos funciones adicionales para abrir HTML que luego le pasa los datos a JavaScript y luego se los pasa a Apps Script. Nada de lo anterior, solo creamos del codigo Apps Script desde Spread Sheet, creamos una funcion que se conecta con el documento platilla que recibe los datos desde filas y columnas y que se ejecuta en un bucle hasta que no encuentra mas filas.
Creamos la tabla que contiene la informacion que se colocara en el Documento ademas de un boton que al hacer click desencadenara la funcion.
row
indica desde que fila iniciamos,nameCel
es el nombre de la celda donde iniciamos,currentSheet
se conecta con el Spread Sheet y finalmentecurrentCel
se ubica en el rango señaladonameCel
usando la funciongetRange(nameCel)
//Nos conectamos al documento donde se encuentra la plantilla utilizando su Id
var currentDoc = DriveApp.getFileById('1U0WAP6dFPRYfZOW8jSPSJ8Vo2UthIdNaQV0zWs3oFGY')
var row = 2;
var nameCel = 'A'+row;
var currentSheet = SpreadsheetApp.getActive();
var currentCel = currentSheet.getRange(nameCel);
El bucle solo se ejecuta solo si la celda donde estamos ubicados no esta vacia.
while(!currentCel.isBlank()){...}
Luego de confirmar que la celda no esta vacia, no s desplazamos por la columnas de la fila y asignamos el valor de cada celda en el documento platilla.
documento.getBody().replaceText('<<curso>>',currentSheet.getRange('A'+row).getValue());
documento.getBody().replaceText('<<plataforma>>',currentSheet.getRange('B'+row).getValue());
documento.getBody().replaceText('<<funcion>>',currentSheet.getRange('C'+row).getValue());
El codigo completo es muy similar al de la seccion anterior.
function InsertData() {
var currentDoc = DriveApp.getFileById('1U0WAP6dFPRYfZOW8jSPSJ8Vo2UthIdNaQV0zWs3oFGY')
var row = 2;
var nameCel = 'A'+row;
var currentSheet = SpreadsheetApp.getActive();
var currentCel = currentSheet.getRange(nameCel);
//Ejecuta el bucle si la celda no esta en blanco
while(!currentCel.isBlank()){
//Creamos un nuevo documento, si no lo hacemos perderemos la plantilla
var newDoc= currentDoc.makeCopy('Curso: '+currentSheet.getRange('A'+row).getValue())
var documento = DocumentApp.openById(newDoc.getId());
//Obtenemos la fecha en la que se creo el Certificado
var date = new Date();
var mes = date.getMonth();
var day = date.getDate();
var year = date.getFullYear();
//La funcion switch pemite reemplazar el mes numerico a tipo texto
switch(mes){
case 0: mes = 'Enero'; break;
case 1: mes = 'Febrero'; break;
case 2: mes = 'Marzo'; break;
case 3: mes = 'Abril'; break;
case 4: mes = 'Mayo'; break;
case 5: mes = 'Junio'; break;
case 6: mes = 'Julio'; break;
case 7: mes = 'Agosto'; break;
case 8: mes = 'Septiembre'; break;
case 9: mes = 'Octubre'; break;
case 10: mes = 'Noviembre'; break;
case 11: mes = 'Diciembre'; break;
}
//Reemplazamos las variables <<>> en el texto por aquellas ingresadas por el usuario.
var certyDate = 'Certificado Emitido el dia '+day+' de '+mes+' de '+year;
documento.getBody().replaceText('<<curso>>',currentSheet.getRange('A'+row).getValue());
documento.getBody().replaceText('<<plataforma>>',currentSheet.getRange('B'+row).getValue());
documento.getBody().replaceText('<<funcion>>',currentSheet.getRange('C'+row).getValue());
documento.getBody().replaceText('<<fecha>>',certyDate);
//Shifting Down Cells
row++;
nameCel = 'A'+row;
currentCel = currentSheet.getRange(nameCel);
}
}
Añadir ventana de verificación sobre combinar correspondencia¶
La ventana de verificacion nos permite confirmar la accion del usuario en caso de que la accion no haya sido activada intensionalmente. El codigo es exactamente el mismo que la seccion anterior solo que esta encerrado en condicionales para ejecutarse o no segun la repuesta del usuario.
function InsertData() {
var ui = SpreadsheetApp.getUi();
var answer = ui.alert('Estas a punto de geenerar los documentos?',ui.ButtonSet.YES_NO)
if(answer == ui.Button.YES){
//Aqui va todo el codigo fuente...
//Confirma la ejecucion del mismo
ui.alert('Los documentos se han creado satisfactoriamente');
}
else
{
//Confirma la cancelacion del mismo.
ui.alert('Acabas de cancelar la generacion de de Documentos');
}
Añadiendo casillas de verificación¶
Entre mas valiaciones e informacion tenga usuario este tendra mas informacion de que no se ha creado y en caso de haberlo creado, indicaremos cuando. El codigo de creacion de documentos a partir de una patilla es el mismo y solo se añade una estructura de control IF
para validar si el docuemento fue creado previamente.
//Ejecuta el bucle si la celda no esta en blanco
while(!currentCel.isBlank()){
//El condicional valida si la columna D o de ENVIADO se cuentra marcada con true sino crea el documento
if (currentSheet.getRange('D'+row).getValue() != true)
{
//Aqui va el codigo ....
//Creamos en Checkbox y justo despues de crearlo lo marcamos
currentSheet.getRange('D'+row).insertCheckboxes();
currentSheet.getRange('D'+row).setValue(true);
currentSheet.getRange('E'+row).setValue(date)
}
El codigo completo hasta el momento:
function InsertData() {
var ui = SpreadsheetApp.getUi();
var answer = ui.alert('Estas a punto de geenerar los documentos?',ui.ButtonSet.YES_NO)
if(answer == ui.Button.YES){
var currentDoc = DriveApp.getFileById('1U0WAP6dFPRYfZOW8jSPSJ8Vo2UthIdNaQV0zWs3oFGY')
var row = 2;
var nameCel = 'A'+row;
var currentSheet = SpreadsheetApp.getActive();
var currentCel = currentSheet.getRange(nameCel);
//Ejecuta el bucle si la celda no esta en blanco
while(!currentCel.isBlank()){
//El condicional valida si la columna D o de ENVIADO se cuentra marcada con true sino crea el documento
if (currentSheet.getRange('D'+row).getValue() != true)
{
//Aqui va el codigo ....
//Creamos un nuevo documento, si no lo hacemos perderemos la plantilla
var newDoc= currentDoc.makeCopy('Curso: '+currentSheet.getRange('A'+row).getValue())
var documento = DocumentApp.openById(newDoc.getId());
//Obtenemos la fecha en la que se creo el Certificado
var date = new Date();
var mes = date.getMonth();
var day = date.getDate();
var year = date.getFullYear();
//La funcion switch pemite reemplazar el mes numerico a tipo texto
switch(mes){
case 0: mes = 'Enero'; break;
case 1: mes = 'Febrero'; break;
case 2: mes = 'Marzo'; break;
case 3: mes = 'Abril'; break;
case 4: mes = 'Mayo'; break;
case 5: mes = 'Junio'; break;
case 6: mes = 'Julio'; break;
case 7: mes = 'Agosto'; break;
case 8: mes = 'Septiembre'; break;
case 9: mes = 'Octubre'; break;
case 10: mes = 'Noviembre'; break;
case 11: mes = 'Diciembre'; break;
}
//Reemplazamos las variables <<>> en el texto por aquellas ingresadas por el usuario.
var certyDate = 'Certificado Emitido el dia '+day+' de '+mes+' de '+year;
documento.getBody().replaceText('<<curso>>',currentSheet.getRange('A'+row).getValue());
documento.getBody().replaceText('<<plataforma>>',currentSheet.getRange('B'+row).getValue());
documento.getBody().replaceText('<<funcion>>',currentSheet.getRange('C'+row).getValue());
documento.getBody().replaceText('<<fecha>>',certyDate);
//Creamos en Checkbox y justo despues de crearlo lo marcamos
currentSheet.getRange('D'+row).insertCheckboxes();
currentSheet.getRange('D'+row).setValue(true);
currentSheet.getRange('E'+row).setValue(date)
}
//Shifting Down Cells
row++;
nameCel = 'A'+row;
currentCel = currentSheet.getRange(nameCel);
}
ui.alert('Los documentos se han creado satisfactoriamente');
}
else
{
ui.alert('Acabas de cancelar la generacion de de Documentos');
}
}
Generar PDF a partir de un documento de Google¶
Crear PDF y guardarlo en la carpeta raiz de Google Drive. Lo primero es ejecutar saveAndClose()
para que el PDF no se cree mientras se guarda el el DOC sino que lo haga cuando ya haya sido creado. Indicamos el tipo de documento con getAs()
y con setName()
ademas de dale nombre añadimos el tipo de archivo .pdf
. Finalmente creamos el PDF en la carpeta raiz de Drive.
documento.saveAndClose();
var docPdf = documento.getAs('application/pdf');
docPdf.setName(documento.getName()+'.pdf');
DriveApp.createFile(docPdf);
Crear carpetas y mover archivos¶
La carpeta raiz es DriveApp
y por esto si creamos una carpeta esta se guarda alli a no ser que indiquemos mas instrucciones
var carpeta =DriveApp.createFolder('Certificados: '+ new Date());
Luego de haber creado la carpeta debemos mover los archivo de DriveApp
a la Carpeta.
//Donde var newDoc= currentDoc.makeCopy('Curso: '+currentSheet.getRange('A'+row).getValue())
var documentoPdf = DriveApp.createFile(docPdf);
documentoPdf.moveTo(carpeta);
newDoc.moveTo(carpeta);
Si queramos guardar la carpeta dentro de Otra carpeta entonces debemos seguir los siguientes pasos:
Creamos una carpeta manualmente, donde se almacenaran las carpetas por cada ejecucion del codigo.
Movemos manualmente tanto el Spread Sheet(Paramentros Certificados) como Docs(Platilla Certificados).
Ahora que la el Spread Sheet no esta en la carpeta raiz sino en una subcarpeta debemos obtener
getFileById()
de la subcarpeta y usamos las funciones.getParents().next()
para indicar la ruta de la carpeta padre.
var idHoja = SpreadsheetApp.getActive().getId();
var carpetaPadre = DriveApp.getFileById(idHoja).getParents().next();
//Finalemte creamos la carpeta, esto solo se debe hace fuera del bucle y es llamada desde `while`.
var carpeta =carpetaPadre.createFolder('Certificados: '+ new Date());
Mejorando función combinar correspondencia¶
El objetivo es indicarle al usuario si enverdad se han generado documentos. En el codigo anterior se mostraba el mensaje de alerta Se han creado los documentos
incluado cuando no era el caso. Ahora colocaremos condicionales adicionales para entragar la informacion correcta.
Ahora crearemos la carpeta dentro del
while
para evitar que se creen carpetas vacias, como recordaras antes se creaba una carpeta antes de ejecutar el codigo.Para evitar que se crea una carpeta por cada documento usamos un condicional para que el bucle solo pueda acceder a la creacion de carpeta si y solo si encontro algun documento y ademas lo haga una sola vez por todos los documentos.
//El condicional valida si la columna D o de ENVIADO se cuentra marcada con true sino crea el documento
if (currentSheet.getRange('D'+row).getValue() != true)
{
//documentosGenerados es una variable que se incrementa solo si encuentra una documento por crear.
documentosGenerados++;
//documentosGenerados va a incrementar varias veces pero solo se creara la carpeta cuanto sea igual a 1
if (documentosGenerados == 1){
//Creamos una carpeta en Drive
var idHoja = SpreadsheetApp.getActive().getId();
var carpetaPadre = DriveApp.getFileById(idHoja).getParents().next();
var carpeta =carpetaPadre.createFolder('Certificados: '+ new Date());
}
//Codigo ....
}
Ahora que solo se creara la carpeta si hay documentos por crear solo falta agregar los ventanas de alerta para notificar al usuario.
if (documentosGenerados>0)
ui.alert('Se han generado ' + documentosGenerados + 'documentos');
else
ui.alert('No se han encontrado datos por lo cual no se generaron documentos')
Enviar correos electrónicos con PDF adjunto¶
Indice
Para enviar un correo electronico necesitamos primero crear una lista que contenga los correo electronicos en Google Sheets
, luego usamos las funcion GmailApp.sendEmail(destinatario,titulo,cuerpo,{attachments:[documento]})
le pasamos los paramentros obtenidos y listo.😎
var destinatario = currentSheet.getRange('F'+row).getValue();
var titulo = 'Certificado: ' + currentSheet.getRange('B'+row).getValue();
var cuerpo = 'Enhorabuena, a continuacion adjuntamos el certificado de ' + currentSheet.getRange('F'+row).getValue()+ ' que obtubiste en ' + currentSheet.getRange('B'+row).getValue();
GmailApp.sendEmail(destinatario,titulo,cuerpo,{attachments:[documentoPdf]})
Funciones personalizadas en Google Sheets¶
Las funciones personalizadas pueden ser usadas dentro de las celdas de excel, solo tenemos de ejecutarlas y entregarle los parametros que requiere la funcion, es como ejecutar cualquier funcion mativa de excel.
La funcion
=DOUBLE(A2)
toma un valor y retorna el cuadrado de ese valor.
function DOUBLE(x){
return x**2;
}
Bucle FOR Doble sobre un rango de celdas en Google Sheets¶
Operar arreglos de datos a partir de estructuras iterativas.
function DoubleArray(datos) {
//Valida si hay mas de un dato en la funcion.
if(Array.isArray(datos)){
var result = [];
//Se posiciona en la celda A1 y valida el tamaño del Arreglo de arriba a abajo.
for(var row = 0; row < datos.length;row++){
result[row] = new Array(datos[row].length);
//La primera posicion es datos[1]=A1, datos[2]=A2, ahora los convertimos en array
//new Array(A1.length) y determinamos en tamaño a nivel de columnas.
for(var cols = 0; cols<result[row].length;cols++){
//result[1][1]=A1, result[1][2]=B1..., calculamos el doble de cada celda de la tabla
//pero lo parsemos entes de guardarlo en la matriz.
result[row][cols] = parseInt(datos[row][cols])*2;
}
}
return result;
}
//Si no hay un rango de valores solo calculamos el doble.
else
{
return datos*2;
}
}
Bucle FOR IN Doble sobre un rango de celdas¶
A continuacion se muestra como se puede ejecutar el mimo codigo a partir de un bucle For In
function DoubleArrayForIn(datos) {
if(Array.isArray(datos)){
var result = [];
for(var row in datos)
//Array para guardar los elementos de las filas
var dataRow = [];
for(var cols in datos[row]){
//Push permite añandir cada elemento en dataRow
dataRow.push(parseInt(datos[row][cols])*2);
}
result.push(dataRow)
}
return result;
}
else
{
return datos*2;
}
}
Bucle FOREACH Doble sobre un rango de celdas¶
El uso es ForEach
es mas simplificado de todos los For
hasta el momento. A continuacion se muetran desde la forma mas larga hasta la mas corta con arrow functions
.
ForEach se compone de un elemento iterable y de una funcion como argumento que contiene el codigo correspondiente.
function DoubleForEach(datos){
//Vector que almacena la informacion resultante.
var result = [];
if(Array.isArray(datos)){
//Primer forEach se encarga de recorrer las filas
datos.forEach(function(row){
//Segundo forEach se encarga de recorrer las columnas
//dataRow corresponde al vector de cada fila
var dataRow = []
row.forEach(function(column){
//Caculamos el doble de cada celda en la medida que recorremos el array de cada fila
dataRow.push(column*2)
});
//Guardamos cada vector dataRow en result hasta construir la matriz
result.push(dataRow)
});
return result;
}
else{
return datos*2;
}
}
Utilizamos arrow functions para hacer el codigo mas legible.
function DoubleForEach(datos){
var result = [];
if(Array.isArray(datos)){
datos.forEach(row =>{
var dataRow = []
row.forEach(column=> dataRow.push(column*2));
result.push(dataRow)
});
return result;
}
else{
return datos*2;
}
}
Utilizamos un indice para cada vector en vez de crear un array por cada fila.
function DoubleForEach(datos){
var result = [];
if(Array.isArray(datos)){
datos.forEach((row,idxrow) =>{
//Creamos un array para cada una de las filas.
result[idxrow] = new Array(datos[idxrow].length);
//Calculamos el doble de cada elemento del array de cada fila.
row.forEach((cell,idxcol)=> result[idxrow][idxcol] = cell*2);
});
return result;
}
else{
return datos*2;
}
}
La siguiente funcion calcula la sumatoria total de un arreglo.
function DoubleTotal(datos){
var result = 0;
if(Array.isArray(datos)){
datos.forEach(row => row.forEach(col => result += col*2));
return result;
}
else{
return datos*2;
}
}
Función MAP para manipular matrices y arrays¶
Funcion que obtiene otra matriz pero utilizando la funcion map.
function MapArray(datos){
if (Array.isArray(datos)){
return datos.map(row => row.map(cell => cell*2));
}
else{
return datos *2;
}
}
Funcion que obtiene la sumatoria del doble de cada celda, utilizando map
.
function MapTotalArray(datos){
var resul = 0;
if (Array.isArray(datos)){
return datos.map(row => row.map(cell => result +=cell*2));
}
else{
return datos *2;
}
}
Función REDUCE para analizar matrices y arrays¶
Al aplicar la funcion reduce sobre una matriz el codigo quedaria de la siguiente forma:.
function MapTotalArray(datos){
//Debido a que solo es posible cacular el doble a partir del segundo paramentro
//colocalos el cero el cual al momento de la ejecicion de convertira en el primero
return datos.reduce(((a,b)=> a+b.reduce(((c,d)=> c+d*2),0)),0);
}
Función FILTER sobre rango de celdas¶
Esta funcion permite aplicar un filtro sobre los datos, es decir reducir el tamaño del arreglo. Si queremos realizar una reduccion de los datos, podemos primero filtart los datos y luego pasarlos a una funcion que haga la reduccion.
function FilterArray(datos){
if (Array.isArray(datos)){
//Se convierte cada fila en un array luego aplicamos filter.
return datos.map(row => row.filter(cell => cell > 5));
}
else{
return datos.filter(cell => cell > 5);
}
}
Funciones con varios parámetros¶
La documentacion de una funcion permite al usuario tener mas informacion hacerca de su uso como saber el tipo de dato que debe ingresar. El proceso se debe seguir tal cual como aparece a continuacion.
/**
* Multiplicar celdas por el valor almacenado en otra celda
*
* @param {number|Array<Array<number>>} datos - Celda o Rango de Celdas que queremos multiplicar
* @para {number} multiplicador- Celda multiplicadora.
* @customfunction
*/
function MULTIPLICADOR(datos,multiplicador){
//Posibles Errores
if (Array.isArray(multiplicador) || multiplicador==null) return 'Error: El se aceptan Arrays o Nulos'
if (Array.isArray(datos)){
return datos.map(row => row.map(cell => cell*multiplicador));
}
else{
return datos *2;
}
}