Skip to content

Commit

Permalink
Add query for Assessment registry Count
Browse files Browse the repository at this point in the history
- total assessment count
- total stakeholder count
- collection technique count
- multisector and single sector assessment
  • Loading branch information
sudan45 committed Aug 14, 2023
1 parent d19221d commit df9fdb2
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 38 deletions.
153 changes: 123 additions & 30 deletions apps/assessment_registry/dashboard_schema.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,45 @@
import itertools
import graphene
from .models import AssessmentRegistry, MethodologyAttribute
from dataclasses import dataclass
from collections import defaultdict
from deep.caches import CacheHelper
from django.db.models import Count
from django.db import models

from utils.graphene.enums import EnumDescription
from .enums import (
AssessmentRegistryCoordinationTypeEnum,
AssessmentRegistryDataCollectionTechniqueTypeEnum,
)
from django.db.models import Count
from .models import AssessmentRegistry, MethodologyAttribute


def get_global_filters(_filter: dict, date_field="created_at"):
return {
f"{date_field}__gte": _filter["date_from"],
f"{date_field}__lte": _filter["date_to"],
}


@dataclass
class AssessmentDashboardStat:
cache_key: str
assessment_registry_qs: models.QuerySet
methodology_attribute_qs: models.QuerySet


class AssessmentDashboardFilterInputType(graphene.InputObjectType):
date_from = graphene.Date(required=True)
date_to = graphene.Date(required=True)


class AssessmentCountType(graphene.ObjectType):
coordinated_joint = graphene.Field(AssessmentRegistryCoordinationTypeEnum)
coordinated_joint_display = graphene.String()
coordinated_joint_display = EnumDescription(required=False)
count = graphene.Int()

def resolve_coordinated_joint_display(self, info):
return AssessmentRegistry.CoordinationType(
self.coordinated_joint).label
return AssessmentRegistry.CoordinationType(self.coordinated_joint).label


class StakeholderCountType(graphene.ObjectType):
Expand All @@ -24,10 +49,10 @@ class StakeholderCountType(graphene.ObjectType):

class CollectionTechniqueCountType(graphene.ObjectType):
data_collection_technique = graphene.Field(
AssessmentRegistryDataCollectionTechniqueTypeEnum
AssessmentRegistryDataCollectionTechniqueTypeEnum, required=True
)
data_collection_technique_display = graphene.String()
count = graphene.Int()
data_collection_technique_display = EnumDescription(required=False)
count = graphene.Int(required=True)

