Ejercicio: Panel del dueño con Google Sheets
Objetivo
Convertir un pedido del bot en una fila de hoja de cálculo, proteger la entrada con un secreto compartido y calcular los números que el dueño quiere ver en su panel. Todo se comprueba con funciones puras.
Cómo se trabaja
La parte A es práctica real con tu cuenta de Google (usa una hoja de prueba, nunca la de un cliente real). La parte B son funciones de JavaScript puro que se comprueban en esta página. Un pedido tiene la forma { id, telefono, items: [{ nombre, cantidad, precio }], total, entrega, direccion, pago, estado, creadoEn }, con creadoEn en milisegundos.
💡 Reto extra
Añade topProductos(filas, n) que lea la columna de productos ("2 x Leche; 1 x Arroz"), sume cantidades por producto entre todas las filas y devuelva los n más vendidos. Es el primer gráfico que le gustaría ver al dueño.
Pasos
Marca cada paso a medida que lo completes. Tu avance se guarda en este navegador.
💡 Pista 1: Orden de columnas
Fecha, Pedido, Telefono, Productos, Total, Entrega, Direccion, Pago, Estado: la fila es un arreglo con esos nueve valores en ese orden. items.map(...).join("; ") arma la columna de productos.
💡 Pista 2: Comparar el secreto sin romperse
Envuelve JSON.parse en try/catch. Después comprueba typeof datos.secreto === "string" y compara con ===. Recuerda devolver false si el secreto esperado es una cadena vacía.
💡 Pista 3: Sumar sin errores de decimales
Suma en céntimos: Math.round(total * 100) por fila, y divide entre 100 al final. Así 0.1 + 0.2 no te da 0.30000000000000004.
🔎 Comprueba tu trabajo
Pega tu código y pulsa Comprobar. La revisión ocurre en tu navegador; nada se envía a ningún sitio. Cada punto en rojo incluye una pista. Pega solo el JavaScript, sin las etiquetas <script>.
✅ Ver una solución posible
Intenta resolverlo antes de mirar. Tu versión puede ser distinta y también correcta.
function pedidoAFila(p) {
return [
new Date(p.creadoEn).toISOString(),
p.id,
p.telefono,
p.items.map((i) => `${i.cantidad} x ${i.nombre}`).join("; "),
p.total,
p.entrega,
p.direccion ?? "",
p.pago,
p.estado,
];
}
function autorizado(cuerpo, secreto) {
if (!secreto) return false;
let datos;
try { datos = JSON.parse(cuerpo); } catch { return false; }
return typeof datos?.secreto === "string" && datos.secreto === secreto;
}
function resumenDelDia(filas, dia) {
let pedidos = 0;
let centimos = 0;
for (const fila of filas) {
if (!String(fila[0]).startsWith(dia) || fila[8] === "cancelado") continue;
pedidos++;
centimos += Math.round(fila[4] * 100);
}
return { pedidos, total: centimos / 100 };
}
function porEstado(filas) {
const conteo = {};
for (const fila of filas) conteo[fila[8]] = (conteo[fila[8]] ?? 0) + 1;
return conteo;
}