refactor:alteração modal de add product na comanda

This commit is contained in:
2025-06-30 18:08:37 -03:00
parent 7dd76db5ba
commit 377fac4f1c
12 changed files with 200 additions and 162 deletions

View File

@@ -6,7 +6,7 @@ from django.shortcuts import render, redirect
from comandas.models import Comanda, ProductComanda
from orders.models import Order
from products.models import Product
from payments.models import Payments
from payments.models import Payments, somar
from typePay.models import TypePay
from gestaoRaul.decorators import group_required
from websocket_client.websocketClient import enviar_mensagem
@@ -29,80 +29,6 @@ from asgiref.sync import async_to_sync
# print(f"Erro ao enviar mensagem via websocket: {e}")
def somar(consumo:ProductComanda, comanda:Comanda):
parcial = Payments.objects.filter(comanda=comanda)
totalParcial = Decimal(0)
total:Decimal = Decimal(0)
for p in parcial:
totalParcial += p.value
for produto in consumo:
total += Decimal(produto.product.price)
valores = {
'total':total,
'parcial':totalParcial,
'taxa': round(total * Decimal(0.1), 2),
'totalSemTaxa':total - totalParcial,
'totalComTaxa': round((total - totalParcial)+(total * Decimal(0.1)),2)
}
return valores
def listProduct(request, comanda_id):
product = request.GET.get("search-product")
allProducts = Product.objects.filter(name__icontains=product)
products = []
for p in allProducts:
if p.active == True:
products.append(p)
return render(request, "htmx_components/comandas/htmx_list_products.html", {"products": products,'comanda_id':comanda_id})
@group_required(groupName='Garçom')
def addProduct(request, product_id, comanda_id):
config = {
'taxa': False
}
obs = request.GET.get("obs")
product_comanda = ProductComanda(comanda_id=comanda_id, product_id=product_id)
product_comanda.save()
product = Product.objects.get(id=product_id)
comanda = Comanda.objects.get(id=comanda_id)
parcial = Payments.objects.filter(comanda=comanda)
if product.cuisine == True:
order = Order(id_comanda=comanda, id_product=product, productComanda=product_comanda, obs='')
order.save()
msg = JsonResponse({
'type': 'broadcast',
'message': f"""
<div class="m-card" id="m-card-{order.id}">
<h4>{product.name}</h4>
<h4 id="obs-{order.id}"> {order.obs}</h4>
<h4>{comanda.name} - {comanda.mesa.name}</h4>
<h4> {order.queue.strftime("%d/%m/%Y - %H:%M")}</h4>
<h4> Atendente: {comanda.user.first_name}</h4>
<form method="path" action="/pedidos/preparing/{order.id}/">
<button class="btn-primary" type="submit">Preparar</button>
</form>
</div>
""",
'local':'cozinha',
'tipo':'add',
'id':order.id,
'speak': f'Novo pedido! {product.name}, para {comanda.name}.'
})
try:
# Chama a função async dentro da view normal
async_to_sync(enviar_mensagem)(mensagem)
# return JsonResponse({"status": "Mensagem enviada com sucesso"})
except Exception as e:
print("Erro add product websocket: ",e)
# return JsonResponse({"status": "Erro", "erro": str(e)}, status=500)
# asyncio.run(enviar_mensagem(msg))
consumo = ProductComanda.objects.filter(comanda=comanda_id)
valores = somar(consumo,comanda)
return render(request, "htmx_components/comandas/htmx_list_products_in_comanda.html",{'config':config, 'valores':valores,'parcials':parcial,'consumo': consumo,'comanda':comanda})
@group_required(groupName='Garçom')

View File

