modified: app.py
new file: templates/admin_report_modulo.html new file: templates/admin_reportes_index.html new file: templates/admin_reportes_menu.html modified: templates/macros/navbar.html
This commit is contained in:
118
app.py
118
app.py
@@ -6,6 +6,7 @@ import random
|
|||||||
import string
|
import string
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = "super_secret_dev_key"
|
app.secret_key = "super_secret_dev_key"
|
||||||
@@ -848,6 +849,123 @@ def edit_rendicion(id):
|
|||||||
flash("Rendición actualizada correctamente.", "success")
|
flash("Rendición actualizada correctamente.", "success")
|
||||||
return redirect(url_for('admin_rendiciones'))
|
return redirect(url_for('admin_rendiciones'))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/admin/reportes')
|
||||||
|
@admin_required # Asumo que usas este decorador
|
||||||
|
def admin_reportes_index():
|
||||||
|
conn = sqlite3.connect(DB_NAME)
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# Ahora hacemos un JOIN con zonas para poder agruparlos en la vista
|
||||||
|
c.execute('''
|
||||||
|
SELECT m.id, m.name, z.name
|
||||||
|
FROM modulos m
|
||||||
|
JOIN zonas z ON m.zona_id = z.id
|
||||||
|
ORDER BY z.name, m.name
|
||||||
|
''')
|
||||||
|
modulos = c.fetchall()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return render_template('admin_reportes_index.html', modulos=modulos)
|
||||||
|
|
||||||
|
@app.route('/admin/reportes/modulo/<int:modulo_id>/menu')
|
||||||
|
@admin_required
|
||||||
|
def admin_reportes_menu_modulo(modulo_id):
|
||||||
|
# Esta ruta muestra las opciones de reporte para un módulo específico
|
||||||
|
conn = sqlite3.connect(DB_NAME)
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
c.execute("SELECT name FROM modulos WHERE id = ?", (modulo_id,))
|
||||||
|
modulo_info = c.fetchone()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
if not modulo_info:
|
||||||
|
flash("Módulo no encontrado.", "danger")
|
||||||
|
return redirect(url_for('admin_reportes_index'))
|
||||||
|
|
||||||
|
modulo_name = modulo_info[0]
|
||||||
|
|
||||||
|
return render_template('admin_reportes_menu.html', modulo_id=modulo_id, modulo_name=modulo_name)
|
||||||
|
|
||||||
|
@app.route('/admin/reportes/modulo/<int:modulo_id>')
|
||||||
|
@admin_required
|
||||||
|
def report_modulo_periodo(modulo_id):
|
||||||
|
# Por defecto, mes actual
|
||||||
|
mes_actual = date.today().month
|
||||||
|
anio_actual = date.today().year
|
||||||
|
dias_en_periodo = [f'{d:02}' for d in range(1, 32)] # Rango de 31 días
|
||||||
|
|
||||||
|
conn = sqlite3.connect(DB_NAME)
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
c.execute("SELECT name FROM modulos WHERE id = ?", (modulo_id,))
|
||||||
|
modulo_info = c.fetchone()
|
||||||
|
if not modulo_info:
|
||||||
|
conn.close()
|
||||||
|
flash("Módulo no encontrado.", "danger")
|
||||||
|
return redirect(url_for('admin_reportes_index'))
|
||||||
|
modulo_name = modulo_info[0]
|
||||||
|
|
||||||
|
# 1. Obtener finanzas (pagos y gastos) agrupadas por día
|
||||||
|
c.execute('''
|
||||||
|
SELECT strftime('%d', fecha) as dia,
|
||||||
|
SUM(venta_debito), SUM(venta_credito), SUM(venta_mp), SUM(venta_efectivo), SUM(gastos)
|
||||||
|
FROM rendiciones
|
||||||
|
WHERE modulo_id = ? AND strftime('%m', fecha) = ? AND strftime('%Y', fecha) = ?
|
||||||
|
GROUP BY dia
|
||||||
|
''', (modulo_id, f'{mes_actual:02}', str(anio_actual)))
|
||||||
|
finanzas_db = c.fetchall()
|
||||||
|
|
||||||
|
# 2. Obtener comisiones agrupadas por día
|
||||||
|
c.execute('''
|
||||||
|
SELECT strftime('%d', r.fecha) as dia,
|
||||||
|
SUM(ri.cantidad * ri.comision_historica) as comision_total
|
||||||
|
FROM rendicion_items ri
|
||||||
|
JOIN rendiciones r ON ri.rendicion_id = r.id
|
||||||
|
WHERE r.modulo_id = ? AND strftime('%m', r.fecha) = ? AND strftime('%Y', r.fecha) = ?
|
||||||
|
GROUP BY dia
|
||||||
|
''', (modulo_id, f'{mes_actual:02}', str(anio_actual)))
|
||||||
|
comisiones_db = c.fetchall()
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
# 3. Estructurar los datos para la tabla web
|
||||||
|
data_por_dia = {dia: {'debito': 0, 'credito': 0, 'mp': 0, 'efectivo': 0, 'gastos': 0, 'comision': 0, 'venta_total': 0} for dia in dias_en_periodo}
|
||||||
|
|
||||||
|
for row in finanzas_db:
|
||||||
|
dia, debito, credito, mp, efectivo, gastos = row
|
||||||
|
venta_total = (debito or 0) + (credito or 0) + (mp or 0) + (efectivo or 0)
|
||||||
|
data_por_dia[dia].update({
|
||||||
|
'debito': debito or 0,
|
||||||
|
'credito': credito or 0,
|
||||||
|
'mp': mp or 0,
|
||||||
|
'efectivo': efectivo or 0,
|
||||||
|
'gastos': gastos or 0,
|
||||||
|
'venta_total': venta_total
|
||||||
|
})
|
||||||
|
|
||||||
|
for row in comisiones_db:
|
||||||
|
dia, comision = row
|
||||||
|
data_por_dia[dia]['comision'] = comision or 0
|
||||||
|
|
||||||
|
# 4. Calcular totales del mes para el Footer y las Tarjetas (KPIs)
|
||||||
|
totales_mes = {'debito': 0, 'credito': 0, 'mp': 0, 'efectivo': 0, 'gastos': 0, 'comision': 0, 'venta_total': 0}
|
||||||
|
dias_activos = 0
|
||||||
|
|
||||||
|
for dia, datos in data_por_dia.items():
|
||||||
|
if datos['venta_total'] > 0 or datos['gastos'] > 0:
|
||||||
|
dias_activos += 1
|
||||||
|
for k in totales_mes.keys():
|
||||||
|
totales_mes[k] += datos[k]
|
||||||
|
|
||||||
|
return render_template('admin_report_modulo.html',
|
||||||
|
modulo_name=modulo_name,
|
||||||
|
mes_nombre=f'{mes_actual:02}/{anio_actual}',
|
||||||
|
dias_en_periodo=dias_en_periodo,
|
||||||
|
data_por_dia=data_por_dia,
|
||||||
|
totales_mes=totales_mes,
|
||||||
|
dias_activos=dias_activos)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
init_db()
|
init_db()
|
||||||
app.run(host='0.0.0.0', port=5000, debug=True)
|
app.run(host='0.0.0.0', port=5000, debug=True)
|
||||||
147
templates/admin_report_modulo.html
Normal file
147
templates/admin_report_modulo.html
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
{% extends "macros/base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Reporte: Finanzas - {{ modulo_name }}{% endblock %}
|
||||||
|
|
||||||
|
{% block styles %}
|
||||||
|
<style>
|
||||||
|
.numeric-cell {
|
||||||
|
text-align: right;
|
||||||
|
font-family: 'Courier New', Courier, monospace;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.total-column {
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: #e9ecef !important;
|
||||||
|
}
|
||||||
|
.sticky-col {
|
||||||
|
position: sticky;
|
||||||
|
left: 0;
|
||||||
|
z-index: 10;
|
||||||
|
background-color: #f8f9fa !important;
|
||||||
|
border-right: 2px solid #dee2e6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<div>
|
||||||
|
<a href="{{ url_for('admin_reportes_menu_modulo', modulo_id=request.view_args.get('modulo_id', 0)) }}" class="btn btn-outline-secondary btn-sm mb-2">
|
||||||
|
<i class="bi bi-arrow-left"></i> Volver al Menú
|
||||||
|
</a>
|
||||||
|
<h2>Resumen Financiero y Medios de Pago</h2>
|
||||||
|
</div>
|
||||||
|
<div class="text-end">
|
||||||
|
<div><strong class="text-primary fs-5">{{ modulo_name }}</strong></div>
|
||||||
|
<div class="text-muted"><small>Período: {{ mes_nombre }}</small></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-3 mb-4">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card bg-success text-white shadow-sm h-100 border-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="text-uppercase small mb-1 opacity-75">Venta Total Mensual</div>
|
||||||
|
<h3 class="card-title mb-0">${{ "{:,.0f}".format(totales_mes.venta_total).replace(',', '.') }}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card bg-info text-dark shadow-sm h-100 border-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="text-uppercase small mb-1 opacity-75">Comisiones Generadas</div>
|
||||||
|
<h3 class="card-title mb-0">${{ "{:,.0f}".format(totales_mes.comision).replace(',', '.') }}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card bg-danger text-white shadow-sm h-100 border-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="text-uppercase small mb-1 opacity-75">Total Gastos</div>
|
||||||
|
<h3 class="card-title mb-0">-${{ "{:,.0f}".format(totales_mes.gastos).replace(',', '.') }}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card bg-warning text-dark shadow-sm h-100 border-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="text-uppercase small mb-1 opacity-75">Días Trabajados</div>
|
||||||
|
<h3 class="card-title mb-0">{{ dias_activos }} <span class="fs-6 fw-normal">/ 31</span></h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card shadow-sm border-0">
|
||||||
|
<div class="card-header border-0 bg-transparent d-flex justify-content-between align-items-center pb-0">
|
||||||
|
<span class="fw-bold text-muted text-uppercase"><i class="bi bi-calendar3 me-1"></i> Desglose Diario</span>
|
||||||
|
|
||||||
|
<button class="btn btn-success btn-sm shadow-sm" onclick="alert('Próximamente: Esto descargará un Excel con el detalle de todos los productos vendidos por día.')">
|
||||||
|
<i class="bi bi-file-earmark-excel-fill me-1"></i> Exportar Detalle Completo (.xlsx)
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-bordered table-striped table-hover table-sm mb-0 text-nowrap" style="font-size: 0.85rem;">
|
||||||
|
<thead class="table-dark text-center align-middle">
|
||||||
|
<tr>
|
||||||
|
<th class="sticky-col py-2" rowspan="2">Día</th>
|
||||||
|
<th class="py-2 total-column text-success" rowspan="2">VENTA TOTAL</th>
|
||||||
|
<th class="py-2 text-info" rowspan="2">COMISIÓN</th>
|
||||||
|
<th class="py-2 text-danger" rowspan="2">GASTOS</th>
|
||||||
|
<th class="py-1 border-bottom-0" colspan="4">MEDIOS DE PAGO</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="py-1 text-muted">Crédito</th>
|
||||||
|
<th class="py-1 text-muted">Débito</th>
|
||||||
|
<th class="py-1 text-muted">Mercado Pago</th>
|
||||||
|
<th class="py-1 text-muted">Efectivo/Dep.</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for dia in dias_en_periodo %}
|
||||||
|
{% set d = data_por_dia[dia] %}
|
||||||
|
<tr>
|
||||||
|
<td class="align-middle sticky-col numeric-cell fw-bold text-center">{{ dia }}</td>
|
||||||
|
|
||||||
|
<td class="align-middle numeric-cell total-column text-success">
|
||||||
|
{{ ("$" ~ "{:,.0f}".format(d.venta_total).replace(',', '.')) if d.venta_total > 0 else "-" }}
|
||||||
|
</td>
|
||||||
|
<td class="align-middle numeric-cell text-info fw-bold">
|
||||||
|
{{ ("$" ~ "{:,.0f}".format(d.comision).replace(',', '.')) if d.comision > 0 else "-" }}
|
||||||
|
</td>
|
||||||
|
<td class="align-middle numeric-cell text-danger">
|
||||||
|
{{ ("-$" ~ "{:,.0f}".format(d.gastos).replace(',', '.')) if d.gastos > 0 else "-" }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="align-middle numeric-cell text-muted">{{ ("$" ~ "{:,.0f}".format(d.credito).replace(',', '.')) if d.credito > 0 else "-" }}</td>
|
||||||
|
<td class="align-middle numeric-cell text-muted">{{ ("$" ~ "{:,.0f}".format(d.debito).replace(',', '.')) if d.debito > 0 else "-" }}</td>
|
||||||
|
<td class="align-middle numeric-cell text-muted">{{ ("$" ~ "{:,.0f}".format(d.mp).replace(',', '.')) if d.mp > 0 else "-" }}</td>
|
||||||
|
<td class="align-middle numeric-cell text-muted">{{ ("$" ~ "{:,.0f}".format(d.efectivo).replace(',', '.')) if d.efectivo > 0 else "-" }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
<tfoot class="table-group-divider fw-bold bg-dark text-white sticky-bottom">
|
||||||
|
<tr>
|
||||||
|
<td class="align-middle sticky-col py-2 text-center">TOTAL</td>
|
||||||
|
<td class="align-middle numeric-cell py-2 fs-6 text-success border-end border-light">
|
||||||
|
${{ "{:,.0f}".format(totales_mes.venta_total).replace(',', '.') }}
|
||||||
|
</td>
|
||||||
|
<td class="align-middle numeric-cell py-2 text-info">
|
||||||
|
${{ "{:,.0f}".format(totales_mes.comision).replace(',', '.') }}
|
||||||
|
</td>
|
||||||
|
<td class="align-middle numeric-cell py-2 text-danger border-end border-light">
|
||||||
|
-${{ "{:,.0f}".format(totales_mes.gastos).replace(',', '.') }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="align-middle numeric-cell py-2">${{ "{:,.0f}".format(totales_mes.credito).replace(',', '.') }}</td>
|
||||||
|
<td class="align-middle numeric-cell py-2">${{ "{:,.0f}".format(totales_mes.debito).replace(',', '.') }}</td>
|
||||||
|
<td class="align-middle numeric-cell py-2">${{ "{:,.0f}".format(totales_mes.mp).replace(',', '.') }}</td>
|
||||||
|
<td class="align-middle numeric-cell py-2">${{ "{:,.0f}".format(totales_mes.efectivo).replace(',', '.') }}</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
52
templates/admin_reportes_index.html
Normal file
52
templates/admin_reportes_index.html
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
{% extends "macros/base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Panel de Reportes{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h2><i class="bi bi-graph-up text-primary me-2"></i>Panel de Reportes</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<p class="text-muted">Selecciona un módulo para ver sus reportes disponibles.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% for zona_name, lista_modulos in modulos|groupby(2) %}
|
||||||
|
<div class="zona-section mb-5">
|
||||||
|
<h4 class="text-info border-bottom border-secondary pb-2 mb-4">
|
||||||
|
<i class="bi bi-geo-alt-fill me-2"></i>Zona: {{ zona_name }}
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
<div class="row g-4">
|
||||||
|
{% for mod in lista_modulos %}
|
||||||
|
<div class="col-md-4 col-sm-6">
|
||||||
|
<a href="{{ url_for('admin_reportes_menu_modulo', modulo_id=mod[0]) }}" class="text-decoration-none">
|
||||||
|
<div class="card shadow-sm h-100 border-0 hover-shadow transition-all bg-dark-subtle">
|
||||||
|
<div class="card-body text-center py-4">
|
||||||
|
<div class="mb-3">
|
||||||
|
<i class="bi bi-shop display-4 text-info"></i>
|
||||||
|
</div>
|
||||||
|
<h5 class="card-title text-body">{{ mod[1] }}</h5>
|
||||||
|
<span class="badge bg-primary mt-2">Ver Reportes <i class="bi bi-arrow-right ms-1"></i></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-info">No hay módulos registrados en el sistema.</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.hover-shadow:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
box-shadow: 0 .5rem 1rem rgba(0,0,0,.3)!important;
|
||||||
|
border-color: #0dcaf0 !important; /* Resalta en azul claro (info) al pasar el mouse */
|
||||||
|
}
|
||||||
|
.transition-all {
|
||||||
|
transition: all .3s ease-in-out;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
117
templates/admin_reportes_menu.html
Normal file
117
templates/admin_reportes_menu.html
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
{% extends "macros/base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Menú de Reportes - {{ modulo_name }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<div>
|
||||||
|
<a href="{{ url_for('admin_reportes_index') }}" class="btn btn-outline-secondary btn-sm mb-2">
|
||||||
|
<i class="bi bi-arrow-left"></i> Volver a Módulos
|
||||||
|
</a>
|
||||||
|
<h2>Reportes: <span class="text-info">{{ modulo_name }}</span></h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-4 mt-2">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card border-0 shadow-sm h-100 hover-card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex align-items-center mb-3">
|
||||||
|
<div class="bg-primary text-white rounded p-3 me-3">
|
||||||
|
<i class="bi bi-cash-coin fs-4"></i>
|
||||||
|
</div>
|
||||||
|
<h5 class="card-title mb-0">Detalle de Ventas y Medios de Pago</h5>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted small">Análisis detallado de ventas diarias, productos vendidos y consolidado mensual.</p>
|
||||||
|
<a href="{{ url_for('report_modulo_periodo', modulo_id=modulo_id) }}" class="btn btn-primary w-100">Generar Reporte</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card border-0 shadow-sm h-100 hover-card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex align-items-center mb-3">
|
||||||
|
<div class="bg-success text-white rounded p-3 me-3">
|
||||||
|
<i class="bi bi-percent fs-4"></i>
|
||||||
|
</div>
|
||||||
|
<h5 class="card-title mb-0">Comisiones</h5>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted small">Cálculo de comisiones generadas por los trabajadores en este módulo.</p>
|
||||||
|
<button class="btn btn-outline-success w-100" onclick="alert('Reporte en construcción')">Generar Reporte</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card border-0 shadow-sm h-100 hover-card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex align-items-center mb-3">
|
||||||
|
<div class="bg-warning text-dark rounded p-3 me-3">
|
||||||
|
<i class="bi bi-clock-history fs-4"></i>
|
||||||
|
</div>
|
||||||
|
<h5 class="card-title mb-0">Control de Horarios</h5>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted small">Registro de horas de entrada y salida de los trabajadores y acompañantes.</p>
|
||||||
|
<button class="btn btn-outline-warning w-100" onclick="alert('Reporte en construcción')">Generar Reporte</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card border-0 shadow-sm h-100 hover-card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex align-items-center mb-3">
|
||||||
|
<div class="bg-info text-dark rounded p-3 me-3">
|
||||||
|
<i class="bi bi-building fs-4"></i>
|
||||||
|
</div>
|
||||||
|
<h5 class="card-title mb-0">Centros Comerciales</h5>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted small">Reporte de datos exigidos por la administración del centro comercial.</p>
|
||||||
|
<button class="btn btn-outline-info w-100" onclick="alert('Reporte en construcción')">Generar Reporte</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card border-0 shadow-sm h-100 hover-card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex align-items-center mb-3">
|
||||||
|
<div class="bg-secondary text-white rounded p-3 me-3">
|
||||||
|
<i class="bi bi-calculator fs-4"></i>
|
||||||
|
</div>
|
||||||
|
<h5 class="card-title mb-0">Cálculo de IVA</h5>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted small">Proyección de impuestos basados en las ventas declaradas.</p>
|
||||||
|
<button class="btn btn-outline-secondary w-100" onclick="alert('Reporte en construcción')">Generar Reporte</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card border-0 shadow-sm h-100 hover-card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex align-items-center mb-3">
|
||||||
|
<div class="bg-danger text-white rounded p-3 me-3">
|
||||||
|
<i class="bi bi-shield-exclamation fs-4"></i>
|
||||||
|
</div>
|
||||||
|
<h5 class="card-title mb-0">Robos y Mermas</h5>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted small">Cuadratura de inventario y registro de pérdida de productos.</p>
|
||||||
|
<button class="btn btn-outline-danger w-100" onclick="alert('Reporte en construcción')">Generar Reporte</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.hover-card {
|
||||||
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
background-color: #1e2125; /* Fondo oscuro sutil */
|
||||||
|
}
|
||||||
|
.hover-card:hover {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
box-shadow: 0 .5rem 1rem rgba(0,0,0,.25)!important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
@@ -40,6 +40,11 @@
|
|||||||
<i class="bi bi-box-seam me-1"></i> Productos
|
<i class="bi bi-box-seam me-1"></i> Productos
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% if request.endpoint and 'reporte' in request.endpoint %}active fw-bold text-white{% endif %}" href="{{ url_for('admin_reportes_index') }}">
|
||||||
|
<i class="bi bi-graph-up me-1"></i> Reportes
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {{ 'active fw-bold' if request.endpoint == 'worker_dashboard' }}" href="{{ url_for('worker_dashboard') }}">
|
<a class="nav-link {{ 'active fw-bold' if request.endpoint == 'worker_dashboard' }}" href="{{ url_for('worker_dashboard') }}">
|
||||||
|
|||||||
Reference in New Issue
Block a user