modified: routes_admin.py

modified:   templates/admin_rendiciones.html
	modified:   templates/macros/modals.html
This commit is contained in:
2026-03-25 09:05:12 -03:00
parent 46bfb93566
commit e5f085d0cf
3 changed files with 185 additions and 31 deletions

View File

@@ -296,10 +296,27 @@ def register_admin_routes(app):
@app.route('/admin/rendiciones')
@admin_required
def admin_rendiciones():
# Capturamos todos los filtros
mes_seleccionado = request.args.get('mes')
anio_seleccionado = request.args.get('anio')
dia_seleccionado = request.args.get('dia')
zona_id_seleccionada = request.args.get('zona_id')
modulo_id_seleccionado = request.args.get('modulo_id')
# Si no viene la variable 'mes' en la URL, significa que es la primera vez que entramos
if request.args.get('mes') is None:
hoy = date.today()
mes_seleccionado = f"{hoy.month:02d}"
anio_seleccionado = str(hoy.year)
dia_seleccionado = f"{hoy.day:02d}" # <-- Forzamos el día actual
mes_seleccionado = mes_seleccionado.zfill(2)
conn = get_db_connection()
c = conn.cursor()
c.execute('''
# Construimos la consulta base tipo Lego
query = '''
SELECT r.id, r.fecha, w.name, m.name,
r.venta_debito, r.venta_credito, r.venta_mp, r.venta_efectivo, r.gastos, r.observaciones,
c_w.name, r.worker_id, r.companion_id, r.modulo_id,
@@ -309,19 +326,35 @@ def register_admin_routes(app):
JOIN workers w ON r.worker_id = w.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
''')
WHERE strftime('%m', r.fecha) = ? AND strftime('%Y', r.fecha) = ?
'''
params = [mes_seleccionado, anio_seleccionado]
# Añadimos las piezas extra si el usuario las seleccionó
if dia_seleccionado:
query += " AND strftime('%d', r.fecha) = ?"
params.append(dia_seleccionado.zfill(2))
if zona_id_seleccionada:
query += " AND m.zona_id = ?"
params.append(zona_id_seleccionada)
if modulo_id_seleccionado:
query += " AND r.modulo_id = ?"
params.append(modulo_id_seleccionado)
query += " ORDER BY r.fecha DESC, r.id DESC"
c.execute(query, tuple(params))
rendiciones_basicas = c.fetchall()
rendiciones_completas = []
for r in rendiciones_basicas:
# Cambia esto:
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,
ri.id -- <--- Agregamos el ID de la fila aquí (será el índice 6)
ri.id
FROM rendicion_items ri
JOIN productos p ON ri.producto_id = p.id
WHERE ri.rendicion_id = ?
@@ -330,22 +363,42 @@ def register_admin_routes(app):
total_calculado = sum(item[4] for item in items)
comision_total = sum(item[5] for item in items)
r_completa = r + (items, total_calculado, comision_total)
rendiciones_completas.append(r_completa)
# Cargar catálogos para los selects
c.execute("SELECT id, name, tipo, modulo_id FROM workers WHERE is_admin = 0 ORDER BY name")
workers = c.fetchall()
c.execute("SELECT id, name FROM modulos ORDER BY name")
# Ahora traemos el zona_id para poder filtrar los módulos por zona en el frontend
c.execute("SELECT id, name, zona_id FROM modulos ORDER BY name")
modulos = c.fetchall()
c.execute("SELECT id, name FROM zonas ORDER BY name")
zonas = c.fetchall()
c.execute("SELECT DISTINCT strftime('%Y', fecha) FROM rendiciones ORDER BY 1 DESC")
anios_db = c.fetchall()
anios_disponibles = [row[0] for row in anios_db] if anios_db else [str(date.today().year)]
if str(date.today().year) not in anios_disponibles:
anios_disponibles.insert(0, str(date.today().year))
conn.close()
dias_disponibles = [f"{d:02d}" for d in range(1, 32)]
return render_template('admin_rendiciones.html',
rendiciones=rendiciones_completas,
workers=workers,
modulos=modulos)
modulos=modulos,
zonas=zonas,
mes_actual=mes_seleccionado,
anio_actual=anio_seleccionado,
dia_actual=dia_seleccionado,
zona_actual=zona_id_seleccionada,
modulo_actual=modulo_id_seleccionado,
anios_disponibles=anios_disponibles,
dias_disponibles=dias_disponibles)
@app.route('/admin/rendiciones/delete/<int:id>', methods=['POST'])
@admin_required

