Skip to content

Commit

Permalink
Merge pull request #535 from Esmat-Farjad/feat/stock_dashboard
Browse files Browse the repository at this point in the history
stock dashboard completed
  • Loading branch information
shtayeb authored Jan 7, 2025
2 parents 14bda26 + efd62c6 commit 2140f7d
Show file tree
Hide file tree
Showing 13 changed files with 608 additions and 177 deletions.
34 changes: 32 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ markdown = "^3.6"
django-mailer = "^2.3.2"
gunicorn = "^23.0.0"
django-extensions = "^3.2.3"
plotly = "5.24.1"


[tool.poetry.group.dev.dependencies]
Expand Down
104 changes: 0 additions & 104 deletions src/project_reports/exports.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import datetime
import json

from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
Expand All @@ -10,8 +9,6 @@

from project_reports.filters import MonthlyReportsFilter, Organization5WFilter
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 .models import ActivityPlanReport, DisaggregationLocationReport, ProjectMonthlyReport, TargetLocationReport
Expand Down Expand Up @@ -87,57 +84,6 @@ def cluster_5w_dashboard_export(request, code):
return HttpResponse(response, status=500)


@login_required
def cluster_5w_stock_report_export(request, code):
cluster = get_object_or_404(Cluster, code=code)

body = json.loads(request.body)

from_date = body.get("from")
if not from_date:
from_date = datetime.date(datetime.datetime.now().year, 1, 1)

to_date = body.get("to")
if not to_date:
to_date = datetime.datetime.now().date()

user_country = request.user.profile.country

filter_params = {
"stockreport__cluster__in": [cluster],
"state__in": ["submitted"],
"from_date__lte": to_date,
"due_date__gte": from_date,
"warehouse_location__user__profile__country": user_country,
}

organization_code = body.get("organization")
if organization_code:
filter_params["warehouse_location__organization__code"] = organization_code

if not is_cluster_lead(
user=request.user,
clusters=[
cluster.code,
],
):
raise PermissionDenied
try:
stock_monthly_reports = (
StockMonthlyReport.objects.select_related("warehouse_location")
.prefetch_related(Prefetch("stockreport_set", queryset=StockReport.objects.all()))
.filter(**filter_params)
.distinct()
)
response = HttpResponse(content_type="text/csv")
response["Content-Disposition"] = "attachment; filename=reports.csv"
write_csv_columns_and_rows(stock_monthly_reports, response)
return response
except Exception as e:
response = {"error": str(e)}
return HttpResponse(response, status=500)


@login_required
def org_5w_dashboard_export(request, code):
org = get_object_or_404(Organization, code=code)
Expand Down Expand Up @@ -229,53 +175,3 @@ def export_monthly_report_view(request, pk):
except Exception as e:
response = {"error": str(e)}
return HttpResponse(response, status=500)


def export_org_stock_monthly_report(request, code):
org = get_object_or_404(Organization, code=code)

if not org.code == request.user.profile.organization.code and not is_cluster_lead(
request.user, org.clusters.values_list("code", flat=True)
):
raise PermissionDenied

# body = json.loads(request.body)

# cluster_code = body.get("cluster")
# from_date = body.get("from")
# if not from_date:
# from_date = datetime.date(datetime.datetime.now().year, 1, 1)

# to_date = body.get("to")
# if not to_date:
# to_date = datetime.datetime.now().date()

filter_params = {
"warehouse_location__organization": org,
"state__in": ["submitted"],
# "from_date__lte": to_date,
# "due_date__gte": from_date,
}

# cluster_code = body.get("cluster")
# if cluster_code:
# filter_params["stockreport__cluster__code__in"] = [
# cluster_code,
# ]
stock_monthly_report = (
StockMonthlyReport.objects.select_related("warehouse_location")
.prefetch_related(Prefetch("stockreport_set", queryset=StockReport.objects.all()))
.filter(**filter_params)
.distinct()
)
today = datetime.datetime.now()
filename = today.today().strftime("%d-%m-%Y")

