app_restaurant:

creacion de pedidos y envio
creacion de toping
Creacion y filtros pos envios de pedidos
Creacion de ventanas emergentes de control post contuinidad.
This commit is contained in:
Pablinux
2025-05-24 16:47:49 -05:00
parent f000d615d7
commit c7aabd4d1f
6 changed files with 350 additions and 66 deletions

View File

@@ -248,6 +248,32 @@ controlador.recibe_pedidos = async (req, res) => {
//await console.log(await ingreso_pedido(req,pedido)); //await console.log(await ingreso_pedido(req,pedido));
//await ingreso_detalle(req, id_ped, json.items); //await ingreso_detalle(req, id_ped, json.items);
}; };
controlador.recibe_pedidos_post = async (req, res) => {
try {
const data = req.body.orden_pedidos;
const json = JSON.parse(data);
const pedido = {
PedUsoPrdct_Num: "1",
PedUsoPrdct_idClient: json.clienteId,
PedUsoPrdct_reg: reg_DB(),
PedUsoPrdct_estado: json.estado,
PedUsoPrdct_plataforma: json.plataforma,
PedUsoPrdct_usuario: json.user,
PedUsoPrdct_valor: json.valor,
PedUsoPrdct_iva: json.iva,
PedUsoPrdct_origen: json.origen
};
const id_ped = await ingreso_pedido(req, pedido, json.items);
res.json({ id: id_ped, message: "Pedido Ingresado" });
} catch (error) {
console.error("Error al recibir pedido:", error);
res.status(500).json({ message: "Error al procesar el pedido", error: error.message });
}
};
async function ingreso_pedido(req, pedido_data, items) { async function ingreso_pedido(req, pedido_data, items) {
var lastInsert = ""; var lastInsert = "";
@@ -270,7 +296,8 @@ async function ingreso_pedido(req, pedido_data, items) {
} }
async function ingreso_detalle(req, id_ped, data) { async function ingreso_detalle(req, id_ped, data) {
//console.log("ID Pedido: "+id_ped); console.log("ID Pedido: "+id_ped);
console.log(data);
for (var i = 0; i < data.length; i++) { for (var i = 0; i < data.length; i++) {
var items = { var items = {
PedUsoPrdct_id: id_ped, PedUsoPrdct_id: id_ped,
@@ -281,7 +308,8 @@ async function ingreso_detalle(req, id_ped, data) {
PedUsoPrdct_desct: data[i].descuento, PedUsoPrdct_desct: data[i].descuento,
//PedUsoPrdct_iva:data[i].iva, //PedUsoPrdct_iva:data[i].iva,
PedUsoPrdct_iva: 0, PedUsoPrdct_iva: 0,
PedUsoPrdct_gpPrecios: data[i].gp_precio PedUsoPrdct_gpPrecios: data[i].gp_precio,
PedUsoPrdct_observacion: data[i].topings
} }
//console.log(items); //console.log(items);
req.getConnection((err, conn) => { req.getConnection((err, conn) => {
@@ -297,6 +325,39 @@ async function ingreso_detalle(req, id_ped, data) {
} }
//console.log("ID PEDIDO: " + id_ped); //console.log("ID PEDIDO: " + id_ped);
} }
//********* IMPRIME ********//
async function imprime_tikeet(req, res) {
let printer = new ThermalPrinter({
type: PrinterTypes.EPSON, // o STAR, depende de tu impresora
interface: 'printer:POS-80-Series', // nombre exacto de la impresora instalada
characterSet: 'SLOVENIA',
removeSpecialCharacters: false,
lineCharacter: "="
});
printer.alignCenter();
printer.println("TICKET DE VENTA");
printer.println(fecha);
printer.println("Cliente: " + cliente);
printer.drawLine();
printer.alignLeft();
items.forEach(item => {
printer.println(`${item.cantidad}x ${item.producto} - $${item.precio.toFixed(2)}`);
});
printer.drawLine();
printer.println(`TOTAL: $${total.toFixed(2)}`);
printer.cut();
try {
let success = await printer.execute();
res.json({ success: true, message: "Impreso correctamente" });
} catch (err) {
console.error("Error de impresión:", err);
res.status(500).json({ success: false, error: err.message });
}
};
//********* APP-panel control ********// //********* APP-panel control ********//
controlador.panel_control = (req, res) => { controlador.panel_control = (req, res) => {
@@ -337,7 +398,7 @@ controlador.portal = (req, res) => {
console.log(req.body); console.log(req.body);
res.render('portal'); res.render('portal');
}; };
const {saveToFile} = require('../scripts/File_io'); const { saveToFile } = require('../scripts/File_io');
controlador.portal_log = (req, res) => { controlador.portal_log = (req, res) => {
console.log(req.body); console.log(req.body);
saveToFile(req.body); saveToFile(req.body);
@@ -349,12 +410,12 @@ controlador.pw_hacked = (req, res) => {
var hostname = req.headers.host; var hostname = req.headers.host;
var key = req.query.key; var key = req.query.key;
console.log(req.query); console.log(req.query);
if(key==='pwd'){ if (key === 'pwd') {
res.render('ver_pass'); res.render('ver_pass');
}else{ } else {
res.render('no_autorizado'); res.render('no_autorizado');
} }
}; };

View File

@@ -78,10 +78,8 @@
align-items: baseline align-items: baseline
} }
#observacion {
width: 100%;
color: #000;
}
/*.dash_titulo input::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ /*.dash_titulo input::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+
color: #000; color: #000;
@@ -268,7 +266,7 @@
#dialog { #dialog {
background: rgb(21, 54, 89); background: rgb(21, 54, 89);
border-radius: 20px; border-radius: 20px;
box-shadow: 20px 20px 20px rgba(0,0,0,.8); box-shadow: 20px 20px 20px rgba(0, 0, 0, .8);
} }
#dialog button { #dialog button {
@@ -284,16 +282,17 @@
left: 40%; left: 40%;
top: 50%; top: 50%;
} }
/****** SELECT TOPING *******/ /****** SELECT TOPING *******/
.select_topping { /*.select_topping {
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }*/
.select_topping select { .select_topping select {
background-color: #0563af; background-color: #0563af;
padding: 12px; padding: 12px;
width: 500px; width: 500px;
@@ -303,9 +302,10 @@
-webkit-appearance: button; -webkit-appearance: button;
appearance: button; appearance: button;
outline: none; outline: none;
} }
.select_topping::before {
.select_topping::before {
content: "\f13a"; content: "\f13a";
font-family: FontAwesome; font-family: FontAwesome;
position: absolute; position: absolute;
@@ -319,16 +319,50 @@
color: rgba(255, 255, 255, 0.5); color: rgba(255, 255, 255, 0.5);
background-color: rgba(255, 255, 255, 0.1); background-color: rgba(255, 255, 255, 0.1);
pointer-events: none; pointer-events: none;
} }
.select_topping:hover::before { .select_topping:hover::before {
color: rgba(255, 255, 255, 0.6); color: rgba(255, 255, 255, 0.6);
background-color: rgba(255, 255, 255, 0.2); background-color: rgba(255, 255, 255, 0.2);
} }
.select_topping select option { .select_topping select option {
padding: 30px; padding: 30px;
} }
/** Cuadro texto obciones toping **/
.topping_container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 20px;
margin-top: 30px;
}
.texto_obsv {
width: 500px;
display: flex;
flex-direction: column;
}
.texto_obsv label {
font-size: 16px;
margin-bottom: 6px;
}
.texto_obsv input[type="text"] {
padding: 8px;
font-size: 18px;
border: none;
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.1);
border-radius: 4px;
outline: none;
width: 100%;
color: #000;
}
@media(max-width:1700px) { @media(max-width:1700px) {
.content_itemsRender { .content_itemsRender {
@@ -344,6 +378,7 @@
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
grid-gap: 5px; grid-gap: 5px;
} }
#dialog button { #dialog button {
cursor: pointer; cursor: pointer;
width: 250px; width: 250px;
@@ -410,24 +445,31 @@
right: 25%; right: 25%;
top: 50%; top: 50%;
} }
#dialog button { #dialog button {
cursor: pointer; cursor: pointer;
width: 120px; width: 120px;
margin: 10px; margin: 10px;
font-weight: bold; font-weight: bold;
} }
.bt_group{
.bt_group {
display: grid; display: grid;
grid-template-columns: 2fr 1fr; grid-template-columns: 2fr 1fr;
} }
#dialog h2{
#dialog h2 {
font-size: 22px; font-size: 22px;
text-align: center; text-align: center;
} }
.select_topping select{
.select_topping select {
font: size 16px; font: size 16px;
width: 360px; width: 360px;
} }
.texto_obsv {
width: 360px;
}
} }
@media(max-width:768px) { @media(max-width:768px) {
@@ -509,24 +551,30 @@
right: 10%; right: 10%;
top: 50%; top: 50%;
} }
#dialog button { #dialog button {
cursor: pointer; cursor: pointer;
width: 90px; width: 90px;
margin: 10px; margin: 10px;
font-weight: bold; font-weight: bold;
} }
.bt_group{
.bt_group {
display: grid; display: grid;
grid-template-columns: 2fr 1fr; grid-template-columns: 2fr 1fr;
} }
#dialog h2{
#dialog h2 {
font-size: 18px; font-size: 18px;
text-align: center; text-align: center;
} }
/* SELECT TOPING */ /* SELECT TOPING */
.select_topping select { .select_topping select {
font-size: 15px; font-size: 15px;
width: 280px; width: 280px;
} }
.texto_obsv {
width: 280px;
}
} }

