diff --git a/.env-example b/.env-example index 5096312a..608ba8ac 100644 --- a/.env-example +++ b/.env-example @@ -21,4 +21,7 @@ DATABASE_URL='postgres://mfl_testing:mfl_testing@localhost:5432/mfl_testing' FRONTEND_URL='http://localhost:8062' REALTIME_INDEX = true HTTPS_ENABLED = false -ALLOWED_HOSTS=".localhost, .health.go.ke" \ No newline at end of file +ALLOWED_HOSTS=".localhost, .health.go.ke" + +# Toggle synchronization of the facilities to KHIS Tracker +PUSH_TO_TRACKER=false \ No newline at end of file diff --git a/after_disaster_scripts.py b/after_disaster_scripts.py index 814e974b..f47a366e 100755 --- a/after_disaster_scripts.py +++ b/after_disaster_scripts.py @@ -78,14 +78,13 @@ def load_wards_and_sub_counties_json_file(): try: county_obj = County.objects.get(name__contains=county_name) except: - import pdb - pdb.set_trace() + try: constituency_obj = Constituency.objects.get( name=constituency_name, county=county_obj) except: - import pdb - pdb.set_trace() + + try: sub = SubCounty.objects.get( name=sub_county_name.lower(), county=county_obj) @@ -105,8 +104,8 @@ def load_wards_and_sub_counties_json_file(): county_name, constituency_name, sub_county_name, ward_name) except: - import pdb - pdb.set_trace() + + def delete_unwanted_facilities(): @@ -126,8 +125,8 @@ def delete_unwanted_facilities(): for fc in FacilityContact.everything.filter(facility=facility): for con in Contact.objects.filter(contact=fc.contact): con.delete() - import pdb - pdb.set_trace() + + fc.delete() for unit in FacilityUnit.objects.filter(facility=facility): diff --git a/chul/models.py b/chul/models.py index d4bc2102..68ed7ac3 100755 --- a/chul/models.py +++ b/chul/models.py @@ -226,6 +226,15 @@ def pending_updates(self): return chu.updates except ChuUpdateBuffer.DoesNotExist: return {} + except ChuUpdateBuffer.MultipleObjectsReturned: + + latest_chu = ChuUpdateBuffer.objects.filter( + is_approved=False, + is_rejected=False, + health_unit=self + ).order_by('-updated').first() + return latest_chu.updates + @property def latest_update(self): @@ -283,6 +292,7 @@ def push_chu_to_dhis2(self): }, "openingDate": self.date_operational.strftime("%Y-%m-%d"), } + metadata_payload = { "keph": 'axUnguN4QDh' } @@ -484,19 +494,23 @@ def validate_atleast_one_attribute_updated(self): raise ValidationError({"__all__": ["Nothing was edited"]}) def update_basic_details(self): - basic_details = json.loads(self.basic) - if 'status' in basic_details: - basic_details['status_id'] = basic_details.get( - 'status').get('status_id') - basic_details.pop('status') - if 'facility' in basic_details: - basic_details['facility_id'] = basic_details.get( - 'facility').get('facility_id') - basic_details.pop('facility') - - for key, value in basic_details.iteritems(): - setattr(self.health_unit, key, value) - self.health_unit.save() + if self.basic: + basic_details = json.loads(self.basic) + if 'status' in basic_details: + basic_details['status_id'] = basic_details.get( + 'status').get('status_id') + basic_details.pop('status') + if 'facility' in basic_details: + basic_details['facility_id'] = basic_details.get( + 'facility').get('facility_id') + basic_details.pop('facility') + + + for key, value in basic_details.iteritems(): + setattr(self.health_unit, key, value) + if 'basic' in basic_details: + setattr(self.health_unit, 'facility_id', basic_details.get('basic').get('facility')) + self.health_unit.save() def update_workers(self): chews = json.loads(self.workers) diff --git a/chul/serializers.py b/chul/serializers.py index 3e7f8c14..842c6eee 100755 --- a/chul/serializers.py +++ b/chul/serializers.py @@ -341,3 +341,8 @@ class CHURatingSerializer(AbstractFieldsMixin, serializers.ModelSerializer): class Meta(AbstractFieldsMixin.Meta): model = CHURating +class ChulSummarySerializer(serializers.ModelSerializer): + # count=serializers.IntegerField() + class Meta: + model = None + fields = '__all__' \ No newline at end of file diff --git a/chul/urls.py b/chul/urls.py index a0e4bb18..815e7be1 100755 --- a/chul/urls.py +++ b/chul/urls.py @@ -48,6 +48,10 @@ url(r'^units/(?P[^/]+)/$', views.CommunityHealthUnitDetailView.as_view(), name='community_health_unit_detail'), + url(r'^summary/$', + views.CommunityHealthUnitSummaryView.as_view(), + name='community_health_unit_summary'), + url(r'^chu_ratings/$', views.CHURatingListView.as_view(), name='chu_ratings'), diff --git a/chul/views.py b/chul/views.py index b2c64530..311454ee 100755 --- a/chul/views.py +++ b/chul/views.py @@ -1,7 +1,11 @@ +from django.http import JsonResponse from django.template import loader, Context from django.utils import timezone from django.views.decorators.cache import never_cache from rest_framework import generics +from django.db.models import Count +from django.db import connection +from django.apps import apps from common.views import AuditableDetailViewMixin, DownloadPDFMixin from common.models import UserConstituency, UserCounty, UserSubCounty from .models import ( @@ -17,6 +21,7 @@ from .serializers import ( CommunityHealthUnitSerializer, + ChulSummarySerializer, CommunityHealthWorkerSerializer, CommunityHealthWorkerContactSerializer, StatusSerializer, @@ -40,22 +45,32 @@ class FilterCommunityUnitsMixin(object): - def get_queryset(self, *args, **kwargs): - custom_queryset = kwargs.pop('custom_queryset', None) - if hasattr(custom_queryset, 'count'): - self.queryset = custom_queryset - - if not self.request.user.has_perm( - "facilities.view_unpublished_facilities"): - self.queryset = self.queryset.filter(facility__approved=True) - - if not self.request.user.has_perm( - "chul.view_rejected_chus"): - self.queryset = self.queryset.filter(is_approved=True) - + def filter_approved_chus(self): + if self.request.user.has_perm( + "chul.view_unapproved_facilities") \ + is False and 'approved' in [ + field.name for field in + self.queryset.model._meta.get_fields()]: + + # filter both facilities and facilities materialized view + try: + self.queryset = self.queryset.filter(approved=True, operation_status__is_public_visible=True) + except: + self.queryset = self.queryset.filter(approved=True, is_public_visible=True) + + def filter_rejected_chus(self): + if self.request.user.has_perm("chul.view_rejected_chus") \ + is False and ('rejected' in [ + field.name for field in + self.queryset.model._meta.get_fields()]): + self.queryset = self.queryset.filter(rejected=False) + + def filter_for_national_users(self): if self.request.user.is_national: self.queryset = self.queryset + + def filter_for_county_users(self): if self.request.user.county: self.queryset = self.queryset.filter( facility__ward__constituency__county__in=[ @@ -63,20 +78,42 @@ def get_queryset(self, *args, **kwargs): user=self.request.user) ]) - if self.request.user.constituency: + def filter_for_sub_county_users(self): + if self.request.user.sub_county: self.queryset = self.queryset.filter( - facility__ward__constituency__in=[ - uc.constituency for uc in UserConstituency.objects.filter( + facility__ward__sub_county__in=[ + us.sub_county for us in UserSubCounty.objects.filter( user=self.request.user) ]) - if self.request.user.sub_county: + def filter_for_consituency_users(self): + if self.request.user.constituency: self.queryset = self.queryset.filter( - facility__ward__sub_county__in=[ - us.sub_county for us in UserSubCounty.objects.filter( + facility__ward__constituency__in=[ + uc.constituency for uc in UserConstituency.objects.filter( user=self.request.user) ]) + + + def get_queryset(self, *args, **kwargs): + custom_queryset = kwargs.pop('custom_queryset', None) + if hasattr(custom_queryset, 'count'): + self.queryset = custom_queryset + + self.filter_for_county_users() + self.filter_for_consituency_users() + self.filter_for_sub_county_users() + self.filter_rejected_chus() + + # if not self.request.user.has_perm( + # "facilities.view_unpublished_facilities"): + # self.queryset = self.queryset.filter(facility__approved=True) + + # if not self.request.user.has_perm( + # "chul.view_rejected_chus"): + # self.queryset = self.queryset.filter(is_approved=True) + return self.queryset def filter_queryset(self, queryset): @@ -84,17 +121,18 @@ def filter_queryset(self, queryset): Overridden in order to constrain search results to what a user should see. """ - if 'search' in self.request.query_params: - search_term = self.request.query_params.get('search') - if search_term.isdigit(): - queryset = self.queryset.filter(code=search_term) - else: - queryset = super( - FilterCommunityUnitsMixin, self).filter_queryset(queryset) - else: - queryset = super( - FilterCommunityUnitsMixin, self).filter_queryset(queryset) - + # if 'search' in self.request.query_params: + # search_term = self.request.query_params.get('search') + # if search_term.isdigit(): + # queryset = self.queryset.filter(code=search_term) + # else: + # queryset = super( + # FilterCommunityUnitsMixin, self).filter_queryset(queryset) + # else: + # queryset = super( + # FilterCommunityUnitsMixin, self).filter_queryset(queryset) + + queryset = super(FilterCommunityUnitsMixin, self).filter_queryset(queryset) return self.get_queryset(custom_queryset=queryset) @@ -176,6 +214,7 @@ class CommunityHealthUnitContactListView(generics.ListCreateAPIView): ordering_fields = ('health_unit', 'contact', ) + class CommunityHealthUnitContactDetailView( AuditableDetailViewMixin, generics.RetrieveUpdateDestroyAPIView): @@ -215,6 +254,20 @@ class CommunityHealthUnitDetailView( queryset = CommunityHealthUnit.objects.all() serializer_class = CommunityHealthUnitSerializer +class CommunityHealthUnitSummaryView(generics.ListAPIView): + def get_queryset(self): + with connection.cursor() as cursor: + cursor.execute("SELECT chul_status.name, COUNT(chul_communityhealthunit.status_id) As counts FROM chul_communityhealthunit INNER JOIN chul_status ON chul_communityhealthunit.status_id = chul_status.id GROUP BY chul_status.name") + rows = cursor.fetchall() + return rows + + def list(self, request, *args, **kwargs): + queryset = self.get_queryset() + data = [] + for row in queryset: + data.append({"name": row[0], "count": row[1]}) + return JsonResponse(data, safe=False) + class CommunityHealthWorkerListView(generics.ListCreateAPIView): @@ -312,6 +365,7 @@ class ChuUpdateBufferListView( serializer_class = ChuUpdateBufferSerializer filter_class = ChuUpdateBufferFilter ordering_fields = ('health_unit', ) + # print(queryset) class ChuUpdateBufferDetailView( diff --git a/common/migrations/0020_auto_20221205_0904.py b/common/migrations/0020_auto_20221205_0904.py new file mode 100644 index 00000000..5c5728ff --- /dev/null +++ b/common/migrations/0020_auto_20221205_0904.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.27 on 2022-12-05 09:04 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0019_auto_20191021_1227'), + ] + + operations = [ + migrations.AlterField( + model_name='apiauthentication', + name='client_secret', + field=models.CharField(default=b'', max_length=255), + ), + migrations.AlterField( + model_name='apiauthentication', + name='password', + field=models.CharField(default=b'', max_length=255), + ), + migrations.AlterField( + model_name='apiauthentication', + name='server', + field=models.CharField(default=b'http://testhis.uonbi.ac.ke/', max_length=255), + ), + migrations.AlterField( + model_name='apiauthentication', + name='username', + field=models.CharField(default=b'kmhfl_integration', max_length=255), + ), + ] diff --git a/common/migrations/0021_auto_20230302_0642.py b/common/migrations/0021_auto_20230302_0642.py new file mode 100644 index 00000000..fc96a803 --- /dev/null +++ b/common/migrations/0021_auto_20230302_0642.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.27 on 2023-03-02 06:42 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0020_auto_20221205_0904'), + ] + + operations = [ + migrations.AlterField( + model_name='apiauthentication', + name='server', + field=models.CharField(default=b'https://test.hiskenya.org/', max_length=255), + ), + ] diff --git a/common/static/js/ace_editor/snippets/python.js b/common/static/js/ace_editor/snippets/python.js index ee023b2b..c8cfb76c 100755 --- a/common/static/js/ace_editor/snippets/python.js +++ b/common/static/js/ace_editor/snippets/python.js @@ -1 +1 @@ -ace.define("ace/snippets/python",["require","exports","module"],function(e,t,n){"use strict";t.snippetText='snippet #!\n #!/usr/bin/env python\nsnippet imp\n import ${1:module}\nsnippet from\n from ${1:package} import ${2:module}\n# Module Docstring\nsnippet docs\n \'\'\'\n File: ${1:FILENAME:file_name}\n Author: ${2:author}\n Description: ${3}\n \'\'\'\nsnippet wh\n while ${1:condition}:\n ${2:# TODO: write code...}\n# dowh - does the same as do...while in other languages\nsnippet dowh\n while True:\n ${1:# TODO: write code...}\n if ${2:condition}:\n break\nsnippet with\n with ${1:expr} as ${2:var}:\n ${3:# TODO: write code...}\n# New Class\nsnippet cl\n class ${1:ClassName}(${2:object}):\n """${3:docstring for $1}"""\n def __init__(self, ${4:arg}):\n ${5:super($1, self).__init__()}\n self.$4 = $4\n ${6}\n# New Function\nsnippet def\n def ${1:fname}(${2:`indent(\'.\') ? \'self\' : \'\'`}):\n """${3:docstring for $1}"""\n ${4:# TODO: write code...}\nsnippet deff\n def ${1:fname}(${2:`indent(\'.\') ? \'self\' : \'\'`}):\n ${3:# TODO: write code...}\n# New Method\nsnippet defs\n def ${1:mname}(self, ${2:arg}):\n ${3:# TODO: write code...}\n# New Property\nsnippet property\n def ${1:foo}():\n doc = "${2:The $1 property.}"\n def fget(self):\n ${3:return self._$1}\n def fset(self, value):\n ${4:self._$1 = value}\n# Ifs\nsnippet if\n if ${1:condition}:\n ${2:# TODO: write code...}\nsnippet el\n else:\n ${1:# TODO: write code...}\nsnippet ei\n elif ${1:condition}:\n ${2:# TODO: write code...}\n# For\nsnippet for\n for ${1:item} in ${2:items}:\n ${3:# TODO: write code...}\n# Encodes\nsnippet cutf8\n # -*- coding: utf-8 -*-\nsnippet clatin1\n # -*- coding: latin-1 -*-\nsnippet cascii\n # -*- coding: ascii -*-\n# Lambda\nsnippet ld\n ${1:var} = lambda ${2:vars} : ${3:action}\nsnippet .\n self.\nsnippet try Try/Except\n try:\n ${1:# TODO: write code...}\n except ${2:Exception}, ${3:e}:\n ${4:raise $3}\nsnippet try Try/Except/Else\n try:\n ${1:# TODO: write code...}\n except ${2:Exception}, ${3:e}:\n ${4:raise $3}\n else:\n ${5:# TODO: write code...}\nsnippet try Try/Except/Finally\n try:\n ${1:# TODO: write code...}\n except ${2:Exception}, ${3:e}:\n ${4:raise $3}\n finally:\n ${5:# TODO: write code...}\nsnippet try Try/Except/Else/Finally\n try:\n ${1:# TODO: write code...}\n except ${2:Exception}, ${3:e}:\n ${4:raise $3}\n else:\n ${5:# TODO: write code...}\n finally:\n ${6:# TODO: write code...}\n# if __name__ == \'__main__\':\nsnippet ifmain\n if __name__ == \'__main__\':\n ${1:main()}\n# __magic__\nsnippet _\n __${1:init}__${2}\n# python debugger (pdb)\nsnippet pdb\n import pdb; pdb.set_trace()\n# ipython debugger (ipdb)\nsnippet ipdb\n import ipdb; ipdb.set_trace()\n# ipython debugger (pdbbb)\nsnippet pdbbb\n import pdbpp; pdbpp.set_trace()\nsnippet pprint\n import pprint; pprint.pprint(${1})${2}\nsnippet "\n """\n ${1:doc}\n """\n# test function/method\nsnippet test\n def test_${1:description}(${2:self}):\n ${3:# TODO: write code...}\n# test case\nsnippet testcase\n class ${1:ExampleCase}(unittest.TestCase):\n \n def test_${2:description}(self):\n ${3:# TODO: write code...}\nsnippet fut\n from __future__ import ${1}\n#getopt\nsnippet getopt\n try:\n # Short option syntax: "hv:"\n # Long option syntax: "help" or "verbose="\n opts, args = getopt.getopt(sys.argv[1:], "${1:short_options}", [${2:long_options}])\n \n except getopt.GetoptError, err:\n # Print debug info\n print str(err)\n ${3:error_action}\n\n for option, argument in opts:\n if option in ("-h", "--help"):\n ${4}\n elif option in ("-v", "--verbose"):\n verbose = argument\n',t.scope="python"}) \ No newline at end of file +ace.define("ace/snippets/python",["require","exports","module"],function(e,t,n){"use strict";t.snippetText='snippet #!\n #!/usr/bin/env python\nsnippet imp\n import ${1:module}\nsnippet from\n from ${1:package} import ${2:module}\n# Module Docstring\nsnippet docs\n \'\'\'\n File: ${1:FILENAME:file_name}\n Author: ${2:author}\n Description: ${3}\n \'\'\'\nsnippet wh\n while ${1:condition}:\n ${2:# TODO: write code...}\n# dowh - does the same as do...while in other languages\nsnippet dowh\n while True:\n ${1:# TODO: write code...}\n if ${2:condition}:\n break\nsnippet with\n with ${1:expr} as ${2:var}:\n ${3:# TODO: write code...}\n# New Class\nsnippet cl\n class ${1:ClassName}(${2:object}):\n """${3:docstring for $1}"""\n def __init__(self, ${4:arg}):\n ${5:super($1, self).__init__()}\n self.$4 = $4\n ${6}\n# New Function\nsnippet def\n def ${1:fname}(${2:`indent(\'.\') ? \'self\' : \'\'`}):\n """${3:docstring for $1}"""\n ${4:# TODO: write code...}\nsnippet deff\n def ${1:fname}(${2:`indent(\'.\') ? \'self\' : \'\'`}):\n ${3:# TODO: write code...}\n# New Method\nsnippet defs\n def ${1:mname}(self, ${2:arg}):\n ${3:# TODO: write code...}\n# New Property\nsnippet property\n def ${1:foo}():\n doc = "${2:The $1 property.}"\n def fget(self):\n ${3:return self._$1}\n def fset(self, value):\n ${4:self._$1 = value}\n# Ifs\nsnippet if\n if ${1:condition}:\n ${2:# TODO: write code...}\nsnippet el\n else:\n ${1:# TODO: write code...}\nsnippet ei\n elif ${1:condition}:\n ${2:# TODO: write code...}\n# For\nsnippet for\n for ${1:item} in ${2:items}:\n ${3:# TODO: write code...}\n# Encodes\nsnippet cutf8\n # -*- coding: utf-8 -*-\nsnippet clatin1\n # -*- coding: latin-1 -*-\nsnippet cascii\n # -*- coding: ascii -*-\n# Lambda\nsnippet ld\n ${1:var} = lambda ${2:vars} : ${3:action}\nsnippet .\n self.\nsnippet try Try/Except\n try:\n ${1:# TODO: write code...}\n except ${2:Exception}, ${3:e}:\n ${4:raise $3}\nsnippet try Try/Except/Else\n try:\n ${1:# TODO: write code...}\n except ${2:Exception}, ${3:e}:\n ${4:raise $3}\n else:\n ${5:# TODO: write code...}\nsnippet try Try/Except/Finally\n try:\n ${1:# TODO: write code...}\n except ${2:Exception}, ${3:e}:\n ${4:raise $3}\n finally:\n ${5:# TODO: write code...}\nsnippet try Try/Except/Else/Finally\n try:\n ${1:# TODO: write code...}\n except ${2:Exception}, ${3:e}:\n ${4:raise $3}\n else:\n ${5:# TODO: write code...}\n finally:\n ${6:# TODO: write code...}\n# if __name__ == \'__main__\':\nsnippet ifmain\n if __name__ == \'__main__\':\n ${1:main()}\n# __magic__\nsnippet _\n __${1:init}__${2}\n# python debugger (pdb)\nsnippet pdb\n ; \n# ipython debugger (ipdb)\nsnippet ipdb\n import ipdb; ipdb.set_trace()\n# ipython debugger (pdbbb)\nsnippet pdbbb\n import pdbpp; pdbpp.set_trace()\nsnippet pprint\n import pprint; pprint.pprint(${1})${2}\nsnippet "\n """\n ${1:doc}\n """\n# test function/method\nsnippet test\n def test_${1:description}(${2:self}):\n ${3:# TODO: write code...}\n# test case\nsnippet testcase\n class ${1:ExampleCase}(unittest.TestCase):\n \n def test_${2:description}(self):\n ${3:# TODO: write code...}\nsnippet fut\n from __future__ import ${1}\n#getopt\nsnippet getopt\n try:\n # Short option syntax: "hv:"\n # Long option syntax: "help" or "verbose="\n opts, args = getopt.getopt(sys.argv[1:], "${1:short_options}", [${2:long_options}])\n \n except getopt.GetoptError, err:\n # Print debug info\n print str(err)\n ${3:error_action}\n\n for option, argument in opts:\n if option in ("-h", "--help"):\n ${4}\n elif option in ("-v", "--verbose"):\n verbose = argument\n',t.scope="python"}) \ No newline at end of file diff --git a/common/views/app_views.py b/common/views/app_views.py index 0b97c22d..5f016909 100755 --- a/common/views/app_views.py +++ b/common/views/app_views.py @@ -27,6 +27,10 @@ OwnerType, Owner, Service, + Infrastructure, + InfrastructureCategory, + Speciality, + SpecialityCategory, KephLevel ) from users.models import JobTitle @@ -663,12 +667,17 @@ def get(self, request): 'admission_status': (FacilityAdmissionStatus, ('id', 'name')), 'chu_status': (chu_models.Status, ('id', 'name', )), 'service_category': (ServiceCategory, ('id', 'name')), + 'infrastructure_category': (InfrastructureCategory, ('id', 'name')), + 'speciality_category': (SpecialityCategory, ('id', 'name')), + 'speciality': (Speciality, ('id', 'name', 'category')), 'owner_type': (OwnerType, ('id', 'name')), 'owner': (Owner, ('id', 'name', 'owner_type')), 'service': (Service, ('id', 'name', 'category')), 'keph_level': (KephLevel, ('id', 'name')), + 'infrastructure': (Infrastructure, ('id', 'name', 'category')), 'job_title': (JobTitle, ('id', 'name')) } + if fields: resp = {} for key in fields.split(","): diff --git a/config/settings/base.py b/config/settings/base.py index 8e89fd95..e43e6b67 100755 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -7,7 +7,7 @@ # Override in production via env env = environ.Env( - DATABASE_URL=(str, 'postgres://mfl:mfl@localhost:5432/mfl'), + DATABASE_URL=(str, 'postgres://mfl:mfl@localhost:5433/mfl'), DEBUG=(bool, True), FRONTEND_URL=(str, "http://localhost:8062"), REALTIME_INDEX=(bool, False), @@ -23,13 +23,14 @@ ADMINS=(str, "admin:admin@example.com,"), SERVER_EMAIL=(str, "root@localhost"), ALLOWED_HOSTS=(str, "localhost"), - DHIS_ENDPOINT=(str, "http://testhis.uonbi.ac.ke/"), + DHIS_ENDPOINT=(str, "https://test.hiskenya.org/"), DHIS_USERNAME=(str, 'kmhfl_integration'), DHIS_PASSWORD=(str, ''), DHIS_CLIENT_ID=(str, '102'), + PUSH_TO_DHIS=(bool, True), DHIS_CLIENT_SECRET=(str, '') ) -env.read_env(os.path.join(BASE_DIR, '.env')) +# env.read_env(os.path.join(BASE_DIR, '.env')) ADMINS = tuple( tuple(name.split(':')) for name in env('ADMINS').split(',') if name != '' @@ -43,11 +44,11 @@ DATABASES = { 'default': { 'ENGINE': 'django.contrib.gis.db.backends.postgis', - 'HOST': ENV_DB['HOST'], - 'NAME': ENV_DB['NAME'], - 'PASSWORD': ENV_DB['PASSWORD'], - 'PORT': ENV_DB['PORT'], - 'USER': ENV_DB['USER'], + 'HOST': '127.0.0.1', + 'NAME': 'mfl', + 'PASSWORD': 'mfl@pa55w0rd', + 'PORT': '5433', + 'USER': 'mfladmin', } } # Env should have DATABASE_URL MIDDLEWARE = ( diff --git a/data/management/commands/data_reports.py b/data/management/commands/data_reports.py index 3eee1bbf..21e272ee 100755 --- a/data/management/commands/data_reports.py +++ b/data/management/commands/data_reports.py @@ -83,8 +83,8 @@ def handle(self, *args, **kwargs): # JobTitle.objects.get(name=jt) # except JobTitle.DoesNotExist: # print jt - # import pdb - # pdb.set_trace() + # + # f_type_name = f_type.split('\n') print len(f_type_name) print FacilityType.objects.count() diff --git a/data/management/commands/port_data.py b/data/management/commands/port_data.py index ee718ffa..fe462ac0 100755 --- a/data/management/commands/port_data.py +++ b/data/management/commands/port_data.py @@ -59,8 +59,8 @@ def _help_create_file( } ] json_data = template.render(context) # NOQA - # import pdb - # pdb.set_trace() + # + # # json_file.write(json_data, indent=4) json.dump(to_write, json_file, indent=4) @@ -2323,8 +2323,8 @@ def port_data(): else: value = obj[field.get("v1_pos")] except: - import pdb - pdb.set_trace() + + if value: row_data[field.get("v2")] = value else: diff --git a/dev_requirements.txt b/dev_requirements.txt new file mode 100644 index 00000000..18d3b84f --- /dev/null +++ b/dev_requirements.txt @@ -0,0 +1,95 @@ +amqp==1.4.9 +ansible==1.9.6 +anyjson==0.3.3 +apache-libcloud==0.17.0 +apipkg==1.5 +backports.ssl-match-hostname==3.7.0.1 +billiard==3.3.0.23 +boto==2.38.0 +cairocffi==0.9.0 +CairoSVG==1.0.22 +celery==3.1.19 +certifi==2019.3.9 +cffi==1.12.2 +chardet==3.0.4 +commonmark==0.8.1 +coreapi==2.3.3 +coreschema==0.0.4 +coverage==3.7.1 +cssselect2==0.2.1 +defusedxml==0.5.0 +dj-database-url==0.4.0 +Django==1.11.27 +django-allauth==0.39.1 +django-braces==1.13.0 +django-cors-headers==2.1.0 +django-debug-toolbar==1.8 +django-environ==0.3.1 +django-filter==1.0.4 +django-oauth-toolkit==0.11.0 +django-redis==4.0.0 +django-rest-auth==0.9.1 +django-rest-swagger==2.1.0 +django-reversion==2.0.5 +django-storages==1.1.8 +djangorestframework==3.6.3 +djangorestframework-csv==1.3.4 +djangorestframework-gis==0.8.2 +djangorestframework-xml==1.0.1 +docutils==0.14 +drf-extensions==0.3.1 +ecdsa==0.13 +execnet==1.5.0 +Fabric==1.10.5 +filechunkio==1.6 +flake8==2.3.0 +future==0.17.1 +gunicorn==19.3.0 +html5lib==0.9999999 +idna==2.8 +itypes==1.1.0 +Jinja2==2.10 +kombu==3.0.37 +Markdown==2.5.2 +MarkupSafe==1.1.1 +mccabe==0.6.1 +mock==1.0.1 +model-mommy==1.2.6 +oauthlib==1.1.2 +openapi-codec==1.3.2 +paramiko==1.18.5 +pdfrw==0.4 +pep8==1.7.1 +psycopg2==2.7 +py==1.8.0 +pycparser==2.19 +pycrypto==2.6.1 +pyflakes==2.1.1 +Pyphen==0.9.5 +pytest==2.7.3 +pytest-django==2.8.0 +pytest-xdist==1.11 +python-coveralls==2.5.0 +python-dateutil==2.8.0 +python-openid==2.2.5 +pytz==2018.9 +PyYAML==5.1 +recommonmark==0.1.1 +redis==3.2.1 +requests==2.21.0 +requests-oauthlib==1.2.0 +sh==1.12.14 +Shapely==1.5.17.post1 +simplejson==3.16.0 +six==1.9.0 +sqlparse==0.1.19 +tinycss2==0.6.1 +tox==1.9.2 +uritemplate==3.0.0 +urllib3==1.24.1 +virtualenv==12.0.7 +WeasyPrint==0.42.3 +webencodings==0.5.1 +Werkzeug==0.10.4 +wheel==0.33.1 +XlsxWriter==0.7.9 diff --git a/facilities/filters/facility_filters.py b/facilities/filters/facility_filters.py index 4a2818fa..2e339d8d 100755 --- a/facilities/filters/facility_filters.py +++ b/facilities/filters/facility_filters.py @@ -352,19 +352,48 @@ class Meta(CommonFieldsFilterset.Meta): class FacilityFilter(CommonFieldsFilterset): def service_filter(self, qs, name, value): - categories = value.split(',') + services = value.split(',') facility_ids = [] - for facility in self.filter(): - for cat in categories: + for facility in qs.filter(): + for _service in services: service_count = FacilityService.objects.filter( - service__category=cat, + service=_service, facility=facility).count() if service_count > 0: facility_ids.append(facility.id) return qs.filter(id__in=list(set(facility_ids))) + def infrastructure_filter(self, qs, name, value): + infrastructure = value.split(',') + facility_ids = [] + + for facility in qs.filter(): + for _infra in infrastructure: + infrastructure_count = FacilityInfrastructure.objects.filter( + infrastructure=_infra, + facility=facility).count() + if infrastructure_count > 0: + facility_ids.append(facility.id) + + return qs.filter(id__in=list(set(facility_ids))) + + + def hr_filter(self, qs, name, value): + specialities = value.split(',') + facility_ids = [] + + for facility in qs.filter(): + for _speciality in specialities: + speciality_count = FacilitySpecialist.objects.filter( + speciality=_speciality, + facility=facility).count() + if speciality_count > 0: + facility_ids.append(facility.id) + + return qs.filter(id__in=list(set(facility_ids))) + def filter_approved_facilities(self, qs, name, value): if value in TRUTH_NESS: @@ -392,8 +421,8 @@ def filter_incomplete_facilities(self, qs, name, value): return qs.exclude(id__in=[facility.id for facility in incomplete]) def facilities_pending_approval(self, qs, name, value): - incomplete = qs.filter(code=not None) - incomplete_facility_ids = [facility.id for facility in incomplete] + fac_pend_appr = qs.filter(code=not None) + fac_pend_appr_facility_ids = [facility.id for facility in fac_pend_appr] if value in TRUTH_NESS: return qs.filter( Q( @@ -404,12 +433,12 @@ def facilities_pending_approval(self, qs, name, value): Q( Q(rejected=False), Q(has_edits=True) | Q(approved=None,rejected=False)) - ).exclude(id__in=incomplete_facility_ids) + ).exclude(id__in=fac_pend_appr_facility_ids) else: return qs.filter( Q(rejected=True) | Q(has_edits=False) & Q(approved=None) - ).exclude(id__in=incomplete_facility_ids) + ).exclude(id__in=fac_pend_appr_facility_ids) def filter_national_rejected(self, qs, name, value): rejected_national = qs.filter(rejected=False,code=None, @@ -424,7 +453,7 @@ def filter_number_beds(self, qs, name, value): return qs.filter(number_of_beds__gte=1) def filter_number_cots(self, qs, name, value): - return self.filter(number_of_cots__gte=1) + return qs.filter(number_of_cots__gte=1) id = ListCharFilter(lookup_expr='icontains') name = django_filters.CharFilter(lookup_expr='icontains') @@ -474,8 +503,12 @@ def filter_number_cots(self, qs, name, value): coerce=strtobool) is_approved = django_filters.CharFilter( method='filter_approved_facilities') - service_category = django_filters.CharFilter( - method=service_filter) + service = django_filters.CharFilter( + method='service_filter') + infrastructure = django_filters.CharFilter( + method='infrastructure_filter') + speciality = django_filters.CharFilter( + method='hr_filter') has_edits = django_filters.TypedChoiceFilter( choices=BOOLEAN_CHOICES, coerce=strtobool) diff --git a/facilities/migrations/0022_auto_20211026_0950.py b/facilities/migrations/0022_auto_20211026_0950.py deleted file mode 100644 index 701e5624..00000000 --- a/facilities/migrations/0022_auto_20211026_0950.py +++ /dev/null @@ -1,245 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.27 on 2021-10-26 09:50 -from __future__ import unicode_literals - -import common.fields -import common.models.base -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion -import django.utils.timezone -import uuid - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('facilities', '0021_auto_20211026_0831'), - ] - - operations = [ - migrations.CreateModel( - name='FacilityInfrastructure', - fields=[ - ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('created', models.DateTimeField(default=django.utils.timezone.now)), - ('updated', models.DateTimeField(default=django.utils.timezone.now)), - ('deleted', models.BooleanField(default=False)), - ('active', models.BooleanField(default=True, help_text=b'Indicates whether the record has been retired?')), - ('search', models.CharField(blank=True, editable=False, max_length=255, null=True)), - ('count', models.IntegerField(blank=True, default=0, help_text=b'The actual number of infrastructure items in a facility.')), - ('present', models.BooleanField(default=False, help_text=b'True if the listed infrastructure is present.')), - ('created_by', models.ForeignKey(default=common.models.base.get_default_system_user_id, on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL)), - ], - options={ - 'ordering': ('-updated', '-created'), - 'default_permissions': ('add', 'change', 'delete', 'view'), - 'abstract': False, - }, - ), - migrations.CreateModel( - name='FacilitySpecialist', - fields=[ - ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('created', models.DateTimeField(default=django.utils.timezone.now)), - ('updated', models.DateTimeField(default=django.utils.timezone.now)), - ('deleted', models.BooleanField(default=False)), - ('active', models.BooleanField(default=True, help_text=b'Indicates whether the record has been retired?')), - ('search', models.CharField(blank=True, editable=False, max_length=255, null=True)), - ('count', models.IntegerField(blank=True, default=0, help_text=b'The actual number of specialists for this speciality.')), - ('created_by', models.ForeignKey(default=common.models.base.get_default_system_user_id, on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL)), - ], - options={ - 'ordering': ('-updated', '-created'), - 'default_permissions': ('add', 'change', 'delete', 'view'), - 'abstract': False, - }, - ), - migrations.CreateModel( - name='Infrastructure', - fields=[ - ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('created', models.DateTimeField(default=django.utils.timezone.now)), - ('updated', models.DateTimeField(default=django.utils.timezone.now)), - ('deleted', models.BooleanField(default=False)), - ('active', models.BooleanField(default=True, help_text=b'Indicates whether the record has been retired?')), - ('search', models.CharField(blank=True, editable=False, max_length=255, null=True)), - ('name', models.CharField(max_length=255, unique=True)), - ('description', models.TextField(blank=True, null=True)), - ('abbreviation', models.CharField(blank=True, help_text=b'A short form for the infrastructure', max_length=50, null=True)), - ('numbers', models.NullBooleanField(default=True, help_text=b'A flag to indicate whether an infrastructure item can have count/numbers tracked ')), - ('code', common.fields.SequenceField(blank=True, editable=False, unique=True)), - ], - options={ - 'ordering': ('-updated', '-created'), - 'default_permissions': ('add', 'change', 'delete', 'view'), - 'abstract': False, - 'verbose_name_plural': 'infrastructure', - }, - bases=(common.models.base.SequenceMixin, models.Model), - ), - migrations.CreateModel( - name='InfrastructureCategory', - fields=[ - ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('created', models.DateTimeField(default=django.utils.timezone.now)), - ('updated', models.DateTimeField(default=django.utils.timezone.now)), - ('deleted', models.BooleanField(default=False)), - ('active', models.BooleanField(default=True, help_text=b'Indicates whether the record has been retired?')), - ('search', models.CharField(blank=True, editable=False, max_length=255, null=True)), - ('name', models.CharField(help_text=b'What is the name of the category? ', max_length=100)), - ('description', models.TextField(blank=True, null=True)), - ('abbreviation', models.CharField(blank=True, help_text=b'A short form of the category e.g ANC for antenatal', max_length=50, null=True)), - ('created_by', models.ForeignKey(default=common.models.base.get_default_system_user_id, on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL)), - ('parent', models.ForeignKey(blank=True, help_text=b'The parent category under which the category falls', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='sub_categories', to='facilities.InfrastructureCategory')), - ('updated_by', models.ForeignKey(default=common.models.base.get_default_system_user_id, on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL)), - ], - options={ - 'ordering': ('-updated', '-created'), - 'default_permissions': ('add', 'change', 'delete', 'view'), - 'abstract': False, - 'verbose_name_plural': 'specialities categories', - }, - ), - migrations.CreateModel( - name='Speciality', - fields=[ - ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('created', models.DateTimeField(default=django.utils.timezone.now)), - ('updated', models.DateTimeField(default=django.utils.timezone.now)), - ('deleted', models.BooleanField(default=False)), - ('active', models.BooleanField(default=True, help_text=b'Indicates whether the record has been retired?')), - ('search', models.CharField(blank=True, editable=False, max_length=255, null=True)), - ('name', models.CharField(max_length=255, unique=True)), - ('description', models.TextField(blank=True, null=True)), - ('abbreviation', models.CharField(blank=True, help_text=b'A short form for the speciality', max_length=50, null=True)), - ('code', common.fields.SequenceField(blank=True, editable=False, unique=True)), - ], - options={ - 'ordering': ('-updated', '-created'), - 'default_permissions': ('add', 'change', 'delete', 'view'), - 'abstract': False, - 'verbose_name_plural': 'specialities', - }, - bases=(common.models.base.SequenceMixin, models.Model), - ), - migrations.CreateModel( - name='SpecialityCategory', - fields=[ - ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('created', models.DateTimeField(default=django.utils.timezone.now)), - ('updated', models.DateTimeField(default=django.utils.timezone.now)), - ('deleted', models.BooleanField(default=False)), - ('active', models.BooleanField(default=True, help_text=b'Indicates whether the record has been retired?')), - ('search', models.CharField(blank=True, editable=False, max_length=255, null=True)), - ('name', models.CharField(help_text=b'What is the name of the category? ', max_length=100)), - ('description', models.TextField(blank=True, null=True)), - ('abbreviation', models.CharField(blank=True, help_text=b'A short form of the category e.g ANC for antenatal', max_length=50, null=True)), - ('created_by', models.ForeignKey(default=common.models.base.get_default_system_user_id, on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL)), - ('parent', models.ForeignKey(blank=True, help_text=b'The parent category under which the category falls', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='sub_categories', to='facilities.SpecialityCategory')), - ('updated_by', models.ForeignKey(default=common.models.base.get_default_system_user_id, on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL)), - ], - options={ - 'ordering': ('-updated', '-created'), - 'default_permissions': ('add', 'change', 'delete', 'view'), - 'abstract': False, - 'verbose_name_plural': 'specialities categories', - }, - ), - migrations.AddField( - model_name='facility', - name='accredited_lab_iso_15189', - field=models.BooleanField(default=False, help_text=b'Indicate if facility is accredited Lab ISO 15189'), - ), - migrations.AddField( - model_name='facility', - name='admitting_maternity_general', - field=models.NullBooleanField(help_text=b'A flag to indicate whether facility admits both maternity & general casualty patients'), - ), - migrations.AddField( - model_name='facility', - name='admitting_maternity_only', - field=models.NullBooleanField(help_text=b'A flag to indicate whether facility admits only maternity patients'), - ), - migrations.AddField( - model_name='facility', - name='number_of_isolation_beds', - field=models.PositiveIntegerField(default=0, help_text=b'The number of isolation beds that a facility has e.g 0'), - ), - migrations.AddField( - model_name='facility', - name='number_of_maternity_beds', - field=models.PositiveIntegerField(default=0, help_text=b'The number of maternity beds that a facility has e.g 0'), - ), - migrations.AddField( - model_name='facilityupdates', - name='humanresources', - field=models.TextField(blank=True, null=True), - ), - migrations.AddField( - model_name='facilityupdates', - name='infrastructure', - field=models.TextField(blank=True, null=True), - ), - migrations.AddField( - model_name='speciality', - name='category', - field=models.ForeignKey(help_text=b'The classification that the specialities lies in.', on_delete=django.db.models.deletion.PROTECT, related_name='category_specialities', to='facilities.SpecialityCategory'), - ), - migrations.AddField( - model_name='speciality', - name='created_by', - field=models.ForeignKey(default=common.models.base.get_default_system_user_id, on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='speciality', - name='updated_by', - field=models.ForeignKey(default=common.models.base.get_default_system_user_id, on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='infrastructure', - name='category', - field=models.ForeignKey(help_text=b'The classification that the infrastructure item lies in.', on_delete=django.db.models.deletion.PROTECT, related_name='category_infrastructure', to='facilities.InfrastructureCategory'), - ), - migrations.AddField( - model_name='infrastructure', - name='created_by', - field=models.ForeignKey(default=common.models.base.get_default_system_user_id, on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='infrastructure', - name='updated_by', - field=models.ForeignKey(default=common.models.base.get_default_system_user_id, on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='facilityspecialist', - name='facility', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='facility_specialists', to='facilities.Facility'), - ), - migrations.AddField( - model_name='facilityspecialist', - name='speciality', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='facilities.Speciality'), - ), - migrations.AddField( - model_name='facilityspecialist', - name='updated_by', - field=models.ForeignKey(default=common.models.base.get_default_system_user_id, on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='facilityinfrastructure', - name='facility', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='facility_infrastructure', to='facilities.Facility'), - ), - migrations.AddField( - model_name='facilityinfrastructure', - name='infrastructure', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='facilities.Infrastructure'), - ), - migrations.AddField( - model_name='facilityinfrastructure', - name='updated_by', - field=models.ForeignKey(default=common.models.base.get_default_system_user_id, on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL), - ), - ] diff --git a/facilities/migrations/0022_auto_20230302_0658.py b/facilities/migrations/0022_auto_20230302_0658.py new file mode 100644 index 00000000..cb434f14 --- /dev/null +++ b/facilities/migrations/0022_auto_20230302_0658.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.27 on 2023-03-02 06:58 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('facilities', '0021_auto_20211026_0831'), + ] + + operations = [ + migrations.AddField( + model_name='facility', + name='number_of_inpatient_beds', + field=models.PositiveIntegerField(default=0, help_text=b'The number of General In-patient beds that a facility has e.g 0'), + ), + ] diff --git a/facilities/migrations/faciliities_excel_export_27_oct_21.sql b/facilities/migrations/faciliities_excel_export_27_oct_21.sql new file mode 100644 index 00000000..c9dfab34 --- /dev/null +++ b/facilities/migrations/faciliities_excel_export_27_oct_21.sql @@ -0,0 +1,77 @@ +DROP MATERIALIZED VIEW IF EXISTS facilities_excel_export; + +create materialized view facilities_excel_export as +SELECT facilities_facility.id, + facilities_facility.search, + facilities_facility.name, + facilities_facility.official_name AS officialname, + facilities_facility.code, + facilities_facility.registration_number, + facilities_facility.number_of_beds AS beds, + facilities_facility.number_of_cots AS cots, + common_ward.name AS ward_name, + common_ward.id AS ward, + facilities_facility.approved, + facilities_facility.created, + facilities_facility.updated, + facilities_facility.open_whole_day, + facilities_facility.open_public_holidays, + facilities_facility.open_weekends, + facilities_facility.open_late_night, + facilities_facility.closed, + facilities_facility.is_published, + facilities_facility.approved_national_level, + common_county.name AS county_name, + common_county.id AS county, + common_constituency.name AS constituency_name, + common_constituency.id AS constituency, + common_subcounty.name AS sub_county_name, + common_subcounty.id AS sub_county, + facilities_facilitytype.name AS facility_type_name, + facilities_facilitytype.id AS facility_type, + facilities_facilitytypecat.name AS facility_type_category, + facilities_facilitytypecat.id AS facility_type_parent, + facilities_kephlevel.name AS keph_level_name, + facilities_kephlevel.id AS keph_level, + facilities_owner.name AS owner_name, + facilities_owner.id AS owner, + facilities_ownertype.name AS owner_type_name, + facilities_ownertype.id AS owner_type, + facilities_regulatingbody.name AS regulatory_body_name, + facilities_regulatingbody.id AS regulatory_body, + facilities_facilitystatus.name AS operation_status_name, + facilities_facilitystatus.id AS operation_status, + facilities_facilitystatus.is_public_visible, + facilities_facilityadmissionstatus.name AS admission_status_name, + facilities_facilityadmissionstatus.id AS admission_status, + st_x(mfl_gis_facilitycoordinates.coordinates) AS lat, + st_y(mfl_gis_facilitycoordinates.coordinates) AS long, + ARRAY(SELECT DISTINCT facilities_facilityservice.service_id + FROM facilities_facilityservice + WHERE facilities_facilityservice.facility_id = facilities_facility.id) AS services, + ARRAY(SELECT DISTINCT facilities_service.category_id + FROM facilities_facilityservice + JOIN facilities_service ON facilities_service.id = facilities_facilityservice.service_id + WHERE facilities_facilityservice.facility_id = facilities_facility.id) AS categories, + ARRAY(SELECT DISTINCT facilities_service.name + FROM facilities_service + JOIN facilities_facilityservice ON facilities_service.id = facilities_facilityservice.service_id + WHERE facilities_facilityservice.facility_id = facilities_facility.id) AS service_names +FROM facilities_facility + LEFT JOIN facilities_kephlevel ON facilities_kephlevel.id = facilities_facility.keph_level_id + LEFT JOIN facilities_owner ON facilities_owner.id = facilities_facility.owner_id + LEFT JOIN facilities_ownertype ON facilities_owner.owner_type_id = facilities_ownertype.id + LEFT JOIN facilities_facilitytype ON facilities_facilitytype.id = facilities_facility.facility_type_id + LEFT JOIN facilities_facilitytype facilities_facilitytypecat + ON facilities_facilitytypecat.id = facilities_facilitytype.parent_id + LEFT JOIN facilities_regulatingbody ON facilities_regulatingbody.id = facilities_facility.regulatory_body_id + LEFT JOIN facilities_facilitystatus ON facilities_facilitystatus.id = facilities_facility.operation_status_id + LEFT JOIN facilities_facilityadmissionstatus ON facilities_facilityadmissionstatus.id = facilities_facility.admission_status_id + LEFT JOIN common_ward ON common_ward.id = facilities_facility.ward_id + LEFT JOIN common_constituency ON common_constituency.id = common_ward.constituency_id + LEFT JOIN common_subcounty ON common_subcounty.id = common_ward.sub_county_id + LEFT JOIN common_county ON common_county.id = common_constituency.county_id + LEFT JOIN mfl_gis_facilitycoordinates ON mfl_gis_facilitycoordinates.facility_id = facilities_facility.id; + +alter materialized view facilities_excel_export owner to postgres; + diff --git a/facilities/models/facility_models.py b/facilities/models/facility_models.py index 7b83ebce..95ede8f0 100755 --- a/facilities/models/facility_models.py +++ b/facilities/models/facility_models.py @@ -161,7 +161,7 @@ def get_org_unit_id(self, code): # ) def get_parent_id(self, ward_id): - print self.session_store[self.oauth2_token_variable_name] + print (self.session_store[self.oauth2_token_variable_name]) r = requests.get( settings.DHIS_ENDPOINT+"api/organisationUnits.json", auth=(settings.DHIS_USERNAME, settings.DHIS_PASSWORD), @@ -1046,6 +1046,10 @@ class Facility(SequenceMixin, AbstractBase): default=0, help_text="The number of High Dependency Units (HDU) beds" " that a facility has e.g 0") + number_of_inpatient_beds = models.PositiveIntegerField( + default=0, + help_text="The number of General In-patient beds" + " that a facility has e.g 0") # number_of_maternity_beds = models.PositiveIntegerField( default=0, @@ -1224,8 +1228,10 @@ def push_new_facility(self, code=None): kmhfl_dhis2_facility_type_mapping = { "20b86171-0c16-47e1-9277-5e773d485c33": "YQK9pleIoeB", "5eb392ac-d10a-40c9-b525-53dac866ef6c": "lTrpyOiOcM6", + "8949eeb0-40b1-43d4-a38d-5d4933dc209f": "lTrpyOiOcM6", "ccc1600e-9a24-499f-889f-bd9f0bdc4b95": "YQK9pleIoeB", "d8d741b1-21c5-45c8-86d0-a2094bf9bda6": "YQK9pleIoeB", + "85f2099b-a2f8-49f4-9798-0cb48c0875ff": "YQK9pleIoeB", "869118aa-0e97-4f47-b6b7-1f295d109c8f": "YQK9pleIoeB", "a8af148f-b1b6-4eed-9d86-07d4f3135229": "YQK9pleIoeB", "74755372-99ba-4b70-bca8-a583f03990bc": "lTrpyOiOcM6", @@ -1245,8 +1251,10 @@ def push_new_facility(self, code=None): "188551b7-4f22-4fc4-b07b-f9c9aeeea872": "rhKJPLo27x7", "e5923a48-6b22-42c4-a4e6-6c5a5e8e0b0e": "YQK9pleIoeB", "55d65dd6-5351-4cf4-a6d9-e05ce6d343ab": "mVrepdLAqSD", + "87626d3d-fd19-49d9-98da-daca4afe85bf": "mVrepdLAqSD", "79158397-0d87-4d0e-8694-ad680a907a79": "YQK9pleIoeB", "031293d9-fd8a-4682-a91e-a4390d57b0cf": "YQK9pleIoeB", + "4369eec8-0416-4e16-b013-e635ce46a02f": "YQK9pleIoeB", } kmhfl_dhis2_ownership_mapping = { "d45541f8-3b3d-475b-94f4-17741d468135": "aRxa6o8GqZN", @@ -1269,6 +1277,9 @@ def push_new_facility(self, code=None): "93c0fe24-3f12-4be2-b5ff-027e0bd02274": "AaAF5EmS1fk", "c3bab995-0c29-433c-b39c-6b86d6084f5f": "AaAF5EmS1fk", "6cb92834-107c-404a-91fa-cf60b1eb5333": "aRxa6o8GqZN", + "2e651780-2ed4-4f8c-9061-6e5acf95d581": "AaAF5EmS1fk", + "30af7e3f-cd52-4ca0-b5dc-d8b1040a9808": "AaAF5EmS1fk", + "d64bbd8a-4013-463b-a238-c346cee66a92": "AaAF5EmS1fk", } kmhfl_dhis2_keph_mapping = { "ed23da85-4c92-45af-80fa-9b2123769f49": "FpY8vg4gh46", @@ -1534,6 +1545,7 @@ def latest_approval_or_rejection(self): def get_facility_services(self): """Digests the facility_services for the sake of frontend.""" services = self.facility_services.all() + return [ { "id": service.id, @@ -1556,7 +1568,9 @@ def get_facility_services(self): @property def get_facility_contacts(self): """For the same purpose as the get_facility_services above""" + contacts = self.facility_contacts.all() + return [ { "id": contact.id, @@ -1571,14 +1585,14 @@ def get_facility_contacts(self): def get_facility_infrastructure(self): """For the same purpose as the get_facility_contacts above""" infra = self.facility_infrastructure.all() + return [ { "id": inf.id, - "infrastructure_id": inf.id, - "name": inf.name, - "infrastructure_name": inf.name, - "infrastructure_category": inf.category.id, - "infrastructure_category_name": str(inf.category.name), + "name": inf.infrastructure.name, + "count":inf.count, + "infrastructure_category": inf.infrastructure.category.id, + "infrastructure_category_name": str(inf.infrastructure.category.name), } for inf in infra ] @@ -1586,35 +1600,20 @@ def get_facility_infrastructure(self): @property def get_facility_specialities(self): """For the same purpose as the get_facility_infra... above""" - hr = self.facility_specialities.all() - return [ - { - "id": h_r.id, - "speciality_id": h_r.id, - "name": h_r.name, - "speciality_name": h_r.name, - "speciality_category": h_r.category.id, - "speciality_category_name": str(h_r.category.name), - } - for h_r in hr - ] + hr = self.facility_specialists.all() - @property - def get_facility_humanresources(self): - """For the same purpose as the get_facility_infra... above""" - hr = self.facility_humanresources.all() return [ { "id": h_r.id, - "speciality_id": h_r.id, - "name": h_r.name, - "speciality_name": h_r.name, - "speciality_category": h_r.category.id, - "speciality_category_name": str(h_r.category.name), + "name": h_r.speciality.name, + "count": h_r.count, + "speciality_category": h_r.speciality.category.id, + "speciality_category_name": str(h_r.speciality.category.name), } for h_r in hr ] + @property def average_rating(self): avg_service_rating = [ @@ -2058,7 +2057,7 @@ def update_facility(self): new_date = datetime.date(year=value.year, month=value.month, day=value.day) value = new_date elif field_name == 'sub_county_id': - value = SubCounty.objects.get(name=field_changed.get('display_value')).id + value = SubCounty.objects.get(id=field_changed.get('actual_value')).id else: value = field_changed.get("actual_value") @@ -2615,7 +2614,7 @@ class FacilityService(AbstractBase): 'CHRIO') # For services that do not have options, the service will be linked # directly to the - service = models.ForeignKey(Service, on_delete=models.PROTECT,) + service = models.ForeignKey(Service, related_name='service_id', on_delete=models.PROTECT) @property def service_has_options(self): @@ -2890,7 +2889,7 @@ class FacilitySpecialist(AbstractBase): Facility, related_name='facility_specialists', on_delete=models.PROTECT) - speciality = models.ForeignKey(Speciality, on_delete=models.PROTECT,) + speciality = models.ForeignKey(Speciality, related_name='speciality', on_delete=models.PROTECT,) count = models.IntegerField( default=0, @@ -3009,8 +3008,9 @@ class FacilityInfrastructure(AbstractBase): on_delete=models.PROTECT) infrastructure = models.ForeignKey( - Infrastructure, - on_delete=models.PROTECT,) + Infrastructure, + related_name='infrastructure', + on_delete=models.PROTECT,) count = models.IntegerField( default=0, @@ -3042,4 +3042,4 @@ def validate_unique_infrastructure(self): def clean(self, *args, **kwargs): self.validate_unique_infrastructure() -####### infra \ No newline at end of file +####### infra diff --git a/facilities/serializers/facility_serializers.py b/facilities/serializers/facility_serializers.py index ce49ca45..1a8f21d9 100755 --- a/facilities/serializers/facility_serializers.py +++ b/facilities/serializers/facility_serializers.py @@ -464,9 +464,9 @@ class FacilitySerializer( source="get_facility_services") facility_infrastructure = serializers.ReadOnlyField( source="get_facility_infrastructure") + facility_contacts = serializers.ReadOnlyField( + source="get_facility_contacts") facility_humanresources = serializers.ReadOnlyField( - source="get_facility_humanresources") - facility_specialities = serializers.ReadOnlyField( source="get_facility_specialities") is_approved = serializers.ReadOnlyField() has_edits = serializers.ReadOnlyField() @@ -670,6 +670,11 @@ class Meta(AbstractFieldsMixin.Meta): model = FacilityInfrastructure +class ChulSummarySerializer(serializers.ModelSerializer): + # count=serializers.IntegerField() + class Meta: + model = None + fields = '__all__' class FacilityDetailSerializer(FacilitySerializer): facility_services = serializers.ReadOnlyField( @@ -685,13 +690,19 @@ class FacilityDetailSerializer(FacilitySerializer): constituency_code = serializers.ReadOnlyField( source='ward.constituency.code' ) + facility_specialists = FacilitySpecialistSerializer(many=True, required=False) + # specialists = serializers.ReadOnlyField( + # source="get_facility_specialities") + ward_code = serializers.ReadOnlyField(source='ward.code') service_catalogue_active = serializers.ReadOnlyField() facility_units = FacilityUnitSerializer(many=True, required=False) facility_infrastructure = FacilityInfrastructureSerializer(many=True, required=False) + # infrastructure = serializers.ReadOnlyField( + # source="get_facility_infrastructure") officer_in_charge = serializers.ReadOnlyField() - keph_level_name = serializers.ReadOnlyField(source='keph_level.name') + keph_level_name = serializers.ReadOnlyField(source='keph_level.name') class Meta(object): model = Facility @@ -831,3 +842,4 @@ def create_facility_child_entity(entity_creator_callable, entity_data): raise ValidationError(self.inlining_errors) return instance + diff --git a/facilities/urls/facility_urls.py b/facilities/urls/facility_urls.py index d089fec4..fa37a095 100755 --- a/facilities/urls/facility_urls.py +++ b/facilities/urls/facility_urls.py @@ -84,7 +84,11 @@ views.FacilityOfficerDetailView.as_view(), name='facility_officer_detail'), - url(r'^dashboard/$', views.DashBoard.as_view(), name='dashboard'), + url(r'^dashboard/$', views.DashBoard.as_view(), + name='dashboard'), + # url(r'^dashboard/(?P[^/]+)/$', views.DashBoard.as_view(), + # name='dashboard'), + url(r'^facility_correction_template/(?P[^/]+)/$', views.FacilityCorrectionTemplate.as_view(), @@ -171,7 +175,7 @@ url(r'^facility_specialists/(?P[^/]+)/$', views.FacilitySpecialistDetailView.as_view(), name='facility_specialist_detail'), - # Infrastructure + # Infrastructurepath url(r'^infrastructure/$', views.InfrastructureListView.as_view(), name='infrastructure_list'), url(r'^infrastructure/(?P[^/]+)/$', views.InfrastructureDetailView.as_view(), name='infrastructure_detail'), @@ -284,4 +288,6 @@ url(r'^facility_depts/(?P[^/]+)/$', views.FacilityDepartmentDetailView.as_view(), name='facility_depts_detail'), + url(r'^reports/static_reports/$', + views.StaticReport.as_view(), name='static_report'), ) diff --git a/facilities/utils.py b/facilities/utils.py index 9226f60e..785db043 100755 --- a/facilities/utils.py +++ b/facilities/utils.py @@ -282,7 +282,7 @@ def _create_contacts(self, data): created_contacts = [] for contact in contacts: - contact_type = ContactType.objects.get(id=contact.get('type')) + contact_type = ContactType.objects.get(id=contact.get('contact_type')) contact_dict = { "contact_type": contact_type, "contact": contact.get('contact') @@ -293,7 +293,7 @@ def _create_contacts(self, data): contact_dict = self._inject_creating_user(contact_dict) contact_dict = self._inject_creating_user(contact_dict) created_contacts.append(Contact.objects.create(**contact_dict)) - + return created_contacts def _create_facility_officer(self, data): diff --git a/facilities/views/__init__.py b/facilities/views/__init__.py index 8ec7bc40..1f9defb9 100755 --- a/facilities/views/__init__.py +++ b/facilities/views/__init__.py @@ -3,4 +3,5 @@ from .facility_setup_views import * # noqa from .facility_special_workflow_views import * # noqa from .service_catalog_views import * # noqa +from .static_reports_view import * # from .facility_human_resource_views import * \ No newline at end of file diff --git a/facilities/views/facility_dashboard.py b/facilities/views/facility_dashboard.py index bd30e59f..f4fead0e 100755 --- a/facilities/views/facility_dashboard.py +++ b/facilities/views/facility_dashboard.py @@ -1,7 +1,10 @@ -from datetime import timedelta +from datetime import timedelta, datetime +from itertools import count +from django.http import JsonResponse from django.utils import timezone from django.db.models import Q +from django.db import connection from rest_framework.views import APIView, Response from common.models import County, SubCounty, Ward @@ -12,13 +15,37 @@ Owner, FacilityStatus, FacilityType, - Facility + Facility,KephLevel ) from ..views import QuerysetFilterMixin class DashBoard(QuerysetFilterMixin, APIView): queryset = Facility.objects.all() + def get_chul_summary(self, start_date=None, end_date=None): + with connection.cursor() as cursor: + sql = "SELECT chul_status.name, COUNT(chul_communityhealthunit.status_id) As counts FROM chul_communityhealthunit INNER JOIN chul_status ON chul_communityhealthunit.status_id = chul_status.id" + params = [] + if start_date: + sql += " WHERE chul_communityhealthunit.date_created >= %s" + params.append(start_date) + if end_date: + if start_date: + sql += " AND chul_communityhealthunit.date_created <= %s" + else: + sql += " WHERE chul_communityhealthunit.date_created <= %s" + params.append(end_date) + sql += " GROUP BY chul_status.name" + cursor.execute(sql, params) + rows = cursor.fetchall() + return rows + + def chul_summary(self, request, *args, **kwargs): + queryset = self.get_chul_summary() + data = [] + for row in queryset: + data.append({"name": row[0], "count": row[1]}) + return data def get_chu_count_in_county_summary(self, county): return CommunityHealthUnit.objects.filter( @@ -48,7 +75,7 @@ def get_facility_county_summary(self): facility_county_summary[str(county.name)] = facility_county_count top_10_counties = sorted( facility_county_summary.items(), - key=lambda x: x[1], reverse=True)[0:20] + key=lambda x: x[1], reverse=True)[0:94] facility_county_summary top_10_counties_summary = [] for item in top_10_counties: @@ -63,11 +90,16 @@ def get_facility_county_summary(self): return top_10_counties_summary if self.request.user.is_national else [] def get_facility_constituency_summary(self): - constituencies = SubCounty.objects.filter( - county=self.request.user.county) - constituencies = constituencies if self.request.user.county else [] + if not self.request.query_params.get('sub_county'): + constituencies = SubCounty.objects.filter( + county=self.request.user.county) \ + if not self.request.query_params.get('ward') and self.request.user.county else [] + else: + constituencies = [SubCounty.objects.get(id=self.request.query_params.get('sub_county'))] + facility_constituency_summary = {} + for const in constituencies: facility_const_count = self.get_queryset().filter( ward__sub_county=const).count() @@ -81,6 +113,7 @@ def get_facility_constituency_summary(self): const = SubCounty.objects.get(name=item[0]) chu_count = self.get_chu_count_in_constituency_summary(const) top_10_consts_summary.append( + { "name": item[0], "count": item[1], @@ -88,10 +121,18 @@ def get_facility_constituency_summary(self): }) return top_10_consts_summary + def get_facility_ward_summary(self): - wards = Ward.objects.filter( + + if not self.request.query_params.get('ward'): + wards = Ward.objects.filter( sub_county=self.request.user.sub_county) \ if self.request.user.sub_county else [] + + else: + wards = [Ward.objects.get(id=self.request.query_params.get('ward'))] + + facility_ward_summary = {} for ward in wards: facility_ward_count = self.get_queryset().filter( @@ -113,6 +154,7 @@ def get_facility_ward_summary(self): }) return top_10_wards_summary + def get_facility_type_summary(self, cty): facility_type_parents_names = [] for f_type in FacilityType.objects.all(): @@ -128,13 +170,20 @@ def get_facility_type_summary(self, cty): summaries[parent] = 0 for facility_type in facility_types: - if not cty: - summaries[facility_type.sub_division] = summaries.get( - facility_type.sub_division) + self.get_queryset().filter( - facility_type=facility_type).count() + if not cty and not self.request.query_params.get('sub_county'): + + summaries[facility_type.sub_division] = summaries.get( + facility_type.sub_division) + self.get_queryset().filter( + facility_type=facility_type).count() else: - summaries[facility_type.sub_division] = self.get_queryset().filter( - facility_type=facility_type, ward__sub_county__county=cty).count() + if not self.request.query_params.get('ward'): + summaries[facility_type.sub_division] = self.get_queryset().filter( + facility_type=facility_type, ward__sub_county__county=cty, sub_county=self.request.query_params.get('sub_county')).count() + else: + summaries[facility_type.sub_division] = self.get_queryset().filter( + facility_type=facility_type, ward__sub_county__county=cty, ward=self.request.query_params.get('ward')).count() + + facility_type_summary = [ {"name": key, "count": value } for key, value in summaries.items() @@ -148,9 +197,10 @@ def get_facility_type_summary(self, cty): def get_facility_owner_summary(self, cty): owners = Owner.objects.all() + facility_owners_summary = [] for owner in owners: - if not cty: + if not cty and not self.request.query_params.get('sub_county'): facility_owners_summary.append( { "name": owner.name, @@ -158,19 +208,29 @@ def get_facility_owner_summary(self, cty): owner=owner).count() }) else: - facility_owners_summary.append( + if not self.request.query_params.get('ward'): + facility_owners_summary.append( + { + "name": owner.name, + "count": self.get_queryset().filter( + ward__sub_county__county=cty, owner=owner, sub_county=self.request.query_params.get('sub_county')).count() + }) + else: + facility_owners_summary.append( { "name": owner.name, "count": self.get_queryset().filter( - ward__sub_county__county=cty, owner=owner).count() + ward__sub_county__county=cty, owner=owner, ward=self.request.query_params.get('ward')).count() }) + return facility_owners_summary + def get_facility_status_summary(self, cty): statuses = FacilityStatus.objects.all() status_summary = [] for status in statuses: - if not cty: + if not cty and not self.request.query_params.get('sub_county'): status_summary.append( { "name": status.name, @@ -178,13 +238,22 @@ def get_facility_status_summary(self, cty): operation_status=status).count() }) else: - status_summary.append( - { - "name": status.name, - "count": self.get_queryset().filter( - ward__sub_county__county=cty, - operation_status=status).count() - }) + if not self.request.query_params.get('ward'): + status_summary.append( + { + "name": status.name, + "count": self.get_queryset().filter( + ward__sub_county__county=cty, + operation_status=status, sub_county=self.request.query_params.get('sub_county')).count() + }) + else: + status_summary.append( + { + "name": status.name, + "count": self.get_queryset().filter( + ward__sub_county__county=cty, + operation_status=status, ward=self.request.query_params.get('ward')).count() + }) return status_summary @@ -192,7 +261,7 @@ def get_facility_owner_types_summary(self, cty): owner_types = OwnerType.objects.all() owner_types_summary = [] for owner_type in owner_types: - if not cty: + if not cty and not self.request.query_params.get('sub_county'): owner_types_summary.append( { "name": owner_type.name, @@ -200,13 +269,23 @@ def get_facility_owner_types_summary(self, cty): owner__owner_type=owner_type).count() }) else: - owner_types_summary.append( - { - "name": owner_type.name, - "count": self.get_queryset().filter( - ward__sub_county__county=cty, - owner__owner_type=owner_type).count() - }) + if not self.request.query_params.get('ward'): + owner_types_summary.append( + { + "name": owner_type.name, + "count": self.get_queryset().filter( + ward__sub_county__county=cty, + owner__owner_type=owner_type, sub_county=self.request.query_params.get('sub_county')).count() + }) + else: + owner_types_summary.append( + { + "name": owner_type.name, + "count": self.get_queryset().filter( + ward__sub_county__county=cty, + owner__owner_type=owner_type, ward=self.request.query_params.get('ward')).count() + }) + return owner_types_summary @@ -312,90 +391,175 @@ def get_recently_created_chus(self, cty): def facilities_pending_approval_count(self, cty): - if not cty: + if not cty and not self.request.query_params.get('sub_county'): updated_pending_approval = self.get_queryset().filter(has_edits=True) + + else: + if not self.request.query_params.get('ward'): + updated_pending_approval = self.get_queryset().filter( + ward__sub_county__county=cty, sub_county=self.request.query_params.get('sub_county'), has_edits=True) + + else: + updated_pending_approval = self.get_queryset().filter( + ward__sub_county__county=cty, ward=self.request.query_params.get('ward'), has_edits=True) + + return len( + list(set(list(updated_pending_approval) )) + ) + def facilities_newly_created_count(self, cty): + if not cty and not self.request.query_params.get('sub_county'): + newly_created = self.queryset.filter(approved=False, rejected=False) else: - updated_pending_approval = self.get_queryset().filter( - ward__sub_county__county=cty, has_edits=True) - newly_created = self.queryset.filter( - ward__sub_county__county=cty, approved=False, rejected=False) + if not self.request.query_params.get('ward'): + + newly_created = self.queryset.filter( + ward__sub_county__county=cty, sub_county=self.request.query_params.get('sub_county'), approved=False, rejected=False) + else: + + newly_created = self.queryset.filter( + ward__sub_county__county=cty, ward=self.request.query_params.get('ward'), approved=False, rejected=False) + return len( - list(set(list(updated_pending_approval) + list(newly_created))) + list(set (list(newly_created))) ) def get_facilities_approved_count(self,cty): - if not cty: + if not cty and not self.request.query_params.get('sub_county'): return self.queryset.filter(approved=True, rejected=False).count() else: - return self.queryset.filter(approved=True, rejected=False, ward__sub_county__county=cty).count() + if not self.request.query_params.get('ward'): + return self.queryset.filter(approved=True, rejected=False, ward__sub_county__county=cty, sub_county=self.request.query_params.get('sub_county')).count() + else: + return self.queryset.filter(approved=True, rejected=False, ward__sub_county__county=cty, ward=self.request.query_params.get('ward')).count() + def get_chus_pending_approval(self, cty): """ Get the number of CHUs pending approval """ - if not cty: + if not cty and not self.request.query_params.get('sub_county'): return CommunityHealthUnit.objects.filter( Q(is_approved=False, is_rejected=False) | Q(has_edits=True)).distinct().filter( facility__in=self.get_queryset()).count() else: - return CommunityHealthUnit.objects.filter( - Q(is_approved=False, is_rejected=False) | - Q(has_edits=True)).distinct().filter( - facility__in=self.get_queryset(), - facility__ward__sub_county__county=cty).count() + if not self.request.query_params.get('ward'): + return CommunityHealthUnit.objects.filter( + Q(is_approved=False, is_rejected=False) | + Q(has_edits=True)).distinct().filter( + facility__in=self.get_queryset(), + facility__ward__sub_county__county=cty, facility__ward__sub_county=self.request.query_params.get('sub_county')).count() + else: + return CommunityHealthUnit.objects.filter( + Q(is_approved=False, is_rejected=False) | + Q(has_edits=True)).distinct().filter( + facility__in=self.get_queryset(), + facility__ward__sub_county__county=cty, facility__ward=self.request.query_params.get('ward')).count() + def get_rejected_chus(self, cty): """ Get the number of CHUs that have been rejected """ - if not cty: + if not cty and not self.request.query_params.get('sub_county'): return CommunityHealthUnit.objects.filter(is_rejected=True).count() else: - return CommunityHealthUnit.objects.filter( - is_rejected=True, - facility__ward__sub_county__county=cty).count() + if not self.request.query_params.get('ward'): + return CommunityHealthUnit.objects.filter( + is_rejected=True, + facility__ward__sub_county__county=cty, facility__ward__sub_county=self.request.query_params.get('sub_county')).count() + else: + return CommunityHealthUnit.objects.filter( + is_rejected=True, + facility__ward__sub_county__county=cty, facility__ward=self.request.query_params.get('ward')).count() + def get_rejected_facilities_count(self, cty): - if not cty: + if not cty and not self.request.query_params.get('sub_county'): return self.get_queryset().filter(rejected=True).count() else: - return self.get_queryset().filter(rejected=True, ward__sub_county__county=cty).count() + if not self.request.query_params.get('ward'): + return self.get_queryset().filter(rejected=True, ward__sub_county__county=cty, sub_county=self.request.query_params.get('sub_county')).count() + else: + return self.get_queryset().filter(rejected=True, ward__sub_county__county=cty, ward=self.request.query_params.get('ward')).count() + def get_closed_facilities_count(self, cty): - if not cty: + if not cty and not self.request.query_params.get('sub_county'): return self.get_queryset().filter(closed=True).count() else: - return self.get_queryset().filter(closed=True, ward__sub_county__county=cty).count() + if not self.request.query_params.get('ward'): + return self.get_queryset().filter(closed=True, ward__sub_county__county=cty, sub_county=self.request.query_params.get('sub_county')).count() + else: + return self.get_queryset().filter(closed=True, ward__sub_county__county=cty, ward=self.request.query_params.get('ward')).count() + + + def get_facilities_kephlevel_count(self,county_name): + """ + Function to get facilities by keph level + """ + if county_name: + keph_level = KephLevel.objects.values("id", "name") + keph_array = [] + for keph in keph_level: + keph_count = Facility.objects.filter(keph_level_id=keph.get("id"),ward__sub_county__county=county_name ).count() + keph_array.append({"name" : keph.get("name"), "count" : keph_count}) + return keph_array + + else: + keph_level = KephLevel.objects.values("id", "name") + keph_array = [] + for keph in keph_level: + keph_count = Facility.objects.filter(keph_level_id=keph.get("id")).count() + keph_array.append({"name" : keph.get("name"), "count" : keph_count}) + + return keph_array + def get(self, *args, **kwargs): + user = self.request.user county_ = user.county + if not self.request.query_params.get('county'): county_ = user.county else: county_ = County.objects.get(id=self.request.query_params.get('county')) - if not county_: + if not county_ and not self.request.query_params.get('sub_county'): + total_facilities = self.get_queryset().count() else: - total_facilities = self.get_queryset().filter( - ward__sub_county__county=county_).count() - if not county_: + if not self.request.query_params.get('ward'): + + total_facilities = self.get_queryset().filter( + ward__sub_county__county=county_, ward__sub_county=self.request.query_params.get('sub_county')).count() + else: + + total_facilities = self.get_queryset().filter( + ward__sub_county__county=county_, ward=self.request.query_params.get('ward')).count() + + if not county_ and not self.request.query_params.get('sub_county'): total_chus = CommunityHealthUnit.objects.filter( facility__in=self.get_queryset()).count() else: - total_chus = CommunityHealthUnit.objects.filter( - facility__in=self.get_queryset().filter( - ward__sub_county__county=county_)).count() + if not self.request.query_params.get('ward'): + total_chus = CommunityHealthUnit.objects.filter( + facility__in=self.get_queryset().filter( + ward__sub_county__county=county_, ward__sub_county=self.request.query_params.get('sub_county'))).count() + else: + total_chus = CommunityHealthUnit.objects.filter( + facility__in=self.get_queryset().filter( + ward__sub_county__county=county_, ward=self.request.query_params.get('ward'))).count() data = { + "keph_level" : self.get_facilities_kephlevel_count(county_), "total_facilities": total_facilities, "county_summary": self.get_facility_county_summary() if user.is_national else [], - "constituencies_summary": self.get_facility_constituency_summary() - if user.county and not user.sub_county else [], - "wards_summary": self.get_facility_ward_summary() - if user.sub_county else [], + "constituencies_summary": self.get_facility_constituency_summary(), + # if user.county and not user.sub_county else [], + "wards_summary": self.get_facility_ward_summary(), + # if user.sub_county else [], "owners_summary": self.get_facility_owner_summary(county_), "types_summary": self.get_facility_type_summary(county_), "status_summary": self.get_facility_status_summary(county_), @@ -403,6 +567,7 @@ def get(self, *args, **kwargs): "recently_created": self.get_recently_created_facilities(county_), "recently_created_chus": self.get_recently_created_chus(county_), "pending_updates": self.facilities_pending_approval_count(county_), + "newly_created": self.facilities_newly_created_count(county_), "rejected_facilities_count": self.get_rejected_facilities_count(county_), "closed_facilities_count": self.get_closed_facilities_count(county_), "rejected_chus": self.get_rejected_chus(county_), @@ -410,7 +575,10 @@ def get(self, *args, **kwargs): "total_chus": total_chus, "approved_facilities": self.get_facilities_approved_count(county_), + } + chul_summary = self.chul_summary( *args, **kwargs) + data["chul_summary"] = chul_summary fields = self.request.query_params.get("fields", None) if fields: diff --git a/facilities/views/facility_views.py b/facilities/views/facility_views.py index 74e8ecfd..d2041de4 100755 --- a/facilities/views/facility_views.py +++ b/facilities/views/facility_views.py @@ -217,6 +217,22 @@ def filter_for_regulators(self): self.queryset = self.queryset.filter( regulatory_body=self.request.user.regulator) + def filter_for_infrastructure(self): + if self.request.user.has_perm("facilities.view_infrastructure") \ + is False and ('infrastructure' in [ + field.name for field in + self.queryset.model._meta.get_fields()]): + self.queryset = self.queryset.filter(infrastructure=self.request.infrastructure) + + + def filter_for_services(self): + if self.request.user.has_perm("facilities.view_facilityservice") \ + is False and ('service' in [ + field.name for field in + self.queryset.model._meta.get_fields()]): + self.queryset = self.queryset.filter(service=self.request.service) + + def get_queryset(self, *args, **kwargs): custom_queryset = kwargs.pop('custom_queryset', None) if hasattr(custom_queryset, 'count'): @@ -231,6 +247,8 @@ def get_queryset(self, *args, **kwargs): self.filter_rejected_facilities() self.filter_closed_facilities() self.filter_approved_facilities() + self.filter_for_infrastructure() + self.filter_for_services() return self.queryset @@ -398,6 +416,7 @@ class FacilityListView(QuerysetFilterMixin, generics.ListCreateAPIView): county -- A list of comma separated county pks
constituency -- A list of comma separated constituency pks
owner -- A list of comma separated owner pks
+ number_of_inpatient_beds -- A list of comma separated integers
number_of_beds -- A list of comma separated integers
number_of_cots -- A list of comma separated integers
open_whole_day -- Boolean True/False
diff --git a/facilities/views/static_reports_view.py b/facilities/views/static_reports_view.py new file mode 100644 index 00000000..19430fa0 --- /dev/null +++ b/facilities/views/static_reports_view.py @@ -0,0 +1,97 @@ +from datetime import timedelta +from itertools import count + +from django.utils import timezone +from django.db.models import Q + +from rest_framework.views import APIView, Response +from common.models import County, SubCounty, Ward +from chul.models import CommunityHealthUnit + +from ..models import ( + OwnerType, + Owner, + FacilityStatus, + FacilityType, + Facility,KephLevel +) +from ..views import QuerysetFilterMixin + + +class StaticReport(QuerysetFilterMixin, APIView): + queryset = Facility.objects.all() + + def get_chu_count_in_county_summary(self, county): + return CommunityHealthUnit.objects.filter( + facility__ward__sub_county__county=county).count() + + def get_chu_count_in_constituency_summary(self, const): + return CommunityHealthUnit.objects.filter( + facility__ward__sub_county=const).count() + + def get_chu_count_in_ward_summary(self, ward): + return CommunityHealthUnit.objects.filter( + facility__ward=ward).count() + + def get_bed_count(self, location): + + if location: + + + # for keph in keph_level: + # objects.values('Category').distinct() + facility_beds_details = Facility.objects.values("number_of_cots", "number_of_beds","number_of_hdu_beds", "number_of_icu_beds", "number_of_isolation_beds","number_of_maternity_beds","owner_id","county_id", "facility_type_id","keph_level_id", "sub_county_id","ward_id", ward__sub_county__county=location) + + return "keph_array" + else: + # + counties = County.objects.values("id","name","code") + facility_beds_details = Facility.objects.values("number_of_cots", "number_of_beds","number_of_hdu_beds", "number_of_icu_beds", "number_of_isolation_beds","number_of_maternity_beds","owner_id","county_id", "facility_type_id","keph_level_id", "sub_county_id","ward_id") + counties_beds_array = [] + + cobedunter = 0 + for county in counties: + for beds_details in facility_beds_details: + if beds_details.get("county_id") is not None and beds_details.get("county_id")==county.get("id"): + counties_beds_array.append({ + "county_name" : county.get("name"), + "count" : beds_details.get("number_of_beds") + }) + summary=[] + final_sum = {} + + for county_data in counties_beds_array: + # print("---------", county_data.get("county_name") != final_sum.get("county")) + if county_data.get("county_name") != final_sum.get("county"): + final_sum[county_data.get("county_name")] = county_data.get("count") + elif county_data.get("county_name") == final_sum.get("county"): + final_sum[county_data.get("county_name")] = county_data.get("count")+county_data.get("count") + + summary = [ + {"name": key, "count": value } for key, value in final_sum.items() + ] + return summary + + + + def get(self, *args, **kwargs): + user = self.request.user + county_ = user.county + if not self.request.query_params.get('county'): + county_ = user.county + else: + county_ = County.objects.get(id=self.request.query_params.get('county')) + + data = { + "beds_by_county" : self.get_bed_count(county_), + + } + + fields = self.request.query_params.get("fields", None) + if fields: + required = fields.split(",") + required_data = { + i: data[i] for i in data if i in required + } + return Response(required_data) + return Response(data) diff --git a/load_all_facilities.py b/load_all_facilities.py index 593b649f..32f13445 100755 --- a/load_all_facilities.py +++ b/load_all_facilities.py @@ -39,7 +39,7 @@ def load_missed_facilities(): try: county = County.objects.filter(name__icontains=county_name)[0] except IndexError: - import pdb; pdb.set_trace() + ; print county, record.get('county') reg_body = None @@ -59,8 +59,8 @@ def load_missed_facilities(): try: operation_status = FacilityStatus.objects.get(name=record.get('operation_status').get('name')) except AttributeError: - import pdb - pdb.set_trace() + + facility_data = { "code": int(record.get('code')), @@ -94,7 +94,7 @@ def load_missed_facilities(): try: ward = prob_ward.filter(name__icontains=fac_ward.get('ward'))[0] except: - import pdb;pdb.set_trace() + ; facility_data['ward'] = ward try: Facility.objects.get(code=int(record.get('code'))) @@ -108,7 +108,7 @@ def load_missed_facilities(): except: pass - # import pdb; pdb.set_trace() + # ; break return len(facs_created) @@ -117,7 +117,7 @@ def load_missed_facilities(): # # try: # # Facility(**facility_data).save() # # except: - # # import pdb; pdb.set_trace() + # # ; # try: # facility = Facility.objects.get(code=record.get('code')) # facility.county = county @@ -206,13 +206,13 @@ def map_facility_types(): try: facility_type_obj = FacilityType.objects.get(name=new_type) except FacilityType.DoesNotExist: - import pdb - pdb.set_trace() + + facility.facility_type = facility_type_obj try: facility.save(allow_save=True) except: - import pdb;pdb.set_trace() + ; diff --git a/reporting/facility_reports.py b/reporting/facility_reports.py index c2302239..c9b8b496 100755 --- a/reporting/facility_reports.py +++ b/reporting/facility_reports.py @@ -150,6 +150,36 @@ def get_report_data(self, *args, **kwargs): filters=filters ) + if report_type == "beds_and_cots_by_keph_level": + keph_level_id = self.request.query_params.get( + "keph_level", None + ) + filters = ( + {} if keph_level_id is None + else {"keph_level": keph_level_id} + ) + + return self._get_beds_and_cots( + vals={'keph_level__name': 'keph_level_name', 'keph_level_id': "keph_level"}, + filters=filters + ) + + if report_type == "beds_and_cots_by_owner": + keph_level_id = self.request.query_params.get( + "owner", None + ) + filters = ( + {} if keph_level_id is None + else {"owner": keph_level_id} + ) + + return self._get_beds_and_cots( + vals={'owner__name': 'owner_name', 'owner_id': "owner"}, + filters=filters + ) + + + more_filters_params = self.request.query_params.get("filters", None) report_config = REPORTS.get(report_type, None) diff --git a/requirements.txt b/requirements.txt index ecf975e2..45139f2e 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,96 @@ --e . \ No newline at end of file + +amqp==1.4.9 +ansible==1.9.6 +anyjson==0.3.3 +apache-libcloud==0.17.0 +apipkg==1.5 +backports.ssl-match-hostname==3.7.0.1 +billiard==3.3.0.23 +boto==2.38.0 +cairocffi==0.9.0 +CairoSVG==1.0.22 +celery==3.1.19 +certifi==2019.3.9 +cffi==1.12.2 +chardet==3.0.4 +commonmark==0.8.1 +coreapi==2.3.3 +coreschema==0.0.4 +coverage==3.7.1 +cssselect2==0.2.1 +defusedxml==0.5.0 +dj-database-url==0.4.0 +Django==1.11.27 +django-allauth==0.39.1 +django-braces==1.13.0 +django-cors-headers==2.1.0 +django-debug-toolbar==1.8 +django-environ==0.3.1 +django-filter==1.0.4 +django-oauth-toolkit==0.11.0 +django-redis==4.0.0 +django-rest-auth==0.9.1 +django-rest-swagger==2.1.0 +django-reversion==2.0.5 +django-storages==1.1.8 +djangorestframework==3.6.3 +djangorestframework-csv==1.3.4 +djangorestframework-gis==0.8.2 +djangorestframework-xml==1.0.1 +docutils==0.14 +drf-extensions==0.3.1 +ecdsa==0.13 +execnet==1.5.0 +Fabric==1.10.5 +filechunkio==1.6 +flake8==2.3.0 +future==0.17.1 +gunicorn==19.3.0 +html5lib==0.9999999 +idna==2.8 +itypes==1.1.0 +Jinja2==2.10 +kombu==3.0.37 +Markdown==2.5.2 +MarkupSafe==1.1.1 +mccabe==0.6.1 +mock==1.0.1 +model-mommy==1.2.6 +oauthlib==1.1.2 +openapi-codec==1.3.2 +paramiko==1.18.5 +pdfrw==0.4 +pep8==1.7.1 +psycopg2==2.7 +psycopg2-binary==2.7.7 +py==1.8.0 +pycparser==2.19 +pycrypto==2.6.1 +pyflakes==2.1.1 +Pyphen==0.9.5 +pytest==2.7.3 +pytest-django==2.8.0 +pytest-xdist==1.11 +python-coveralls==2.5.0 +python-dateutil==2.8.0 +python-openid==2.2.5 +pytz==2018.9 +PyYAML==5.1 +recommonmark==0.1.1 +redis==3.2.1 +requests==2.21.0 +requests-oauthlib==1.2.0 +sh==1.12.14 +Shapely==1.5.17.post1 +simplejson==3.16.0 +six==1.9.0 +sqlparse==0.1.19 +tinycss2==0.6.1 +tox==1.9.2 +uritemplate==3.0.0 +urllib3==1.24.1 +virtualenv==12.0.7 +WeasyPrint==0.42.3 +webencodings==0.5.1 +Werkzeug==0.10.4 +XlsxWriter==0.7.9 diff --git a/scripts.py b/scripts.py index 0b21615e..89ccef27 100755 --- a/scripts.py +++ b/scripts.py @@ -70,21 +70,21 @@ def move_facitlies_to_correct_ward(file_path=None): try: county = County.objects.filter(name__icontains=county_name)[0] except IndexError: - import pdb; pdb.set_trace() + ; prob_ward = Ward.objects.filter(constituency__county=county) try: ward = prob_ward.filter(name__icontains=record.get('ward'))[0] except IndexError: - import pdb - pdb.set_trace() + + fac.ward = ward print county, ward try: fac.save(allow_save=True) except: - import pdb - pdb.set_trace() + + def determine_facilites_already_in_system(): diff --git a/users/serializers.py b/users/serializers.py index f11cec03..c32e8378 100755 --- a/users/serializers.py +++ b/users/serializers.py @@ -133,7 +133,7 @@ def create(self, validated_data): county_level = self.initial_data.pop('is_county_level', False) sub_county_level = self.initial_data.pop('is_sub_county_level', False) permissions = _lookup_permissions( - self.context['request'].DATA + self.context['request'].data ) validated_data.pop('permissions', None)