From 6a4189ddb7385932cfa5de4b539d858a1359cb38 Mon Sep 17 00:00:00 2001 From: Shahryar Tayeb Date: Tue, 17 Dec 2024 08:59:57 +0430 Subject: [PATCH 1/2] handle none types in 5w dashboard - people reached sum --- src/project_reports/views/dashboards.py | 67 +++++++------------------ 1 file changed, 18 insertions(+), 49 deletions(-) diff --git a/src/project_reports/views/dashboards.py b/src/project_reports/views/dashboards.py index 6cad0886..18d85f71 100644 --- a/src/project_reports/views/dashboards.py +++ b/src/project_reports/views/dashboards.py @@ -3,13 +3,14 @@ from django.contrib.auth.decorators import login_required from django.core.cache import cache from django.core.exceptions import PermissionDenied -from django.db.models import Count, Sum +from django.db.models import Count, Sum, Value +from django.db.models.functions import Coalesce from django.shortcuts import get_object_or_404, render -from rh.models import Cluster, Organization -from users.utils import is_cluster_lead from project_reports.filters import Organization5WFilter from project_reports.models import ProjectMonthlyReport +from rh.models import Cluster, Organization +from users.utils import is_cluster_lead @login_required @@ -66,11 +67,15 @@ def cluster_5w_dashboard(request, cluster): .order_by("from_date") .values("from_date") .annotate( - total_people_reached=Sum("activityplanreport__targetlocationreport__disaggregationlocationreport__reached") + total_people_reached=Coalesce( + Sum("activityplanreport__targetlocationreport__disaggregationlocationreport__reached"), Value(0) + ) ) ) - counts["people_reached"] = sum(report["total_people_reached"] for report in people_reached_data) + counts["people_reached"] = 0 + for report in people_reached_data: + counts["people_reached"] += report["total_people_reached"] labels = [report["from_date"].strftime("%b") for report in people_reached_data] data = [ @@ -164,48 +169,6 @@ def org_5w_dashboard(request, code): if cluster_code: filter_params["project__clusters__code__in"] = [cluster_code] - # counts = ProjectMonthlyReport.objects.filter(**filter_params).aggregate( - # report_indicators_count=Count("activityplanreport__activity_plan__indicator", distinct=True), - # report_implementing_partners_count=Count( - # "activityplanreport__targetlocationreport__target_location__implementing_partner", distinct=True - # ), - # report_target_location_province_count=Count( - # "activityplanreport__targetlocationreport__target_location__province", distinct=True - # ), - # ) - - # people_reached_data = ( - # ProjectMonthlyReport.objects.filter( - # **filter_params, - # ) - # .order_by("from_date") - # .values("from_date") - # .annotate( - # total_people_reached=Sum("activityplanreport__targetlocationreport__disaggregationlocationreport__reached") - # ) - # ) - - # people reached by activities - # activity_domains = ( - # ProjectMonthlyReport.objects.filter( - # **filter_params, - # ) - # .values_list("activityplanreport__activity_plan__activity_domain__name", flat=True) - # .distinct() - # ) - - # reach_by_activity = ( - # ProjectMonthlyReport.objects.filter( - # **filter_params, - # ) - # .values( - # "activityplanreport__targetlocationreport__disaggregationlocationreport__disaggregation__name", - # "activityplanreport__activity_plan__activity_domain__name", - # ) - # .annotate( - # total_people_reached=Sum("activityplanreport__targetlocationreport__disaggregationlocationreport__reached"), - # ) - # ) counts = monthly_reports.aggregate( report_indicators_count=Count("activityplanreport__activity_plan__indicator", distinct=True), report_implementing_partners_count=Count( @@ -219,19 +182,25 @@ def org_5w_dashboard(request, code): monthly_reports.order_by("from_date") .values("from_date") .annotate( - total_people_reached=Sum("activityplanreport__targetlocationreport__disaggregationlocationreport__reached") + total_people_reached=Coalesce( + Sum("activityplanreport__targetlocationreport__disaggregationlocationreport__reached"), Value(0) + ) ) ) - counts["people_reached"] = sum(report["total_people_reached"] for report in people_reached_data) + counts["people_reached"] = 0 + for report in people_reached_data: + counts["people_reached"] += report["total_people_reached"] labels = [report["from_date"].strftime("%b") for report in people_reached_data] data = [ report["total_people_reached"] if report["total_people_reached"] is not None else 0 for report in people_reached_data ] + activity_domains = monthly_reports.values_list( "activityplanreport__activity_plan__activity_domain__name", flat=True ).distinct() + reach_by_activity = monthly_reports.values( "activityplanreport__targetlocationreport__disaggregationlocationreport__disaggregation__name", "activityplanreport__activity_plan__activity_domain__name", From 4b5dfc44a5402e2d71bddb38f63ed007a56b446c Mon Sep 17 00:00:00 2001 From: Shahryar Tayeb Date: Tue, 17 Dec 2024 09:00:00 +0430 Subject: [PATCH 2/2] make lint --- src/core/settings/production.py | 10 +++++--- src/guides/factory.py | 1 + src/project_reports/exports.py | 4 ++-- src/project_reports/filters.py | 1 + src/project_reports/forms.py | 1 + src/project_reports/models.py | 1 + src/project_reports/utils.py | 4 ++-- src/project_reports/views/monthly_reports.py | 1 + .../views/report_activity_plans.py | 1 + .../views/report_target_locations.py | 1 + src/project_reports/views/views.py | 1 + src/rh/factory.py | 1 + src/rh/management/commands/load_projects.py | 2 +- src/rh/signals.py | 1 + src/rh/tests/test_views.py | 2 +- src/rh/urls.py | 24 +++++++++++++------ src/rh/utils.py | 2 +- src/rh/views/budget_progress.py | 2 +- src/rh/views/clusters.py | 1 + src/rh/views/exports.py | 1 + src/rh/views/organizations.py | 1 + src/rh/views/projects.py | 1 + src/rh/views/views.py | 8 ++++--- src/stock/admin.py | 1 + src/stock/filter.py | 2 +- src/stock/forms.py | 1 + src/stock/models.py | 1 + src/users/factory.py | 1 + .../management/commands/create_groups.py | 1 + src/users/models.py | 1 + src/users/templatetags/user_lead_clusters.py | 1 + src/users/views/users.py | 1 + 32 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/core/settings/production.py b/src/core/settings/production.py index 130a73eb..5764f215 100644 --- a/src/core/settings/production.py +++ b/src/core/settings/production.py @@ -5,7 +5,9 @@ # ALLOWED_HOSTS=reporthub.immap.org,www.reporthub.immap.org # env.list() splits comma-separated string into a list -ALLOWED_HOSTS = env.list("ALLOWED_HOSTS", default=["localhost","dev.reporthub.immap.org", "www.dev.reporthub.immap.org"]) +ALLOWED_HOSTS = env.list( + "ALLOWED_HOSTS", default=["localhost", "dev.reporthub.immap.org", "www.dev.reporthub.immap.org"] +) # HSTS settings SECURE_HSTS_SECONDS = env("SECURE_HSTS_SECONDS", default=31536000) @@ -16,7 +18,9 @@ SESSION_COOKIE_SECURE = env("SESSION_COOKIE_SECURE", default=True) CSRF_COOKIE_SECURE = env("CSRF_COOKIE_SECURE", default=True) SECURE_SSL_REDIRECT = env("SECURE_SSL_REDIRECT", default=True) -CSRF_TRUSTED_ORIGINS = env("CSRF_TRUSTED_ORIGINS",default=["http://localhost","https://localhost","https://127.0.0.1","http://127.0.0.1"]) +CSRF_TRUSTED_ORIGINS = env( + "CSRF_TRUSTED_ORIGINS", default=["http://localhost", "https://localhost", "https://127.0.0.1", "http://127.0.0.1"] +) SENTRY_DSN = env("SENTRY_DSN", default="") @@ -119,4 +123,4 @@ } } -DJANGO_SUPERUSER_PASSWORD = env("DJANGO_SUPERUSER_PASSWORD",default="change-this") \ No newline at end of file +DJANGO_SUPERUSER_PASSWORD = env("DJANGO_SUPERUSER_PASSWORD", default="change-this") diff --git a/src/guides/factory.py b/src/guides/factory.py index 4b8780da..a636aeba 100644 --- a/src/guides/factory.py +++ b/src/guides/factory.py @@ -1,5 +1,6 @@ import factory from factory.django import DjangoModelFactory + from users.factory import UserFactory from .models import Feedback, Guide, Section diff --git a/src/project_reports/exports.py b/src/project_reports/exports.py index 9d6ee410..ef55b7f5 100644 --- a/src/project_reports/exports.py +++ b/src/project_reports/exports.py @@ -7,13 +7,13 @@ from django.http import HttpResponse from django.shortcuts import get_object_or_404 from openpyxl.styles import Font, NamedStyle + +from project_reports.filters import MonthlyReportsFilter from rh.models import Cluster, Organization, Project from stock.models import StockMonthlyReport, StockReport from stock.utils import write_csv_columns_and_rows from users.utils import is_cluster_lead -from project_reports.filters import MonthlyReportsFilter - from .models import ActivityPlanReport, DisaggregationLocationReport, ProjectMonthlyReport, TargetLocationReport from .utils import write_projects_reports_to_csv diff --git a/src/project_reports/filters.py b/src/project_reports/filters.py index ce6bfc27..7fbf6783 100644 --- a/src/project_reports/filters.py +++ b/src/project_reports/filters.py @@ -1,5 +1,6 @@ import django_filters from django import forms + from rh.models import ( ActivityDomain, ActivityType, diff --git a/src/project_reports/forms.py b/src/project_reports/forms.py index 62a46257..2a3198f0 100644 --- a/src/project_reports/forms.py +++ b/src/project_reports/forms.py @@ -5,6 +5,7 @@ from django.forms.models import inlineformset_factory from django.shortcuts import get_object_or_404 from django.urls import reverse_lazy + from rh.models import ActivityPlan, Disaggregation, Indicator, TargetLocation from .models import ( diff --git a/src/project_reports/models.py b/src/project_reports/models.py index 50614c01..f6f10e41 100644 --- a/src/project_reports/models.py +++ b/src/project_reports/models.py @@ -1,5 +1,6 @@ from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models + from rh.models import ( ActivityPlan, Cluster, diff --git a/src/project_reports/utils.py b/src/project_reports/utils.py index d2ce69cd..4794d9f8 100644 --- a/src/project_reports/utils.py +++ b/src/project_reports/utils.py @@ -4,6 +4,8 @@ from openpyxl.styles import Font, NamedStyle from openpyxl.utils import get_column_letter from openpyxl.worksheet.datavalidation import DataValidation + +from project_reports.models import ResponseType from rh.models import ( Currency, Disaggregation, @@ -16,8 +18,6 @@ UnitType, ) -from project_reports.models import ResponseType - header_style = NamedStyle(name="header") header_style.font = Font(bold=True) diff --git a/src/project_reports/views/monthly_reports.py b/src/project_reports/views/monthly_reports.py index 01684de1..49a85c75 100644 --- a/src/project_reports/views/monthly_reports.py +++ b/src/project_reports/views/monthly_reports.py @@ -17,6 +17,7 @@ from django.utils import timezone from django_htmx.http import HttpResponseClientRedirect from extra_settings.models import Setting + from rh.models import ( ActivityDetail, ActivityDomain, diff --git a/src/project_reports/views/report_activity_plans.py b/src/project_reports/views/report_activity_plans.py index a0fe9146..194afd28 100644 --- a/src/project_reports/views/report_activity_plans.py +++ b/src/project_reports/views/report_activity_plans.py @@ -5,6 +5,7 @@ from django.urls import reverse, reverse_lazy from django.utils.safestring import mark_safe from django_htmx.http import HttpResponseClientRedirect + from rh.models import ActivityPlan from ..forms import ( diff --git a/src/project_reports/views/report_target_locations.py b/src/project_reports/views/report_target_locations.py index acf8ed72..289eb253 100644 --- a/src/project_reports/views/report_target_locations.py +++ b/src/project_reports/views/report_target_locations.py @@ -10,6 +10,7 @@ from django.urls import reverse, reverse_lazy from django.utils.safestring import mark_safe from django_htmx.http import HttpResponseClientRedirect + from rh.models import ( DisaggregationLocation, Project, diff --git a/src/project_reports/views/views.py b/src/project_reports/views/views.py index 738e9f1c..6102765d 100644 --- a/src/project_reports/views/views.py +++ b/src/project_reports/views/views.py @@ -9,6 +9,7 @@ from django.urls import reverse from django.views.decorators.http import require_http_methods from openpyxl import Workbook + from rh.models import ( ActivityDomain, ActivityPlan, diff --git a/src/rh/factory.py b/src/rh/factory.py index c3f9637e..aebb23a4 100644 --- a/src/rh/factory.py +++ b/src/rh/factory.py @@ -4,6 +4,7 @@ import pytz from factory.django import DjangoModelFactory from factory.faker import faker + from users.factory import UserFactory from .models import ( diff --git a/src/rh/management/commands/load_projects.py b/src/rh/management/commands/load_projects.py index 7ae28249..dfbeb28d 100644 --- a/src/rh/management/commands/load_projects.py +++ b/src/rh/management/commands/load_projects.py @@ -7,7 +7,6 @@ from django.db import connection from django.db.models import Q from django.utils import timezone -from users.models import Profile from rh.models import ( ActivityDetail, @@ -29,6 +28,7 @@ TransferMechanismType, UnitType, ) +from users.models import Profile BASE_DIR = Path(__file__).resolve().parent.parent.parent.parent diff --git a/src/rh/signals.py b/src/rh/signals.py index 30a27af6..4a561204 100644 --- a/src/rh/signals.py +++ b/src/rh/signals.py @@ -1,6 +1,7 @@ from django.contrib.auth.models import Group from django.db.models.signals import post_save from django.dispatch import receiver + from users.utils import assign_default_permissions_to_group from .models import Cluster diff --git a/src/rh/tests/test_views.py b/src/rh/tests/test_views.py index c492b6be..36273407 100644 --- a/src/rh/tests/test_views.py +++ b/src/rh/tests/test_views.py @@ -1,9 +1,9 @@ from django.contrib.auth.models import User from django.test import Client, TestCase from django.urls import reverse -from users.models import Profile from rh.models import Cluster, Location, Organization +from users.models import Profile class TestLoggedInViews(TestCase): diff --git a/src/rh/urls.py b/src/rh/urls.py index a8d7230f..6787cde6 100644 --- a/src/rh/urls.py +++ b/src/rh/urls.py @@ -1,13 +1,25 @@ -from django.urls import path from django.conf import settings +from django.urls import path from .views import ( - budget_progress as budget_progress, activity_plans as activity_plans, - projects as projects, - exports as export_views, +) +from .views import ( + budget_progress as budget_progress, +) +from .views import ( clusters as clusters_views, +) +from .views import ( + exports as export_views, +) +from .views import ( organizations as organizations, +) +from .views import ( + projects as projects, +) +from .views import ( target_locations as target_locations, ) from .views.views import ( @@ -225,6 +237,4 @@ ] if settings.DEBUG: - urlpatterns.append( - path(route="test-email/",view=test_email,name="test-email") - ) \ No newline at end of file + urlpatterns.append(path(route="test-email/", view=test_email, name="test-email")) diff --git a/src/rh/utils.py b/src/rh/utils.py index 5a6a9fb7..35fa208d 100644 --- a/src/rh/utils.py +++ b/src/rh/utils.py @@ -2,9 +2,9 @@ from datetime import datetime from django.contrib.auth.models import User -from users.utils import is_cluster_lead from rh.models import Project, TargetLocation +from users.utils import is_cluster_lead def has_permission(user: User, project: Project = None, clusters: list = [], permission: str = ""): diff --git a/src/rh/views/budget_progress.py b/src/rh/views/budget_progress.py index 4df08cc1..54d1428b 100644 --- a/src/rh/views/budget_progress.py +++ b/src/rh/views/budget_progress.py @@ -21,7 +21,7 @@ def create_project_budget_progress_view(request, project): project = get_object_or_404(Project, pk=project) financial_report = project.budgetprogress_set.all() - + if request.method == "POST": form = BudgetProgressForm(request.POST, project=project) country = request.POST.get("country") diff --git a/src/rh/views/clusters.py b/src/rh/views/clusters.py index aaf207f6..4cd988d6 100644 --- a/src/rh/views/clusters.py +++ b/src/rh/views/clusters.py @@ -3,6 +3,7 @@ from django.db.models import Count from django.shortcuts import get_object_or_404, render from extra_settings.models import Setting + from project_reports.filters import MonthlyReportsFilter from project_reports.models import ProjectMonthlyReport diff --git a/src/rh/views/exports.py b/src/rh/views/exports.py index bbf267eb..534bace8 100644 --- a/src/rh/views/exports.py +++ b/src/rh/views/exports.py @@ -10,6 +10,7 @@ from openpyxl import Workbook from openpyxl.styles import Font, NamedStyle from openpyxl.utils import get_column_letter + from rh.utils import DateTimeEncoder from ..filters import ProjectsFilter diff --git a/src/rh/views/organizations.py b/src/rh/views/organizations.py index 52c87986..3a20378d 100644 --- a/src/rh/views/organizations.py +++ b/src/rh/views/organizations.py @@ -4,6 +4,7 @@ from django.core.exceptions import PermissionDenied from django.http import JsonResponse from django.shortcuts import get_object_or_404, render + from rh.models import Organization, TargetLocation from users.utils import is_cluster_lead diff --git a/src/rh/views/projects.py b/src/rh/views/projects.py index 69683e51..16165a27 100644 --- a/src/rh/views/projects.py +++ b/src/rh/views/projects.py @@ -15,6 +15,7 @@ from django.views.decorators.http import require_http_methods from django_htmx.http import HttpResponseClientRedirect from extra_settings.models import Setting + from project_reports.models import ProjectMonthlyReport from ..filters import ProjectsFilter diff --git a/src/rh/views/views.py b/src/rh/views/views.py index 4e9b0198..9dfd88ed 100644 --- a/src/rh/views/views.py +++ b/src/rh/views/views.py @@ -6,13 +6,14 @@ from django.http import JsonResponse from django.shortcuts import render from django.views.decorators.cache import cache_page + from project_reports.models import ProjectMonthlyReport from users.decorators import unauthenticated_user from ..models import ActivityDomain, ActivityType, Cluster, Indicator, Location, Project -def test_email(request,template_name): +def test_email(request, template_name): """ Route: /test-email/{template_name} template_name format: -- @@ -20,9 +21,10 @@ def test_email(request,template_name): """ context = {} - template_name = template_name.replace("-","/") + template_name = template_name.replace("-", "/") + + return render(request=request, template_name=f"{template_name}.html", context=context) - return render(request=request,template_name=f"{template_name}.html",context=context) @login_required def home(request): diff --git a/src/stock/admin.py b/src/stock/admin.py index acb41d3f..cbbfc0fa 100644 --- a/src/stock/admin.py +++ b/src/stock/admin.py @@ -1,4 +1,5 @@ from django.contrib import admin + from rh.models import Location from .models import ( diff --git a/src/stock/filter.py b/src/stock/filter.py index 537f6a2a..6ec481e9 100644 --- a/src/stock/filter.py +++ b/src/stock/filter.py @@ -1,7 +1,7 @@ import django_filters from django import forms -from rh.models import Cluster, Location +from rh.models import Cluster, Location from stock.models import StockItemsType, StockMonthlyReport, StockReport, StockUnit, Warehouse diff --git a/src/stock/forms.py b/src/stock/forms.py index 0122a56f..171d47b5 100644 --- a/src/stock/forms.py +++ b/src/stock/forms.py @@ -1,4 +1,5 @@ from django import forms + from rh.models import Location, Project from .models import StockItemsType, StockMonthlyReport, StockReport, Warehouse diff --git a/src/stock/models.py b/src/stock/models.py index f45adf20..0168a6bf 100644 --- a/src/stock/models.py +++ b/src/stock/models.py @@ -1,4 +1,5 @@ from django.db import models + from rh.models import Cluster, Location, Organization, Project from users.models import User diff --git a/src/users/factory.py b/src/users/factory.py index ee646a3e..91ed1ec4 100644 --- a/src/users/factory.py +++ b/src/users/factory.py @@ -5,6 +5,7 @@ from django.contrib.auth.models import User from factory.django import DjangoModelFactory from factory.faker import faker + from rh.models import Cluster, Location, Organization from .models import Profile diff --git a/src/users/management/commands/create_groups.py b/src/users/management/commands/create_groups.py index 27493e23..ac4b873a 100644 --- a/src/users/management/commands/create_groups.py +++ b/src/users/management/commands/create_groups.py @@ -1,5 +1,6 @@ from django.contrib.auth.models import Group from django.core.management.base import BaseCommand + from rh.models import Cluster from users.utils import assign_default_permissions_to_group diff --git a/src/users/models.py b/src/users/models.py index 4a162630..401c8345 100644 --- a/src/users/models.py +++ b/src/users/models.py @@ -1,5 +1,6 @@ from django.contrib.auth.models import User from django.db import models + from rh.models import Cluster, Location, Organization diff --git a/src/users/templatetags/user_lead_clusters.py b/src/users/templatetags/user_lead_clusters.py index 93ffd785..6547b02e 100644 --- a/src/users/templatetags/user_lead_clusters.py +++ b/src/users/templatetags/user_lead_clusters.py @@ -1,5 +1,6 @@ from django import template from django.contrib.auth.models import User + from rh.models import Cluster register = template.Library() diff --git a/src/users/views/users.py b/src/users/views/users.py index f8dca947..4129259b 100644 --- a/src/users/views/users.py +++ b/src/users/views/users.py @@ -15,6 +15,7 @@ from django.views.decorators.http import require_http_methods from extra_settings.models import Setting from openpyxl import Workbook + from rh.models import Cluster from ..forms import (