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 comandas.models import Comanda, ProductComanda
from orders.models import Order from orders.models import Order
from products.models import Product from products.models import Product
from payments.models import Payments from payments.models import Payments, somar
from typePay.models import TypePay from typePay.models import TypePay
from gestaoRaul.decorators import group_required from gestaoRaul.decorators import group_required
from websocket_client.websocketClient import enviar_mensagem 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}") # 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') @group_required(groupName='Garçom')

View File

@@ -13,6 +13,16 @@ Detalhes {{comanda.name}}
{% block 'head' %} {% block 'head' %}
<link rel="stylesheet" href="{% static 'comandas/css/viewcomanda.css' %}"> <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 %} {% endblock %}
@@ -22,7 +32,7 @@ Detalhes {{comanda.name}}
<input hidden id="id-temp" type="number"> <input hidden id="id-temp" type="number">
<div class="grid-container" > <div class="grid-container" >
<div style="display: flex;padding: 5px;gap:8px"> <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'%} {% if comanda.status != 'OPEN'%}
disabled disabled
{% endif %} {% endif %}
@@ -71,6 +81,7 @@ Detalhes {{comanda.name}}
</div> </div>
<div> <div>
<input hidden type="text" id="h-mesaId" value="{{comanda.mesa.id}}"> <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="name-comanda">Nome: {{comanda.name}} | </span>
<span id="mesa-comanda">Local: {{comanda.mesa}}</span> <span id="mesa-comanda">Local: {{comanda.mesa}}</span>
@@ -173,17 +184,13 @@ Detalhes {{comanda.name}}
<div id="addProduct" popover class="popover"> <div id="addProduct" class="popover">
<div id="toast-add" class="toast-add"> <!-- <div id="productForm" > -->
<p id="toast-message-add"></p> {% csrf_token %}
</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>
<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"> <div id="product-list" class="grid-list-products">
{% for product in products %} {% for product in products %}
<div class="card-product" onclick="addProductComanda({{product.id}}, {{comanda.id}}, '{{product.cuisine}}')" > <div class="card-product" onclick="addProductComanda({{product.id}}, {{comanda.id}}, '{{product.cuisine}}')" >
@@ -192,7 +199,7 @@ Detalhes {{comanda.name}}
</div > </div >
{% endfor %} {% endfor %}
</div> </div>
</form> <!-- </div> -->
</div> </div>

View File

@@ -13,6 +13,8 @@ urlpatterns = [
path('notificacao/', views.notificacao, name='notificacao'), path('notificacao/', views.notificacao, name='notificacao'),
path('editOrders/<int:productComanda_id>/<str:obs>', views.editOrders, name='editOrders'), path('editOrders/<int:productComanda_id>/<str:obs>', views.editOrders, name='editOrders'),
path('closeComanda/<int:comanda_id>/', views.closeComanda, name='closeComanda'), 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 = [ 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('removeProductComanda<int:productComanda_id>/', htmx_views.removeProductComanda, name='removeProductComanda'),
path('reopenComanda<int:comanda_id>/', htmx_views.reopenComanda, name='reopenComanda'), path('reopenComanda<int:comanda_id>/', htmx_views.reopenComanda, name='reopenComanda'),
path('paymentComanda<int:comanda_id>/', htmx_views.paymentComanda, name='paymentComanda'), 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}) 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') @group_required(groupName='Garçom')
def viewComanda(request): def viewComanda(request):
config = { config = {
@@ -167,3 +150,61 @@ def closeComanda(request, comanda_id):
comanda.status = "PAYING" comanda.status = "PAYING"
comanda.save() comanda.save()
return JsonResponse({'status': 'ok', 'obs':'order.obs'}) 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 %} {% for product in products %}
<div <div
onclick="addProductComanda({{product.id}})" onclick="addProductComanda({{product.id}}, {{comanda_id}}, '{{product.cuisine}}')"
class="card-product" class="card-product"
hx-get="{% url 'addProduct' product.id comanda_id %} " >
hx-trigger="click"
hx-target="#list-products-comanda">
{{product.name}} <br> {{product.name}} <br>
R$ {{product.price}} R$ {{product.price}}
</div> </div>

View File

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

View File

@@ -53,6 +53,7 @@
} }
.popover{ .popover{
display: none;
position: relative; position: relative;
width: 98%; width: 98%;
height: 96%; 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(() => { setTimeout(() => {
textField.focus(); time();
}, 500); }, 100);
} function time(){
textField.value = ''; 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() { function openModalAlter() {
document.getElementById('Modal-alter-comanda').style.display = 'block'; document.getElementById('Modal-alter-comanda').style.display = 'block';
var name = document.getElementById('name-comanda').innerText.replace('Nome: ','').replace(' | ', '') 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') { async function addProductComanda(productId, comandaId, cuisine) {
toast.style.backgroundColor = '#28a745'; try {
} else if (type === 'error') { if (!productId || !comandaId) {
toast.style.backgroundColor = '#dc3545'; throw new Error('IDs de produto ou comanda inválidos');
} else if (type === 'info') {
toast.style.backgroundColor = '#ffc107';
} }
const toastMessage = document.getElementById('toast-message-add');
toastMessage.textContent = message;
toast.classList.add('show');
setTimeout(() => { const csrfToken = document.querySelector('[name="csrfmiddlewaretoken"]').value
toast.classList.remove('show'); if (!csrfToken) {
}, duration); throw new Error('Token de segurança não encontrado');
} }
function addProductComanda(productId,comandaId, cuisine) {
obs = document.getElementById('obs'); // if (cuisine === 'ggg') {
if(cuisine == 'ggg'){ // openModalObs();
var obs = openModalObs(); // return;
}else{ // }
fetch(`/comandas/addProduct${productId}/${comandaId}`, {
method: 'GET', // 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: { 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) { // Trata resposta
var listProductsBalcaoElement = document.getElementById("list-products-comanda"); if (!response.ok) {
listProductsBalcaoElement.innerHTML = text; const errorData = await response.json().catch(() => ({}));
}) throw new Error(errorData.message || `Erro HTTP: ${response.status}`);
showToastAdd('Produto adicionado com sucesso!😁','success');
} }
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(){ function taxa(){