offline-pos 0.7.0 · Markdown · OpenAPI · llms.txt · Backends y canales

pos-sheets.gs

Google Sheets: el puente de Apps Script

Una planilla de Google Sheets puede ser el backend del POS, sin servidor y sin costo: el catálogo y los clientes se cargan en la planilla, y las ventas, cobranzas y movimientos de caja llegan solos a sus pestañas. El POS habla con la planilla a través de un puente de Apps Script, un solo archivo que se pega en la planilla y se implementa como aplicación web: pos-sheets.gs.

Esta página acompaña al contrato 4.6.0 (el mismo que la guía para integradores). Bajá siempre el archivo de las docs del canal donde están tus terminales.

Qué hace y qué no

El puente es un backend más del POS, con el mismo contrato que un backend REST pero con otro transporte (ver "El contrato del puente", abajo). En el POS se elige como tipo de conexión "Google Sheets".

Instalar

  1. Creá una planilla vacía y abrí Extensiones > Apps Script. El proyecto nuevo trae un archivo, Código.gs: reemplazá todo su contenido con pos-sheets.gs (en la página de esta guía, el botón Copiar el código) y guardá.
  2. Implementar > Nueva implementación > Aplicación web, con "Ejecutar como": Yo y "Quién tiene acceso": Cualquier persona.
  3. Autorizá el acceso. Google pide solo acceso a esta planilla ("See, edit, create, and delete this spreadsheet"): el archivo lleva la anotación @OnlyCurrentDoc en su primer comentario justamente para eso. Si la pantalla dice "all your Google Sheets spreadsheets", cancelá y revisá que la anotación siga ahí. El aviso de "app no verificada" es normal en un script propio.
  4. Abrí la URL de la aplicación web que te muestra Google (https://script.google.com/macros/s/…/exec): es la página de la planilla, donde se prepara y desde donde se abre el POS.

"Cualquier persona" no significa que cualquiera pueda editar la planilla: el script corre con tus permisos y solo expone lo que necesitan el POS y la página. Es la única forma de que el POS escriba sin que nadie tenga que iniciar sesión en Google. La página nunca borra nada: preparar solo anda con la planilla sin preparar, y reiniciar exige que alguien que edita la planilla lo permita (ver "Probar de nuevo", abajo).

(Opcional) Para que solo tus terminales puedan escribir, protegé el puente con un secreto compartido: en Apps Script, Configuración del proyecto > Propiedades de la secuencia de comandos > agregá SHARED_SECRET con el valor que quieras. Cada terminal lo carga una vez en la configuración del POS: el link de la página nunca lo lleva.

Preparar la planilla

La página de una planilla sin preparar pide el nombre del comercio, la sucursal, la caja y con qué empezar:

Al tocar Preparar la planilla, se crean las pestañas, la planilla toma el nombre del comercio (es el que muestra el POS) y la pestaña Configuración guarda el comercio, la sucursal y la caja. La primera pestaña es el Tablero (abajo).

Abrir el POS en cada terminal

Desde cada terminal, abrí la página de la planilla (la URL de la aplicación web; en el Tablero, el link Abrir el POS en una caja), poné el nombre de esa caja y tocá Abrir el POS. El POS se abre con esta planilla, la sucursal y la caja ya cargadas: si la terminal no tenía datos, prueba la conexión y entra directo a la venta. Si tenía datos de otra conexión, o la planilla tiene un secreto compartido, abre su configuración con todo precargado, para que decidas qué hacer con los datos o completes el secreto.

El link lleva la URL de esa implementación, así una copia de la planilla nunca conecta al POS con la original, y nunca lleva el secreto: la página es pública. Sin la página, también se puede elegir "Google Sheets" en /CONFIG del POS y pegar la URL de la aplicación web.

El Tablero

La primera pestaña resume lo que pasa en el comercio, con fórmulas que se actualizan solas con cada venta que llega del POS: lo vendido hoy, los tickets de hoy, lo vendido en 7 días, el fiado pendiente, las ventas de cada uno de los últimos 14 días (con un gráfico), los medios de pago, los 10 productos más vendidos y lo que debe cada cliente. Los montos ya descuentan las anulaciones.

Si movés columnas de las otras pestañas, las fórmulas las siguen solas. A una planilla preparada antes de que existiera el Tablero, la página le ofrece Agregar el tablero, sin tocar nada más.

La pestaña Configuración

Pares clave/valor que el puente encuentra por el texto de la clave (columna A), no por la fila, y debajo los pasos para conectar una terminal. Se le puede dar formato o moverla.

El secreto compartido nunca va en esta pestaña: viajaría con cada copia de la planilla.

Probar de nuevo

Para volver a empezar (por ejemplo, después de probar con datos de ejemplo), poné Sí en "Permitir reiniciar" y recargá la página: Reiniciar la planilla borra todas las pestañas (también las tuyas), deja una hoja vacía y vuelve al formulario. Las terminales que estaban conectadas guardan lo que vendieron: conviene volver a abrir el POS desde la página y elegir borrar sus datos.

El portal: abrir la planilla desde el POS

Con la terminal conectada, el comando /PLANILLA y el botón "Abrir planilla" de la barra de estado abren la planilla en una pestaña nueva. No hay token: abrirla ya exige una cuenta de Google con acceso a la planilla.

Actualizar el puente

  1. Copiá pos-sheets.gs de las docs del canal donde están tus terminales.
  2. En la planilla: Extensiones > Apps Script, reemplazá el contenido de Código.gs y guardá. Si tu proyecto tiene los archivos de una versión anterior (bridge.gs y columnas.gs), borralos: todo está ahora en un solo archivo.
  3. Andá a Implementar > Administrar implementaciones > lápiz sobre la implementación existente > Versión: Nueva versión > Implementar.

La URL de la aplicación web no cambia y no hace falta tocar el POS. No crees una implementación nueva: tendría otra URL, y conectar el POS a otra URL es otra conexión.

Una planilla anterior se actualiza sola: el puente agrega al final de cada pestaña las columnas opcionales nuevas que le falten, y las filas que ya estaban quedan como estaban. Después de actualizar, el primer pedido del POS puede volver a traer todos los productos y clientes: es esperado.

Cómo se ve y cómo se edita la planilla

Pestañas: Tablero, Productos y Clientes (los carga el comercio), Ventas, Pagos, CuentaCorriente, MovimientosCaja y Cobranzas (las escribe el puente), Configuración, y dos ocultas que usa el puente (_PushLots y _Snapshot).

El puente encuentra cada columna por su encabezado, no por su posición, sin distinguir mayúsculas, acentos ni espacios. Podés:

Las demás columnas no se pueden borrar ni renombrar: el puente responde con un error que dice cuál falta (Falta la columna 'Precio' en la pestaña Productos) y el POS lo muestra. Para renombrar una columna o un valor, cambiá su etiqueta en pos-sheets.gs: los textos de la planilla están juntos, en COLUMN_LABELS y VALUE_LABELS.

Cada pestaña nueva nace con formato por columna (texto para ids y códigos, importes con miles y decimales, fechas reales, cantidades con hasta tres decimales, listas desplegables en los valores fijos); las filas nuevas copian el formato de la fila 2.

No conviertas en tabla (Formato > Convertir en tabla) las pestañas que escribe el puente: la tabla no deja copiar el formato a las filas nuevas y la venta queda en una fila vacía. Para tus propias consultas, armá una pestaña aparte con QUERY o FILTER sobre ellas, como el Tablero. Tampoco se crean tablas desde el puente: hacerlo desde Apps Script exige un permiso sobre todas tus planillas o todo tu Drive.

Qué guarda cada evento

Cada fila que escribe el puente lleva el dispositivo, la sucursal y el punto de venta de la terminal. Un evento nunca se modifica: una anulación es otro registro que apunta al original.

CuentaCorriente es el libro de cada cliente: ventas a cuenta en positivo, acreditaciones y cobranzas en negativo. El saldo que el POS muestra de un cliente es la suma de sus filas.

El contrato del puente

Un integrador no necesita esta sección para usar el puente: es para quien quiera entenderlo o escribir otro cliente.

POST <URL de la aplicación web> con Content-Type: text/plain;charset=utf-8 (a propósito, no application/json: evita el preflight OPTIONS, que Apps Script no maneja) y un body JSON:

{
  "action": "pushBatch",
  "payload": { "deviceId": "3f0c…", "events": [] },
  "idempotencyKey": "01J…",
  "sharedSecret": "…",
  "contractVersion": "4.6.0"
}

La respuesta siempre es HTTP 200 y el resultado viaja en el body:

{ "ok": true, "data": {} }
{ "ok": false, "error": "mensaje" }
{ "ok": false, "error": "mensaje", "code": "incompatible-contract", "contractVersion": "4.6.0" }

Apps Script no expone los headers, así que la versión del contrato y el secreto van en el body. Con otra versión mayor, el puente responde incompatible-contract sin procesar nada: el POS no recibe ack y lo pendiente espera en la terminal hasta que se actualice el puente.

Acciones:

pushBatch y pullBatch toman el lock del script: la foto y el estado de los lotes son siempre del mismo instante.

Cursor del pull. Sheets no registra cuándo cambió cada fila. El puente guarda una huella del contenido de cada fila de Productos y Clientes en la pestaña oculta _Snapshot y la compara en cada pull: una fila nueva o cambiada toma la hora actual, y el cursor es la hora más nueva de cada pestaña. Así cubre igual una edición a mano en la planilla que una escritura del propio puente.

Limitaciones