modified: routes_admin.py
modified: templates/admin_rendiciones.html modified: templates/macros/modals.html
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 %}
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user