View File

@@ -7,7 +7,75 @@
{% endblock %}
{% block content %}
<h2 class="mb-4">Historial de Rendiciones</h2>
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="mb-0">Historial de Rendiciones</h2>
</div>
<div class="card shadow-sm mb-4 border-0">
<div class="card-body bg-body-tertiary rounded p-3">
<form method="GET" action="{{ url_for('admin_rendiciones') }}" id="filterForm">
<div class="row g-2 align-items-end">
<div class="col-md-2">
<label class="form-label small text-muted mb-1">Año</label>
<select name="anio" class="form-select form-select-sm">
{% for anio in anios_disponibles %}
<option value="{{ anio }}" {% if anio_actual == anio %}selected{% endif %}>{{ anio }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-2">
<label class="form-label small text-muted mb-1">Mes</label>
<select name="mes" class="form-select form-select-sm">
<option value="01" {% if mes_actual == '01' %}selected{% endif %}>Enero</option>
<option value="02" {% if mes_actual == '02' %}selected{% endif %}>Febrero</option>
<option value="03" {% if mes_actual == '03' %}selected{% endif %}>Marzo</option>
<option value="04" {% if mes_actual == '04' %}selected{% endif %}>Abril</option>
<option value="05" {% if mes_actual == '05' %}selected{% endif %}>Mayo</option>
<option value="06" {% if mes_actual == '06' %}selected{% endif %}>Junio</option>
<option value="07" {% if mes_actual == '07' %}selected{% endif %}>Julio</option>
<option value="08" {% if mes_actual == '08' %}selected{% endif %}>Agosto</option>
<option value="09" {% if mes_actual == '09' %}selected{% endif %}>Septiembre</option>
<option value="10" {% if mes_actual == '10' %}selected{% endif %}>Octubre</option>
<option value="11" {% if mes_actual == '11' %}selected{% endif %}>Noviembre</option>
<option value="12" {% if mes_actual == '12' %}selected{% endif %}>Diciembre</option>
</select>
</div>
<div class="col-md-1">
<label class="form-label small text-muted mb-1">Día</label>
<select name="dia" class="form-select form-select-sm">
<option value="">Todos</option>
{% for d in dias_disponibles %}
<option value="{{ d }}" {% if dia_actual == d %}selected{% endif %}>{{ d }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-3">
<label class="form-label small text-muted mb-1">Zona</label>
<select name="zona_id" id="zonaSelect" class="form-select form-select-sm">
<option value="">Todas las Zonas</option>
{% for z in zonas %}
<option value="{{ z[0] }}" {% if zona_actual|string == z[0]|string %}selected{% endif %}>{{ z[1] }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-3">
<label class="form-label small text-muted mb-1">Módulo</label>
<select name="modulo_id" id="moduloSelect" class="form-select form-select-sm">
<option value="">Todos los Módulos</option>
{% for m in modulos %}
<option value="{{ m[0] }}" data-zona="{{ m[2] }}" {% if modulo_actual|string == m[0]|string %}selected{% endif %}>{{ m[1] }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-1">
<button type="submit" class="btn btn-primary btn-sm w-100"><i class="bi bi-search"></i> Filtrar</button>
</div>
</div>
</form>
</div>
</div>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
@@ -105,7 +173,11 @@
const toggleSwitch = document.getElementById(toggleId);
if (toggleSwitch && tipoJornada) {
// Explicitly set to true if Full Time, false otherwise
toggleSwitch.checked = (tipoJornada === 'Full Time');
} else if (toggleSwitch && !selectElement.value) {
// If "Sin acompañante" is selected, turn it off
toggleSwitch.checked = false;
}
// Actualizar el badge también
@@ -206,4 +278,35 @@
});
});
</script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const zonaSelect = document.getElementById('zonaSelect');
const moduloSelect = document.getElementById('moduloSelect');
const moduloOptions = Array.from(moduloSelect.options);
function filterModulos() {
const selectedZona = zonaSelect.value;
moduloOptions.forEach(option => {
if (option.value === "") {
// Siempre mostramos "Todos los Módulos"
option.style.display = '';
} else if (!selectedZona || option.dataset.zona === selectedZona) {
option.style.display = '';
} else {
option.style.display = 'none';
// Si el módulo seleccionado acaba de ocultarse, reseteamos el select
if (option.selected) {
moduloSelect.value = "";
}
}
});
}
zonaSelect.addEventListener('change', filterModulos);
// Ejecutar al cargar la página por si ya viene con una zona filtrada
filterModulos();
});
</script>
{% endblock %}