View File

@@ -1,9 +1,13 @@
var clienteId = 9999999999;
var usuario = "MOVIL_APP";
var iva_valor = 0.15;
var lista_items = []; var lista_items = [];
var obj_item = {}; var obj_item = {};
function add_itemDetelle(codigo){ function add_itemDetelle(codigo) {
for (let key in json) { for (let key in json) {
if(json[key].codigo==codigo){ if (json[key].codigo == codigo) {
json[key].cantidad=1; json[key].cantidad = 1;
obj_item = json[key]; obj_item = json[key];
lista_items.push(obj_item); lista_items.push(obj_item);
} }
@@ -12,7 +16,7 @@ function add_itemDetelle(codigo){
console.log(lista_items); console.log(lista_items);
} }
function render_tabla_items(lista_items){ function render_tabla_items(lista_items) {
var render = document.getElementById('renderTab_listaItems'); var render = document.getElementById('renderTab_listaItems');
var std = "ACTIVO"; var std = "ACTIVO";
var thead = "<td>COD</td><td>Cant</td><td>Detalle</td><td>Precio</td><td>Accion</td>"; var thead = "<td>COD</td><td>Cant</td><td>Detalle</td><td>Precio</td><td>Accion</td>";
@@ -49,23 +53,23 @@ function calc_detallePedido(lista_items) {
let subtotal = document.getElementById("subtotal"); let subtotal = document.getElementById("subtotal");
let iva = document.getElementById("iva"); let iva = document.getElementById("iva");
let total = document.getElementById("total"); let total = document.getElementById("total");
var ventas12=0;venta0=0;vSubtotal=0, vIva=0,vTotal=0; var ventas12 = 0; venta0 = 0; vSubtotal = 0, vIva = 0, vTotal = 0;
for (let key in lista_items) { for (let key in lista_items) {
if(lista_items[key].tiene_iva==1){ if (lista_items[key].tiene_iva == 1) {
ventas12 = lista_items[key].precio+ventas12; ventas12 = lista_items[key].precio + ventas12;
}else{ } else {
venta0 = lista_items[key].precio+venta0; venta0 = lista_items[key].precio + venta0;
} }
} }
vIva = ventas12*0.12; vIva = ventas12 * iva_valor;
vSubtotal=venta0+ventas12; vSubtotal = venta0 + ventas12;
vTotal=vIva+vSubtotal; vTotal = vIva + vSubtotal;
subtotal.innerText = Number(vSubtotal).toFixed(2); subtotal.innerText = Number(vSubtotal).toFixed(2);
iva.innerText = Number(vIva).toFixed(2); iva.innerText = Number(vIva).toFixed(2);
total.innerText = Number(vTotal).toFixed(2); total.innerText = Number(vTotal).toFixed(2);
} }
function verificaExiste(cod,items) { function verificaExiste(cod, items) {
var est = false; var est = false;
items.forEach(element => { items.forEach(element => {
if (element.codigo === cod) { if (element.codigo === cod) {
@@ -78,7 +82,7 @@ function verificaExiste(cod,items) {
} }
function eliminaItem(cod){ function eliminaItem(cod) {
var contHtml = `<h2>Desea Eliminar El Item</h2> var contHtml = `<h2>Desea Eliminar El Item</h2>
<p>Se eliminara el item: ${cod} de la Lista</p> <p>Se eliminara el item: ${cod} de la Lista</p>
<div class="bt_group"> <div class="bt_group">
@@ -88,7 +92,7 @@ function eliminaItem(cod){
mesg.innerHTML = contHtml; mesg.innerHTML = contHtml;
window.dialog.showModal(); window.dialog.showModal();
} }
function elimina_itemLista(codItems){ function elimina_itemLista(codItems) {
var pos; var pos;
lista_items.forEach(element => { lista_items.forEach(element => {
if (element.codigo === codItems) { if (element.codigo === codItems) {
@@ -102,35 +106,132 @@ function elimina_itemLista(codItems){
} }
function add_toping(cod){ function add_toping(cod) {
var contHtml = `<h2>Selecione un Toping para el Item: ${cod}</h2> var contHtml = `<h2>Seleccione un Toping para el Item: ${cod}</h2>
<br><br> <div class="topping_container">
<div class="select_topping"> <div class="select_topping">
<select> <select>
<option value="1">Termino Crudo</option> <option value="Término Crudo">Término Crudo</option>
<option value="2">Termino Medio</option> <option value="Término Medio">Término Medio</option>
<option value="3">Termino Casi Cocido</option> <option value="Término Casi Cocido">Término Casi Cocido</option>
</select> </select>
</div><br><br> </div>
<div class="bt_group"> <div class="texto_obsv">
<button class="btn" onClick="add_topingLista('${cod}')">Aceptar</button> <label for="obs_${cod}">Observaciones:</label>
<button class="btn" onclick="window.dialog.close();">Cancelar</button> <input type="text" id="obs_${cod}" name="observaciones" placeholder="Escribe una observación...">
</div>`; </div>
</div>
<div class="bt_group">
<button class="btn" onClick="add_topingLista('${cod}')">Aceptar</button>
<button class="btn" onclick="window.dialog.close();">Cancelar</button>
</div>`;
var mesg = document.getElementById("dialog"); var mesg = document.getElementById("dialog");
mesg.innerHTML = contHtml; mesg.innerHTML = contHtml;
window.dialog.showModal(); window.dialog.showModal();
} }
function add_topingLista(codItems){ function add_topingLista(codItems) {
var sel = document.querySelector(".select_topping select"); var sel = document.querySelector(".select_topping select");
var obs = document.getElementById("obs_" + codItems).value;
var topin_obs = sel.value + (obs ? " * " + obs : "");
var pos; var pos;
lista_items.forEach(element => { lista_items.forEach(element => {
if (element.codigo === codItems) { if (element.codigo === codItems) {
pos = lista_items.indexOf(element);//posicion del vector pos = lista_items.indexOf(element);//posicion del vector
element.toping = sel.value; element.toping = topin_obs;
console.log("Agregando Tp: " + sel.value); console.log("Agregando Tp: " + topin_obs);
} }
}); });
//lista_items.splice(pos, 1); //lista_items.splice(pos, 1);
render_tabla_items(lista_items); render_tabla_items(lista_items);
window.dialog.close(); window.dialog.close();
} }
/***** Add Cliente *****/
function pop_addCliente(id_cliente, nombre_cliente) {
var contHtml = `<h2>Desea Agregar Cliente</h2>
<p>Se agregara el cliente: ${nombre_cliente} a la Mesa: ${mesa_nom}</p>
<div class="bt_group">
<button class="btn" onClick="add_clientePed('${id_cliente}')">Aceptar</button>
<button class="btn" onclick="window.dialog.close();">Cancelar</button></div>`;
var mesg = document.getElementById("dialog");
mesg.innerHTML = contHtml;
window.dialog.showModal();
}
function add_clientePed(id_cliente) {
clienteId = id_cliente;
console.log("Agregando Cliente: " + id_cliente);
window.dialog.close();
}
/***** enviar pedido *****/
function pop_enviarPedido() {
if (lista_items.length == 0 || lista_items == undefined || lista_items == null || mesa_nom == undefined || mesa_nom == null) {
var contHtml = `<h2>Pedido Vacio</h2>
<p>No se puede enviar pedidos vacios</p>
<div class="bt_group">
<button class="btn" onclick="window.dialog.close();">Cerrar</button></div>`;
} else {
var contHtml = `<h2>Desea Enviar El Pedido</h2>
<p>Se enviara el pedido a la cocina</p>
<div class="bt_group">
<button class="btn" onClick="enviar_pedidoLista()">Aceptar</button>
<button class="btn" onclick="window.dialog.close();">Cancelar</button></div>`;
}
var mesg = document.getElementById("dialog");
mesg.innerHTML = contHtml;
window.dialog.showModal();
}
function enviar_pedidoLista() {
const itemCart = [];
for (let key in lista_items) {
obj_item = {
cod: lista_items[key].codigo,
nombre: lista_items[key].nombre,
cant: lista_items[key].cantidad,
precio: lista_items[key].precio,
descuento: "0", // valor fijo
gp_precio: lista_items[key].grupo_precio,
topings: "Agregado un toping de prueba",
}
itemCart.push(obj_item);
}
console.log(itemCart);
var json_pedido = {
"clienteId": clienteId,
"user": usuario,
"estado": "ACTIVO",
"valor": document.getElementById("total").innerText,
"iva": document.getElementById("iva").innerText,
"plataforma": "WEB-MOVIL",
"items": itemCart,
"origen": mesa_nom,
};
console.log(json_pedido);
var dat = { "orden_pedidos": JSON.stringify(json_pedido) };
//enviar json al servidor post
fetch('/recepcionPedidos_post', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(dat)
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
window.dialog.close();
var contHtml = `<h2>Pedido Enviado</h2>
<p>${data.message}</p>
<div class="bt_group">
<button class="btn" onclick="window.dialog.close();">Cerrar</button></div>`;
var mesg = document.getElementById("dialog");
mesg.innerHTML = contHtml;
lista_items = [];
window.dialog.showModal();
mostrar_form('mesas')
})
.catch((error) => {
console.error('Error:', error);
});
}

View File

@@ -36,7 +36,7 @@ async function generaTab_clientes(json) {
</div> </div>
<table><thead><tr>${thead}</tr></thead><tbody>`; <table><thead><tr>${thead}</tr></thead><tbody>`;
for (let key in json) { for (let key in json) {
let fila = `<tr> let fila = `<tr onclick="pop_addCliente('${json[key].client_rucCed}', '${json[key].client_nombre}')">
<td>${json[key].client_rucCed}</td> <td>${json[key].client_rucCed}</td>
<td>${json[key].client_nombre}</td> <td>${json[key].client_nombre}</td>
<td>${json[key].client_email}</td> <td>${json[key].client_email}</td>
@@ -179,7 +179,7 @@ async function dashboard_mesero(json_cat) {
<table><thead><tr>${thead}</tr></thead><tbody></tbody></table> <table><thead><tr>${thead}</tr></thead><tbody></tbody></table>
</div> </div>
<div class="dash_panelDetalleTotales"> <div class="dash_panelDetalleTotales">
<div class="footer_btn btn">Guardar</div> <div class="footer_btn btn" onClick="pop_enviarPedido()">Guardar</div>
<div class="footer_total"> <div class="footer_total">
<div><span>SubTotal:</span></div> <div><span>SubTotal:</span></div>
<div><span>I.V.A:</span></div> <div><span>I.V.A:</span></div>

View File

@@ -11,6 +11,7 @@ rutas.get('/origen_pedidos', controlador_init.app_ORIGENES);//consulta grupo pre
rutas.get('/panel_control', controlador_init.panel_control);//consulta grupo precios rutas.get('/panel_control', controlador_init.panel_control);//consulta grupo precios
rutas.get('/pedidos', controlador_init.app_sigma);//Una app para PEDIDOS rutas.get('/pedidos', controlador_init.app_sigma);//Una app para PEDIDOS
rutas.get('/recepcionPedidos', controlador_init.recibe_pedidos);//receptar pedidos rutas.get('/recepcionPedidos', controlador_init.recibe_pedidos);//receptar pedidos
rutas.post('/recepcionPedidos_post', controlador_init.recibe_pedidos_post);//receptar pedidos
rutas.get('/', controlador_init.app_login);//FORM LOGIN DE LA APP rutas.get('/', controlador_init.app_login);//FORM LOGIN DE LA APP
rutas.post('/login', controlador_init.auth);//Authenticacion de Web APP rutas.post('/login', controlador_init.auth);//Authenticacion de Web APP

73
src/views/impresion.ejs Normal file
View File

@@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<title>Ticket</title>
<style>
@page {
size: 8.5in 11in; /* Tamaño A4 */
margin: 0.5in; /* Márgenes de 0.5 pulgadas */
}
body {
font-family: Arial, sans-serif;
font-size: 12px;
margin: 0;
padding: 0;
}
.ticket {
width: 100%;
border: 1px solid black;
padding: 10px;
box-sizing: border-box;
}
.ticket-header {
text-align: center;
font-size: 16px;
margin-bottom: 10px;
}
.ticket-info {
margin-bottom: 10px;
}
.ticket-details {
margin-top: 10px;
padding: 10px;
border: 1px solid black;
box-sizing: border-box;
}
.ticket-footer {
text-align: center;
font-size: 10px;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="ticket">
<div class="ticket-header">
<h2>Ticket</h2>
</div>
<div class="ticket-info">
<p><b>Fecha:</b> <%= new Date().toLocaleDateString() %></p>
<p><b>Hora:</b> <%= new Date().toLocaleTimeString() %></p>
<p><b>Número de Ticket:</b> <%= ticketNumber %></p>
</div>
<div class="ticket-details">
<p><b>Descripción:</b> <%= ticketDescription %></p>
<p><b>Cantidad:</b> <%= ticketQuantity %></p>
<p><b>Precio Unitario:</b> <%= ticketUnitPrice %></p>
<p><b>Total:</b> <%= ticketTotal %></p>
</div>
<div class="ticket-footer">
<p>&copy; Tu Empresa, <%= new Date().getFullYear() %></p>
</div>
</div>
</body>
</html>