try:
response = HttpResponse(content_type="text/csv")
response["Content-Disposition"] = f"attachment; filename={code}_stock_reports_exported_on_{filename}.csv"
write_csv_columns_and_rows(stock_monthly_report, response)
return response
except Exception as e:
print(f"Error: {e}")
return HttpResponse(status=500)
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@
<div class="top-panel pb-2 pt-4 flex flex-col items-center justify-between gap-2 sm:flex-row">
<h2 class="locations text-red-be">{{ request.resolver_match.kwargs.cluster|capfirst }} 5W Dashboard</h2>
<div class="actions-panel">
<a class="export-button btn btn-gray"
<!-- <a class="export-button btn btn-gray"
href="{% url 'cluster-5w-stock-report-export' request.resolver_match.kwargs.cluster %}"
title="{{request.resolver_match.kwargs.cluster }}_5w_stock_reports_">
<span class="btn-text">Export Stocks Reports</span>
<span class="icon-download"></span>
<!-- spinner start-->
spinner start
<img class="downloading"
style="width: 1.2rem"
src="{% static 'images/spinner.gif' %}" />
<!-- spinner end -->
</a>
spinner end
</a> -->
<a class="export-button btn btn-red"
href="{% url 'export-cluster-5w-dashboard' request.resolver_match.kwargs.cluster %}?{{request.GET.urlencode}}"
title="{{request.resolver_match.kwargs.cluster }}_5w_projects_reports_">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,10 @@
<div class="top-panel pb-2 pt-4 flex flex-col items-center justify-between gap-2 sm:flex-row">
<h2 class="locations text-red-be">{{ request.user.profile.organization }}'s 5W Dashboard</h2>
<div class="actions-panel">
<a class=" btn btn-gray"
href="{% url 'export-org-5w-stock-reports' user.profile.organization.code %}"
<a class=" btn btn-red"
href="{% url 'stock-dashboard' %}"
title="{{user.profile.organization.code}}_5w_stock_reports_">
<span class="btn-text">Export Stock Reports</span>
<span class="icon-download"></span>
<!-- spinner start-->
<img class="downloading"
style="width: 1.2rem"
src="{% static 'images/spinner.gif' %}" />
<!-- spinner end -->
<span class="btn-text">Stock Dashboard</span>
</a>
<a class=" btn btn-red"
href="{% url 'export-org-5w-dashboard' user.profile.organization.code %}?{{request.GET.urlencode}}"
Expand Down
15 changes: 5 additions & 10 deletions src/project_reports/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,19 +158,14 @@
export_views.cluster_5w_dashboard_export,
name="export-cluster-5w-dashboard",
),
path(
"stock-reports/cluster/<str:code>/export",
export_views.cluster_5w_stock_report_export,
name="cluster-5w-stock-report-export",
),
# path(
# "stock-reports/cluster/<str:code>/export",
# export_views.cluster_5w_stock_report_export,
# name="cluster-5w-stock-report-export",
# ),
path(
"project/monthly-report/export/<int:pk>",
export_views.export_monthly_report_view,
name="export_monthly_report",
),
path(
"stock/report/organization/<str:code>/export",
export_views.export_org_stock_monthly_report,
name="export-org-5w-stock-reports",
),
]
8 changes: 1 addition & 7 deletions src/project_reports/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,6 @@ def write_projects_reports_to_csv(monthly_progress_report, response):
else:
continue

disaggregation_list.append("total")
disaggregation_cols.append("total")

if disaggregations:
for disaggregation_col in disaggregation_cols:
columns.append(disaggregation_col)
Expand Down Expand Up @@ -256,10 +253,7 @@ def write_projects_reports_to_csv(monthly_progress_report, response):
disaggregation_location.disaggregation.name: disaggregation_location.reached
for disaggregation_location in disaggregation_locations
}
total_disaggregation = 0
for value in disaggregation_location_list.values():
total_disaggregation += value
disaggregation_location_list["total"] = total_disaggregation

# Update disaggregation_data with values from disaggregation_location_list
for disaggregation_entry in disaggregation_list:
if disaggregation_entry not in disaggregation_location_list:
Expand Down
41 changes: 41 additions & 0 deletions src/stock/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,44 @@ class Meta:

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)


class StockDashboardFilter(django_filters.FilterSet):
from_date = django_filters.DateFilter(
field_name="stockmonthlyreport__from_date",
label="From Date",
lookup_expr="exact",
widget=forms.DateInput(
attrs={
"type": "date",
}
),
)
due_date = django_filters.DateFilter(
field_name="stockmonthlyreport__due_date",
label="To Date",
lookup_expr="exact",
widget=forms.DateInput(attrs={"type": "date"}),
)
name = django_filters.ModelChoiceFilter(
lookup_expr="icontains", queryset=Warehouse.objects.all(), label="Warehouse Name"
)
status = django_filters.ChoiceFilter(
field_name="stockmonthlyreport__stockreport__status",
choices=StockReport.STATUS_TYPES,
label="Stock Status",
)
cluster = django_filters.ModelMultipleChoiceFilter(
field_name="stockmonthlyreport__stockreport__cluster",
queryset=Cluster.objects.all(),
lookup_expr="exact",
label="Clusters / Sectors",
widget=forms.SelectMultiple(attrs={"class": "custom-select"}),
)

class Meta:
mode = Warehouse
fields = ["from_date", "due_date", "name", "status", "cluster"]

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Loading

0 comments on commit 2140f7d

Please sign in to comment.