caja menor y libro diario
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
/*************************************************
|
||||
* APP LUISA - API con Google Apps Script
|
||||
*
|
||||
* Esta API conecta el frontend con Google Sheets.
|
||||
*
|
||||
* ESTRUCTURA DE CADA HOJA:
|
||||
* Columna A: Fecha
|
||||
* Columna B: Tipo (Ingreso / Gasto)
|
||||
* Columna C: Descripción
|
||||
* Columna D: Monto
|
||||
* Columna E: ID ← identificador del registro en SQLite
|
||||
*
|
||||
* La primera fila debe ser el encabezado.
|
||||
*
|
||||
* ACCIONES (parámetro "accion" en el body del POST):
|
||||
* - "nuevo" o "actualizar": crea la fila si el ID no existe,
|
||||
* o actualiza la fila que tenga ese ID
|
||||
* - "borrar": elimina la fila que tenga ese ID
|
||||
*************************************************/
|
||||
|
||||
const SPREADSHEET_ID = "PEGA_AQUI_EL_ID_DE_TU_HOJA"; // ⚠️ Reemplazar con tu ID
|
||||
|
||||
// ============ LEER DATOS (GET) ============
|
||||
// Uso: URL?hoja=CajaMenor
|
||||
function doGet(e) {
|
||||
const nombreHoja = e.parameter.hoja || "CajaMenor";
|
||||
const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
|
||||
const hoja = ss.getSheetByName(nombreHoja);
|
||||
|
||||
if (!hoja) {
|
||||
return responderJSON({ error: "La hoja '" + nombreHoja + "' no existe" });
|
||||
}
|
||||
|
||||
const datos = hoja.getDataRange().getValues();
|
||||
const encabezados = datos[0];
|
||||
const filas = datos.slice(1);
|
||||
|
||||
// Convertir a array de objetos
|
||||
const resultado = filas.map(fila => {
|
||||
const objeto = {};
|
||||
encabezados.forEach((encabezado, i) => {
|
||||
objeto[encabezado] = fila[i];
|
||||
});
|
||||
return objeto;
|
||||
});
|
||||
|
||||
return responderJSON({ datos: resultado });
|
||||
}
|
||||
|
||||
// ============ GUARDAR / ACTUALIZAR / BORRAR (POST) ============
|
||||
// Body: { hoja, accion, id, datos: { Fecha, Tipo, Descripción, Monto } }
|
||||
function doPost(e) {
|
||||
try {
|
||||
// Log de depuración: grabar en una hoja llamada "Logs" para ver si doPost se ejecuta
|
||||
logDebug("doPost iniciado. postData: " + JSON.stringify(e.postData));
|
||||
|
||||
let body;
|
||||
if (e.postData && e.postData.contents) {
|
||||
try {
|
||||
body = JSON.parse(e.postData.contents);
|
||||
logDebug("Parseado postData.contents como JSON");
|
||||
} catch (parseErr) {
|
||||
logDebug("FALLÓ parse JSON. Tipo: " + (e.postData.type || "N/A") + " | Contenido: " + e.postData.contents);
|
||||
body = e.parameter || {};
|
||||
}
|
||||
} else if (e.postData && e.postData.type === "application/json") {
|
||||
body = JSON.parse(e.parameter);
|
||||
} else {
|
||||
logDebug("No había postData. Params: " + JSON.stringify(e.parameter || {}));
|
||||
body = e.parameter || {};
|
||||
}
|
||||
|
||||
const nombreHoja = body.hoja || "CajaMenor";
|
||||
const accion = body.accion || "nuevo";
|
||||
const id = String(body.id || "");
|
||||
const datos = body.datos || {};
|
||||
|
||||
logDebug("Parsed body: hoja=" + nombreHoja + " accion=" + accion + " id=" + id);
|
||||
|
||||
const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
|
||||
const hoja = ss.getSheetByName(nombreHoja);
|
||||
|
||||
if (!hoja) {
|
||||
return responderJSON({ error: "La hoja '" + nombreHoja + "' no existe" });
|
||||
}
|
||||
|
||||
const encabezados = hoja.getRange(1, 1, 1, hoja.getLastColumn()).getValues()[0];
|
||||
let indiceId = indiceColumnaId(encabezados);
|
||||
|
||||
// Si no existe la columna "Id", la creamos al final para no dañar datos
|
||||
if (indiceId === -1) {
|
||||
hoja.getRange(1, encabezados.length + 1).setValue("Id");
|
||||
encabezados.push("Id");
|
||||
indiceId = encabezados.length - 1;
|
||||
logDebug("La columna 'Id' no existía en " + nombreHoja + ". Se creó en la columna " + (indiceId + 1));
|
||||
}
|
||||
|
||||
// Buscar si ya existe una fila con ese ID en la columna de ID
|
||||
const filaExistente = buscarFilaPorId(hoja, id, indiceId);
|
||||
logDebug("buscarFilaPorId(" + id + ") => fila " + filaExistente);
|
||||
|
||||
if (accion === "borrar") {
|
||||
if (filaExistente > 0) {
|
||||
hoja.deleteRow(filaExistente);
|
||||
logDebug("Borrado fila " + filaExistente + " id=" + id);
|
||||
return responderJSON({ ok: true, mensaje: "Registro borrado" });
|
||||
}
|
||||
logDebug("Nada que borrar id=" + id + ". IDs en hoja: " + listarIds(hoja, indiceId));
|
||||
return responderJSON({ ok: true, mensaje: "Nada que borrar" });
|
||||
}
|
||||
|
||||
if (filaExistente > 0) {
|
||||
// ACTUALIZAR
|
||||
encabezados.forEach((encabezado, i) => {
|
||||
if (i === indiceId) {
|
||||
hoja.getRange(filaExistente, i + 1).setValue(id);
|
||||
} else if (datos[encabezado] !== undefined) {
|
||||
hoja.getRange(filaExistente, i + 1).setValue(datos[encabezado]);
|
||||
}
|
||||
});
|
||||
return responderJSON({ ok: true, mensaje: "Registro actualizado" });
|
||||
}
|
||||
|
||||
// NUEVO
|
||||
const nuevaFila = encabezados.map((encabezado, i) => {
|
||||
if (i === indiceId) return id;
|
||||
return datos[encabezado] || "";
|
||||
});
|
||||
hoja.appendRow(nuevaFila);
|
||||
|
||||
return responderJSON({ ok: true, mensaje: "Registro guardado correctamente" });
|
||||
|
||||
} catch (error) {
|
||||
logDebug("ERROR doPost: " + error.message);
|
||||
return responderJSON({ error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
// ============ LOG DE DEPURACIÓN ============
|
||||
function logDebug(mensaje) {
|
||||
try {
|
||||
const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
|
||||
let hojaLog = ss.getSheetByName("Logs");
|
||||
if (!hojaLog) {
|
||||
hojaLog = ss.insertSheet("Logs");
|
||||
hojaLog.appendRow(["Fecha", "Mensaje"]);
|
||||
}
|
||||
hojaLog.appendRow([new Date(), mensaje]);
|
||||
} catch (e) {
|
||||
// Si no puede logear, ignora
|
||||
}
|
||||
}
|
||||
|
||||
// ============ BUSCAR COLUMNA ID ============
|
||||
// Encuentra el índice de la columna cuyo encabezado sea "id" sin importar mayúsculas.
|
||||
// Si no existe, devuelve -1 (el doPost se encarga de crearla al final).
|
||||
function indiceColumnaId(encabezados) {
|
||||
for (let i = 0; i < encabezados.length; i++) {
|
||||
if (String(encabezados[i]).trim().toLowerCase() === "id") return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ============ BUSCAR FILA POR ID ============
|
||||
// Busca el ID en la columna ID indicada. Devuelve el número de fila o 0 si no existe.
|
||||
function buscarFilaPorId(hoja, id, indiceColumnaId) {
|
||||
if (!id || indiceColumnaId === null || indiceColumnaId < 0) return 0;
|
||||
const ultimaFila = hoja.getLastRow();
|
||||
if (ultimaFila < 2) return 0; // solo encabezados
|
||||
|
||||
const columnaId = hoja.getRange(2, indiceColumnaId + 1, ultimaFila - 1, 1).getValues();
|
||||
for (let i = 0; i < columnaId.length; i++) {
|
||||
if (String(columnaId[i][0]).trim() === id.trim()) {
|
||||
return i + 2; // +2: fila 1 es encabezado, índice base 1
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ============ LISTAR IDs (para depurar) ============
|
||||
function listarIds(hoja, indiceColumnaId) {
|
||||
const ultimaFila = hoja.getLastRow();
|
||||
if (ultimaFila < 2) return "(hoja sin datos)";
|
||||
const valores = hoja.getRange(2, indiceColumnaId + 1, ultimaFila - 1, 1).getValues();
|
||||
return "[" + valores.map(v => "'" + String(v[0]) + "'").join(", ") + "]";
|
||||
}
|
||||
|
||||
// ============ FUNCIÓN AUXILIAR ============
|
||||
function responderJSON(objeto) {
|
||||
return ContentService
|
||||
.createTextOutput(JSON.stringify(objeto))
|
||||
.setMimeType(ContentService.MimeType.JSON);
|
||||
}
|
||||
Reference in New Issue
Block a user