Cree archivos PDF a partir de plantillas con Python y Scripts de Google

A menudo, es útil crear archivos PDF a partir de sus scripts de Python. Ya sea que esté creando facturas, cartas, informes o cualquier otro documento que contenga mucha repetición de formato pero solo un poco de contenido dinámico, agregar algo de automatización puede ahorrarle muchas horas.

Tiene algunas opciones para esto. Los habituales son:

  1. Utilice una biblioteca PDF como reportlab para generar archivos PDF directamente (p. ej. https://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/)
  2. Utilice una biblioteca de plantillas HTML como Jinja2 y convierta de HTML a PDF (por ejemplo, consulte http://pbpython.com/pdf-reports.html)
  3. Utilice una API de terceros como https://pdfgeneratorapi.com/.

Para la opción 1, generar archivos PDF directamente desde Python puede hacer que el formato sea muy difícil. Tienes que dibujar todo lo que necesites elemento por elemento, usando código, e incluso una vez que tienes una plantilla que se ve como la quieres, es difícil de mantener.

La opción 2 a menudo puede funcionar mejor, pero aún tiene que construir el código HTML de Jinja, y a veces la conversión de HTML a PDF no sale como esperaba.

La opción 3 requiere que construya la plantilla primero utilizando la interfaz web de un servicio en línea. Aunque tienes una interfaz de arrastrar y soltar, es bastante torpe y difícil hacer que tu plantilla se vea como quieras. Por lo general, también tiene que pagar para usar el servicio.

Si bien una de las opciones anteriores puede funcionar para usted, si no le gusta ninguna de ellas, también puede hackear una API de generación de documentos basada en Google Drive. Obtendrás una API gratuita y podrás usar Google Docs como herramienta de plantillas, que es bastante potente y tiene muchas plantillas preexistentes para cosas como facturas, cartas y CV.

Empecé con una plantilla de factura que encontré en línea. Se parece a esto:

 Plantilla de factura de Google Docs

En este tutorial, explicaremos cómo crear una API que genere estas facturas y le permita insertar mediante programación el número de factura desde un script Python externo. En realidad, tendría que hacer lo mismo para muchos de los otros campos, pero comenzaremos con un ejemplo simple por razones de demostración.

Escribiremos algunas líneas de código de script de Google App y algunas líneas de código Python.

Crear una plantilla de documento

Utilice una de las plantillas de documentos integradas de Google, busque en línea una que se ajuste a sus necesidades o cree la suya propia en docs.google.com. (Necesitarás una cuenta de Google).

Agregue marcadores de posición donde necesite información dinámica. En el ejemplo a continuación, he agregado el NÚMERO DE FACTURA {invoice_id} en lugar de la identificación» 456 » que tenía en el documento original. No hay nada especial en esta sintaxis using usaremos una función básica de búsqueda y reemplazo más adelante para cambiar esto por la información real, así que use algo que es poco probable que aparezca en el documento final.

Tome nota de su ID de documento, que es la parte resaltada en la barra de direcciones URL.

 Plantilla de factura con marcador de posición

Configuración de un script personalizado de Google

Vaya a Google Drive, presione «Nuevo» en la esquina superior izquierda. En» Más», selecciona» Script de Google Apps «si está disponible o» Conectar más aplicaciones » si no lo ves.

 Conectar más aplicaciones

Busque «script de aplicaciones» y elija conectarlo. Es posible que veas algunos mensajes de advertencia que te pregunten si confías en ti mismo. Di que sí.

 Agregar Script de aplicaciones

Una vez que pueda crear un nuevo Script de aplicación, verá un script en blanco predeterminado que se ve de la siguiente manera.

Script en blanco de Google Apps

Elimine el código que ve allí y reemplácelo con una función createDocument que se vea de la siguiente manera.

function createDocument(invoice_id) { var TEMPLATE_ID = '1Ybq8r_SiWu4Z4-_Z6S0IW1L8FJywfpjPAATPCvvkKk8'; var documentId = DriveApp.getFileById(TEMPLATE_ID).makeCopy().getId(); drivedoc = DriveApp.getFileById(documentId); drivedoc.setName("Invoice " + invoice_id); doc = DocumentApp.openById(documentId); var body = doc.getBody(); body.replaceText('{invoice_id}', invoice_id); drivedoc.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.EDIT); return "https://docs.google.com/document/d/" + documentId + "/export?format=pdf";}

En la línea 2, cambie el TEMPLATE_ID por el ID del documento que copió de la barra de direcciones URL de su documento de Google con plantilla.

Este código encuentra el documento con plantilla, crea una copia del mismo y establece el nombre del archivo en «Factura» más cualquier invoice_id que pasemos. A continuación, abre el nuevo archivo a través de DocumentApp (en lugar de la aplicación Drive, para que podamos obtener el contenido del archivo y editarlo). Busca en el documento el marcador de posición que agregamos ({invoice_id}) y lo reemplaza con el invoice_id real que la función toma como entrada. A continuación, establece que el documento sea de acceso público y devuelve una URL que irá directamente a una exportación PDF para ese documento.

Debajo de esta función, agregue otra llamada doGet. Mientras que la función anterior se puede nombrar cualquier cosa, doGet es una función especial en los scripts de Google Apps, por lo que deberá nombrarla exactamente doGet. Esta función se encargará de las solicitudes web entrantes después de que hayamos implementado nuestra aplicación.

El código para la función doGet es el siguiente. Pegue esto debajo de la función anterior createDocument().

function doGet(e) { var invoice_id = e.parameter.invoice_id; var url = createDocument(invoice_id); return ContentService.createTextOutput(url);}

Esto toma el invoice_id como un parámetro de URL, lo pasa a nuestra función createDocument que acabamos de escribir y devuelve la URL del documento creado como texto sin formato.

Publicación de nuestra API

En el menú» Publicar», seleccione «Implementar como aplicación web»

Implementar como aplicación web

Se le pedirá que nombre el proyecto. Ponle un nombre como «API PDF» o cualquier otra cosa que quieras.

 Nombrar el proyecto

Verá un nuevo menú para establecer las opciones para implementar su aplicación web.

Opciones de implementación

Agregue un mensaje como «implementación inicial» en donde dice » Nuevo «y elija» Cualquiera, incluso anónimo » en la configuración de acceso. Deje la configuración de ejecución como «Yo».

Advertencia: Si comparte el enlace en un lugar público, las personas pueden abusar del servicio y enviarlo spam con solicitudes automáticas. Google puede bloquear tu cuenta por abuso si esto sucede, así que mantén el enlace seguro.

Pulsa el botón Implementar y anota la URL que verás en la siguiente ventana emergente.

La URL de tu aplicación

¿Agregar «?invoice_id = 1» hasta el final de la URL y visítela en su navegador. Debería verse algo como

https://script.google.com/macros/s/AKfycbxDiKpTGqMijZmU8-0cPj06DBFjDOPYZJ9IFvhcO111GCh8jqxC/exec?invoice_id=1

Si todo salió bien, deberías ver un enlace de Google Docs mostrado.

 Respuesta de nuestra aplicación web

Si visita la URL, debe descargarse un PDF de la factura con el marcador de posición cambiado a 1.

Actualización de la aplicación

Si ve un error en su lugar, o no recibe una respuesta, es probable que haya cometido un error en el código. Puede cambiarlo y actualizar la implementación de la misma manera que la implementó inicialmente. La pantalla de actualización solo es ligeramente diferente de la pantalla de implementación.

 Actualizar las opciones de implementación

Lo único complicado es que debe seleccionar «Nuevo» como la versión para cada cambio que realice. Si realiza cambios en el código y actualiza una versión anterior, los cambios no surtirán efecto, lo que no es obvio en la interfaz de usuario. (Como pueden ver, me tomó varios intentos hacer esto bien.).

Crear nuestras facturas desde Python

Ahora podemos crear facturas y guardarlas localmente desde un script de Python. El siguiente código muestra cómo generar tres facturas en un bucle for.

import requestsurl = "https://script.google.com/macros/s/AKfycbyYL5jhEstkuzZAmZjo0dUIyAmzUc1XL5B-01fHRHx8h63cieXc/exec?invoice_id={}"invoice_ids = for invoice_id in invoice_ids: print("processing ", invoice_id) response = requests.get(url.format(invoice_id)) print("file generated") response = requests.get(response.content) print("file downloaded") with open("invoice{}.pdf".format(invoice_id), "wb") as f: f.write(response.content)

Tenga en cuenta que el proceso de creación y descarga es bastante lento, por lo que tomará unos segundos cada factura que cree.

Probablemente haya notado que esta es una solución bastante «hackeada» para generar archivos PDF desde dentro de Python. La funcionalidad de «reemplazar» es bastante limitada en comparación con un lenguaje de plantillas adecuado, y el paso de datos a través de una solicitud get también tiene limitaciones. Si pasa por algo más complicado que un ID de factura, primero codificará la URL de los datos. Puede hacer esto en Python usando el módulo urllib.parse. Un ejemplo de modificación del script Python para tratar datos más complicados es el siguiente.

import requestsimport urllib.parseurl = "https://script.google.com/macros/s/AKfycbyYL5jhEstkuzZAmZjo0dUIyAmzUc1XL5B-01fHRHx8h63cieXc/exec?"invoice_ids = for invoice_id in invoice_ids: print("processing ", invoice_id) payload = {"invoice_id": invoice_id} u = url + urllib.parse.urlencode(payload) response = requests.get(u) print("file generated") response = requests.get(response.content) print(response.content) print("file downloaded") with open("invoice{}.pdf".format(invoice_id), "wb") as f: f.write(response.content)

Pero todavía hay limitaciones de qué tipo de datos y cuánto puede pasar solo usando URL, por lo que tendría que modificar el script para usar solicitudes POST en su lugar si estuviera enviando muchos datos dinámicos.

También es bastante lento en comparación con algunos de los otros métodos que discutimos al principio, y Google tiene algunas limitaciones en la cantidad de archivos que puede crear automáticamente de esta manera.

Dicho esto, ser capaz de generar plantillas utilizando Google Docs puede ser rápido y potente, por lo que tendrás que evaluar las compensaciones por ti mismo.

También tenga en cuenta que este es un ejemplo bastante artificial, donde podríamos haber ejecutado el script Python desde el Ecosistema de Google, y evitar la necesidad de configurar una API pública que podría ser abusada si otras personas descubrieran la URL. Sin embargo, es posible que tenga una aplicación Python existente, no alojada en Google, que necesite conectarse con archivos PDF generados automáticamente, y este método aún le permite configurar un «microservicio» autónomo dentro del ecosistema de Google que permite una generación fácil de PDF.

Conclusión