diff --git a/.github/workflows/ci-prod.yml b/.github/workflows/ci-prod.yml new file mode 100644 index 00000000..9db3fc10 --- /dev/null +++ b/.github/workflows/ci-prod.yml @@ -0,0 +1,36 @@ +name: CI-Prod + +on: + push: + branches: [ mfr-api-prod ] + + +jobs: + + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Deploy to VPS + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.SERVER_HOST }} + port: ${{ secrets.SERVER_PORT }} + username: ${{ secrets.SERVER_USER }} + password: ${{ secrets.SERVER_KEY }} + script: | + set -e + cd /opt/mfl_api + if ! [[ -d './.git' ]]; then git init; fi + if ! [[ `git remote -v | awk '{print $1}' | head -n 1` =~ 'origin' ]]; then git remote add origin ${{ github.server_url }}${{ github.username }}/${{ github.repository }}.git; fi + git stash + git pull origin mfr-api-prod + echo ${{ secrets.SERVER_KEY }} | sudo -S service supervisor restart + + + + + + + \ No newline at end of file diff --git a/chul/models.py b/chul/models.py index 85cd843e..7c2ec046 100755 --- a/chul/models.py +++ b/chul/models.py @@ -304,12 +304,15 @@ def average_rating(self): def rating_count(self): return self.chu_ratings.count() + def push_chu_to_dhis2(self): from facilities.models.facility_models import DhisAuth import requests + dhisauth = DhisAuth() dhisauth.get_oauth2_token() - facility_dhis_id = self.get_facility_dhis2_parent_id() if self.facility.reporting_in_dhis else None + + facility_dhis_id = self.get_facility_dhis2_parent_id() # if self.facility.reporting_in_dhis else None unit_uuid_status = dhisauth.get_org_unit_id(self.code) unit_uuid = unit_uuid_status[0] new_chu_payload = { @@ -330,8 +333,7 @@ def push_chu_to_dhis2(self): if facility_dhis_id is not None: if unit_uuid_status[1] == 'retrieved': - LOGGER.info("[>>>>>] Retrieved CHU") - + r = requests.put( settings.DHIS_ENDPOINT + "api/organisationUnits/" + new_chu_payload.pop('id'), auth=(settings.DHIS_USERNAME, settings.DHIS_PASSWORD), @@ -340,10 +342,12 @@ def push_chu_to_dhis2(self): }, json=new_chu_payload ) - print("Update CHU Response", r.url, r.status_code, r.json()) - LOGGER.info("Update CHU Response: %s" % r.text) + + LOGGER.info("[DEBUG] Response(retrived): {}".format(r.text)) + + else: - LOGGER.info("[>>>>>] Payload for new CHU: {}".format(new_chu_payload)); + r = requests.post( settings.DHIS_ENDPOINT + "api/organisationUnits", auth=(settings.DHIS_USERNAME, settings.DHIS_PASSWORD), @@ -353,20 +357,24 @@ def push_chu_to_dhis2(self): json=new_chu_payload ) - print("Create CHU Response", r.url, r.status_code, r.json()) - LOGGER.info("Create CHU Response: %s" % r.text) + LOGGER.info("[DEBUG] Response(generated): {}".format(r.text)) - if r.json()["status"] != "OK": - LOGGER.error("Failed PUSH: error -> {}".format(r.text)) - raise ValidationError( - { - "Error!": ["An error occured while pushing Community Unit to DHIS2. This is may be caused by the " - "existance of an organisation unit with as similar name as to the one you are creating. " - "Or some specific information like codes are not unique"] - } - ) - self.push_chu_metadata(metadata_payload, unit_uuid) + + + if r.json()["status"] != "OK": + LOGGER.error("[DEBUG]: Repsonse(error):{}".format(r.text)) + + raise ValidationError( + { + "Error!": ["An error occured while pushing Community Unit to DHIS2. This is may be caused by the " + "existance of an organisation unit with as similar name as to the one you are creating. " + "Or some specific information like codes are not unique"] + } + ) + self.push_chu_metadata(metadata_payload, unit_uuid) else: + LOGGER.error("[DEBUG] facility_dhis_id: {}".format(facility_dhis_id)) + raise ValidationError( { "Error!": ["Could not find Facility DHIS ID, when pushing CU to DHIS"] @@ -386,33 +394,43 @@ def push_chu_metadata(self, metadata_payload, chu_uid): ) LOGGER.info('Metadata CUs pushed successfullly') + + + def get_facility_dhis2_parent_id(self): - from facilities.models.facility_models import DhisAuth + # from facilities.models.facility_models import DhisAuth import requests - r = requests.get( - settings.DHIS_ENDPOINT + "api/organisationUnits.json", - auth=(settings.DHIS_USERNAME, settings.DHIS_PASSWORD), - headers={ - "Accept": "application/json" - }, - params={ - "query": self.facility.code, - "fields": "id,name", - "filter": "level:in:[5]", - "paging": "false" - } - ) - if len(r.json()["organisationUnits"]) is 1 and "id" in r.json()["organisationUnits"][0]: - if r.json()["organisationUnits"][0]["id"]: - return r.json()["organisationUnits"][0]["id"] - else: - raise ValidationError( - { - "Error!": ["Unable to resolve exact Facility linked to the CHU in DHIS2"] + if hasattr(self, "facility") and hasattr(self.facility, "code"): + r = requests.get( + settings.DHIS_ENDPOINT + "api/organisationUnits.json", + auth=(settings.DHIS_USERNAME, settings.DHIS_PASSWORD), + headers={ + "Accept": "application/json" + }, + params={ + "query": self.facility.code, + "fields": "id,name", + "filter": "level:in:[5]", + "paging": "false" } ) + if len(r.json()["organisationUnits"]) is 1 and "id" in r.json()["organisationUnits"][0]: + if r.json()["organisationUnits"][0]["id"]: + return r.json()["organisationUnits"][0]["id"] + else: + raise ValidationError( + { + "Error!": ["Unable to find facility with code {} in KHIS.".format(self.facility.code)] + } + ) + else: + raise ValidationError({ + "Error": ["The linked facility for this CU does not have an MFL code. Therefore it is not in KHIS"] + }) + + class Meta(AbstractBase.Meta): unique_together = ('name', 'facility',) @@ -544,34 +562,44 @@ def update_basic_details(self): 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 key is not "basic": + setattr(self.health_unit, key, value) if 'basic' in basic_details: - setattr(self.health_unit, 'facility_id', basic_details.get('basic').get('facility')) + if 'basic' in basic_details.get('basic'): + if 'facility' in basic_details.get('basic').get('basic'): + setattr(self.health_unit, 'facility_id', basic_details.get('basic').get('basic').get('facility')) + else: + if 'facility' in basic_details.get('basic'): + 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) + for chew in chews: chew['health_unit'] = self.health_unit chew['created_by_id'] = self.created_by_id chew['updated_by_id'] = self.updated_by_id chew.pop('created_by', None) chew.pop('updated_by', None) - if 'id' in chew: + + if hasattr(chew, 'id'): chew_obj = CommunityHealthWorker.objects.get( id=chew['id']) chew_obj.first_name = chew['first_name'] chew_obj.last_name = chew['last_name'] - if 'is_incharge' in chew: + if hasattr(chew, 'is_incharge'): chew_obj.is_incharge = chew['is_incharge'] chew_obj.save() else: CommunityHealthWorker.objects.create(**chew) def update_services(self): + services = json.loads(self.services) CHUServiceLink.objects.filter(health_unit=self.health_unit).delete() for service in services: @@ -620,9 +648,11 @@ def update_contacts(self): @property def updates(self): updates = {} + if self.basic and self.basic is not None: json_basic = json.loads(self.basic) - updates['basic'] = json_basic['basic'] if 'basic' in json_basic else json_basic + updates['basic'] = json_basic['basic'] if hasattr(json_basic, 'basic') else json_basic + if self.contacts: updates['contacts'] = json.loads(self.contacts) if self.workers: @@ -631,6 +661,7 @@ def updates(self): updates['services'] = json.loads(self.services) updates['updated_by'] = self.updated_by.get_full_name return updates + def clean(self, *args, **kwargs): if not self.is_approved and not self.is_rejected: diff --git a/chul/serializers.py b/chul/serializers.py index 485b5a32..7b1d0411 100755 --- a/chul/serializers.py +++ b/chul/serializers.py @@ -121,7 +121,17 @@ def buffer_updates( try: update = ChuUpdateBuffer.objects.get( health_unit=chu_instance, - is_approved=False, is_rejected=False) + is_approved=False, is_rejected=False) if len(ChuUpdateBuffer.objects.filter( + health_unit=chu_instance, + is_approved=False, is_rejected=False)) == 1 else ChuUpdateBuffer.objects.filter( + health_unit=chu_instance, + is_approved=False, is_rejected=False)[0] if len(ChuUpdateBuffer.objects.filter( + health_unit=chu_instance, + is_approved=False, is_rejected=False)) > 1 else None + + if update is None: + raise ChuUpdateBuffer.DoesNotExist + except ChuUpdateBuffer.DoesNotExist: update = ChuUpdateBuffer.objects.create( health_unit=chu_instance, @@ -166,6 +176,65 @@ def buffer_updates( update.contacts = contacts update.save() + # Previous lateest commit: mfr-api-prod + # def buffer_updates( + # self, validated_data, chu_instance, chews=None, contacts=None, + # services=None): + + # try: + # chu_updates = ChuUpdateBuffer.objects.filter( + # health_unit=chu_instance, + # is_approved=False, is_rejected=False) + + # update = chu_updates[0] if chu_updates.__len__() > 0 else None + + # if update is None: + # raise ChuUpdateBuffer.DoesNotExist + + # except ChuUpdateBuffer.DoesNotExist: + # update = ChuUpdateBuffer.objects.create( + # health_unit=chu_instance, + # created_by_id=self.context['request'].user.id, + # updated_by_id=self.context['request'].user.id, + # is_new=True) + # basic_updates = self.get_basic_updates(chu_instance, validated_data) + + # update.basic = basic_updates if basic_updates \ + # and not update.basic else update.basic + + # if chews: + # for chew in chews: + # chew.pop('created', None) + # chew.pop('updated', None) + # chew.pop('updated_by', None) + # chew.pop('created_by', None) + + # chews = json.dumps(chews) + # update.workers = chews + + # if services: + # for service in services: + # sev_rec = CHUService.objects.get(id=service['service']) + # service.pop('created', None) + # service.pop('updated', None) + # service.pop('updated_by', None) + # service.pop('created_by', None) + # service['name'] = sev_rec.name + + # services = json.dumps(services) + # update.services = services + + # if contacts: + # for contact in contacts: + # contact_type = ContactType.objects.get( + # id=contact['contact_type']) + # contact['contact_type_name'] = contact_type.name + + # contacts = json.dumps(contacts) + + # update.contacts = contacts + # update.save() + def _ensure_all_chew_required_provided(self, chew): if 'first_name' and 'last_name' not in chew: self.inlined_errors.update({ diff --git a/facilities/filters/facility_filters.py b/facilities/filters/facility_filters.py index 92b2fa56..30fa44b0 100755 --- a/facilities/filters/facility_filters.py +++ b/facilities/filters/facility_filters.py @@ -401,54 +401,83 @@ def filter_approved_facilities(self, qs, name, value): return qs.filter(Q(approved=True)) else: return qs.filter(Q(approved=None) | Q(rejected=True)) + + def filter_facilities_with_pending_updates(self, qs, name, value): + + if value in TRUTH_NESS: + facilities_pending_updates = qs.filter(has_edits=True) + + facilities_latest_updates_ids = [f.id for f in facilities_pending_updates if f.latest_update is None] + + return facilities_pending_updates.exclude(id__in=facilities_latest_updates_ids) def filter_unpublished_facilities_national_level(self, qs, name, value): """ This is in order to allow the facilities to be seen so that they can be approved at the national level and assigned an MFL code. """ - - incomplete_facilities = [facility.id for facility in qs.filter(code=None) if not facility.is_complete] if value in TRUTH_NESS: - return qs.filter( - approved_national_level=None, approved=True, has_edits=False, closed=False, rejected=False, - ).exclude(id__in=incomplete_facilities) + pending_approval_qs = qs.filter( + Q(Q(approved_national_level=None) | Q(approved_national_level=False)), + approved=True, + has_edits=False, + closed=False, + rejected=False, + code=None + ) + + incomplete_pending_approval_ids = [facility.id for facility in pending_approval_qs if not facility.is_complete] + + return pending_approval_qs.exclude(id__in=incomplete_pending_approval_ids) + else: - return qs.filter( - approved_national_level=True, approved=True, has_edits=False, closed=False, rejected=False, - ).exclude(id__in=incomplete_facilities) + approved_qs = qs.filter( + approved_national_level=True, approved=True, has_edits=False, closed=False, rejected=False + ) + + incomplete_approved_qs = [facility.id for facility in approved_qs if not facility.is_complete] + + return approved_qs.exclude(id__in=incomplete_approved_qs) def filter_incomplete_facilities(self, qs, name, value): """ Filter the incomplete/complete facilities """ - incomplete_facilities = [facility for facility in qs.filter() if not facility.is_complete] + all_facilities = qs.all() if value in TRUTH_NESS: - return incomplete_facilities + complete_facilities_ids = [facility.id for facility in all_facilities if facility.is_complete] + return all_facilities.exclude(id__in=complete_facilities_ids) else: - return qs.exclude(id__in=incomplete_facilities) + incomplete_facilities_ids = [facility.id for facility in all_facilities if not facility.is_complete] + return all_facilities.exclude(id__in=incomplete_facilities_ids) def facilities_pending_approval(self, qs, name, value): - # incomplete = qs.filter(code=not None) - # incomplete_facility_ids = [facility.id for facility in incomplete] - incomplete_facilities = [facility.id for facility in qs.filter(code=None) if not facility.is_complete] + if value in TRUTH_NESS: - return qs.filter( - Q( + pending_validation_qs = qs.filter( has_edits=False, approved=None, rejected=False, - approved_national_level=None - )).exclude(id__in=incomplete_facilities) + approved_national_level=None, + code=None + ) + + incomplete_pending_validation_ids = [facility.id for facility in pending_validation_qs if not facility.is_complete] + + return pending_validation_qs.exclude(id__in=incomplete_pending_validation_ids) else: - return qs.filter( + validated_qs = qs.filter( rejected=False, has_edits=False, approved=True, approved_national_level=None - ).exclude(id__in=incomplete_facilities) + ) + + incomplete_validated_ids = [facility.id for facility in validated_qs if not facility.is_complete] + + return validated_qs.exclude(id__in=incomplete_validated_ids) def filter_national_rejected(self, qs, name, value): @@ -464,7 +493,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') @@ -543,6 +572,8 @@ def filter_number_cots(self, qs, name, value): method='filter_incomplete_facilities') to_publish = django_filters.CharFilter( method='filter_unpublished_facilities_national_level') + have_updates = django_filters.CharFilter( + method='filter_facilities_with_pending_updates') approved_national_level = django_filters.TypedChoiceFilter( choices=BOOLEAN_CHOICES, coerce=strtobool) diff --git a/facilities/models/facility_models.py b/facilities/models/facility_models.py index e856cd3d..f5f7c4d5 100755 --- a/facilities/models/facility_models.py +++ b/facilities/models/facility_models.py @@ -135,13 +135,8 @@ def get_org_unit_id(self, code): "paging": "false" } ) - print("Get Org Unit ID Response", r.text, str(code)) - if len(r.json()["organisationUnits"]) is 1: - # raise ValidationError( - # { - # "Error!": ["This facility is already available in DHIS2. Please ensure details are correct"] - # } - # ) + + if len(r.json()["organisationUnits"]) is 1 and "id" in r.json()["organisationUnits"][0]: return [r.json()["organisationUnits"][0]["id"], 'retrieved'] else: r_generate_orgunit_uid = requests.get( @@ -151,6 +146,7 @@ def get_org_unit_id(self, code): "Accept": "application/json" }, ) + # print("New OrgUnit UID Generated-", r_generate_orgunit_uid.json()['codes'][0]) return [r_generate_orgunit_uid.json()['codes'][0], 'generated'] # raise ValidationError( @@ -161,7 +157,9 @@ def get_org_unit_id(self, code): # ) def get_parent_id(self, ward_id): + # 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), @@ -182,13 +180,14 @@ def get_parent_id(self, ward_id): if dhis2_facility[0]["id"] is None: raise ValidationError( { - "Error!": ["Unable to resolve exact parent of the new facility in DHIS2"] + "Error!": ["Unable to resolve exact parent of the facility in DHIS2"] } ) else: return dhis2_facility[0]["id"] - def push_facility_to_dhis2(self, new_facility_payload, new_facility=True): + def push_facility_to_dhis2(self, new_facility_payload, new_facility): + if new_facility: r = requests.post( settings.DHIS_ENDPOINT+"api/organisationUnits", @@ -200,10 +199,23 @@ def push_facility_to_dhis2(self, new_facility_payload, new_facility=True): }, json=new_facility_payload ) - LOGGER.info("Create Facility Response: %s" % r.text) + + if r.json()["status"] != "OK": + + raise ValidationError( + { + "Error!": [ + "An error occured while creating the facility in KHIS Aggregate. This is may be caused by the " + "existance of an organisation unit with as similar name as to the one you are creating. KHIS Error: {}".format(r.text) + ] + } + ) else: + # LOGGER.error("new_facility_payload:{}".format(new_facility_payload['id'])) + # raise ValueError("new_facility_payload:{}".format(new_facility_payload)) + facility = requests.get( - settings.DHIS_ENDPOINT + "api/organisationUnits/" + new_facility_payload.pop('id'), + settings.DHIS_ENDPOINT + "api/organisationUnits/" + new_facility_payload['id'], auth=(settings.DHIS_USERNAME, settings.DHIS_PASSWORD), headers={ "Accept": "application/json" @@ -212,25 +224,25 @@ def push_facility_to_dhis2(self, new_facility_payload, new_facility=True): ) - if facility.json()['id'] == new_facility_payload.pop('id'): + if facility.json()['id'] == new_facility_payload['id']: r = requests.put( - settings.DHIS_ENDPOINT + "api/organisationUnits/" + new_facility_payload.pop('id'), + settings.DHIS_ENDPOINT + "api/organisationUnits/" + new_facility_payload['id'], auth=(settings.DHIS_USERNAME, settings.DHIS_PASSWORD), headers={ "Accept": "application/json" }, json=new_facility_payload ) - LOGGER.info("Update Facility Response: %s" % r.text) - if r.json()["status"] != "OK": - LOGGER.error('Facility feedback: %s' % r.text) - raise ValidationError( - { - "Error!": ["An error occured while pushing facility to DHIS2. This is may be caused by the " - "existance of an organisation unit with as similar name as to the one you are creating. " - "Or some specific information like codes are not unique"] - } - ) + + + if r.json()["status"] != "OK": + + raise ValidationError( + { + "Error!": ["An error occured while updating this facility in KHIS Aggregate. KHIS Error {}".format(r.text)] + } + ) + def push_facility_metadata(self, metadata_payload, facility_uid): # Keph Level @@ -278,7 +290,9 @@ def push_facility_metadata(self, metadata_payload, facility_uid): def push_facility_updates_to_dhis2(self, org_unit_id, facility_updates_payload): r = requests.put( - settings.DHIS_ENDPOINT + "api/organisationUnits/"+org_unit_id[0], + + settings.DHIS_ENDPOINT + "api/organisationUnits/" + org_unit_id, + auth=(settings.DHIS_USERNAME, settings.DHIS_PASSWORD), headers={ "Accept": "application/json" @@ -286,24 +300,29 @@ def push_facility_updates_to_dhis2(self, org_unit_id, facility_updates_payload): json=facility_updates_payload ) - print("Update Facility Response", r.url, r.status_code, r.json()) - LOGGER.info('[>>>>>>>>>>>>>] Org_unit_id: {} \n payload: {} \n response: {}'.format(org_unit_id, facility_updates_payload, r.json())) + + # print("Update Facility Response", r.url, r.status_code, r.json()) + # LOGGER.info('[DEBUG]: parent_id: {} \n [DEBUG]: payload: {} \n [DEBUG]: response: {}'.format(org_unit_id, facility_updates_payload, r.json())) if r.json()["status"] != "OK": - r = requests.post( - settings.DHIS_ENDPOINT + "api/organisationUnits/", - auth=(settings.DHIS_USERNAME, settings.DHIS_PASSWORD), - headers={ - "Accept": "application/json" - }, - json=facility_updates_payload - ) - # raise ValidationError( - # { - # "Error!": ["Unable to push facility updates to DHIS2"] - # } - # ) + # r = requests.post( + # settings.DHIS_ENDPOINT + "api/organisationUnits/", + # auth=(settings.DHIS_USERNAME, settings.DHIS_PASSWORD), + # headers={ + # "Accept": "application/json" + # }, + # json=facility_updates_payload + # ) + + raise ValidationError( + { + "Error!": ["Unable to push facility updates to KHIS. Created a new facility {}".format(r)] + } + ) + else: + return r.json() + def format_coordinates(self, str_coordinates): coordinates_str_list = str_coordinates.split(" ") @@ -700,7 +719,7 @@ def _ensure_a_user_is_linked_to_just_one_regulator(self): else: msg = "The user {0} was successfully linked to the regulator {1}"\ "".format(self.user.id, self.regulatory_body.id) - LOGGER.info(msg) + LOGGER.info("[DEBUG]: {}".format(msg)) def make_user_national_user(self): self.user.is_national = True @@ -1029,7 +1048,7 @@ class FacilityExportExcelMaterialView(models.Model): long = models.CharField(max_length=30, null=True, blank=True) lat = models.CharField(max_length=30, null=True, blank=True) approved_national_level = models.BooleanField(default=False) - + class Meta(object): managed = False ordering = ('-created', ) @@ -1109,6 +1128,7 @@ class Facility(SequenceMixin, AbstractBase): default=0, help_text="The number of maternity theatres " " that a facility has e.g 0") + number_of_minor_theatres = models.PositiveIntegerField( default=0, help_text="The number of minor theatres " @@ -1118,7 +1138,9 @@ class Facility(SequenceMixin, AbstractBase): help_text="The number of eye theatres " " that a facility has e.g 0") new_born_unit = models.BooleanField(default=False) + out_reach_services = models.BooleanField(default=False) + open_whole_day = models.BooleanField( default=False, help_text="Does the facility operate 24 hours a day") @@ -1270,6 +1292,7 @@ class Facility(SequenceMixin, AbstractBase): dhis2_api_auth = DhisAuth() def push_new_facility(self, code=None): + # If is approved national level and operational status is opertaional and is reporting to dhis and SETTINGS.PUSH_TO_DHIS is True; then push faciliti DHIS if self.approved_national_level and str(self.operation_status.id) == 'ae75777e-5ce3-4ac9-a17e-63823c34b55e' \ and self.reporting_in_dhis is True and settings.PUSH_TO_DHIS: from mfl_gis.models import FacilityCoordinates @@ -1282,7 +1305,9 @@ def push_new_facility(self, code=None): "20b86171-0c16-47e1-9277-5e773d485c33": "YQK9pleIoeB", "5eb392ac-d10a-40c9-b525-53dac866ef6c": "lTrpyOiOcM6", "8949eeb0-40b1-43d4-a38d-5d4933dc209f": "lTrpyOiOcM6", + "0b7f9699-6024-4813-8801-38f188c834f5": "lTrpyOiOcM6", + "ccc1600e-9a24-499f-889f-bd9f0bdc4b95": "YQK9pleIoeB", "d8d741b1-21c5-45c8-86d0-a2094bf9bda6": "YQK9pleIoeB", "85f2099b-a2f8-49f4-9798-0cb48c0875ff": "YQK9pleIoeB", @@ -1308,8 +1333,10 @@ def push_new_facility(self, code=None): "87626d3d-fd19-49d9-98da-daca4afe85bf": "mVrepdLAqSD", "79158397-0d87-4d0e-8694-ad680a907a79": "YQK9pleIoeB", "031293d9-fd8a-4682-a91e-a4390d57b0cf": "YQK9pleIoeB", + "4369eec8-0416-4e16-b013-e635ce46a02f": "YQK9pleIoeB", "9ad22615-48f2-47b3-8241-4355bb7db835" : "rhKJPLo27x7", + } kmhfl_dhis2_ownership_mapping = { "d45541f8-3b3d-475b-94f4-17741d468135": "aRxa6o8GqZN", @@ -1335,6 +1362,7 @@ def push_new_facility(self, code=None): "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", @@ -1347,6 +1375,7 @@ def push_new_facility(self, code=None): facility_code = str(code) else: facility_code = str(self.code) + new_facility_payload = { "id": dhis2_org_unit_id[0], "code": facility_code, @@ -1361,12 +1390,21 @@ def push_new_facility(self, code=None): re.search(r'\((.*?)\)', str(FacilityCoordinates.objects.values('coordinates') .get(facility_id=self.id)['coordinates'])).group(1)) } + metadata_payload = { "facility_type": kmhfl_dhis2_facility_type_mapping[str(self.facility_type_id)], "keph": kmhfl_dhis2_keph_mapping[str(self.keph_level_id)], "ownership": kmhfl_dhis2_ownership_mapping[str(self.owner_id)] } + new_facility = True + + + # LOGGER.error("[DEBUG] dhis2_org_unit_id[1]{}:".format(dhis2_org_unit_id[1])) + + # raise ValueError("[DEBUG] dhis2_org_unit_id[1]{}:".format(dhis2_org_unit_id[1])) + + if dhis2_org_unit_id[1] == 'retrieved': new_facility = False self.dhis2_api_auth.push_facility_to_dhis2(new_facility_payload, new_facility) @@ -1376,7 +1414,6 @@ def push_new_facility(self, code=None): else: pass - def validate_facility_name(self): if self.pk: @@ -1577,6 +1614,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, @@ -1599,7 +1637,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, @@ -1658,6 +1698,7 @@ def get_facility_specialities(self): # for h_r in hr # ] + @property def average_rating(self): avg_service_rating = [ @@ -1825,7 +1866,7 @@ def _dump_updates(self, origi_model): return json.dumps(data) else: message = "The facility was not scheduled for update" - LOGGER.info(message) + LOGGER.info("[DEBUG]: {}".format(message)) def index_facility_material_view(self): """ @@ -2101,16 +2142,19 @@ 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': + print('field_name error', field_changed.get('display_value')) + value = SubCounty.objects.get(id=field_changed.get('actual_value')).id else: value = field_changed.get("actual_value") setattr(self.facility, field_name, value) self.facility.save(allow_save=True) - #if self.facility.code and self.facility.is_complete and self.facility.approved_national_level: - # self.facility.push_new_facility(self.facility.code) - self.push_facility_updates() + + if self.facility.code and self.facility.is_complete and self.facility.approved_national_level: + #self.facility.push_new_facility(self.facility.code) + self.push_facility_updates() def update_facility_services(self): @@ -2237,6 +2281,7 @@ def validate_only_one_update_at_a_time(self): raise ValidationError(error) def push_facility_updates(self): + # Don't push facility updates to KHIS if facility not validated , approved nationally and reporting to KHIS if self.facility.is_approved and self.facility.approved_national_level and self.facility.reporting_in_dhis: from mfl_gis.models import FacilityCoordinates @@ -2245,14 +2290,18 @@ def push_facility_updates(self): dhis2_parent_id = self.dhis2_api_auth.get_parent_id(self.facility.ward.code) dhis2_org_unit_id = self.dhis2_api_auth.get_org_unit_id(self.facility.code) - + + + coordinates = self.dhis2_api_auth.format_coordinates( re.search(r'\((.*?)\)', str(FacilityCoordinates.objects.values('coordinates') .get(facility_id=self.facility.id)['coordinates'])).group(1)) - LOGGER.error('[>>>>>Info] coordinates: {}, FacilityCoordinatesObj: {}'.format(coordinates, FacilityCoordinates.objects.values('coordinates') - .get(facility_id=self.facility.id)['coordinates'])) + # LOGGER.error('[>>>>>Info] coordinates: {}, FacilityCoordinatesObj: {}'.format(coordinates, FacilityCoordinates.objects.values('coordinates') + # .get(facility_id=self.facility.id)['coordinates'])) + new_facility_updates_payload = { + "id": dhis2_org_unit_id[0], "code": str(self.facility.code), "name": str(self.facility.name), "shortName": str(self.facility.name), @@ -2266,8 +2315,20 @@ def push_facility_updates(self): # print("Names;", "Official Name:", self.facility.official_name, "Name:", self.facility.name) # + + # LOGGER.error("[DEBUG] dhis2_org_unit_id[1]{}:".format(dhis2_org_unit_id[1])) + + # raise ValueError("[DEBUG] dhis2_org_unit_id[1]{}:".format(dhis2_org_unit_id[1])) + print("New Facility Push Payload => ", new_facility_updates_payload) - self.dhis2_api_auth.push_facility_updates_to_dhis2(dhis2_org_unit_id, new_facility_updates_payload) + + # LOGGER.error("[DEBUG] dhis2_org_unit_id[1]{}:".format(dhis2_org_unit_id[1])) + + # raise ValueError("[DEBUG] dhis2_org_unit_id[1]{}:".format(dhis2_org_unit_id[1])) + + new_facility = False if dhis2_org_unit_id[1] == 'retrieved' else True + + self.dhis2_api_auth.push_facility_to_dhis2(new_facility_updates_payload, new_facility) def clean(self, *args, **kwargs): self.validate_only_one_update_at_a_time() @@ -2940,8 +3001,10 @@ class FacilitySpecialist(AbstractBase): Facility, related_name='facility_specialists', on_delete=models.PROTECT) + speciality = models.ForeignKey(Speciality, related_name='speciality', on_delete=models.PROTECT) + count = models.IntegerField( default=0, blank=True, @@ -3060,9 +3123,11 @@ class FacilityInfrastructure(AbstractBase): infrastructure = models.ForeignKey( Infrastructure, + related_name='infrastructure', on_delete=models.PROTECT) + count = models.IntegerField( default=0, blank=True, diff --git a/facilities/utils.py b/facilities/utils.py index 785db043..b2a7b118 100755 --- a/facilities/utils.py +++ b/facilities/utils.py @@ -281,20 +281,22 @@ def _create_contacts(self, data): contacts = data.get('contacts', []) created_contacts = [] - for contact in contacts: - contact_type = ContactType.objects.get(id=contact.get('contact_type')) - contact_dict = { - "contact_type": contact_type, - "contact": contact.get('contact') - } - try: - created_contacts.append(Contact.objects.get(**contact_dict)) - except Contact.DoesNotExist: - 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 + if len(contacts) >= 1: + for contact in contacts: + if 'contact_type' in contact: + contact_type = ContactType.objects.get(id=contact.get('contact_type')) + contact_dict = { + "contact_type": contact_type, + "contact": contact.get('contact') + } + try: + created_contacts.append(Contact.objects.get(**contact_dict)) + except Contact.DoesNotExist: + 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): facility = Facility.objects.get(id=data['facility_id']) diff --git a/facilities/views/facility_dashboard.py b/facilities/views/facility_dashboard.py index 5446c49c..32c604c8 100755 --- a/facilities/views/facility_dashboard.py +++ b/facilities/views/facility_dashboard.py @@ -526,7 +526,7 @@ def get_facilities_kephlevel_count(self, county_name, period_start, period_end): def _get_user_top_level(self): userid = self.request.user.groups.all()[0].id resultobject = {'userlevel': ''} - if userid == 5 or userid == 6 or userid == 7: + if userid == 5 or userid == 6 or userid == 7 or userid == 11: resultobject['userlevel'] = 'national' elif userid == 1 or userid == 12: resultobject['userlevel'] = 'county' diff --git a/facilities/views/facility_views.py b/facilities/views/facility_views.py index 6ee387bd..39211731 100755 --- a/facilities/views/facility_views.py +++ b/facilities/views/facility_views.py @@ -1,4 +1,5 @@ import json +import logging from django.utils import timezone from rest_framework import generics, status @@ -8,6 +9,7 @@ from common.views import AuditableDetailViewMixin from common.utilities import CustomRetrieveUpdateDestroyView + from common.models import ( ContactType, UserConstituency, UserCounty, UserSubCounty ) @@ -94,6 +96,8 @@ ) +LOGGER = logging.getLogger(__name__) + class QuerysetFilterMixin(object): """ Filter that only allows users to list facilities in their county @@ -653,8 +657,9 @@ def populate_officer_incharge_contacts(self, officer_in_charge): Resolves the contact_type_name for the officer_in_charge contacts """ for contact in officer_in_charge['contacts']: + LOGGER.info('contact: {}'.format(contact)) contact['contact_type_name'] = ContactType.objects.get( - id=contact.get('type')).name + id=contact.get('contact_type')).name return officer_in_charge def populate_officer_incharge_job_title(self, officer_in_charge):