diff --git a/services/manso/package-lock.json b/services/manso/package-lock.json index c775380..62c66bd 100644 --- a/services/manso/package-lock.json +++ b/services/manso/package-lock.json @@ -16,7 +16,8 @@ "express": "^5.1.0", "express-ejs-layouts": "^2.5.1", "pg": "^8.16.3", - "pg-format": "^1.0.4" + "pg-format": "^1.0.4", + "serve-favicon": "^2.5.1" }, "devDependencies": { "cross-env": "^10.0.0", @@ -1293,6 +1294,31 @@ "node": ">= 18" } }, + "node_modules/serve-favicon": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.1.tgz", + "integrity": "sha512-JndLBslCLA/ebr7rS3d+/EKkzTsTi1jI2T9l+vHfAaGJ7A7NhtDpSZ0lx81HCNWnnE0yHncG+SSnVf9IMxOwXQ==", + "license": "MIT", + "dependencies": { + "etag": "~1.8.1", + "fresh": "~0.5.2", + "ms": "~2.1.3", + "parseurl": "~1.3.2", + "safe-buffer": "~5.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-favicon/node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/serve-static": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", diff --git a/services/manso/package.json b/services/manso/package.json index 8b22432..0723c09 100644 --- a/services/manso/package.json +++ b/services/manso/package.json @@ -22,7 +22,8 @@ "express": "^5.1.0", "express-ejs-layouts": "^2.5.1", "pg": "^8.16.3", - "pg-format": "^1.0.4" + "pg-format": "^1.0.4", + "serve-favicon": "^2.5.1" }, "keywords": [], "description": "Workarround para tener un MVP que llegue al verano para usarse" diff --git a/services/manso/src/index.js b/services/manso/src/index.js index e0b1a01..651985e 100644 --- a/services/manso/src/index.js +++ b/services/manso/src/index.js @@ -1,5 +1,6 @@ // app/src/index.js import chalk from 'chalk'; // Colores! +import favicon from 'serve-favicon'; // Favicon import express from 'express'; import expressLayouts from 'express-ejs-layouts'; import cors from 'cors'; @@ -47,6 +48,14 @@ app.set("layout", "layouts/main"); // Archivos estáticos app.use(express.static(path.join(__dirname, "public"))); +app.use('/favicon', express.static(path.join(__dirname, 'public', 'favicon'), { + maxAge: '1y' +})); + +app.use(favicon(path.join(__dirname, 'public', 'favicon', 'favicon.ico'), { + maxAge: '1y' +})); + // ---------------------------------------------------------- // Configuración de conexión PostgreSQL // ---------------------------------------------------------- @@ -57,7 +66,6 @@ const dbConfig = { database: process.env.DB_NAME, port: process.env.DB_LOCAL_PORT ? Number(process.env.DB_LOCAL_PORT) : undefined, ssl: process.env.PGSSL === 'true' ? { rejectUnauthorized: false } : undefined, - max: 10 }; const pool = new Pool(dbConfig); @@ -393,25 +401,40 @@ app.get('/api/comandas', async (req, res, next) => { // Detalle de una comanda (con nombres de productos) -app.get('/api/comandas/:id/detalle', async (req, res, next) => { - try { - const id = parseInt(req.params.id, 10); - if (!Number.isInteger(id) || id <= 0) { - return res.status(400).json({ error: 'id inválido' }); - } - - const sql = ` - SELECT - id_det_comanda, id_producto, producto_nombre, - cantidad, pre_unitario, subtotal, observaciones - FROM public.v_comandas_detalle_items +// GET /api/comandas/:id/detalle +app.get('/api/comandas/:id/detalle', (req, res, next) => + pool.query( + `SELECT id_det_comanda, id_producto, producto_nombre, + cantidad, pre_unitario, subtotal, observaciones + FROM public.v_comandas_detalle_items WHERE id_comanda = $1::int - ORDER BY id_det_comanda - `; - const { rows } = await pool.query(sql, [id]); - res.json(rows); - } catch (e) { next(e); } -}); + ORDER BY id_det_comanda`, + [req.params.id] + ) + .then(r => res.json(r.rows)) + .catch(next) +); + + +// app.get('/api/comandas/:id/detalle', async (req, res, next) => { +// try { +// const id = parseInt(req.params.id, 10); +// if (!Number.isInteger(id) || id <= 0) { +// return res.status(400).json({ error: 'id inválido' }); +// } + +// const sql = ` +// SELECT +// id_det_comanda, id_producto, producto_nombre, +// cantidad, pre_unitario, subtotal, observaciones +// FROM public.v_comandas_detalle_items +// WHERE id_comanda = $1::int +// ORDER BY id_det_comanda +// `; +// const { rows } = await pool.query(sql, [id]); +// res.json(rows); +// } catch (e) { next(e); } +// }); // app.get('/api/comandas/:id/detalle', async (req, res, next) => { diff --git a/services/manso/src/public/favicon/android-chrome-192x192.png b/services/manso/src/public/favicon/android-chrome-192x192.png new file mode 100644 index 0000000..1210323 Binary files /dev/null and b/services/manso/src/public/favicon/android-chrome-192x192.png differ diff --git a/services/manso/src/public/favicon/android-chrome-512x512.png b/services/manso/src/public/favicon/android-chrome-512x512.png new file mode 100644 index 0000000..1b029ab Binary files /dev/null and b/services/manso/src/public/favicon/android-chrome-512x512.png differ diff --git a/services/manso/src/public/favicon/apple-touch-icon.png b/services/manso/src/public/favicon/apple-touch-icon.png new file mode 100644 index 0000000..4164fdb Binary files /dev/null and b/services/manso/src/public/favicon/apple-touch-icon.png differ diff --git a/services/manso/src/public/favicon/favicon-16x16.png b/services/manso/src/public/favicon/favicon-16x16.png new file mode 100644 index 0000000..eabf7e6 Binary files /dev/null and b/services/manso/src/public/favicon/favicon-16x16.png differ diff --git a/services/manso/src/public/favicon/favicon-32x32.png b/services/manso/src/public/favicon/favicon-32x32.png new file mode 100644 index 0000000..e98f802 Binary files /dev/null and b/services/manso/src/public/favicon/favicon-32x32.png differ diff --git a/services/manso/src/public/favicon/favicon.ico b/services/manso/src/public/favicon/favicon.ico new file mode 100644 index 0000000..c8e2059 Binary files /dev/null and b/services/manso/src/public/favicon/favicon.ico differ diff --git a/services/manso/src/public/favicon/site.webmanifest b/services/manso/src/public/favicon/site.webmanifest new file mode 100644 index 0000000..45dc8a2 --- /dev/null +++ b/services/manso/src/public/favicon/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/services/manso/src/views/comandas.ejs b/services/manso/src/views/comandas.ejs index 996abb3..df979d5 100644 --- a/services/manso/src/views/comandas.ejs +++ b/services/manso/src/views/comandas.ejs @@ -90,6 +90,123 @@ filtro: '' }; + // Genera el HTML del ticket de cocina (80mm aprox) + function buildKitchenTicketHTML(data) { + const mesaTxt = `Mesa #${data.mesa_numero ?? '—'}${data.mesa_apodo ? ' · ' + data.mesa_apodo : ''}`; + const obs = (data.observaciones && data.observaciones.trim()) ? data.observaciones.trim() : ''; + + const productosHtml = data.productos.map(p => ` +
+
x${p.cantidad}
+
${p.nombre}
+
+ `).join(''); + + return ` + + + + Ticket Cocina + + + +
+
COMANDA COCINA
+
#${data.id_comanda}
+
+ +
Fecha: ${data.fecha} ${data.hora}
+
${mesaTxt}
+
Mozo: ${data.usuario || '—'}
+ + ${obs ? `
OBSERVACIONES:
${obs}
` : ''} + +
+
PRODUCTOS
+ ${productosHtml} + +
+
Ítems: ${data.items} · Unidades: ${data.units}
+ +
— fin —
+
+ + + + diff --git a/services/manso/src/views/partials/_head.ejs b/services/manso/src/views/partials/_head.ejs index f664db4..10f17df 100644 --- a/services/manso/src/views/partials/_head.ejs +++ b/services/manso/src/views/partials/_head.ejs @@ -5,6 +5,14 @@ + + + + + + + +