diff --git a/app.py b/app.py index 43d5e1a..9ada6f6 100644 --- a/app.py +++ b/app.py @@ -438,6 +438,92 @@ def api_ocr_ticket(): except Exception as e: return jsonify({"ok": False, "mensaje": f"Error al procesar la imagen: {str(e)}"}), 500 +# ----------------------------------------------------------------------- +# Estadisticas de consumo +# ----------------------------------------------------------------------- +@app.route("/estadisticas") +@login_required +def estadisticas(): + return render_template("estadisticas.html", nombre=session.get("nombre", "")) + +@app.route("/api/estadisticas") +@login_required +def api_estadisticas(): + import csv as _csv + usuario = session["usuario"] + datos_dir = BASE_DIR / "datos" / usuario + tickets_dir = get_tickets_dir(usuario) + + # Contar archivos de tickets + try: + total_tickets = sum(1 for f in tickets_dir.iterdir() if f.is_file()) + except Exception: + total_tickets = 0 + + # Leer gasto_mensual.csv + meses = [] + gasto_csv = datos_dir / "gasto_mensual.csv" + if gasto_csv.exists(): + with open(gasto_csv, encoding="utf-8") as fh: + for row in _csv.DictReader(fh): + try: + meses.append({"mes": str(row.get("mes", "")), + "gasto": round(float(row.get("precio_total", 0)), 2)}) + except ValueError: + pass + meses.sort(key=lambda x: x["mes"]) + _ES = ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"] + for m in meses: + try: + partes = m["mes"].split("-") + m["label"] = _ES[int(partes[1]) - 1] + " " + partes[0][-2:] + except Exception: + m["label"] = m["mes"] + + gastos_v = [m["gasto"] for m in meses] + gasto_medio = round(sum(gastos_v) / len(gastos_v), 2) if gastos_v else 0.0 + gasto_anual = round(sum(gastos_v[-12:]), 2) if gastos_v else 0.0 + + hoy = datetime.now() + mes_actual_key = hoy.strftime("%Y-%m") + mes_ant_key = (hoy.replace(day=1) - timedelta(days=1)).strftime("%Y-%m") + gasto_mes_actual = next((m["gasto"] for m in meses if m["mes"] == mes_actual_key), 0.0) + gasto_mes_anterior = next((m["gasto"] for m in meses if m["mes"] == mes_ant_key), 0.0) + + # Leer resumen_productos.csv + top_gasto = [] + top_frecuencia = [] + productos_unicos = 0 + resumen_csv = datos_dir / "resumen_productos.csv" + if resumen_csv.exists(): + with open(resumen_csv, encoding="utf-8") as fh: + rows = list(_csv.DictReader(fh)) + productos_unicos = len(rows) + top_gasto = [ + {"producto": r["producto"], + "gasto_total": round(float(r.get("gasto_total", 0)), 2), + "veces": int(r.get("veces_comprado", 0))} + for r in sorted(rows, key=lambda r: float(r.get("gasto_total", 0)), reverse=True)[:10] + ] + top_frecuencia = [ + {"producto": r["producto"], + "veces_comprado": int(r.get("veces_comprado", 0)), + "gasto_total": round(float(r.get("gasto_total", 0)), 2)} + for r in sorted(rows, key=lambda r: int(r.get("veces_comprado", 0)), reverse=True)[:10] + ] + + return jsonify({ + "gasto_medio_mensual": gasto_medio, + "gasto_mes_actual": gasto_mes_actual, + "gasto_mes_anterior": gasto_mes_anterior, + "gasto_anual": gasto_anual, + "total_tickets": total_tickets, + "productos_unicos": productos_unicos, + "meses": meses[-18:], + "top_productos_gasto": top_gasto, + "top_productos_frecuencia": top_frecuencia, + }) + # ----------------------------------------------------------------------- # Entry point # ----------------------------------------------------------------------- diff --git a/templates/estadisticas.html b/templates/estadisticas.html new file mode 100644 index 0000000..09a38a5 --- /dev/null +++ b/templates/estadisticas.html @@ -0,0 +1,328 @@ + + + + + + Estadísticas — Lista de la Compra + + + + + +
+

Estadísticas

+
+ ← Lista de la compra + {{ nombre }} + Salir +
+
+

Cargando estadísticas...

+ +
⏳ Cargando datos…
+ + + + + + diff --git a/templates/index.html b/templates/index.html index b8e3118..3e89e4a 100644 --- a/templates/index.html +++ b/templates/index.html @@ -14,6 +14,7 @@ {% if session.get('usuario') == 'admin' %} Usuarios {% endif %} + 📊 Estadísticas {{ nombre }} Salir