def update_historical_data(domain, locations=None): """ If we don't have a record of this supply point being updated, run through all historical data and just fill in with zeros. """ org_summaries = OrganizationSummary.objects.order_by('date') if org_summaries.count() == 0: return start_date = org_summaries[0].date if locations is None: if not ILSGatewayConfig.for_domain(domain).all_stock_data: locations = _get_test_locations(domain) else: locations = Location.by_domain(domain) for sp in locations: try: SupplyPointWarehouseRecord.objects.get(supply_point=sp._id) except SupplyPointWarehouseRecord.DoesNotExist: # we didn't have a record so go through and historically update # anything we maybe haven't touched for year, month in months_between(start_date, sp.sql_location.created_at): window_date = datetime(year, month, 1) for cls in [OrganizationSummary, ProductAvailabilityData, GroupSummary]: _init_warehouse_model(cls, sp, window_date) SupplyPointWarehouseRecord.objects.create(supply_point=sp._id, create_date=datetime.utcnow())
def update_historical_data_for_location(loc): """ Fill with zeros data for all months between default start date and date of earliest location's summary. E.g. Location is created at 2016-02-10 and earliest summary is from 2016-03-01 whereas default start date is equal to 2012-01-01, so we need to generate data for all months between 2012-01-01 and 2016-03-01. This function is important for all locations created after initial run of report runner. """ start_date = default_start_date() try: earliest_org_summary = OrganizationSummary.objects.filter( location_id=loc.location_id).earliest('date') earliest_org_summary_date = earliest_org_summary.date except OrganizationSummary.DoesNotExist: earliest_org_summary_date = loc.created_at if start_date >= earliest_org_summary_date: return for year, month in months_between(start_date, earliest_org_summary_date): window_date = datetime(year, month, 1) for cls in [ OrganizationSummary, ProductAvailabilityData, GroupSummary ]: _init_warehouse_model(cls, loc, window_date)
def update_historical_data(domain, locations=None): """ If we don't have a record of this supply point being updated, run through all historical data and just fill in with zeros. """ org_summaries = OrganizationSummary.objects.order_by('date') if org_summaries.count() == 0: return start_date = org_summaries[0].date if locations is None: if not ILSGatewayConfig.for_domain(domain).all_stock_data: locations = _get_test_locations(domain) else: locations = Location.by_domain(domain) for sp in locations: try: SupplyPointWarehouseRecord.objects.get(supply_point=sp._id) except SupplyPointWarehouseRecord.DoesNotExist: # we didn't have a record so go through and historically update # anything we maybe haven't touched for year, month in months_between(start_date, sp.sql_location.created_at): window_date = datetime(year, month, 1) for cls in [ OrganizationSummary, ProductAvailabilityData, GroupSummary ]: _init_warehouse_model(cls, sp, window_date) SupplyPointWarehouseRecord.objects.create( supply_point=sp._id, create_date=datetime.utcnow())
def child_age(self): if self.status == 'mother': non_adjusted_month = len(months_between(self.dod, self.reporting_window_start)) - 1 # anchor date should be their one month birthday anchor_date = add_months_to_date(self.dod, 1) month = self._adjust_for_vhnd_presence(non_adjusted_month, anchor_date) if month < 1: self.case_is_out_of_range = True return month
def child_age(self): if self.status == 'mother': non_adjusted_month = len(months_between(self.dod, self.reporting_window_start)) - 1 # anchor date should be their one month birthday anchor_date = add_months_to_date(self.dod, 1) month = self._adjust_for_vhnd_presence(non_adjusted_month, anchor_date) if month < 1: raise InvalidRow('child month %s not valid' % month) return month
def _get_keys(startdate, enddate, clinic_id): # assumes the start date is set to the first the end date to the last of the month # if there's no clinic specified just use the whole range if not clinic_id: startkey = [startdate.year, startdate.month - 1] endkey = [enddate.year, enddate.month - 1, {}] return [{"startkey": startkey, "endkey": endkey}] else: # otherwise only include results for this clinic return [{"startkey": [year, month - 1, clinic_id], "endkey": [year, month -1, clinic_id, {}]} \ for year, month in months_between(startdate, enddate)]
def preg_month(self): if self.status == 'pregnant': base_window_start = add_months_to_date(self.edd, -9) non_adjusted_month = len(months_between(base_window_start, self.reporting_window_start)) - 1 # the date to check one month after they first become eligible, # aka the end of their fourth month of pregnancy vhnd_date_to_check = add_months_to_date(self.preg_first_eligible_date, 1) month = self._adjust_for_vhnd_presence(non_adjusted_month, vhnd_date_to_check) if month < 4 or month > 9: raise InvalidRow('pregnancy month %s not valid' % month) return month
def get_first_days(self, current_month, num_previous_months, as_datespans=False): enddate = current_month or datetime.datetime.utcnow() enddate = self.get_first_day_of_month(enddate.year, enddate.month) (start_year, start_month) = add_months(enddate.year, enddate.month, -num_previous_months) startdate = self.get_last_day_of_month(start_year, start_month) months = months_between(startdate, enddate) month_dates = list() for year, month in months: if as_datespans: month_dates.append(self.get_month_datespan((year, month))) else: month_dates.append(self.get_first_day_of_month(year, month)) datespan = self.get_month_datespan((startdate.year, startdate.month), (enddate.year, enddate.month)) return month_dates, datespan
def preg_month(self): if self.status == 'pregnant': if not self.edd: raise InvalidRow('No edd found for pregnant mother.') base_window_start = add_months_to_date(self.edd, -9) try: non_adjusted_month = len(months_between(base_window_start, self.reporting_window_start)) - 1 except AssertionError: self.case_is_out_of_range = True non_adjusted_month = 0 # the date to check one month after they first become eligible, # aka the end of their fourth month of pregnancy vhnd_date_to_check = add_months_to_date(self.preg_first_eligible_date, 1) month = self._adjust_for_vhnd_presence(non_adjusted_month, vhnd_date_to_check) if month < 4 or month > 9: self.case_is_out_of_range = True return month
def get_first_days(self, current_month, num_previous_months, as_datespans=False): enddate = current_month or datetime.datetime.utcnow() enddate = self.get_first_day_of_month(enddate.year, enddate.month) (start_year, start_month) = add_months(enddate.year, enddate.month, -num_previous_months) startdate = self.get_last_day_of_month(start_year, start_month) months = months_between(startdate, enddate) month_dates = list() for year, month in months: if as_datespans: month_dates.append(self.get_month_datespan((year, month))) else: month_dates.append(self.get_first_day_of_month(year, month)) datespan = self.get_month_datespan( (startdate.year, startdate.month), (enddate.year, enddate.month) ) return month_dates, datespan
def update_historical_data_for_location(loc): """ Fill with zeros data for all months between default start date and date of earliest location's summary. E.g. Location is created at 2016-02-10 and earliest summary is from 2016-03-01 whereas default start date is equal to 2012-01-01, so we need to generate data for all months between 2012-01-01 and 2016-03-01. This function is important for all locations created after initial run of report runner. """ start_date = default_start_date() try: earliest_org_summary = OrganizationSummary.objects.filter(location_id=loc.location_id).earliest('date') earliest_org_summary_date = earliest_org_summary.date except OrganizationSummary.DoesNotExist: earliest_org_summary_date = loc.sql_location.created_at if start_date >= earliest_org_summary_date: return for year, month in months_between(start_date, earliest_org_summary_date): window_date = datetime(year, month, 1) for cls in [OrganizationSummary, ProductAvailabilityData, GroupSummary]: _init_warehouse_model(cls, loc, window_date)
class ConditionsMet(object): method_map = { "atri": [('name', "List of Beneficiary", True), ('awc_name', "AWC Name", True), ('husband_name', "Husband Name", True), ('month', "Month", True), ('window', "Window", True), ('one', "1", True), ('two', "2", True), ('three', "3", True), ('four', "4", True), ('five', "5", True), ('cash', "Cash to be transferred", True), ('owner_id', "Owner Id", False), ('block_name', "Block Name", False), ('closed', 'Closed', False)], 'wazirganj': [('name', "List of Beneficiary", True), ('awc_name', "AWC Name", True), ('status', "Current status", True), ('month', "Month", True), ('window', "Window", True), ('one', "1", True), ('two', "2", True), ('four', "3", True), ('five', "4", True), ('cash', "Cash to be transferred", True), ('owner_id', "Owner Id", False), ('block_name', "Block Name", False), ('closed', 'Closed', False)] } def __init__(self, case, report): if report.snapshot is not None: report.filter( lambda key: case['_source'][key], # case.awc_name, case.block_name [('awc_name', 'awcs'), ('block_name', 'block'), ('owner_id', 'gp'), ('closed', 'is_open')], ) img_elem = '<div style="width:100px !important;"><img src="/static/opm/img/%s"></div>' met = { 'window_1_1': None, 'window_1_2': None, 'window_2_1': None, 'window_2_2': None, 'attendance_vhnd_3': None, 'attendance_vhnd_6': None, 'child1_vhndattend_calc': None, 'prev_child1_vhndattend_calc': None, 'child1_attendance_vhnd': None, 'weight_tri_1': None, 'prev_weight_tri_1': None, 'weight_tri_2': None, 'prev_weight_tri_2': None, 'child1_growthmon_calc': None, 'prev_child1_growthmon_calc': None, 'child1_excl_breastfeed_calc': None, 'prev_child1_excl_breastfeed_calc': None, 'child1_ors_calc': None, 'prev_child1_ors_calc': None, 'child1_weight_calc': None, 'child1_register_calc': None, 'child1_measles_calc': None, 'prev_child1_weight_calc': None, 'prev_child1_register_calc': None, 'prev_child1_measles_calc': None, 'child1_suffer_diarrhea': None, 'interpret_grade_1': None } def get_property(obj, name, default=None): if name in obj: if type(obj[name]) is dict: return obj[name] return obj[name] else: return default if default is not None else EMPTY_FIELD def get_property_from_forms(forms, met_properties): for form in forms: for k, v in met_properties.iteritems(): if k == 'child1_suffer_diarrhea': if 'child_1' in form.form and k in form.form['child_1']: met_properties[k] = form.form['child_1'][k] else: if k in form.form: met_properties[k] = form.form[k] return met_properties case_obj = CommCareCase.get(case['_source']['_id']) self.block_name = get_property(case_obj, 'block_name', '') self.owner_id = get_property(case_obj, 'owner_id', '') self.closed = get_property(case_obj, 'closed', False) forms = case_obj.get_forms() birth_spacing_prompt = [] for form in forms: if 'birth_spacing_prompt' in form.form: birth_spacing_prompt.append(form.form['birth_spacing_prompt']) filtered_forms = [ form for form in case_obj.get_forms() if report.datespan.startdate <= form.received_on <= report.datespan.enddate ] get_property_from_forms(filtered_forms, met) dod = get_property(case_obj, 'dod') if dod and dod != EMPTY_FIELD: try: child_age = len( months_between( datetime.datetime(dod.year, dod.month, dod.day), datetime.datetime.now())) except AssertionError: child_age = -1 else: child_age = -1 if get_property(case_obj, 'mother_preg_outcome', '') == '1': self.status = 'mother' elif get_property(case_obj, 'mother_preg_outcome', '') == '': self.status = 'pregnant' else: raise InvalidRow met_one = False met_two = False met_three = False met_four = False met_five = False preg_month = get_property(case_obj, 'pregnancy_month', 0) or 0 if self.status == 'pregnant': if '1' in [ met['window_1_1'], met['window_1_2'], met['window_2_1'], met['window_2_2'], met['attendance_vhnd_3'], met['attendance_vhnd_6'] ]: met_one = True if (preg_month == '6' and '1' in [ met['weight_tri_1'], met['prev_weight_tri_1'] ]) or (preg_month == '9' and '1' in [met['weight_tri_2'], met['prev_weight_tri_2']]): met_two = True elif self.status == 'mother': if '1' in [ met['child1_vhndattend_calc'], met['prev_child1_vhndattend_calc'], met['child1_attendance_vhnd'] ]: met_one = True if '1' in [ met['child1_growthmon_calc'], met['prev_child1_growthmon_calc'] ]: met_two = True if (child_age == 3 and (met['child1_weight_calc'] or met['prev_child1_weight_calc'])) or \ (child_age == 6 and (met['child1_register_calc'] or met['prev_child1_register_calc'])) or \ (child_age == 9 and (met['child1_measles_calc'] or met['prev_child1_measles_calc'])): met_three = True if child_age == 6 and ('1' in [ met['child1_excl_breastfeed_calc'], met['prev_child1_excl_breastfeed_calc'] ]): met_four = True if child_age in [6, 9, 12] and '1' in [ met['child1_ors_calc'], met['prev_child1_ors_calc'] ]: met_five = True self.name = get_property(case_obj, 'name') self.awc_name = get_property(case_obj, 'awc_name') self.husband_name = get_property(case_obj, 'husband_name') self.window = get_property(case_obj, 'which_window') if self.status == 'pregnant': self.month = get_property(case_obj, 'pregnancy_month') self.one = img_elem % M_ATTENDANCE_Y if preg_month == '9' else img_elem % M_ATTENDANCE_N self.two = img_elem % M_WEIGHT_Y if preg_month in [ '6', '9' ] else img_elem % M_WEIGHT_N self.three = img_elem % IFA_Y if int( preg_month) < 7 else img_elem % IFA_N self.four = '' if report.block.lower() == 'wazirganj': if child_age > 23 and '1' in birth_spacing_prompt: self.five = img_elem % SPACING_PROMPT_Y else: self.five = img_elem % SPACING_PROMPT_N else: self.five = '' elif self.status == 'mother': if child_age != -1: self.month = child_age else: self.month = EMPTY_FIELD self.one = img_elem % C_ATTENDANCE_Y if 0 <= child_age <= 1 else img_elem % C_ATTENDANCE_N self.two = img_elem % C_WEIGHT_Y if child_age % 3 == 0 else img_elem % C_WEIGHT_N if child_age == 3: if met['child1_weight_calc'] or met['prev_child1_weight_calc']: self.three = img_elem % CHILD_WEIGHT_Y else: self.three = img_elem % CHILD_WEIGHT_N elif child_age == 6: if met['child1_register_calc'] or met[ 'prev_child1_register_calc']: self.three = img_elem % C_REGISTER_Y else: self.three = img_elem % C_REGISTER_N elif child_age == 9: if met['child1_measles_calc'] or met[ 'prev_child1_measles_calc']: self.three = img_elem % MEASLEVACC_Y else: self.three = img_elem % MEASLEVACC_N else: self.three = '' self.four = img_elem % EXCBREASTFED_Y if child_age == 6 else img_elem % EXCBREASTFED_N if child_age in [3, 6, 9]: if met['child1_suffer_diarrhea'] == '1': self.five = img_elem % ORSZNTREAT_Y else: self.five = img_elem % ORSZNTREAT_N elif child_age == [24, 36]: if met['interpret_grade_1'] == 'normal': self.five = img_elem % GRADE_NORMAL_Y else: self.five = img_elem % GRADE_NORMAL_N else: self.five = '' if report.block.lower() == 'atri': if child_age == 24: self.cash = '<span style="color: green;">Rs. 2000</span>' elif child_age == 36: self.cash = '<span style="color: green;">Rs. 3000</span>' elif met_one or met_two or met_three or met_four or met_five: self.cash = '<span style="color: green;">Rs. 250</span>' else: self.cash = '<span style="color: red;">Rs. 0</span>' elif report.block.lower() == 'wazirganj': if met_one or met_two or met_four or met_five: self.cash = '<span style="color: green;">Rs. 250</span>' else: self.cash = '<span style="color: red;">Rs. 0</span>'
def process_non_facility_warehouse_data(org, start_date, end_date, strict=True): facs = get_nested_children(org) fac_ids = [f._id for f in facs] logging.info("processing non-facility %s (%s), %s children" % (org.name, str(org._id), len(facs))) for year, month in months_between(start_date, end_date): window_date = datetime(year, month, 1) org_summary = OrganizationSummary.objects.get_or_create(supply_point=org._id, date=window_date)[0] org_summary.total_orgs = len(facs) sub_summaries = OrganizationSummary.objects.filter(date=window_date, supply_point__in=fac_ids) subs_with_lead_time = [s for s in sub_summaries if s.average_lead_time_in_days] # lead times if subs_with_lead_time: days_sum = sum([s.average_lead_time_in_days for s in subs_with_lead_time]) org_summary.average_lead_time_in_days = days_sum / len(subs_with_lead_time) else: org_summary.average_lead_time_in_days = 0 org_summary.save() # product availability prods = Product.ids_by_domain(org.domain) for p in prods: product_data = ProductAvailabilityData.objects.get_or_create(product=p, supply_point=org._id, date=window_date)[0] sub_prods = ProductAvailabilityData.objects.filter(product=p, supply_point__in=fac_ids, date=window_date) product_data.total = sum([p.total for p in sub_prods]) if strict: assert product_data.total == len(facs), \ "total should match number of sub facilities" product_data.with_stock = sum([p.with_stock for p in sub_prods]) product_data.without_stock = sum([p.without_stock for p in sub_prods]) product_data.without_data = product_data.total - product_data.with_stock - product_data.without_stock product_data.save() dg = DeliveryGroups(month=month, facs=facs) for type in NEEDED_STATUS_TYPES: gsum = GroupSummary.objects.get_or_create(org_summary=org_summary, title=type)[0] sub_sums = GroupSummary.objects.filter(title=type, org_summary__in=sub_summaries).all() # TODO: see if moving the aggregation to the db makes it # faster, if this is slow gsum.total = sum([s.total for s in sub_sums]) gsum.responded = sum([s.responded for s in sub_sums]) gsum.on_time = sum([s.on_time for s in sub_sums]) gsum.complete = sum([s.complete for s in sub_sums]) # gsum.missed_response = sum([s.missed_response for s in sub_sums]) gsum.save() if type == SupplyPointStatusTypes.DELIVERY_FACILITY: expected = len(dg.delivering()) elif type == SupplyPointStatusTypes.R_AND_R_FACILITY: expected = len(dg.submitting()) elif type == SupplyPointStatusTypes.SOH_FACILITY \ or type == SupplyPointStatusTypes.SUPERVISION_FACILITY: expected = len(facs) if gsum.total != expected: logging.info("expected %s but was %s for %s" % (expected, gsum.total, gsum)) for alert_type in ['rr_not_submitted', 'delivery_not_received', 'soh_not_responding', 'rr_not_responded', 'delivery_not_responding']: sub_alerts = Alert.objects.filter(supply_point__in=fac_ids, date=window_date, type=alert_type) aggregate_response_alerts(org, window_date, sub_alerts, alert_type)
def process_facility_warehouse_data(fac, start_date, end_date): """ process all the facility-level warehouse tables """ logging.info("processing facility %s (%s)" % (fac.name, str(fac._id))) for alert_type in ['soh_not_responding', 'rr_not_responded', 'delivery_not_responding']: alert = Alert.objects.filter(supply_point=fac._id, date__gte=start_date, date__lt=end_date, type=alert_type) alert.delete() supply_point_id = fac.linked_supply_point()._id new_statuses = SupplyPointStatus.objects.filter( supply_point=fac._id, status_date__gte=start_date, status_date__lt=end_date ).order_by('status_date') process_facility_statuses(fac, new_statuses) new_reports = StockReport.objects.filter( stocktransaction__case_id=supply_point_id, date__gte=start_date, date__lt=end_date, stocktransaction__type='stockonhand' ).order_by('date') process_facility_product_reports(fac, new_reports) new_trans = StockTransaction.objects.filter( case_id=supply_point_id, report__date__gte=start_date, report__date__lt=end_date ).order_by('report__date') process_facility_transactions(fac, new_trans) # go through all the possible values in the date ranges # and make sure there are warehouse tables there for year, month in months_between(start_date, end_date): window_date = datetime(year, month, 1) # create org_summary for every fac/date combo org_summary, created = OrganizationSummary.objects.get_or_create(supply_point=fac._id, date=window_date) org_summary.total_orgs = 1 alt = average_lead_time(fac, window_date) if alt: alt = alt.days org_summary.average_lead_time_in_days = alt or 0 org_summary.save() # create group_summary for every org_summary title combo for title in NEEDED_STATUS_TYPES: group_summary, created = GroupSummary.objects.get_or_create(org_summary=org_summary, title=title) # update all the non-response data not_responding_facility(org_summary) # update product availability data update_product_availability_facility_data(org_summary) # alerts populate_no_primary_alerts(fac, window_date) populate_facility_stockout_alerts(fac, window_date)
def update_product_availability_facility_data(facility, products, start_date, end_date): # product availability existing_data = ProductAvailabilityData.objects.filter( date__range=(datetime(start_date.year, start_date.month, 1), datetime(end_date.year, end_date.month, 1)), location_id=facility.get_id) product_data_dict = {(pa.date, pa.location_id, pa.product): pa for pa in existing_data} product_data_list = [] previous_month = {} for year, month in months_between(start_date, end_date): window_date = datetime(year, month, 1) for p in products: now = datetime.utcnow() if (window_date, facility.get_id, p.product_id) in product_data_dict: previous_month[p.product_id] = product_data_dict[ window_date, facility.get_id, p.product_id] continue else: product_data = ProductAvailabilityData( date=window_date, location_id=facility.get_id, product=p.product_id, create_date=now, update_date=now) # set defaults product_data.total = 1 prev = None if p.product_id in previous_month: prev = previous_month[p.product_id] if not prev: previous_reports = ProductAvailabilityData.objects.filter( product=p.product_id, location_id=facility.location_id, date__lt=window_date, total=1) if previous_reports.count(): prev = previous_reports.latest('date') if prev: product_data.with_stock = prev.with_stock product_data.without_stock = prev.without_stock product_data.without_data = prev.without_data else: # otherwise we use the defaults product_data.with_stock = 0 product_data.without_stock = 0 product_data.without_data = 1 if product_data.pk is not None: product_data.save() else: product_data_list.append(product_data) assert (product_data.with_stock + product_data.without_stock + product_data.without_data) == 1, \ "bad product data config for %s" % product_data previous_month[p.product_id] = product_data ProductAvailabilityData.objects.bulk_create(product_data_list)
def process_facility_warehouse_data(facility, start_date, end_date, runner): """ process all the facility-level warehouse tables """ logging.info("processing facility %s (%s)" % (facility.name, str(facility._id))) try: runner.location = facility.sql_location runner.save() except SQLLocation.DoesNotExist: # TODO Temporary fix facility.delete() return for alert_type in [ const.SOH_NOT_RESPONDING, const.RR_NOT_RESPONDED, const.DELIVERY_NOT_RESPONDING ]: alert = Alert.objects.filter(location_id=facility._id, date__gte=start_date, date__lt=end_date, type=alert_type) alert.delete() supply_point_id = facility.linked_supply_point()._id location_id = facility._id new_statuses = SupplyPointStatus.objects.filter( location_id=facility._id, status_date__gte=start_date, status_date__lt=end_date).order_by('status_date').iterator() process_facility_statuses(location_id, new_statuses) new_reports = StockReport.objects.filter( stocktransaction__case_id=supply_point_id, date__gte=start_date, date__lt=end_date, stocktransaction__type='stockonhand').order_by('date').iterator() process_facility_product_reports(location_id, new_reports) new_trans = StockTransaction.objects.filter( case_id=supply_point_id, report__date__gte=start_date, report__date__lt=end_date, ).exclude(type='consumption').order_by('report__date').iterator() process_facility_transactions(location_id, new_trans) # go through all the possible values in the date ranges # and make sure there are warehouse tables there for year, month in months_between(start_date, end_date): window_date = datetime(year, month, 1) # create org_summary for every fac/date combo org_summary, created = OrganizationSummary.objects.get_or_create( location_id=facility._id, date=window_date) org_summary.total_orgs = 1 alt = average_lead_time(facility._id, window_date) if alt: alt = alt.days org_summary.average_lead_time_in_days = alt or 0 org_summary.save() # create group_summary for every org_summary title combo for title in const.NEEDED_STATUS_TYPES: GroupSummary.objects.get_or_create(org_summary=org_summary, title=title) # update all the non-response data not_responding_facility(org_summary) # update product availability data update_product_availability_facility_data(org_summary) # alerts with transaction.atomic(): populate_no_primary_alerts(facility, window_date) populate_facility_stockout_alerts(facility, window_date)
def process_non_facility_warehouse_data(location, start_date, end_date, runner=None, strict=True): facs = get_non_archived_facilities_below(location, end_date) start_date = datetime(start_date.year, start_date.month, 1) end_date = datetime(end_date.year, end_date.month, 1) if runner: runner.location = location runner.save() fac_ids = [f.location_id for f in facs] logging.info("processing non-facility %s (%s), %s children" % (location.name, str(location.location_id), len(facs))) prods = SQLProduct.objects.filter(domain=location.domain, is_archived=False) sub_summaries = OrganizationSummary.objects.filter( location_id__in=fac_ids, date__range=(start_date, end_date), average_lead_time_in_days__gt=0).values('date').annotate( average_time=Avg('average_lead_time_in_days')) sub_summaries = {(subsummary['date'].year, subsummary['date'].month): subsummary for subsummary in sub_summaries} sub_prods = ProductAvailabilityData.objects.filter( location_id__in=fac_ids, date__range=(start_date, end_date)).values('product', 'date').annotate( total_sum=Sum('total'), with_stock_sum=Sum('with_stock'), without_stock_sum=Sum('without_stock'), ) sub_prods = {((sub_prod['date'].year, sub_prod['date'].month), sub_prod['product']): sub_prod for sub_prod in sub_prods} sub_group_summaries = GroupSummary.objects.filter( org_summary__location_id__in=fac_ids, org_summary__date__range=(start_date, end_date)).values( 'title', 'org_summary__date').annotate(total_sum=Sum('total'), responded_sum=Sum('responded'), on_time_sum=Sum('on_time'), complete_sum=Sum('complete')) sub_group_summaries = {((sub_group_summary['org_summary__date'].year, sub_group_summary['org_summary__date'].month), sub_group_summary['title']): sub_group_summary for sub_group_summary in sub_group_summaries} total_orgs = len(facs) for year, month in months_between(start_date, end_date): window_date = datetime(year, month, 1) org_summary = OrganizationSummary.objects.get_or_create( location_id=location.location_id, date=window_date)[0] org_summary.total_orgs = total_orgs # lead times if (year, month) in sub_summaries: sub_summary = sub_summaries[year, month] org_summary.average_lead_time_in_days = sub_summary['average_time'] else: org_summary.average_lead_time_in_days = 0 org_summary.save() # product availability for p in prods: product_data = ProductAvailabilityData.objects.get_or_create( product=p.product_id, location_id=location.location_id, date=window_date)[0] sub_prod = sub_prods.get(((year, month), p.product_id), {}) product_data.total = sub_prod.get('total_sum', 0) if strict: assert product_data.total == total_orgs, \ "total should match number of sub facilities %s-%s" % (product_data.total, total_orgs) product_data.with_stock = sub_prod.get('with_stock_sum', 0) product_data.without_stock = sub_prod.get('without_stock_sum', 0) product_data.without_data = product_data.total - product_data.with_stock - product_data.without_stock product_data.save() dg = DeliveryGroups(month=month, facs=facs) for status_type in const.NEEDED_STATUS_TYPES: gsum = GroupSummary.objects.get_or_create(org_summary=org_summary, title=status_type)[0] sub_sum = sub_group_summaries.get(((year, month), status_type), {}) gsum.total = sub_sum.get('total_sum', 0) gsum.responded = sub_sum.get('responded_sum', 0) gsum.on_time = sub_sum.get('on_time_sum', 0) gsum.complete = sub_sum.get('complete_sum', 0) gsum.save() if status_type == SupplyPointStatusTypes.DELIVERY_FACILITY: expected = len(dg.delivering()) elif status_type == SupplyPointStatusTypes.R_AND_R_FACILITY: expected = len(dg.submitting()) elif status_type == SupplyPointStatusTypes.SOH_FACILITY \ or status_type == SupplyPointStatusTypes.SUPERVISION_FACILITY: expected = len(facs) if gsum.total != expected: logging.info("expected %s but was %s for %s" % (expected, gsum.total, gsum)) for alert_type in [ const.RR_NOT_SUBMITTED, const.DELIVERY_NOT_RECEIVED, const.SOH_NOT_RESPONDING, const.RR_NOT_RESPONDED, const.DELIVERY_NOT_RESPONDING ]: sub_alerts = Alert.objects.filter(location_id__in=fac_ids, date=window_date, type=alert_type) aggregate_response_alerts(location.location_id, window_date, sub_alerts, alert_type) update_historical_data_for_location(location)
def process_facility_warehouse_data(facility, start_date, end_date, runner): """ process all the facility-level warehouse tables """ logging.info("processing facility %s (%s)" % (facility.name, str(facility._id))) try: runner.location = facility.sql_location runner.save() except SQLLocation.DoesNotExist: # TODO Temporary fix facility.delete() return for alert_type in [const.SOH_NOT_RESPONDING, const.RR_NOT_RESPONDED, const.DELIVERY_NOT_RESPONDING]: alert = Alert.objects.filter(location_id=facility._id, date__gte=start_date, date__lt=end_date, type=alert_type) alert.delete() supply_point_id = facility.linked_supply_point()._id location_id = facility._id new_statuses = SupplyPointStatus.objects.filter( location_id=facility._id, status_date__gte=start_date, status_date__lt=end_date ).order_by('status_date').iterator() process_facility_statuses(location_id, new_statuses) new_reports = StockReport.objects.filter( stocktransaction__case_id=supply_point_id, date__gte=start_date, date__lt=end_date, stocktransaction__type='stockonhand' ).order_by('date').iterator() process_facility_product_reports(location_id, new_reports) new_trans = StockTransaction.objects.filter( case_id=supply_point_id, report__date__gte=start_date, report__date__lt=end_date, ).exclude(type='consumption').order_by('report__date').iterator() process_facility_transactions(location_id, new_trans) # go through all the possible values in the date ranges # and make sure there are warehouse tables there for year, month in months_between(start_date, end_date): window_date = datetime(year, month, 1) # create org_summary for every fac/date combo org_summary, created = OrganizationSummary.objects.get_or_create( location_id=facility._id, date=window_date ) org_summary.total_orgs = 1 alt = average_lead_time(facility._id, window_date) if alt: alt = alt.days org_summary.average_lead_time_in_days = alt or 0 org_summary.save() # create group_summary for every org_summary title combo for title in const.NEEDED_STATUS_TYPES: GroupSummary.objects.get_or_create(org_summary=org_summary, title=title) # update all the non-response data not_responding_facility(org_summary) # update product availability data update_product_availability_facility_data(org_summary) # alerts with transaction.atomic(): populate_no_primary_alerts(facility, window_date) populate_facility_stockout_alerts(facility, window_date)
def __init__(self, case, report): report.filter( lambda key: case['_source'][key], # case.awc_name, case.block_name [('awc_name', 'awcs'), ('block_name', 'block'), ('owner_id', 'gp'), ('closed', 'is_open')], ) img_elem = '<div style="width:100px !important;"><img src="/static/opm/img/%s"></div>' met = { 'window_1_1': None, 'window_1_2': None, 'window_2_1': None, 'window_2_2': None, 'attendance_vhnd_3': None, 'attendance_vhnd_6': None, 'child1_vhndattend_calc': None, 'prev_child1_vhndattend_calc': None, 'child1_attendance_vhnd': None, 'weight_tri_1': None, 'prev_weight_tri_1': None, 'weight_tri_2': None, 'prev_weight_tri_2': None, 'child1_growthmon_calc': None, 'prev_child1_growthmon_calc': None, 'child1_excl_breastfeed_calc': None, 'prev_child1_excl_breastfeed_calc': None, 'child1_ors_calc': None, 'prev_child1_ors_calc': None, 'child1_weight_calc': None, 'child1_register_calc': None, 'child1_measles_calc': None, 'prev_child1_weight_calc': None, 'prev_child1_register_calc': None, 'prev_child1_measles_calc': None, 'child1_suffer_diarrhea': None, 'interpret_grade_1': None } def get_property(obj, name, default=None): if name in obj: if type(obj[name]) is dict: return obj[name] return obj[name] else: return default if default is not None else EMPTY_FIELD def get_property_from_forms(forms, met_properties): for form in forms: for k, v in met_properties.iteritems(): if k == 'child1_suffer_diarrhea': if 'child_1' in form.form and k in form.form['child_1']: met_properties[k] = form.form['child_1'][k] else: if k in form.form: met_properties[k] = form.form[k] return met_properties case_obj = CommCareCase.get(case['_source']['_id']) self.block_name = get_property(case_obj, 'block_name', '') self.owner_id = get_property(case_obj, 'owner_id', '') self.closed = get_property(case_obj, 'closed', False) forms = case_obj.get_forms() birth_spacing_prompt = [] for form in forms: if 'birth_spacing_prompt' in form.form: birth_spacing_prompt.append(form.form['birth_spacing_prompt']) filtered_forms = [form for form in case_obj.get_forms() if report.datespan.startdate <= form.received_on <= report.datespan.enddate] get_property_from_forms(filtered_forms, met) dod = get_property(case_obj, 'dod') if dod and dod != EMPTY_FIELD: try: child_age = len(months_between(datetime.datetime(dod.year, dod.month, dod.day), datetime.datetime.now())) except AssertionError: child_age = -1 else: child_age = -1 if get_property(case_obj, 'mother_preg_outcome', '') == '1': self.status = 'mother' elif get_property(case_obj, 'mother_preg_outcome', '') == '': self.status = 'pregnant' else: raise InvalidRow met_one = False met_two = False met_three = False met_four = False met_five = False preg_month = get_property(case_obj, 'pregnancy_month', 0) or 0 if self.status == 'pregnant': if '1' in [met['window_1_1'], met['window_1_2'], met['window_2_1'], met['window_2_2'], met['attendance_vhnd_3'], met['attendance_vhnd_6']]: met_one = True if (preg_month == '6' and '1' in [met['weight_tri_1'], met['prev_weight_tri_1']]) or (preg_month == '9' and '1' in [met['weight_tri_2'], met['prev_weight_tri_2']]): met_two = True elif self.status == 'mother': if '1' in [met['child1_vhndattend_calc'], met['prev_child1_vhndattend_calc'], met['child1_attendance_vhnd']]: met_one = True if '1' in [met['child1_growthmon_calc'], met['prev_child1_growthmon_calc']]: met_two = True if (child_age == 3 and (met['child1_weight_calc'] or met['prev_child1_weight_calc'])) or \ (child_age == 6 and (met['child1_register_calc'] or met['prev_child1_register_calc'])) or \ (child_age == 9 and (met['child1_measles_calc'] or met['prev_child1_measles_calc'])): met_three = True if child_age == 6 and ('1' in [met['child1_excl_breastfeed_calc'], met['prev_child1_excl_breastfeed_calc']]): met_four = True if child_age in [6, 9, 12] and '1' in [met['child1_ors_calc'], met['prev_child1_ors_calc']]: met_five = True self.name = get_property(case_obj, 'name') self.awc_name = get_property(case_obj, 'awc_name') self.husband_name = get_property(case_obj, 'husband_name') self.window = get_property(case_obj, 'which_window') if self.status == 'pregnant': self.month = get_property(case_obj, 'pregnancy_month') self.one = img_elem % M_ATTENDANCE_Y if preg_month == '9' else img_elem % M_ATTENDANCE_N self.two = img_elem % M_WEIGHT_Y if preg_month in ['6', '9'] else img_elem % M_WEIGHT_N self.three = img_elem % IFA_Y if int(preg_month) < 7 else img_elem % IFA_N self.four = '' if report.block.lower() == 'wazirganj': if child_age > 23 and '1' in birth_spacing_prompt: self.five = img_elem % SPACING_PROMPT_Y else: self.five = img_elem % SPACING_PROMPT_N else: self.five = '' elif self.status == 'mother': if child_age != -1: self.month = child_age else: self.month = EMPTY_FIELD self.one = img_elem % C_ATTENDANCE_Y if 0 <= child_age <= 1 else img_elem % C_ATTENDANCE_N self.two = img_elem % C_WEIGHT_Y if child_age % 3 == 0 else img_elem % C_WEIGHT_N if child_age == 3: if met['child1_weight_calc'] or met['prev_child1_weight_calc']: self.three = img_elem % CHILD_WEIGHT_Y else: self.three = img_elem % CHILD_WEIGHT_N elif child_age == 6: if met['child1_register_calc'] or met['prev_child1_register_calc']: self.three = img_elem % C_REGISTER_Y else: self.three = img_elem % C_REGISTER_N elif child_age == 9: if met['child1_measles_calc'] or met['prev_child1_measles_calc']: self.three = img_elem % MEASLEVACC_Y else: self.three = img_elem % MEASLEVACC_N else: self.three = '' self.four = img_elem % EXCBREASTFED_Y if child_age == 6 else img_elem % EXCBREASTFED_N if child_age in [3, 6, 9]: if met['child1_suffer_diarrhea'] == '1': self.five = img_elem % ORSZNTREAT_Y else: self.five = img_elem % ORSZNTREAT_N elif child_age == [24, 36]: if met['interpret_grade_1'] == 'normal': self.five = img_elem % GRADE_NORMAL_Y else: self.five = img_elem % GRADE_NORMAL_N else: self.five = '' if report.block.lower() == 'atri': if child_age == 24: self.cash = '<span style="color: green;">Rs. 2000</span>' elif child_age == 36: self.cash = '<span style="color: green;">Rs. 3000</span>' elif met_one or met_two or met_three or met_four or met_five: self.cash = '<span style="color: green;">Rs. 250</span>' else: self.cash = '<span style="color: red;">Rs. 0</span>' elif report.block.lower == 'wazirganj': if met_one or met_two or met_four or met_five: self.cash = '<span style="color: green;">Rs. 250</span>' else: self.cash = '<span style="color: red;">Rs. 0</span>'
def process_non_facility_warehouse_data(location, start_date, end_date, runner=None, strict=True): if runner: runner.location = location.sql_location runner.save() facs = get_non_archived_facilities_below(location) fac_ids = [f._id for f in facs] logging.info("processing non-facility %s (%s), %s children" % (location.name, str(location.location_id), len(facs))) for year, month in months_between(start_date, end_date): window_date = datetime(year, month, 1) org_summary = OrganizationSummary.objects.get_or_create( location_id=location.location_id, date=window_date )[0] org_summary.total_orgs = len(facs) sub_summaries = OrganizationSummary.objects.filter(date=window_date, location_id__in=fac_ids) subs_with_lead_time = [s for s in sub_summaries if s.average_lead_time_in_days] # lead times if subs_with_lead_time: days_sum = sum([s.average_lead_time_in_days for s in subs_with_lead_time]) org_summary.average_lead_time_in_days = days_sum / len(subs_with_lead_time) else: org_summary.average_lead_time_in_days = 0 org_summary.save() # product availability prods = SQLProduct.objects.filter(domain=location.domain, is_archived=False) for p in prods: product_data = ProductAvailabilityData.objects.get_or_create(product=p.product_id, location_id=location.location_id, date=window_date)[0] sub_prods = ProductAvailabilityData.objects.filter(product=p.product_id, location_id__in=fac_ids, date=window_date) product_data.total = sum([p.total for p in sub_prods]) if strict: assert product_data.total == len(facs), \ "total should match number of sub facilities" product_data.with_stock = sum([p.with_stock for p in sub_prods]) product_data.without_stock = sum([p.without_stock for p in sub_prods]) product_data.without_data = product_data.total - product_data.with_stock - product_data.without_stock product_data.save() dg = DeliveryGroups(month=month, facs=facs) for status_type in const.NEEDED_STATUS_TYPES: gsum = GroupSummary.objects.get_or_create(org_summary=org_summary, title=status_type)[0] sub_sums = GroupSummary.objects.filter(title=status_type, org_summary__in=sub_summaries).all() # TODO: see if moving the aggregation to the db makes it # faster, if this is slow gsum.total = sum([s.total for s in sub_sums]) gsum.responded = sum([s.responded for s in sub_sums]) gsum.on_time = sum([s.on_time for s in sub_sums]) gsum.complete = sum([s.complete for s in sub_sums]) # gsum.missed_response = sum([s.missed_response for s in sub_sums]) gsum.save() if status_type == SupplyPointStatusTypes.DELIVERY_FACILITY: expected = len(dg.delivering()) elif status_type == SupplyPointStatusTypes.R_AND_R_FACILITY: expected = len(dg.submitting()) elif status_type == SupplyPointStatusTypes.SOH_FACILITY \ or status_type == SupplyPointStatusTypes.SUPERVISION_FACILITY: expected = len(facs) if gsum.total != expected: logging.info("expected %s but was %s for %s" % (expected, gsum.total, gsum)) for alert_type in [const.RR_NOT_SUBMITTED, const.DELIVERY_NOT_RECEIVED, const.SOH_NOT_RESPONDING, const.RR_NOT_RESPONDED, const.DELIVERY_NOT_RESPONDING]: sub_alerts = Alert.objects.filter(location_id__in=fac_ids, date=window_date, type=alert_type) aggregate_response_alerts(location.location_id, window_date, sub_alerts, alert_type)
def process_non_facility_warehouse_data(location, start_date, end_date, runner, strict=True): runner.location = location.sql_location runner.save() facs = get_non_archived_facilities_below(location) fac_ids = [f._id for f in facs] logging.info("processing non-facility %s (%s), %s children" % (location.name, str(location._id), len(facs))) for year, month in months_between(start_date, end_date): window_date = datetime(year, month, 1) org_summary = OrganizationSummary.objects.get_or_create( location_id=location._id, date=window_date)[0] org_summary.total_orgs = len(facs) sub_summaries = OrganizationSummary.objects.filter( date=window_date, location_id__in=fac_ids) subs_with_lead_time = [ s for s in sub_summaries if s.average_lead_time_in_days ] # lead times if subs_with_lead_time: days_sum = sum( [s.average_lead_time_in_days for s in subs_with_lead_time]) org_summary.average_lead_time_in_days = days_sum / len( subs_with_lead_time) else: org_summary.average_lead_time_in_days = 0 org_summary.save() # product availability prods = SQLProduct.objects.filter(domain=location.domain, is_archived=False) for p in prods: product_data = ProductAvailabilityData.objects.get_or_create( product=p.product_id, location_id=location._id, date=window_date)[0] sub_prods = ProductAvailabilityData.objects.filter( product=p.product_id, location_id__in=fac_ids, date=window_date) product_data.total = sum([p.total for p in sub_prods]) if strict: assert product_data.total == len(facs), \ "total should match number of sub facilities" product_data.with_stock = sum([p.with_stock for p in sub_prods]) product_data.without_stock = sum( [p.without_stock for p in sub_prods]) product_data.without_data = product_data.total - product_data.with_stock - product_data.without_stock product_data.save() dg = DeliveryGroups(month=month, facs=facs) for status_type in const.NEEDED_STATUS_TYPES: gsum = GroupSummary.objects.get_or_create(org_summary=org_summary, title=status_type)[0] sub_sums = GroupSummary.objects.filter( title=status_type, org_summary__in=sub_summaries).all() # TODO: see if moving the aggregation to the db makes it # faster, if this is slow gsum.total = sum([s.total for s in sub_sums]) gsum.responded = sum([s.responded for s in sub_sums]) gsum.on_time = sum([s.on_time for s in sub_sums]) gsum.complete = sum([s.complete for s in sub_sums]) # gsum.missed_response = sum([s.missed_response for s in sub_sums]) gsum.save() if status_type == SupplyPointStatusTypes.DELIVERY_FACILITY: expected = len(dg.delivering()) elif status_type == SupplyPointStatusTypes.R_AND_R_FACILITY: expected = len(dg.submitting()) elif status_type == SupplyPointStatusTypes.SOH_FACILITY \ or status_type == SupplyPointStatusTypes.SUPERVISION_FACILITY: expected = len(facs) if gsum.total != expected: logging.info("expected %s but was %s for %s" % (expected, gsum.total, gsum)) for alert_type in [ const.RR_NOT_SUBMITTED, const.DELIVERY_NOT_RECEIVED, const.SOH_NOT_RESPONDING, const.RR_NOT_RESPONDED, const.DELIVERY_NOT_RESPONDING ]: sub_alerts = Alert.objects.filter(location_id__in=fac_ids, date=window_date, type=alert_type) aggregate_response_alerts(location._id, window_date, sub_alerts, alert_type)
def process_facility_warehouse_data(facility, start_date, end_date, runner=None): """ process all the facility-level warehouse tables """ logging.info("processing facility %s (%s)" % (facility.name, str(facility._id))) sql_location = facility.sql_location if runner: runner.location = sql_location runner.save() for alert_type in [const.SOH_NOT_RESPONDING, const.RR_NOT_RESPONDED, const.DELIVERY_NOT_RESPONDING]: alert = Alert.objects.filter(location_id=facility._id, date__gte=start_date, date__lt=end_date, type=alert_type) alert.delete() supply_point_id = sql_location.supply_point_id location_id = facility._id new_statuses = SupplyPointStatus.objects.filter( location_id=facility._id, status_date__gte=start_date, status_date__lt=end_date ).order_by('status_date').iterator() process_facility_statuses(location_id, new_statuses) new_reports = StockReport.objects.filter( stocktransaction__case_id=supply_point_id, date__gte=start_date, date__lt=end_date, stocktransaction__type='stockonhand' ).distinct().order_by('date').iterator() process_facility_product_reports(location_id, new_reports) new_trans = get_latest_transaction_from_each_month(supply_point_id, start_date, end_date) process_facility_transactions(location_id, new_trans, start_date, end_date) products = SQLProduct.objects.filter(domain=facility.domain, is_archived=False) users = get_users_by_location_id(facility.domain, facility.get_id) # go through all the possible values in the date ranges # # and make sure there are warehouse tables there for year, month in months_between(start_date, end_date): window_date = datetime(year, month, 1) # create org_summary for every fac/date combo org_summary, created = OrganizationSummary.objects.get_or_create( location_id=facility._id, date=window_date ) org_summary.total_orgs = 1 alt = average_lead_time(facility._id, window_date) if alt: alt = alt.days org_summary.average_lead_time_in_days = alt or 0 org_summary.save() # create group_summary for every org_summary title combo for title in const.NEEDED_STATUS_TYPES: GroupSummary.objects.get_or_create(org_summary=org_summary, title=title) # update all the non-response data not_responding_facility(org_summary) # alerts with transaction.atomic(): populate_no_primary_alerts(facility, window_date, users) populate_facility_stockout_alerts(facility, window_date) update_product_availability_facility_data(facility, products, start_date, end_date) update_historical_data_for_location(facility)
def process_facility_warehouse_data(facility, start_date, end_date, runner=None): """ process all the facility-level warehouse tables """ logging.info("processing facility %s (%s)" % (facility.name, str(facility.location_id))) sql_location = facility.sql_location if runner: runner.location = sql_location runner.save() for alert_type in [ const.SOH_NOT_RESPONDING, const.RR_NOT_RESPONDED, const.DELIVERY_NOT_RESPONDING ]: alert = Alert.objects.filter(location_id=facility.location_id, date__gte=start_date, date__lt=end_date, type=alert_type) alert.delete() supply_point_id = sql_location.supply_point_id location_id = facility.location_id new_statuses = SupplyPointStatus.objects.filter( location_id=facility.location_id, status_date__gte=start_date, status_date__lt=end_date).order_by('status_date').iterator() process_facility_statuses(location_id, new_statuses) new_reports = StockReport.objects.filter( stocktransaction__case_id=supply_point_id, date__gte=start_date, date__lt=end_date, stocktransaction__type='stockonhand').distinct().order_by( 'date').iterator() process_facility_product_reports(location_id, new_reports) new_trans = get_latest_transaction_from_each_month(supply_point_id, start_date, end_date) process_facility_transactions(location_id, new_trans, start_date, end_date) products = SQLProduct.objects.filter(domain=facility.domain, is_archived=False) users = get_users_by_location_id(facility.domain, facility.get_id) # go through all the possible values in the date ranges # # and make sure there are warehouse tables there for year, month in months_between(start_date, end_date): window_date = datetime(year, month, 1) # create org_summary for every fac/date combo org_summary, created = OrganizationSummary.objects.get_or_create( location_id=facility.location_id, date=window_date) org_summary.total_orgs = 1 alt = average_lead_time(facility.location_id, window_date) if alt: alt = alt.days org_summary.average_lead_time_in_days = alt or 0 org_summary.save() # create group_summary for every org_summary title combo for title in const.NEEDED_STATUS_TYPES: GroupSummary.objects.get_or_create(org_summary=org_summary, title=title) # update all the non-response data not_responding_facility(org_summary) # alerts with transaction.atomic(): populate_no_primary_alerts(facility, window_date, users) populate_facility_stockout_alerts(facility, window_date) update_product_availability_facility_data(facility, products, start_date, end_date) update_historical_data_for_location(facility)
def process_non_facility_warehouse_data(location, start_date, end_date, runner=None, strict=True): start_date = datetime(start_date.year, start_date.month, 1) end_date = datetime(end_date.year, end_date.month, 1) if runner: runner.location = location.sql_location runner.save() facs = get_non_archived_facilities_below(location) fac_ids = [f._id for f in facs] logging.info("processing non-facility %s (%s), %s children" % (location.name, str(location.location_id), len(facs))) prods = SQLProduct.objects.filter(domain=location.domain, is_archived=False) sub_summaries = OrganizationSummary.objects.filter( location_id__in=fac_ids, date__range=(start_date, end_date), average_lead_time_in_days__gt=0 ).values('date').annotate(average_time=Avg('average_lead_time_in_days')) sub_summaries = { (subsummary['date'].year, subsummary['date'].month): subsummary for subsummary in sub_summaries } sub_prods = ProductAvailabilityData.objects.filter( location_id__in=fac_ids, date__range=(start_date, end_date) ).values('product', 'date').annotate( total_sum=Sum('total'), with_stock_sum=Sum('with_stock'), without_stock_sum=Sum('without_stock'), ) sub_prods = { ((sub_prod['date'].year, sub_prod['date'].month), sub_prod['product']): sub_prod for sub_prod in sub_prods } sub_group_summaries = GroupSummary.objects.filter( org_summary__location_id__in=fac_ids, org_summary__date__range=(start_date, end_date) ).values('title', 'org_summary__date').annotate( total_sum=Sum('total'), responded_sum=Sum('responded'), on_time_sum=Sum('on_time'), complete_sum=Sum('complete') ) sub_group_summaries = { ((sub_group_summary['org_summary__date'].year, sub_group_summary['org_summary__date'].month), sub_group_summary['title']): sub_group_summary for sub_group_summary in sub_group_summaries } total_orgs = len(facs) for year, month in months_between(start_date, end_date): window_date = datetime(year, month, 1) org_summary = OrganizationSummary.objects.get_or_create( location_id=location.location_id, date=window_date )[0] org_summary.total_orgs = total_orgs # lead times if (year, month) in sub_summaries: sub_summary = sub_summaries[year, month] org_summary.average_lead_time_in_days = sub_summary['average_time'] else: org_summary.average_lead_time_in_days = 0 org_summary.save() # product availability for p in prods: product_data = ProductAvailabilityData.objects.get_or_create(product=p.product_id, location_id=location.location_id, date=window_date)[0] sub_prod = sub_prods.get(((year, month), p.product_id), {}) product_data.total = sub_prod.get('total_sum', 0) if strict: assert product_data.total == total_orgs, \ "total should match number of sub facilities %s-%s" % (product_data.total, total_orgs) product_data.with_stock = sub_prod.get('with_stock_sum', 0) product_data.without_stock = sub_prod.get('without_stock_sum', 0) product_data.without_data = product_data.total - product_data.with_stock - product_data.without_stock product_data.save() dg = DeliveryGroups(month=month, facs=facs) for status_type in const.NEEDED_STATUS_TYPES: gsum = GroupSummary.objects.get_or_create(org_summary=org_summary, title=status_type)[0] sub_sum = sub_group_summaries.get(((year, month), status_type), {}) gsum.total = sub_sum.get('total_sum', 0) gsum.responded = sub_sum.get('responded_sum', 0) gsum.on_time = sub_sum.get('on_time_sum', 0) gsum.complete = sub_sum.get('complete_sum', 0) gsum.save() if status_type == SupplyPointStatusTypes.DELIVERY_FACILITY: expected = len(dg.delivering()) elif status_type == SupplyPointStatusTypes.R_AND_R_FACILITY: expected = len(dg.submitting()) elif status_type == SupplyPointStatusTypes.SOH_FACILITY \ or status_type == SupplyPointStatusTypes.SUPERVISION_FACILITY: expected = len(facs) if gsum.total != expected: logging.info("expected %s but was %s for %s" % (expected, gsum.total, gsum)) for alert_type in [const.RR_NOT_SUBMITTED, const.DELIVERY_NOT_RECEIVED, const.SOH_NOT_RESPONDING, const.RR_NOT_RESPONDED, const.DELIVERY_NOT_RESPONDING]: sub_alerts = Alert.objects.filter(location_id__in=fac_ids, date=window_date, type=alert_type) aggregate_response_alerts(location.location_id, window_date, sub_alerts, alert_type) update_historical_data_for_location(location)
def update_product_availability_facility_data(facility, products, start_date, end_date): # product availability existing_data = ProductAvailabilityData.objects.filter( date__range=( datetime(start_date.year, start_date.month, 1), datetime(end_date.year, end_date.month, 1) ), location_id=facility.get_id ) product_data_dict = { (pa.date, pa.location_id, pa.product): pa for pa in existing_data } product_data_list = [] previous_month = {} for year, month in months_between(start_date, end_date): window_date = datetime(year, month, 1) for p in products: now = datetime.utcnow() if (window_date, facility.get_id, p.product_id) in product_data_dict: previous_month[p.product_id] = product_data_dict[window_date, facility.get_id, p.product_id] continue else: product_data = ProductAvailabilityData( date=window_date, location_id=facility.get_id, product=p.product_id, create_date=now, update_date=now ) # set defaults product_data.total = 1 prev = None if p.product_id in previous_month: prev = previous_month[p.product_id] if not prev: previous_reports = ProductAvailabilityData.objects.filter( product=p.product_id, location_id=facility._id, date__lt=window_date, total=1 ) if previous_reports.count(): prev = previous_reports.latest('date') if prev: product_data.with_stock = prev.with_stock product_data.without_stock = prev.without_stock product_data.without_data = prev.without_data else: # otherwise we use the defaults product_data.with_stock = 0 product_data.without_stock = 0 product_data.without_data = 1 if product_data.pk is not None: product_data.save() else: product_data_list.append(product_data) assert (product_data.with_stock + product_data.without_stock + product_data.without_data) == 1, \ "bad product data config for %s" % product_data previous_month[p.product_id] = product_data ProductAvailabilityData.objects.bulk_create(product_data_list)
def __init__(self, case, report): if report.snapshot is not None: report.filter( lambda key: case["_source"][key], # case.awc_name, case.block_name [("awc_name", "awcs"), ("block_name", "block"), ("owner_id", "gp"), ("closed", "is_open")], ) img_elem = '<div style="width:100px !important;"><img src="/static/opm/img/%s"></div>' met = { "window_1_1": None, "window_1_2": None, "window_2_1": None, "window_2_2": None, "attendance_vhnd_3": None, "attendance_vhnd_6": None, "child1_vhndattend_calc": None, "prev_child1_vhndattend_calc": None, "child1_attendance_vhnd": None, "weight_tri_1": None, "prev_weight_tri_1": None, "weight_tri_2": None, "prev_weight_tri_2": None, "child1_growthmon_calc": None, "prev_child1_growthmon_calc": None, "child1_excl_breastfeed_calc": None, "prev_child1_excl_breastfeed_calc": None, "child1_ors_calc": None, "prev_child1_ors_calc": None, "child1_weight_calc": None, "child1_register_calc": None, "child1_measles_calc": None, "prev_child1_weight_calc": None, "prev_child1_register_calc": None, "prev_child1_measles_calc": None, "child1_suffer_diarrhea": None, "interpret_grade_1": None, } def get_property(obj, name, default=None): if name in obj: if type(obj[name]) is dict: return obj[name] return obj[name] else: return default if default is not None else EMPTY_FIELD def get_property_from_forms(forms, met_properties): for form in forms: for k, v in met_properties.iteritems(): if k == "child1_suffer_diarrhea": if "child_1" in form.form and k in form.form["child_1"]: met_properties[k] = form.form["child_1"][k] else: if k in form.form: met_properties[k] = form.form[k] return met_properties case_obj = CommCareCase.get(case["_source"]["_id"]) self.case_id = get_property(case_obj, "_id", "") self.block_name = get_property(case_obj, "block_name", "") self.owner_id = get_property(case_obj, "owner_id", "") self.closed = get_property(case_obj, "closed", False) forms = case_obj.get_forms() birth_spacing_prompt = [] for form in forms: if "birth_spacing_prompt" in form.form: birth_spacing_prompt.append(form.form["birth_spacing_prompt"]) filtered_forms = [ form for form in case_obj.get_forms() if report.datespan.startdate <= form.received_on <= report.datespan.enddate ] get_property_from_forms(filtered_forms, met) dod = get_property(case_obj, "dod") if dod and dod != EMPTY_FIELD: try: child_age = len( months_between(datetime.datetime(dod.year, dod.month, dod.day), datetime.datetime.now()) ) except AssertionError: child_age = -1 else: child_age = -1 if get_property(case_obj, "mother_preg_outcome", "") == "1": self.status = "mother" elif get_property(case_obj, "mother_preg_outcome", "") == "": self.status = "pregnant" else: raise InvalidRow met_one = False met_two = False met_three = False met_four = False met_five = False preg_month = get_property(case_obj, "pregnancy_month", 0) or 0 if self.status == "pregnant": if "1" in [ met["window_1_1"], met["window_1_2"], met["window_2_1"], met["window_2_2"], met["attendance_vhnd_3"], met["attendance_vhnd_6"], ]: met_one = True if (preg_month == "6" and "1" in [met["weight_tri_1"], met["prev_weight_tri_1"]]) or ( preg_month == "9" and "1" in [met["weight_tri_2"], met["prev_weight_tri_2"]] ): met_two = True elif self.status == "mother": if "1" in [ met["child1_vhndattend_calc"], met["prev_child1_vhndattend_calc"], met["child1_attendance_vhnd"], ]: met_one = True if "1" in [met["child1_growthmon_calc"], met["prev_child1_growthmon_calc"]]: met_two = True if ( (child_age == 3 and (met["child1_weight_calc"] or met["prev_child1_weight_calc"])) or (child_age == 6 and (met["child1_register_calc"] or met["prev_child1_register_calc"])) or (child_age == 9 and (met["child1_measles_calc"] or met["prev_child1_measles_calc"])) ): met_three = True if child_age == 6 and ( "1" in [met["child1_excl_breastfeed_calc"], met["prev_child1_excl_breastfeed_calc"]] ): met_four = True if child_age in [6, 9, 12] and "1" in [met["child1_ors_calc"], met["prev_child1_ors_calc"]]: met_five = True self.name = get_property(case_obj, "name") self.awc_name = get_property(case_obj, "awc_name") self.husband_name = get_property(case_obj, "husband_name") self.window = get_property(case_obj, "which_window") if self.status == "pregnant": self.preg_month = get_property(case_obj, "pregnancy_month") self.child_age = EMPTY_FIELD self.one = img_elem % M_ATTENDANCE_Y if preg_month == "9" else img_elem % M_ATTENDANCE_N self.two = img_elem % M_WEIGHT_Y if preg_month in ["6", "9"] else img_elem % M_WEIGHT_N self.three = img_elem % IFA_Y if int(preg_month) < 7 else img_elem % IFA_N self.four = "" if report.block.lower() == "wazirganj": if child_age > 23 and "1" in birth_spacing_prompt: self.five = img_elem % SPACING_PROMPT_Y else: self.five = img_elem % SPACING_PROMPT_N else: self.five = "" elif self.status == "mother": self.preg_month = EMPTY_FIELD if child_age != -1: self.child_age = child_age else: self.child_age = EMPTY_FIELD self.one = img_elem % C_ATTENDANCE_Y if 0 <= child_age <= 1 else img_elem % C_ATTENDANCE_N self.two = img_elem % C_WEIGHT_Y if child_age % 3 == 0 else img_elem % C_WEIGHT_N if child_age == 3: if met["child1_weight_calc"] or met["prev_child1_weight_calc"]: self.three = img_elem % CHILD_WEIGHT_Y else: self.three = img_elem % CHILD_WEIGHT_N elif child_age == 6: if met["child1_register_calc"] or met["prev_child1_register_calc"]: self.three = img_elem % C_REGISTER_Y else: self.three = img_elem % C_REGISTER_N elif child_age == 9: if met["child1_measles_calc"] or met["prev_child1_measles_calc"]: self.three = img_elem % MEASLEVACC_Y else: self.three = img_elem % MEASLEVACC_N else: self.three = "" self.four = img_elem % EXCBREASTFED_Y if child_age == 6 else img_elem % EXCBREASTFED_N if child_age in [3, 6, 9]: if met["child1_suffer_diarrhea"] == "1": self.five = img_elem % ORSZNTREAT_Y else: self.five = img_elem % ORSZNTREAT_N elif child_age == [24, 36]: if met["interpret_grade_1"] == "normal": self.five = img_elem % GRADE_NORMAL_Y else: self.five = img_elem % GRADE_NORMAL_N else: self.five = "" if report.block.lower() == "atri": if child_age == 24: self.cash = '<span style="color: green;">Rs. 2000</span>' elif child_age == 36: self.cash = '<span style="color: green;">Rs. 3000</span>' elif met_one or met_two or met_three or met_four or met_five: self.cash = '<span style="color: green;">Rs. 250</span>' else: self.cash = '<span style="color: red;">Rs. 0</span>' elif report.block.lower() == "wazirganj": if met_one or met_two or met_four or met_five: self.cash = '<span style="color: green;">Rs. 250</span>' else: self.cash = '<span style="color: red;">Rs. 0</span>'