def resolve_data_collection_technique_display(self, info):
return MethodologyAttribute.CollectionTechniqueType(
Expand All @@ -36,18 +61,64 @@ def resolve_data_collection_technique_display(self, info):


class AssessmentDashboardStatisticsType(graphene.ObjectType):
total_assessment = graphene.Int(required=True)
total_stakeholder = graphene.Int(required=True)
total_collection_technique = graphene.Int(required=True)
assessment_count = graphene.List(AssessmentCountType)
stakeholder_count = graphene.List(StakeholderCountType)
collection_technique_count = graphene.List(CollectionTechniqueCountType)
model = AssessmentRegistry
total_multisector_assessment = graphene.Int(required=True)
total_singlesector_assessment = graphene.Int(required=True)

@staticmethod
def custom_resolver(info, _filter):
assessment_qs = AssessmentRegistry.objects.filter(
project=info.context.active_project,
**get_global_filters(_filter),
)
methodology_attribute_qs = MethodologyAttribute.objects.filter(
assessment_registry__project_id=info.context.active_project,
**get_global_filters(_filter),
)
cache_key = CacheHelper.generate_hash(_filter.__dict__)
return AssessmentDashboardStat(
cache_key=cache_key,
assessment_registry_qs=assessment_qs,
methodology_attribute_qs=methodology_attribute_qs,
)

@staticmethod
def resolve_total_assessment(root: AssessmentDashboardStat, info) -> int:
return root.assessment_registry_qs.count()

def resolve_assessment_count(self, info):
@staticmethod
def resolve_total_stakeholder(root: AssessmentDashboardStat, info) -> int:
# TODO: when stakeholder manage in a single field
qs = root.assessment_registry_qs.values_list(
"international_partners__title",
"donors__title",
"lead_organizations__title",
"national_partners__title",
"governments__title",
)
return len(set(list(itertools.chain(*qs))))

@staticmethod
def resolve_total_collection_technique(root: AssessmentDashboardStat, info) -> int:
return (
root.methodology_attribute_qs.values("data_collection_technique")
.distinct()
.count()
)

@staticmethod
def resolve_assessment_count(root: AssessmentDashboardStat, info):
assessment = (
self.model.objects.filter(project=info.context.active_project)
.values("coordinated_joint")
root.assessment_registry_qs.values("coordinated_joint")
.annotate(count=Count("coordinated_joint"))
.order_by("coordinated_joint")
)

return [
AssessmentCountType(
coordinated_joint=assessment["coordinated_joint"],
Expand All @@ -56,27 +127,35 @@ def resolve_assessment_count(self, info):
for assessment in assessment
]

def resolve_stakeholder_count(self, info):
stakeholder = (
self.model.objects.filter(project=info.context.active_project)
.values("lead_organizations", "lead_organizations__title")
.annotate(count=Count("lead_organizations"))
.order_by("lead_organizations")
)
@staticmethod
def resolve_stakeholder_count(root: AssessmentDashboardStat, info):
# TODO: when stakeholder manage in a single field
stakeholder_counts = defaultdict(int)
organization_type_fields = [
"lead_organizations__organization_type__title",
"international_partners__organization_type__title",
"donors__organization_type__title",
"national_partners__organization_type__title",
"governments__organization_type__title",
]

for field in organization_type_fields:
stakeholders = root.assessment_registry_qs.values(field)
for stakeholder in stakeholders:
if organization_type_title := stakeholder.get(field):
stakeholder_counts[organization_type_title] += 1
return [
StakeholderCountType(
stakeholder=stakeholder["lead_organizations__title"],
count=stakeholder["count"],
stakeholder=org_type_title,
count=count,
)
for stakeholder in stakeholder
for org_type_title, count in stakeholder_counts.items()
]

def resolve_collection_technique_count(self, info):
@staticmethod
def resolve_collection_technique_count(root: AssessmentDashboardStat, info):
data_collection_technique = (
MethodologyAttribute.objects.filter(
assessment_registry__project_id=info.context.active_project
)
.values("data_collection_technique")
root.methodology_attribute_qs.values("data_collection_technique")
.annotate(count=Count("data_collection_technique"))
.order_by("data_collection_technique")
)
Expand All @@ -88,11 +167,25 @@ def resolve_collection_technique_count(self, info):
for technique in data_collection_technique
]

@staticmethod
def resolve_total_multisector_assessment(
root: AssessmentDashboardStat, info
) -> int:
return root.assessment_registry_qs.filter(sectors__len__gte=2).count()

@staticmethod
def resolve_total_singlesector_assessment(
root: AssessmentDashboardStat, info
) -> int:
return root.assessment_registry_qs.filter(sectors__len=1).count()


class Query:
assessment_dashboard_statistics = graphene.Field(
AssessmentDashboardStatisticsType)
AssessmentDashboardStatisticsType,
filter=AssessmentDashboardFilterInputType(),
)

@staticmethod
def resolve_assessment_dashboard_statistics(root, info, **kwargs):
return AssessmentDashboardStatisticsType
def resolve_assessment_dashboard_statistics(root, info, filter):
return AssessmentDashboardStatisticsType.custom_resolver(info, filter)
28 changes: 28 additions & 0 deletions apps/assessment_registry/filter_set.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import django_filters

from user_resource.filters import UserResourceGqlFilterSet
from .models import AssessmentRegistry
from utils.graphene.filters import IDListFilter