@@ -13,6 +13,16 @@ Detalhes {{comanda.name}}
{% block 'head' %}
<link rel="stylesheet" href="{% static 'comandas/css/viewcomanda.css' %}">
<style>
.swal2-popup {
position: relative; /* Necessário para o posicionamento absoluto do botão */
}
.posi {
position: absolute !important;
top: 0.5em;
right: 0.5em;
}
</style>
{% endblock %}
@@ -22,7 +32,7 @@ Detalhes {{comanda.name}}
<input hidden id="id-temp" type="number">
<div class="grid-container" >
<div style="display: flex;padding: 5px;gap:8px">
<button class="btn-primary" id="openModal" onclick="openModal()" popovertarget="addProduct"
<button class="btn-primary" id="openModal" onclick="openModal()"
{% if comanda.status != 'OPEN'%}
disabled
{% endif %}
@@ -71,6 +81,7 @@ Detalhes {{comanda.name}}
</div>
<div>
<input hidden type="text" id="h-mesaId" value="{{comanda.mesa.id}}">
<input hidden type="text" id="id-comanda" value="{{comanda.id}}">
<span id="name-comanda">Nome: {{comanda.name}} | </span>
<span id="mesa-comanda">Local: {{comanda.mesa}}</span>
@@ -173,17 +184,13 @@ Detalhes {{comanda.name}}
<div id="addProduct" popover class="popover">
<div id="toast-add" class="toast-add">
<p id="toast-message-add"></p>
</div>
<form id="productForm" >
<div style="display: flex;justify-content: space-between;">
<h2>Adicionar Produto</h2> <img class="close" src="{% static 'midia/icons/close-circle.svg' %}" onclick="closeModal()">
</div>
<div id="addProduct" class="popover">
<!-- <div id="productForm" > -->
{% csrf_token %}
<input type="text" id="search-product" name="search-product" placeholder="Buscar Produto" hx-get="{% url 'listProduct' comanda.id %}" hx-trigger="keyup" hx-target="#product-list"><br>
<input type="text" oninput="searchProduct()" id="search-product" name="search-product" placeholder="Buscar Produto" ><br>
<div id="product-list" class="grid-list-products">
{% for product in products %}
<div class="card-product" onclick="addProductComanda({{product.id}}, {{comanda.id}}, '{{product.cuisine}}')" >
@@ -192,7 +199,7 @@ Detalhes {{comanda.name}}
</div >
{% endfor %}
</div>
</form>
<!-- </div> -->
</div>

View File

