Source code for childcount.helpers.chw

#!/usr/bin/env python
# vim: ai ts=4 sts=4 et sw=4 coding=utf-8

"""Helper functions that operate on or
relate to :class:`childcount.models.CHW`
objects.

"""

from datetime import timedelta

from django.utils.translation import ugettext as _

from childcount.indicators import registration
from childcount.indicators import household
from childcount.indicators import family_planning
from childcount.indicators import danger_signs
from childcount.indicators import referral
from childcount.indicators import follow_up
from childcount.indicators import pregnancy
from childcount.indicators import birth
from childcount.indicators import neonatal
from childcount.indicators import under_one
from childcount.indicators import nutrition
from childcount.indicators import fever
from childcount.indicators import medicine_given

from childcount.models import Patient
from childcount.models.reports import PregnancyReport
from childcount.models.reports import FollowUpReport
from childcount.models.reports import ReferralReport
from childcount.models.reports import NutritionReport
from childcount.models.reports import UnderOneReport

[docs]def report_indicators(): return ( { 'title': _("Household"), 'columns': [ {'name': _("Households"), 'ind': registration.Household}, {'name': _("Total HH Visits"), 'ind': household.Total}, {'name': _("% HH Coverage"), 'ind': household.CoveragePerc} ] }, { 'title': _("Family Planning"), 'columns': [ {'name': _("Women 15-49 Seen"), 'ind': family_planning.Women}, {'name': _("Women Using FP"), 'ind': family_planning.Using}, {'name': _("Women Starting FP (or Never Registered)"), 'ind': family_planning.Starting}, ] }, { 'title': _("Follow Up"), 'columns': [ {'name': _("People with DSs"), 'ind': danger_signs.Total}, {'name': _("Cases Urgently Referred OR Treated by CHW"), 'ind': referral.Urgent}, {'name': _("On-Time Follow-Up Visits (between 18 and 72 hours)"), \ 'ind': follow_up.OnTime}, {'name': _("Late Follow-Up Visits (between 72 hours and 7 days)"), \ 'ind': follow_up.Late}, {'name': _("No Follow-Up Visits (never or after 7 days)"), \ 'ind': follow_up.Never}, ] }, { 'title': _("Pregnancy"), 'columns': [ {'name': _("Pregnant Women"), 'ind': pregnancy.Total}, {'name': _("Births"), 'ind': birth.Total}, {'name': _("Births with 4 ANC"), 'ind': birth.WithAncFour}, {'name': _("Babies Known Delivered in Clinic"), \ 'ind': birth.DeliveredInClinic}, {'name': _("Neonatal Reports (within 7 days)"), \ 'ind': neonatal.WithinSevenDaysOfBirth}, ] }, { 'title': _("Under Five"), 'columns': [ {'name': _("Children U5"), 'ind': registration.UnderFive}, {'name': _("Children U5 Known Immunized"),\ 'ind': under_one.UnderFiveImmunizationUpToDate}, {'name': _("MUACs Taken"), 'ind': nutrition.Total}, {'name': _("Active SAM/MAM Cases"), 'ind': nutrition.SamOrMam}, ] }, { 'title': _("Malaria"), 'columns': [ {'name': _("Tested RDTs"), 'ind': fever.Total}, {'name': _("Positive RDTs"), 'ind': fever.RdtPositive}, {'name': _("Anti-malarials Given"), 'ind': medicine_given.Antimalarial}, ] }, { 'title': _("Diarrhea"), 'columns': [ {'name': _("U5 Diarrhea Cases"), 'ind': danger_signs.UnderFiveDiarrhea}, {'name': _("ORS Given"), 'ind': medicine_given.Ors}, ] }, )
"""The common set of :class:`indicator.Indicator` objects used in the CHW reports. """
[docs]def pregnant_needing_anc(period, chw): """Get a list of women assigned to this CHW who are in their 2nd or 3rd trimester of pregnancy who haven't had ANC visits in last 5 five weeks :param period: Time period :type period: An object with :meth:`.start` and :meth:`.end` methods that each return a :class:`datetime.datetime` :param chw: CHW :type chw: :class:`childcount.models.CHW` :returns: list of (:class:`childcount.models.Patient`, last_anc_date, approx_due_date) tuples """ patients = Patient\ .objects\ .filter(chw=chw)\ .pregnant_months(period.start, period.end, 4.0, 9.5,\ False, False) pregs = PregnancyReport\ .objects\ .filter(encounter__encounter_date__gt=\ period.end - timedelta(10 * 30.4375), encounter__encounter_date__lte=\ period.end, encounter__patient__in=patients)\ .order_by('-encounter__encounter_date') seen = [] no_anc = [] women = [] for p in pregs: if p.encounter.patient.pk in seen: continue else: seen.append(p.encounter.patient.pk) days_ago = (period.end - p.encounter.encounter_date).days weeks_ago = days_ago / 7.0 months_ago = weeks_ago / 4.0 preg_month = p.pregnancy_month + months_ago months_left = 9 - preg_month days_left = months_left * 30.475 due_date = period.end + timedelta(days_left) # Current weeks since ANC if p.weeks_since_anc is None: no_anc.append((p.encounter.patient, \ None,\ due_date)) else: weeks_since_anc = p.weeks_since_anc + weeks_ago if weeks_since_anc > 5.0: women.append((p.encounter.patient, \ p.encounter.encounter_date - \ timedelta(7 * p.weeks_since_anc), \ due_date)) women.sort(lambda x,y: cmp(x[1],y[1])) return (no_anc + women)
[docs]def people_without_follow_up(period, chw): """Get a list of people assigned to this CHW who were referred urgently to a clinic who got a late follow-up visit (3-7 days after referral) or no follow-up visit (more than 7 days after referral or never) :param period: Time period :type period: An object with :meth:`.start` and :meth:`.end` methods that each return a :class:`datetime.datetime` :param chw: CHW :type chw: :class:`childcount.models.CHW` :returns: list of :class:`childcount.models.reports.ReferralReport` """ elig = follow_up._eligible(period, chw.patient_set.all()) late = [] never = [] for e in elig: f = FollowUpReport\ .objects\ .filter(encounter__patient__pk=e.encounter.patient.pk, encounter__encounter_date__gt=\ e.encounter.encounter_date+follow_up.DELTA_START_ON_TIME)\ .filter(encounter__encounter_date__lte=\ e.encounter.encounter_date+follow_up.DELTA_START_NEVER) if f.count() == 0: # No follow-up visit at all never.append(e) elif f.filter(encounter__encounter_date__gt=\ e.encounter.encounter_date+follow_up.DELTA_START_LATE).count() > 0: # Follow-up visit was late late.append(e) else: # Follow-up visit was on-time pass return (late, never)
[docs]def kids_needing_muac(period, chw): """Get a list of MUAC-eligible patients assigned to this CHW who have not had a recorded MUAC in the past 90 days (for known healthy children) or the past 30 days (for known malnourished children and children with unknown nutrition status). :param period: Time period :type period: An object with :meth:`.start` and :meth:`.end` methods that each return a :class:`datetime.datetime` :param chw: CHW :type chw: :class:`childcount.models.CHW` :returns: list of (:class:`childcount.models.Patient`, :class:`childcount.models.reports.NutritionReport`) tuples """ # people eligible for MUAC muac_list = Patient\ .objects\ .filter(chw=chw)\ .muac_eligible(period.start, period.end)\ .order_by('encounter__patient__location__code') seen = [] need_muac = [] no_muac = [] one_month_ago = period.end - timedelta(30.4375) three_months_ago = period.end - timedelta(3*30.4375) danger = (NutritionReport.STATUS_SEVERE, \ NutritionReport.STATUS_SEVERE_COMP) for p in muac_list: if p.pk in seen: continue else: seen.append(p.pk) try: nut = NutritionReport\ .objects\ .filter(encounter__patient__pk=p.pk, muac__isnull=False, status__isnull=False)\ .latest('encounter__encounter_date') except NutritionReport.DoesNotExist: no_muac.append((p, None)) continue if nut.status in danger and \ nut.encounter.encounter_date < one_month_ago: need_muac.append((p, nut)) elif nut.encounter.encounter_date < three_months_ago: need_muac.append((p, nut)) else: pass need_muac.sort(lambda x,y:\ cmp(x[1].encounter.encounter_date, \ y[1].encounter.encounter_date)) return no_muac + need_muac
[docs]def kids_needing_immunizations(period, chw): """Get a list of children under five years old assigned to this CHW who are: #. More than 12 months old who have no known immunization record or who were last known to be not fully immunized, or #. Less than 12 months old who have not had an immunization report in the past 90 days. :param period: Time period :type period: An object with :meth:`.start` and :meth:`.end` methods that each return a :class:`datetime.datetime` :param chw: CHW :type chw: :class:`childcount.models.CHW` :returns: :class:`django.db.models.query.QuerySet` of :class:`childcount.models.Patient` """ patients = Patient\ .objects\ .filter(chw=chw) u1imms = UnderOneReport\ .objects\ .encounter_age(0, 365)\ .filter(encounter__patient__in=patients, encounter__encounter_date__gte=period.end-timedelta(days=90), encounter__encounter_date__lte=period.end)\ .latest_for_patient()\ .filter(immunized=UnderOneReport.IMMUNIZED_YES) u5imms = UnderOneReport\ .objects\ .encounter_age(366, 5*365.25)\ .filter(encounter__patient__in=patients, encounter__encounter_date__lte=period.end)\ .latest_for_patient()\ .filter(immunized=UnderOneReport.IMMUNIZED_YES) imms = (u1imms|u5imms) pks = [i[0] for i in imms.values_list('encounter__patient__pk')] print pks return patients\ .under_five(period.start, period.end)\ .exclude(pk__in=pks)\ .order_by('location__code')