class AssessmentDashboardFilterSet(UserResourceGqlFilterSet):
search = django_filters.CharFilter(method="filter_title")
stakeholder = IDListFilter(distinct=True)
lead_organization = IDListFilter(distinct=True)
location = IDListFilter(distinct=True)
sector = IDListFilter(distinct=True)
affected_group = IDListFilter(distinct=True)
family = IDListFilter(distinct=True)
frequency = IDListFilter(distinct=True)
coordination_type = IDListFilter(distinct=True)

class Meta:
model = AssessmentRegistry
fields = ()

def filter_search(self, qs, _, value):
return qs if value is None else qs.filter(project__title=value)

@property
def qs(self):
return super().qs.distinct()
5 changes: 2 additions & 3 deletions apps/project/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@
from assessment_registry.schema import Query as AssessmentRegistryQuery
from unified_connector.schema import UnifiedConnectorQueryType
from assisted_tagging.schema import AssistedTaggingQueryType
from assessment_registry import dashboard_schema as assessment_registry_dashboard

from assessment_registry.dashboard_schema import Query as AssessmentRegistryDashboardQuery
from lead.models import Lead
from entry.models import Entry
from geo.models import Region
Expand Down Expand Up @@ -399,7 +398,7 @@ class ProjectDetailType(
AryQuery,
AnalysisQuery,
AssessmentRegistryQuery,
assessment_registry_dashboard.Query,
AssessmentRegistryDashboardQuery,
# -- End --Project scopped entities
ProjectType,
):
Expand Down
20 changes: 15 additions & 5 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -485,14 +485,24 @@ type AnalyticalStatementType {

type AssessmentCountType {
coordinatedJoint: AssessmentRegistryCoordinationTypeEnum
coordinatedJointDisplay: String
coordinatedJointDisplay: EnumDescription
count: Int
}

input AssessmentDashboardFilterInputType {
dateFrom: Date!
dateTo: Date!
}

type AssessmentDashboardStatisticsType {
totalAssessment: Int!
totalStakeholder: Int!
totalCollectionTechnique: Int!
assessmentCount: [AssessmentCountType]
stakeholderCount: [StakeholderCountType]
collectionTechniqueCount: [CollectionTechniqueCountType]
totalMultisectorAssessment: Int!
totalSinglesectorAssessment: Int!
}

type AssessmentListType {
Expand Down Expand Up @@ -1099,9 +1109,9 @@ type ChangeUserPassword {
}

type CollectionTechniqueCountType {
dataCollectionTechnique: AssessmentRegistryDataCollectionTechniqueTypeEnum
dataCollectionTechniqueDisplay: String
count: Int
dataCollectionTechnique: AssessmentRegistryDataCollectionTechniqueTypeEnum!
dataCollectionTechniqueDisplay: EnumDescription
count: Int!
}

enum ConnectorLeadExtractionStatusEnum {
Expand Down Expand Up @@ -2731,7 +2741,7 @@ type ProjectDetailType {
organizations: [ProjectOrganizationType!]
hasAnalysisFramework: Boolean!
hasAssessmentTemplate: Boolean!
assessmentDashboardStatistics: AssessmentDashboardStatisticsType
assessmentDashboardStatistics(filter: AssessmentDashboardFilterInputType): AssessmentDashboardStatisticsType
assessmentRegistry(id: ID!): AssessmentRegistryType
assessmentRegistries(createdAt: DateTime, createdAtGte: DateTime, createdAtLte: DateTime, modifiedAt: DateTime, modifiedAtGte: DateTime, modifiedAtLte: DateTime, createdBy: [ID], modifiedBy: [ID!], project: [ID], lead: [ID], search: String, page: Int = 1, pageSize: Int): AssessmentRegistryListType
assessmentRegOptions: AssessmentRegistryOptionsType
Expand Down

0 comments on commit df9fdb2

Please sign in to comment.