@@ -13,6 +13,8 @@ urlpatterns = [
path('notificacao/', views.notificacao, name='notificacao'),
path('editOrders/<int:productComanda_id>/<str:obs>', views.editOrders, name='editOrders'),
path('closeComanda/<int:comanda_id>/', views.closeComanda, name='closeComanda'),
path('listProduct/<int:comanda_id>/<str:product>/', views.listProduct, name='listProduct'),
path('product=<int:product_id>/comanda=<int:comanda_id>/', views.addProduct, name='addProduct'),
@@ -20,9 +22,6 @@ urlpatterns = [
htmx_urlpatterns = [
# path('listProduct/', htmx_views.listProduct, name='listProduct'),
path('listProduct/<int:comanda_id>/', htmx_views.listProduct, name='listProduct'),
path('addProduct<int:product_id>/<int:comanda_id>/', htmx_views.addProduct, name='addProduct'),
path('removeProductComanda<int:productComanda_id>/', htmx_views.removeProductComanda, name='removeProductComanda'),
path('reopenComanda<int:comanda_id>/', htmx_views.reopenComanda, name='reopenComanda'),
path('paymentComanda<int:comanda_id>/', htmx_views.paymentComanda, name='paymentComanda'),

View File

@@ -23,23 +23,6 @@ def comandas(request):
return render(request, 'comandas.html', {'comandas': comandas, 'mesas': mesas})
# def somar(consumo:ProductComanda, comanda:Comanda):
# parcial = Payments.objects.filter(comanda=comanda)
# totalParcial = Decimal(0)
# total:Decimal = Decimal(0)
# for p in parcial:
# totalParcial += p.value
# for produto in consumo:
# total += Decimal(produto.product.price)
# valores = {
# 'total':total,
# 'parcial':totalParcial,
# 'taxa': round(total * Decimal(0.1), 2),
# 'totalSemTaxa':total - totalParcial,
# 'totalComTaxa': round((total - totalParcial)+(total * Decimal(0.1)),2)
# }
# return valores
@group_required(groupName='Garçom')
def viewComanda(request):
config = {
@@ -167,3 +150,61 @@ def closeComanda(request, comanda_id):
comanda.status = "PAYING"
comanda.save()
return JsonResponse({'status': 'ok', 'obs':'order.obs'})
@group_required(groupName='Garçom')
def addProduct(request, product_id, comanda_id):
config = {
'taxa': False
}
obs = request.GET.get("obs")
product_comanda = ProductComanda(comanda_id=comanda_id, product_id=product_id)
product_comanda.save()
product = Product.objects.get(id=product_id)
comanda = Comanda.objects.get(id=comanda_id)
parcial = Payments.objects.filter(comanda=comanda)
if product.cuisine == True:
order = Order(id_comanda=comanda, id_product=product, productComanda=product_comanda, obs='')
order.save()
msg = JsonResponse({
'type': 'broadcast',
'message': f"""
<div class="m-card" id="m-card-{order.id}">
<h4>{product.name}</h4>
<h4 id="obs-{order.id}"> {order.obs}</h4>
<h4>{comanda.name} - {comanda.mesa.name}</h4>
<h4> {order.queue.strftime("%d/%m/%Y - %H:%M")}</h4>
<h4> Atendente: {comanda.user.first_name}</h4>
<form method="path" action="/pedidos/preparing/{order.id}/">
<button class="btn-primary" type="submit">Preparar</button>
</form>
</div>
""",
'local':'cozinha',
'tipo':'add',
'id':order.id,
'speak': f'Novo pedido! {product.name}, para {comanda.name}.'
})
try:
# Chama a função async dentro da view normal
async_to_sync(enviar_mensagem)(mensagem)
# return JsonResponse({"status": "Mensagem enviada com sucesso"})
except Exception as e:
print("Erro add product websocket: ",e)
# return JsonResponse({"status": "Erro", "erro": str(e)}, status=500)
# asyncio.run(enviar_mensagem(msg))
consumo = ProductComanda.objects.filter(comanda=comanda_id)
valores = somar(consumo,comanda)
return render(request, "htmx_components/comandas/htmx_list_products_in_comanda.html",{'config':config, 'valores':valores,'parcials':parcial,'consumo': consumo,'comanda':comanda})
def listProduct(request, comanda_id, product):
allProducts = Product.objects.filter(name__icontains=product)
products = []
for p in allProducts:
if p.active == True:
products.append(p)
return render(request, "htmx_components/comandas/htmx_list_products.html", {"products": products,'comanda_id':comanda_id})

Binary file not shown.

View File

@@ -3,11 +3,9 @@
{% for product in products %}
<div
onclick="addProductComanda({{product.id}})"
onclick="addProductComanda({{product.id}}, {{comanda_id}}, '{{product.cuisine}}')"
class="card-product"
hx-get="{% url 'addProduct' product.id comanda_id %} "
hx-trigger="click"
hx-target="#list-products-comanda">
>
{{product.name}} <br>
R$ {{product.price}}
</div>

View File

@@ -178,7 +178,6 @@ function openFullscreen() {
function feedback(message, icon, subMessage) {
console.log(subMessage)
var feedbackMsg = Swal.fire({
color: 'white',
title: message,
@@ -189,5 +188,6 @@ function openFullscreen() {
background: 'rgb(23, 38, 54)',
confirmButtonColor: 'linear-gradient(145deg, #1E2A3B, #2C3E50)',
});
return feedbackMsg;
}

View File

@@ -53,6 +53,7 @@
}
.popover{
display: none;
position: relative;
width: 98%;
height: 96%;

View File

@@ -1,23 +1,52 @@
async function openModal() {
var htmlModal = document.getElementById('addProduct').innerHTML
htmlModal = htmlModal.replace('search-product','search-product-modal')
htmlModal = htmlModal.replace('product-list','product-list-modal')
const { value: formValues } = await Swal.fire({
title: "Adicionar Produto",
html: htmlModal,
width: '100em',
theme: "dark",
didOpen: () => {
Swal.getPopup().classList.add('swal2-noautoclose');
},
showConfirmButton: false,
showCancelButton: true,
cancelButtonText: '&times;',
customClass:{
cancelButton:'posi'
},
focusConfirm: false,
});
function openModal() {
textField = document.getElementById('search-product')
if (textField) {
}
function searchProduct() {
setTimeout(() => {
textField.focus();
}, 500);
}
textField.value = '';
}
time();
}, 100);
function time(){
var search_product = document.getElementById('search-product-modal').value.trim()
var productListElement = document.getElementById("product-list-modal");
var comanda_id = document.getElementById("id-comanda").value;
if(search_product.length == 0 ){search_product ='*';}
fetch(`/comandas/listProduct/${comanda_id}/${search_product}`, {
method: 'GET',}
).then(function(response) {
return response.text();
}).then(function(text) {
productListElement.innerHTML = text;
function closeModal() {
var popover = document.getElementById('addProduct');
popover.hidePopover()
})}
}
function openModalAlter() {
document.getElementById('Modal-alter-comanda').style.display = 'block';
var name = document.getElementById('name-comanda').innerText.replace('Nome: ','').replace(' | ', '')
@@ -328,43 +357,80 @@ function addOrder(id, obs){
}
function showToastAdd(message, type ,duration = 3000) {
const toast = document.getElementById('toast-add');
if (type === 'success') {
toast.style.backgroundColor = '#28a745';
} else if (type === 'error') {
toast.style.backgroundColor = '#dc3545';
} else if (type === 'info') {
toast.style.backgroundColor = '#ffc107';
async function addProductComanda(productId, comandaId, cuisine) {
try {
if (!productId || !comandaId) {
throw new Error('IDs de produto ou comanda inválidos');
}
const toastMessage = document.getElementById('toast-message-add');
toastMessage.textContent = message;
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, duration);
const csrfToken = document.querySelector('[name="csrfmiddlewaretoken"]').value
if (!csrfToken) {
throw new Error('Token de segurança não encontrado');
}
function addProductComanda(productId,comandaId, cuisine) {
obs = document.getElementById('obs');
if(cuisine == 'ggg'){
var obs = openModalObs();
}else{
fetch(`/comandas/addProduct${productId}/${comandaId}`, {
method: 'GET',
// if (cuisine === 'ggg') {
// openModalObs();
// return;
// }
// Mostra estado de carregamento
Swal.update({
title: '<span style="color: white;">Adicionando produto...</span>',
});
// Requisição POST
const response = await fetch(`/comandas/product=${productId}/comanda=${comandaId}/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'}
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({
product_id: productId,
comanda_id: comandaId
})
.then(function(response) {
return response.text();
}).then(function(text) {
var listProductsBalcaoElement = document.getElementById("list-products-comanda");
listProductsBalcaoElement.innerHTML = text;
})
showToastAdd('Produto adicionado com sucesso!😁','success');
});
// Trata resposta
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.message || `Erro HTTP: ${response.status}`);
}
const result = await response.text();
// Atualiza a lista de produtos
const listElement = document.getElementById("list-products-comanda");
if (listElement) {
listElement.innerHTML = result;
}
// Feedback de sucesso
Swal.update({
title: '<span style="color: green;">Produto adicionado! 😁</span>',
});
// Reseta após 2.5 segundos
setTimeout(() => {
Swal.update({
title: '<span style="color: white;">Adicionar Produto</span>'
});
}, 2500);
} catch (error) {
console.error('Erro:', error);
// Feedback de erro
Swal.update({
title: '<span style="color: red;">Falha ao adicionar!</span>',
html: `<div style="color: white; margin-top: 10px;">
${error.message || 'Erro desconhecido'}
</div>`,
icon: 'error',
});
}
}
function taxa(){