rendiciones a modal yipi
This commit is contained in:
34
app.py
34
app.py
@@ -588,20 +588,44 @@ def admin_rendiciones():
|
|||||||
conn = sqlite3.connect(DB_NAME)
|
conn = sqlite3.connect(DB_NAME)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
|
|
||||||
# Fetch all rendiciones, newest first
|
# 1. Obtenemos la cabecera exacta igual que en view_rendicion (Índices 0 al 10)
|
||||||
c.execute('''
|
c.execute('''
|
||||||
SELECT r.id, r.fecha, w.name, m.name, r.turno,
|
SELECT r.id, r.fecha, w.name, m.name, r.turno,
|
||||||
(r.venta_tarjeta + r.venta_mp + r.venta_efectivo) as total_declarado,
|
r.venta_tarjeta, r.venta_mp, r.venta_efectivo, r.gastos, r.observaciones,
|
||||||
r.gastos
|
c_w.name
|
||||||
FROM rendiciones r
|
FROM rendiciones r
|
||||||
JOIN workers w ON r.worker_id = w.id
|
JOIN workers w ON r.worker_id = w.id
|
||||||
JOIN modulos m ON r.modulo_id = m.id
|
JOIN modulos m ON r.modulo_id = m.id
|
||||||
|
LEFT JOIN workers c_w ON r.companion_id = c_w.id
|
||||||
ORDER BY r.fecha DESC, r.id DESC
|
ORDER BY r.fecha DESC, r.id DESC
|
||||||
''')
|
''')
|
||||||
rendiciones = c.fetchall()
|
rendiciones_basicas = c.fetchall()
|
||||||
|
|
||||||
|
rendiciones_completas = []
|
||||||
|
|
||||||
|
# 2. Por cada rendición, buscamos sus ítems y calculamos los totales
|
||||||
|
for r in rendiciones_basicas:
|
||||||
|
c.execute('''
|
||||||
|
SELECT p.name, ri.cantidad, ri.precio_historico, ri.comision_historica,
|
||||||
|
(ri.cantidad * ri.precio_historico) as total_linea,
|
||||||
|
(ri.cantidad * ri.comision_historica) as total_comision
|
||||||
|
FROM rendicion_items ri
|
||||||
|
JOIN productos p ON ri.producto_id = p.id
|
||||||
|
WHERE ri.rendicion_id = ?
|
||||||
|
''', (r[0],))
|
||||||
|
items = c.fetchall()
|
||||||
|
|
||||||
|
total_calculado = sum(item[4] for item in items)
|
||||||
|
comision_total = sum(item[5] for item in items)
|
||||||
|
|
||||||
|
# 3. Anexamos los nuevos datos a la tupla original
|
||||||
|
# r[11] = items, r[12] = total_calculado, r[13] = comision_total
|
||||||
|
r_completa = r + (items, total_calculado, comision_total)
|
||||||
|
rendiciones_completas.append(r_completa)
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return render_template('admin_rendiciones.html', rendiciones=rendiciones)
|
return render_template('admin_rendiciones.html', rendiciones=rendiciones_completas)
|
||||||
|
|
||||||
@app.route('/admin/rendiciones/<int:id>')
|
@app.route('/admin/rendiciones/<int:id>')
|
||||||
@admin_required
|
@admin_required
|
||||||
|
|||||||
@@ -1,132 +0,0 @@
|
|||||||
{% extends "macros/base.html" %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block title %}Detalle de Rendición{% endblock %}
|
|
||||||
|
|
||||||
{% block head %}
|
|
||||||
<!-- HEAD -->
|
|
||||||
{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
||||||
<h2>Detalle de Rendición #{{ rendicion[0] }}</h2>
|
|
||||||
<a href="{{ url_for('admin_rendiciones') }}" class="btn btn-outline-light">Volver al Historial</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-8 mb-4">
|
|
||||||
<div class="card shadow-sm h-100">
|
|
||||||
<div class="card-header bg-secondary text-white">Productos Vendidos</div>
|
|
||||||
<div class="card-body p-0">
|
|
||||||
<table class="table table-striped mb-0">
|
|
||||||
<thead class="table-dark">
|
|
||||||
<tr>
|
|
||||||
<th>Producto</th>
|
|
||||||
<th class="text-center">Cant.</th>
|
|
||||||
<th class="text-end">Precio Un.</th>
|
|
||||||
<th class="text-end">Total Línea</th>
|
|
||||||
<th class="text-end">Comisión</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for item in items %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ item[0] }}</td>
|
|
||||||
<td class="text-center fw-bold">{{ item[1] }}</td>
|
|
||||||
<td class="text-end text-muted">${{ "{:,.0f}".format(item[2]).replace(',', '.') }}</td>
|
|
||||||
<td class="text-end fw-bold">${{ "{:,.0f}".format(item[4]).replace(',', '.') }}</td>
|
|
||||||
<td class="text-end text-success">${{ "{:,.0f}".format(item[5]).replace(',', '.') }}</td>
|
|
||||||
</tr>
|
|
||||||
{% else %}
|
|
||||||
<tr>
|
|
||||||
<td colspan="5" class="text-center py-3">No se registraron productos en esta rendición.</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
<tfoot class="table-group-divider">
|
|
||||||
<tr>
|
|
||||||
<td colspan="3" class="text-end fw-bold">Total Calculado por Sistema:</td>
|
|
||||||
<td class="text-end fw-bold fs-5">${{ "{:,.0f}".format(total_calculado).replace(',', '.') }}</td>
|
|
||||||
<td class="text-end fw-bold text-success">${{ "{:,.0f}".format(comision_total).replace(',', '.') }}</td>
|
|
||||||
</tr>
|
|
||||||
</tfoot>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-4 mb-4">
|
|
||||||
<div class="card shadow-sm mb-4 border-info">
|
|
||||||
<div class="card-header bg-info text-dark fw-bold">Declaración del Trabajador</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<dl class="row mb-0">
|
|
||||||
<dt class="col-sm-5 text-muted">Fecha</dt>
|
|
||||||
<dd class="col-sm-7">{{ rendicion[1] }}</dd>
|
|
||||||
|
|
||||||
<dt class="col-sm-5 text-muted">Trabajador</dt>
|
|
||||||
<dd class="col-sm-7">{{ rendicion[2] }}</dd>
|
|
||||||
|
|
||||||
<dt class="col-sm-5 text-muted">Acompañante</dt>
|
|
||||||
<dd class="col-sm-7">
|
|
||||||
{% if rendicion[10] %}
|
|
||||||
{{ rendicion[10] }}
|
|
||||||
{% else %}
|
|
||||||
<span class="text-muted italic small">Sin acompañante</span>
|
|
||||||
{% endif %}
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt class="col-sm-5 text-muted">Módulo</dt>
|
|
||||||
<dd class="col-sm-7"><span class="badge bg-secondary">{{ rendicion[3] }}</span></dd>
|
|
||||||
|
|
||||||
<dt class="col-sm-5 text-muted">Turno</dt>
|
|
||||||
<dd class="col-sm-7">{{ rendicion[4] }}</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class="d-flex justify-content-between mb-2">
|
|
||||||
<span class="text-muted">Tarjetas:</span>
|
|
||||||
<span>${{ "{:,.0f}".format(rendicion[5]).replace(',', '.') }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex justify-content-between mb-2">
|
|
||||||
<span class="text-muted">Mercado Pago:</span>
|
|
||||||
<span>${{ "{:,.0f}".format(rendicion[6]).replace(',', '.') }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex justify-content-between mb-2">
|
|
||||||
<span class="text-muted">Efectivo:</span>
|
|
||||||
<span>${{ "{:,.0f}".format(rendicion[7]).replace(',', '.') }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% set total_declarado = rendicion[5] + rendicion[6] + rendicion[7] %}
|
|
||||||
|
|
||||||
<div class="d-flex justify-content-between mt-3 pt-2 border-top">
|
|
||||||
<strong class="fs-5">Total Declarado:</strong>
|
|
||||||
<strong class="fs-5">${{ "{:,.0f}".format(total_declarado).replace(',', '.') }}</strong>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if total_declarado != total_calculado %}
|
|
||||||
<div class="alert alert-warning mt-3 mb-0 py-2">
|
|
||||||
<small>⚠️ Discrepancia: El total declarado (${{ "{:,.0f}".format(total_declarado).replace(',', '.') }}) no coincide con la suma de los productos vendidos (${{ "{:,.0f}".format(total_calculado).replace(',', '.') }}).</small>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card shadow-sm border-danger">
|
|
||||||
<div class="card-header bg-danger text-white">Gastos y Observaciones</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="d-flex justify-content-between mb-3">
|
|
||||||
<strong class="text-danger">Monto Gastos:</strong>
|
|
||||||
<strong class="text-danger">-${{ "{:,.0f}".format(rendicion[8]).replace(',', '.') }}</strong>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="text-muted d-block mb-1">Observaciones:</span>
|
|
||||||
<p class="mb-0 bg-dark p-2 rounded border border-secondary" style="font-size: 0.9em;">
|
|
||||||
{{ rendicion[9] if rendicion[9] else "Sin observaciones." }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{% extends "macros/base.html" %}
|
{% extends "macros/base.html" %}
|
||||||
{% from 'macros/modals.html' import view_rendicion_modal %}
|
{% from 'macros/modals.html' import rendicion_detail_modal %}
|
||||||
|
|
||||||
{% block title %}Historial de Rendiciones{% endblock %}
|
{% block title %}Historial de Rendiciones{% endblock %}
|
||||||
|
|
||||||
@@ -9,8 +9,6 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<h2 class="mb-4">Historial de Rendiciones</h2>
|
<h2 class="mb-4">Historial de Rendiciones</h2>
|
||||||
|
|
||||||
{{ view_rendicion_modal() }}
|
|
||||||
|
|
||||||
<div class="card shadow-sm">
|
<div class="card shadow-sm">
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
<table class="table table-striped table-hover mb-0">
|
<table class="table table-striped table-hover mb-0">
|
||||||
@@ -32,17 +30,17 @@
|
|||||||
<td class="align-middle">{{ r[2] }}</td>
|
<td class="align-middle">{{ r[2] }}</td>
|
||||||
<td class="align-middle"><span class="badge bg-info text-dark">{{ r[3] }}</span></td>
|
<td class="align-middle"><span class="badge bg-info text-dark">{{ r[3] }}</span></td>
|
||||||
<td class="align-middle">{{ r[4] }}</td>
|
<td class="align-middle">{{ r[4] }}</td>
|
||||||
<td class="align-middle">${{ "{:,.0f}".format(r[5]).replace(',', '.') }}</td>
|
<td class="align-middle">${{ "{:,.0f}".format((r[5] or 0) + (r[6] or 0) + (r[7] or 0)).replace(',', '.') }}</td>
|
||||||
<td class="align-middle text-danger">${{ "{:,.0f}".format(r[6]).replace(',', '.') }}</td>
|
<td class="align-middle text-danger">${{ "{:,.0f}".format(r[8] or 0).replace(',', '.') }}</td>
|
||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="btn btn-sm btn-primary"
|
class="btn btn-sm btn-primary"
|
||||||
data-bs-toggle="modal"
|
data-bs-toggle="modal"
|
||||||
data-bs-target="#viewRendicionModal"
|
data-bs-target="#viewRendicion{{ r[0] }}">
|
||||||
data-url="{{ url_for('view_rendicion', id=r[0]) }}"
|
|
||||||
data-id="{{ r[0] }}">
|
|
||||||
Ver Detalle
|
Ver Detalle
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{{ rendicion_detail_modal(r, r[11], r[12], r[13]) }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -55,34 +53,3 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block scripts %}
|
|
||||||
<script>
|
|
||||||
const viewModal = document.getElementById('viewRendicionModal');
|
|
||||||
if (viewModal) {
|
|
||||||
viewModal.addEventListener('show.bs.modal', function (event) {
|
|
||||||
const button = event.relatedTarget;
|
|
||||||
const url = button.getAttribute('data-url');
|
|
||||||
const id = button.getAttribute('data-id');
|
|
||||||
|
|
||||||
const title = viewModal.querySelector('#rendicionModalTitle');
|
|
||||||
const body = viewModal.querySelector('#rendicionModalBody');
|
|
||||||
|
|
||||||
title.textContent = `Detalle de Rendición #${id}`;
|
|
||||||
body.innerHTML = '<div class="text-center py-5"><div class="spinner-border text-primary" role="status"></div></div>';
|
|
||||||
|
|
||||||
fetch(url)
|
|
||||||
.then(response => response.text())
|
|
||||||
.then(html => {
|
|
||||||
const parser = new DOMParser();
|
|
||||||
const doc = parser.parseFromString(html, 'text/html');
|
|
||||||
const content = doc.querySelector('.row').outerHTML;
|
|
||||||
body.innerHTML = content;
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
body.innerHTML = '<div class="alert alert-danger">Error al cargar los detalles.</div>';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -117,18 +117,126 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro view_rendicion_modal() %}
|
{% macro rendicion_detail_modal(rendicion, items, total_calculado, comision_total) %}
|
||||||
<div class="modal fade" id="viewRendicionModal" tabindex="-1" aria-hidden="true">
|
<div class="modal fade" id="viewRendicion{{ rendicion[0] }}" tabindex="-1" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-xl modal-dialog-scrollable">
|
<div class="modal-dialog modal-xl modal-dialog-scrollable">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header bg-dark text-white">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="rendicionModalTitle">Detalle de Rendición</h5>
|
<h5 class="modal-title">Detalle de Rendición #{{ rendicion[0] }}</h5>
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body" id="rendicionModalBody">
|
<div class="modal-body text-start">
|
||||||
<div class="text-center py-5">
|
<div class="row">
|
||||||
<div class="spinner-border text-primary" role="status">
|
<div class="col-md-8 mb-4">
|
||||||
<span class="visually-hidden">Cargando</span>
|
<div class="card shadow-sm h-100">
|
||||||
|
<div class="card-header bg-secondary text-white">Productos Vendidos</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<table class="table table-striped mb-0">
|
||||||
|
<thead class="table-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Producto</th>
|
||||||
|
<th class="text-center">Cant.</th>
|
||||||
|
<th class="text-end">Precio Un.</th>
|
||||||
|
<th class="text-end">Total Línea</th>
|
||||||
|
<th class="text-end">Comisión</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in items %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ item[0] }}</td>
|
||||||
|
<td class="text-center fw-bold">{{ item[1] }}</td>
|
||||||
|
<td class="text-end text-muted">${{ "{:,.0f}".format(item[2]).replace(',', '.') }}</td>
|
||||||
|
<td class="text-end fw-bold">${{ "{:,.0f}".format(item[4]).replace(',', '.') }}</td>
|
||||||
|
<td class="text-end text-success">${{ "{:,.0f}".format(item[5]).replace(',', '.') }}</td>
|
||||||
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" class="text-center py-3">No se registraron productos en esta rendición.</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
<tfoot class="table-group-divider">
|
||||||
|
<tr>
|
||||||
|
<td colspan="3" class="text-end fw-bold">Total Calculado por Sistema:</td>
|
||||||
|
<td class="text-end fw-bold fs-5">${{ "{:,.0f}".format(total_calculado or 0).replace(',', '.') }}</td>
|
||||||
|
<td class="text-end fw-bold text-success">${{ "{:,.0f}".format(comision_total or 0).replace(',', '.') }}</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4 mb-4">
|
||||||
|
<div class="card shadow-sm mb-4 border-info">
|
||||||
|
<div class="card-header bg-info text-dark fw-bold">Declaración del Trabajador</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<dl class="row mb-0">
|
||||||
|
<dt class="col-sm-5 text-muted">Fecha</dt>
|
||||||
|
<dd class="col-sm-7">{{ rendicion[1] }}</dd>
|
||||||
|
|
||||||
|
<dt class="col-sm-5 text-muted">Trabajador</dt>
|
||||||
|
<dd class="col-sm-7">{{ rendicion[2] }}</dd>
|
||||||
|
|
||||||
|
<dt class="col-sm-5 text-muted">Acompañante</dt>
|
||||||
|
<dd class="col-sm-7">
|
||||||
|
{% if rendicion[10] %}
|
||||||
|
{{ rendicion[10] }}
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted italic small">Sin acompañante</span>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt class="col-sm-5 text-muted">Módulo</dt>
|
||||||
|
<dd class="col-sm-7"><span class="badge bg-secondary">{{ rendicion[3] }}</span></dd>
|
||||||
|
|
||||||
|
<dt class="col-sm-5 text-muted">Turno</dt>
|
||||||
|
<dd class="col-sm-7">{{ rendicion[4] }}</dd>
|
||||||
|
</dl>
|
||||||
|
<hr>
|
||||||
|
<div class="d-flex justify-content-between mb-2">
|
||||||
|
<span class="text-muted">Tarjetas:</span>
|
||||||
|
<span>${{ "{:,.0f}".format(rendicion[5] or 0).replace(',', '.') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-between mb-2">
|
||||||
|
<span class="text-muted">Mercado Pago:</span>
|
||||||
|
<span>${{ "{:,.0f}".format(rendicion[6] or 0).replace(',', '.') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-between mb-2">
|
||||||
|
<span class="text-muted">Efectivo:</span>
|
||||||
|
<span>${{ "{:,.0f}".format(rendicion[7] or 0).replace(',', '.') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% set total_declarado = rendicion[5] + rendicion[6] + rendicion[7] %}
|
||||||
|
<div class="d-flex justify-content-between mt-3 pt-2 border-top">
|
||||||
|
<strong class="fs-5">Total Declarado:</strong>
|
||||||
|
<strong class="fs-5">${{ "{:,.0f}".format(total_declarado).replace(',', '.') }}</strong>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if total_declarado != total_calculado %}
|
||||||
|
<div class="alert alert-warning mt-3 mb-0 py-2">
|
||||||
|
<small>Discrepancia: El total declarado (${{ "{:,.0f}".format(total_declarado).replace(',', '.') }}) no coincide con la suma de los productos vendidos (${{ "{:,.0f}".format(total_calculado).replace(',', '.') }}).</small>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card shadow-sm border-danger">
|
||||||
|
<div class="card-header bg-danger text-white">Gastos y Observaciones</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex justify-content-between mb-3">
|
||||||
|
<strong class="text-danger">Monto Gastos:</strong>
|
||||||
|
<strong class="text-danger">-${{ "{:,.0f}".format(rendicion[8] or 0).replace(',', '.') }}</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="text-muted d-block mb-1">Observaciones:</span>
|
||||||
|
<p class="mb-0 bg-dark p-2 rounded border border-secondary" style="font-size: 0.9em;">
|
||||||
|
{{ rendicion[9] if rendicion[9] else "Sin observaciones." }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user