from django.views.generic.base import TemplateView from django.contrib.auth.mixins import LoginRequiredMixin class AppsView(LoginRequiredMixin, TemplateView): pass # ───── Existing ────────────────────────────────────────────────────────────── # Calendar apps_calendar_view = AppsView.as_view(template_name="pxy_dashboard/apps/apps-calendar.html") # Chat apps_chat_view = AppsView.as_view(template_name="pxy_dashboard/apps/apps-chat.html") # Email apps_email_inbox_view = AppsView.as_view(template_name="pxy_dashboard/apps/apps-email-inbox.html") apps_email_read = AppsView.as_view(template_name="pxy_dashboard/apps/apps-email-read.html") # Tasks apps_tasks = AppsView.as_view(template_name="pxy_dashboard/apps/apps-tasks.html") apps_tasks_details = AppsView.as_view(template_name="pxy_dashboard/apps/apps-tasks-details.html") # Kanban apps_kanban_board = AppsView.as_view(template_name="pxy_dashboard/apps/apps-kanban.html") # File Manager apps_file_manager = AppsView.as_view(template_name="pxy_dashboard/apps/apps-file-manager.html") # ───── Waste Collection Intelligence ───────────────────────────────────────── # Pre-Operation #apps_zone_definition = AppsView.as_view(template_name="pxy_dashboard/apps/apps-zone-definition.html") apps_route_optimization = AppsView.as_view(template_name="pxy_dashboard/apps/apps-route-optimization.html") apps_dispatch_plan = AppsView.as_view(template_name="pxy_dashboard/apps/apps-dispatch-plan.html") # Operation – Physical & Social Digital Twin apps_urban_digital_twin = AppsView.as_view(template_name="pxy_dashboard/apps/apps-urban-digital-twin.html") apps_whatsapp_bot = AppsView.as_view(template_name="pxy_dashboard/apps/apps-whatsapp-bot.html") apps_telegram_bot = AppsView.as_view(template_name="pxy_dashboard/apps/apps-telegram-bot.html") apps_facebook_pages_bot = AppsView.as_view(template_name="pxy_dashboard/apps/apps-facebook-pages-bot.html") apps_feedback_loop = AppsView.as_view(template_name="pxy_dashboard/apps/apps-feedback-loop.html") # Post-Operation apps_route_analytics = AppsView.as_view(template_name="pxy_dashboard/apps/apps-route-analytics.html") apps_feedback_review = AppsView.as_view(template_name="pxy_dashboard/apps/apps-feedback-review.html") apps_twin_refinement = AppsView.as_view(template_name="pxy_dashboard/apps/apps-twin-refinement.html") # System Control apps_sync_monitor = AppsView.as_view(template_name="pxy_dashboard/apps/apps-sync-monitor.html") apps_logs_webhooks = AppsView.as_view(template_name="pxy_dashboard/apps/apps-logs-webhooks.html") apps_logs_parsing = AppsView.as_view(template_name="pxy_dashboard/apps/apps-logs-parsing.html") apps_logs_limits = AppsView.as_view(template_name="pxy_dashboard/apps/apps-logs-limits.html") apps_config_api = AppsView.as_view(template_name="pxy_dashboard/apps/apps-config-api.html") apps_config_map = AppsView.as_view(template_name="pxy_dashboard/apps/apps-config-map.html") apps_config_collection = AppsView.as_view(template_name="pxy_dashboard/apps/apps-config-collection.html") from django.shortcuts import render from .models import GeoScenario import pandas as pd def zone_definition_view(request): scenario = GeoScenario.objects.last() chart_data = {} viviendas_data = {} city_options = [] scatter_series = {} if scenario and scenario.csv_file: df = pd.read_csv(scenario.csv_file.path) df = df.fillna(0) # Solo conservar zonas con generación total > 0 df = df[df["GEN_TOT"] > 0] # Opciones de ciudad city_options = sorted(df["N_URBANO"].dropna().unique()) selected_city = request.GET.get("city") or (city_options[0] if city_options else None) # Barras por zona (residuos) if selected_city: city_df = df[df["N_URBANO"] == selected_city] grouped = ( city_df.groupby("COD_ZONA")[["GEN_ORG", "GEN_INVA", "GEN_RESTO"]] .sum() .reset_index() .sort_values(by="GEN_ORG", ascending=False) ) chart_data = { "zones": grouped["COD_ZONA"].astype(str).tolist(), "gen_org": grouped["GEN_ORG"].round(2).tolist(), "gen_inva": grouped["GEN_INVA"].round(2).tolist(), "gen_resto": grouped["GEN_RESTO"].round(2).tolist(), } # Barras por zona (viviendas) viviendas_grouped = ( city_df.groupby("COD_ZONA")["num_viviendas"] .sum() .reset_index() .sort_values(by="num_viviendas", ascending=False) ) viviendas_data = { "zones": viviendas_grouped["COD_ZONA"].astype(str).tolist(), "viviendas": viviendas_grouped["num_viviendas"].astype(int).tolist(), } # Dispersión por ciudad scatter_series = { "GEN_ORG": [], "GEN_INVA": [], "GEN_RESTO": [], } city_grouped = ( df.groupby("N_URBANO")[["num_viviendas", "GEN_ORG", "GEN_INVA", "GEN_RESTO"]] .sum() .reset_index() ) for _, row in city_grouped.iterrows(): viviendas = float(row["num_viviendas"]) if viviendas == 0: continue city = row["N_URBANO"] if row["GEN_ORG"] > 0: scatter_series["GEN_ORG"].append({"x": viviendas, "y": float(row["GEN_ORG"]), "city": city}) if row["GEN_INVA"] > 0: scatter_series["GEN_INVA"].append({"x": viviendas, "y": float(row["GEN_INVA"]), "city": city}) if row["GEN_RESTO"] > 0: scatter_series["GEN_RESTO"].append({"x": viviendas, "y": float(row["GEN_RESTO"]), "city": city}) return render(request, "pxy_dashboard/apps/apps-zone-definition.html", { "chart_data": chart_data, "viviendas_data": viviendas_data, "scatter_series": scatter_series, "cities": city_options, "selected_city": selected_city, })