View File

@@ -269,11 +269,8 @@
</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>
<div class="card shadow-sm border-danger mb-0"> <div class="card-header bg-danger text-white fw-bold py-1">Gastos y Observaciones</div> <div class="card-body py-2">
<div class="mb-1"> <label class="small text-danger fw-bold mb-0">Monto Gastos</label> ```
<strong class="text-danger">-${{ "{:,.0f}".format(rendicion[8] or 0).replace(',', '.') }}</strong>
</div>
<div>
@@ -303,14 +300,14 @@
<h5 class="modal-title">Editar Rendición #{{ rendicion[0] }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form method="POST" action="{{ url_for('edit_rendicion', id=rendicion[0]) }}">
<div class="modal-body text-start">
<div class="modal-body text-start">
<form method="POST" action="{{ url_for('edit_rendicion', id=rendicion[0]) }}" id="editRendicionForm_{{ rendicion[0] }}">
<div class="row">
<div class="col-md-8 mb-3">
<div class="card shadow-sm h-100">
<div class="card-header bg-secondary text-white">Productos Vendidos</div>
<div class="card-body p-0">
<div class="table-responsive">
<div class="table-responsive custom-scrollbar" style="max-height: 450px;">
<table class="table table-striped mb-0 text-nowrap">
<thead class="table-dark">
<tr>
@@ -341,7 +338,7 @@
<tr>
<td colspan="3" class="text-end fw-bold">Total Calculado por Sistema:</td>
<td class="text-end fw-bold fs-6 text-primary" id="sys_total_{{ rendicion[0] }}">
${{ "{:,.0f}".format(rendicion[17] or 0).replace(',', '.') }}
${{ "{:,.0f}".format(rendicion[21] or 0).replace(',', '.') }}
</td>
</tr>
</tfoot>
@@ -372,9 +369,9 @@
</select>
<div class="d-flex justify-content-between align-items-center mt-1">
<div id="badge_worker_{{ rendicion[0] }}"></div>
<div class="form-check form-switch m-0">
<input class="form-check-input" type="checkbox" role="switch" name="worker_comision" id="wc_{{ rendicion[0] }}" {% if rendicion[14] %}checked{% endif %}>
<label class="form-check-label text-warning small" for="wc_{{ rendicion[0] }}">$ Sí</label>
<div class="form-check m-0">
<input class="form-check-input" type="checkbox" name="worker_comision" id="wc_{{ rendicion[0] }}" {% if rendicion[14] %}checked{% endif %}>
<label class="form-check-label text-warning small fw-bold" for="wc_{{ rendicion[0] }}">Recive Comisión</label>
</div>
</div>
</div>
@@ -391,9 +388,9 @@
</select>
<div class="d-flex justify-content-between align-items-center mt-1" id="comp_com_div_{{ rendicion[0] }}" {% if not rendicion[12] %}style="display:none;"{% endif %}>
<div id="badge_comp_{{ rendicion[0] }}"></div>
<div class="form-check form-switch m-0">
<input class="form-check-input" type="checkbox" role="switch" name="companion_comision" id="cc_{{ rendicion[0] }}" {% if rendicion[15] %}checked{% endif %}>
<label class="form-check-label text-warning small" for="cc_{{ rendicion[0] }}">$ Sí</label>
<div class="form-check m-0">
<input class="form-check-input" type="checkbox" name="companion_comision" id="cc_{{ rendicion[0] }}" {% if rendicion[15] %}checked{% endif %}>
<label class="form-check-label text-warning small fw-bold" for="cc_{{ rendicion[0] }}">Recive Comisión</label>
</div>
</div>
</div>
@@ -458,11 +455,12 @@
</div>
</div>
</div>
</div> <div class="modal-footer py-2">
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-primary btn-sm px-4">Guardar Cambios</button>
</div>
</form>
</form>
</div>
<div class="modal-footer py-2">
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" form="editRendicionForm_{{ rendicion[0] }}" class="btn btn-primary btn-sm px-4">Guardar Cambios</button>
</div>
</div>
</div>
</div>