def report_chooser(request, report_type, period_type, period_str=None, export=False): if not report_type in ('children', 'maternal', 'commodities'): raise Http404(u"Invalid report type") if (not period_type in ('monthly', 'annual', 'quarterly', 'weekly') or (report_type == 'commodities' and period_type == 'weekly')): raise Http404(u"Invalid period type") # web views and export views are named the same. # difference is the _export suffix. func_suffix = '_export' if export else '' try: view = import_path('unfpa_web.views.%(report_type)s.' '%(period_type)s_%(report_type)s%(suffix)s' % {'report_type': report_type, 'period_type': period_type, 'suffix': func_suffix}) except: raise Http404(u"Incorrect URL.") try: if '-' in period_str: indice, year = period_str.split('-') indice = int(indice) year = int(year) else: indice = None year = int(period_str) except: raise Http404(u"Incorrect period.") if period_type == 'weekly': period = WeekPeriod.find_create_by_weeknum(year, indice) elif period_type == 'monthly': period = MonthPeriod.find_create_from(year, month=indice) elif period_type == 'quarterly': period = QuarterPeriod.find_create_by_quarter(year, indice) elif period_type == 'annual': period = YearPeriod.find_create_from(year) else: # default period is current Month period = MonthPeriod.find_create_by_date(date.today()) return view(request, period)
def create_report(self, author): """ creates and save a MalariaReport based on current data_browser No check nor validation is performed """ period = MonthPeriod.find_create_from(year=self.get('year'), \ month=self.get('month')) entity = Entity.objects.get(slug=self.get('hc'), type__slug='cscom') report = MalariaReport.start(period, entity, author, \ type=MalariaReport.TYPE_SOURCE) report.add_underfive_data(*self.data_for_cat('u5')) report.add_overfive_data(*self.data_for_cat('o5')) report.add_pregnantwomen_data(*self.data_for_cat('pw')) report.add_stockout_data(*self.data_for_cat('so')) with reversion.create_revision(): report.save() reversion.set_user(author.user) #report.save() return report
def unfpa_monthly_product_stockouts(message, args, sub_cmd, **kwargs): """ Incomming: fnuap mps family_planning delivery_services male_condom female_condom oral_pills injectable iud implants female_sterilization male_sterilization amoxicillin_ij amoxicillin_cap_gel amoxicillin_suspension azithromycine_tab azithromycine_suspension benzathine_penicillin cefexime clotrimazole ergometrine_tab ergometrine_vials iron folate iron_folate magnesium_sulfate metronidazole oxytocine ceftriaxone_500 ceftriaxone_1000 comment example: 'fnuap mps 2012 05 wolo 0 0 20 - - - - - 0 0 - - - - - - - - - - - - - - - - - - -' Outgoing: [SUCCES] Le rapport de name a ete enregistre. or [ERREUR] message """ try: # -1 represente le non disponible args = args.replace("-", "-1") reporting_year, reporting_month, location_of_sdp, family_planning, \ delivery_services, male_condom, female_condom,\ oral_pills, injectable, iud, implants, female_sterilization, \ male_sterilization, amoxicillin_ij, amoxicillin_cap_gel, \ amoxicillin_suspension, azithromycine_tab, azithromycine_suspension, \ benzathine_penicillin, cefexime, clotrimazole, ergometrine_tab, \ ergometrine_vials, iron, folate, iron_folate, magnesium_sulfate, \ metronidazole, oxytocine, ceftriaxone_500, ceftriaxone_1000, \ comment = args.split() except: return resp_error(message, u"le rapport") try: period = MonthPeriod.find_create_from(year=int(reporting_year), month=int(reporting_month)) except: message.respond(u"La periode (%s %s) n'est pas valide" % (reporting_month, reporting_year)) return True if period != current_period().previous(): message.respond(u"La periode (%s %s) n'est pas valide, " u"elle doit etre %s" % (reporting_month, reporting_year, current_period().previous())) return True # Entity code try: entity = Entity.objects.get(slug=location_of_sdp) except Entity.DoesNotExist: message.respond(u"Le code %s n'existe pas" % location_of_sdp) return True def check_int(val): try: return int(val) except: return -1 try: comment = comment.replace(u"_", u" ") except: comment = u"" contact = contact_for(message.identity) report = RHCommoditiesReport() if contact: report.created_by = contact else: return resp_error_provider(message) report.type = 0 report.period = period report.entity = entity report.family_planning = check_int(family_planning) report.delivery_services = check_int(delivery_services) report.male_condom = check_int(male_condom) report.female_condom = check_int(female_condom) report.oral_pills = check_int(oral_pills) report.injectable = check_int(injectable) report.iud = check_int(iud) report.implants = check_int(implants) report.female_sterilization = YESNOAVAIL.get(female_sterilization, RHCommoditiesReport.SUPPLIES_NOT_PROVIDED) report.male_sterilization = YESNOAVAIL.get(male_sterilization, RHCommoditiesReport.SUPPLIES_NOT_PROVIDED) report.amoxicillin_ij = check_int(amoxicillin_ij) report.amoxicillin_cap_gel = check_int(amoxicillin_cap_gel) report.amoxicillin_suspension = check_int(amoxicillin_suspension) report.azithromycine_tab = check_int(azithromycine_tab) report.azithromycine_suspension = check_int(azithromycine_suspension) report.benzathine_penicillin = check_int(benzathine_penicillin) report.cefexime = check_int(cefexime) report.clotrimazole = check_int(clotrimazole) report.ergometrine_tab = check_int(ergometrine_tab) report.ergometrine_vials = check_int(ergometrine_vials) report.iron = check_int(iron) report.folate = check_int(folate) report.iron_folate = check_int(iron_folate) report.magnesium_sulfate = check_int(magnesium_sulfate) report.metronidazole = check_int(metronidazole) report.oxytocine = check_int(oxytocine) report.ceftriaxone_500 = check_int(ceftriaxone_500) report.ceftriaxone_1000 = check_int(ceftriaxone_1000) report.comment = check_int(comment) report._status = report.STATUS_VALIDATED try: report.save() message.respond(u"[SUCCES] Le rapport de %(cscom)s pour %(period)s " u"a ete enregistre. " u"Le No de recu est #%(receipt)s." % {'cscom': report.entity.display_full_name(), 'period': report.period, 'receipt': report.receipt}) except IntegrityError: message.respond(u"[ERREUR] il ya deja un rapport pour cette periode") except: message.respond(u"[ERREUR] Le rapport n est pas enregiste") return True
def validate(self): """ Test whether attached data matches PNLP's logic requirements """ no_more_than_text = _("%(field2)s (%(f2value)d) can't be more " \ "than %(field1)s (%(f1value)d)") allcats = ('u5', 'o5', 'pw') noo5cat = ('u5', 'pw') nopwcat = ('u5', 'o5') def test_value_under(fieldref, fieldtest, cats): for cat in cats: try: dic = {'field2': self.field_name('%s_%s' \ % (cat, fieldtest)), \ 'f2value': self.get('%s_%s' % (cat, fieldtest)), \ 'field1': self.field_name('%s_%s' \ % (cat, fieldref)), \ 'f1value': self.get('%s_%s' % (cat, fieldref))} if dic['f1value'] < dic['f2value']: self.errors.add(no_more_than_text % dic, cat) except MissingData: # this missing data should have already been reported pass # total > malaria cases test_value_under('total_consultation_all_causes', \ 'total_suspected_malaria_cases', allcats) # total > malaria simple test_value_under('total_consultation_all_causes', \ 'total_simple_malaria_cases', nopwcat) # total > malaria severe test_value_under('total_consultation_all_causes', \ 'total_severe_malaria_cases', allcats) # suspected > malaria simple test_value_under('total_suspected_malaria_cases', \ 'total_simple_malaria_cases', nopwcat) # suspected > malaria severe test_value_under('total_suspected_malaria_cases', \ 'total_severe_malaria_cases', allcats) # suspected > malaria tested test_value_under('total_suspected_malaria_cases', \ 'total_tested_malaria_cases', allcats) # suspected > malaria confirmed test_value_under('total_suspected_malaria_cases', \ 'total_confirmed_malaria_cases', allcats) # suspected > simple + severe for cat in nopwcat: try: dic = {'field2': _(u"%(simple)s + %(severe)s") % {'simple': \ self.field_name('%s_total_simple_malaria_cases' % cat), \ 'severe': \ self.field_name('%s_total_severe_malaria_cases' % cat)}, \ 'f2value': int(self.get('%s_total_simple_malaria_cases' \ % cat)) \ + int(self.get('%s_total_severe_malaria_cases' \ % cat)), \ 'field1': \ self.field_name('%s_total_suspected_malaria_cases' \ % cat), \ 'f1value': self.get('%s_total_suspected_malaria_cases' \ % cat)} if dic['f1value'] < dic['f2value']: self.errors.add(no_more_than_text % dic, cat) except MissingData: pass # confirmed > simple + severe for cat in nopwcat: try: dic = {'field2': _(u"%(simple)s + %(severe)s") % {'simple': \ self.field_name('%s_total_simple_malaria_cases' % cat), \ 'severe': \ self.field_name('%s_total_severe_malaria_cases' % cat)}, \ 'f2value': int(self.get('%s_total_simple_malaria_cases' \ % cat)) \ + int(self.get('%s_total_severe_malaria_cases' \ % cat)), \ 'field1': \ self.field_name('%s_total_confirmed_malaria_cases' \ % cat), \ 'f1value': self.get('%s_total_confirmed_malaria_cases' \ % cat)} if dic['f1value'] < dic['f2value']: self.errors.add(no_more_than_text % dic, cat) except MissingData: pass # tested > confirmed test_value_under('total_tested_malaria_cases', \ 'total_confirmed_malaria_cases', allcats) # tested > ACT test_value_under('total_tested_malaria_cases', \ 'total_treated_malaria_cases', allcats) # confirmed > act test_value_under('total_confirmed_malaria_cases', \ 'total_treated_malaria_cases', allcats) # total inpatient > malaria inpatient test_value_under('total_inpatient_all_causes', \ 'total_malaria_inpatient', allcats) # total death > malaria death test_value_under('total_death_all_causes', \ 'total_malaria_death', allcats) # PERIOD MONTH # range(1, 12) # already handled. # PERIOD YEAR # range(2010, 2020) # already handled # NO FUTURE if self.get('year') >= date.today().year \ and self.get('month') >= date.today().month: self.errors.add(_(u"The period of data (%(period)s) " \ "is in the future.") % \ {'period': u"%s %d" % \ (self.get('month').__str__().zfill(2), \ self.get('year'))}, 'period') # NO PAST period = MonthPeriod.find_create_from(year=self.get('year'), \ month=self.get('month')) if self.options.is_editing: if self.options.level == 'district': time_over = time_district_over elif self.options.level == 'region': time_over = time_region_over else: time_over = time_cscom_over else: time_over = time_cscom_over if time_over(period) and not self.options.bulk_import: self.errors.add(_(u"The reporting time frame for that " \ "period (%(period)s) is over.") \ % {'period': period}, 'period') # DATE DAY / MONTH / YEAR try: date(self.get('fillin_year'), \ self.get('fillin_month'), self.get('fillin_day')) except ValueError: self.errors.add(_(u"The fillin day (%(day)s) is out of range " \ "for that month (%(month)s)") \ % {'day': \ self.get('fillin_day').__str__().zfill(2), \ 'month': \ self.get('fillin_month').__str__().zfill(2)}, \ 'fillin') # REPORTER NAME pass # ENTITY try: entity = Entity.objects.get(slug=self.get('hc'), \ type__slug='cscom') except Entity.DoesNotExist: entity = None self.errors.add(_(u"The entity code (%(code)s) does not " \ "match any HC.") % {'code': \ self.get('hc')}, 'period') # NO DUPLICATE if not self.options.data_only: period = MonthPeriod.find_create_from(year=self.get('year'), \ month=self.get('month')) if entity \ and MalariaReport.objects.filter(entity=entity, \ period=period).count() > 0: report = MalariaReport.objects.get(entity=entity, period=period) self.errors.add(_(u"There is already a report for " \ "that HC (%(entity)s) and that " \ "period (%(period)s)") % \ {'entity': entity.display_full_name(), \ 'period': period.name()} + u" Recu: %s." % report.receipt, 'period') # User can create such report if self.options.author: if not provider_can('can_submit_report', \ self.options.author, entity) \ and not self.options.bulk_import: self.errors.add(_(u"You don't have permission to send " \ "a report for that " \ "location (%(loc)s).") \ % {'loc': entity.display_full_name()})
def nut_report_update(message, args, sub_cmd, **kwargs): """ Client sent an update to an existing report Only the modified fields are sent. Each section is coded accoding to report codes. All fields are coded according to nutrsc. > nut report-update rgaudin -1355030878 0112 #P &SAM 1d:2 " 1h:2 1l6:2 #C &MAM a0:100 #T v:1 w:0 u:0-EOM-""" def resp_error(code, msg): # make sure we cancel whatever addition message.respond(u"nut report-update error %(code)s|%(msg)s" \ % {'code': code, 'msg': msg}) return True def provider_entity(provider): """ Entity a Provider is attached to """ try: return NUTEntity.objects.get(id=provider.first_access().target.id) except: return None # check that all parts made it together if not args.strip().endswith('-eom-'): return resp_error('BAD_FORM', REPORT_ERRORS['BAD_FORM']) else: args = args.strip()[:-5].strip() # split up sections sections = {} try: parts = args.strip().lower().split('#') for index in range(0, len(parts)): if index == 0: infos = parts[index] else: sections[parts[index][0].upper()] = parts[index][1:] pec_sec = sections.get('P', '').strip() cons_sec = sections.get('C', '').strip() order_sec = sections.get('O', '').strip() other_sec = sections.get('T', '').strip() except: return resp_error('BAD_FORM', REPORT_ERRORS['BAD_FORM']) # split up infos try: username, pwhash, date_str = infos.strip().split() except: return resp_error('BAD_FORM_INFO', REPORT_ERRORS['BAD_FORM_INFO']) # get Provider based on username try: provider = Provider.objects.get(user__username=username) except Provider.DoesNotExist: return resp_error('NO_ACC', REPORT_ERRORS['NO_ACC']) # check that provider pwhash is good if not provider.check_hash(pwhash): return resp_error('BAD_PASS', REPORT_ERRORS['BAD_PASS']) # check that user is not disabled if not provider.is_active: return resp_error('ACC_DIS', REPORT_ERRORS['ACC_DIS']) # check that user has permission to submit report on entity entity = provider_entity(provider) if not entity: return resp_error('NOT_ENT', REPORT_ERRORS['NOT_ENT']) eentity = Entity.objects.get(id=entity.id) if not provider_can('can_submit_report', provider, eentity): return resp_error('NO_PERM', REPORT_ERRORS['NO_PERM']) # parse date and check if period is valid try: month = int(date_str[0:2]) year = int('%s%s' % ('20', date_str[2:4])) period = MonthPeriod.find_create_from(year=year, month=month) except: return resp_error('BAD_FORM_PERIOD', REPORT_ERRORS['BAD_FORM_PERIOD']) # check period is the one we want if not period == current_reporting_period(): return resp_error('BAD_PERIOD', REPORT_ERRORS['BAD_PERIOD']) # global infos infos = {'entity': entity, 'eentity': eentity, 'provider': provider, 'month': month, 'year': year, 'period': period, 'username': username, 'pwhash': pwhash} # Retrieve report try: nut_report = NutritionReport.objects.get(period=infos['period'], entity=infos['entity'], type=Report.TYPE_SOURCE) except: return resp_error('MISS', REPORT_ERRORS['MISS']) reports = [] # common start of error message error_start = u"Impossible d'enregistrer le rapport. " logger.info("Processing PEC") if pec_sec: subs = pec_sec.split('&') subs = subs[1:] for sub in subs: fields = sub.split() cap = fields[0].lower() sub_report = getattr(nut_report, 'pec_%s_report' % cap) for field in fields[1:]: cfield, value = field.split(':') rfield = uncompress_pec_field(cfield) setattr(sub_report, rfield, int(value)) validator = PECReportValidator(sub_report) validator.errors.reset() try: validator.validate() except AttributeError as e: return resp_error('PEC_%s' % cap.upper(), error_start + e.__str__()) except: pass errors = validator.errors # return first error to user if errors.count() > 0: return resp_error('PEC_%s' % cap.upper(), error_start + errors.all()[0]) else: reports.append(sub_report) logger.info("Processing CONS") if cons_sec: subs = cons_sec.split('&') subs = subs[1:] for sub in subs: fields = sub.split() cap = fields[0].lower() logger.info(cap.upper()) for field in fields[1:]: cfield, value = field.split(':') rinpc, rfield = uncompress_cons_field(cfield) sub_report = getattr(getattr(nut_report, 'cons_%s_report' % cap), 'icr')(rinpc) setattr(sub_report, rfield, int(value)) if sub_report.valid and not sub_report in reports: reports.append(sub_report) logger.info("Processing ORDER") if order_sec: subs = order_sec.split('&') subs = subs[1:] for sub in subs: logger.info("\t%s" % sub) fields = sub.split() cap = fields[0].lower() for field in fields[1:]: cfield, value = field.split(':') rinpc, rfield = uncompress_cons_field(cfield) sub_report = getattr(getattr(nut_report, 'order_%s_report' % cap), 'icr')(rinpc) setattr(sub_report, rfield, int(value)) if not sub_report in reports: reports.append(sub_report) logger.info("Processing OTHER") if other_sec: fields = other_sec.split() for field in fields[1:]: cfield, value = field.split(':') rfield = uncompress_pec_field(cfield) sub_report = nut_report.pec_other_report setattr(sub_report, rfield, int(value)) # check validity relative to PEC if not sub_report.total == sub_report.nut_report.sum_all_other: return resp_error('OTHER_INT', REPORT_ERRORS['OTHER_INT']) else: reports.append(sub_report) # check validity of changes # save to DB @reversion.create_revision() @transaction.commit_manually def save_reports(reports, nut_report, provider=None): reversion.set_user(provider.user) reversion.set_comment("SMS report update") for report in reports: print("saving %s" % report) try: sub_report.save() except: transaction.rollback() return False try: nut_report._status = nut_report.STATUS_MODIFIED_AUTHOR nut_report.modified_by = provider nut_report.save() except: transaction.rollback() return False transaction.commit() return True logger.info("Saving reports") if not save_reports(reports, nut_report, provider): logger.warning("Unable to save reports") return resp_error('SRV', REPORT_ERRORS['SRV']) logger.info("Reports saved") ## CONFIRM RESPONSE confirm = "nut report-update ok %s" % nut_report.receipt message.respond(confirm) return True
def palu(message): # common start of error message error_start = u"Impossible d'enregistrer le rapport. " # create variables from text messages. try: args_names = ['kw1', 'username', 'password', 'month', 'year', \ 'u5_total_consultation_all_causes', \ 'u5_total_suspected_malaria_cases', \ 'u5_total_simple_malaria_cases', \ 'u5_total_severe_malaria_cases', \ 'u5_total_tested_malaria_cases', \ 'u5_total_confirmed_malaria_cases', \ 'u5_total_treated_malaria_cases', \ 'u5_total_inpatient_all_causes', \ 'u5_total_malaria_inpatient', \ 'u5_total_death_all_causes', \ 'u5_total_malaria_death', \ 'u5_total_distributed_bednets', \ 'o5_total_consultation_all_causes', \ 'o5_total_suspected_malaria_cases', \ 'o5_total_simple_malaria_cases', \ 'o5_total_severe_malaria_cases', \ 'o5_total_tested_malaria_cases', \ 'o5_total_confirmed_malaria_cases', \ 'o5_total_treated_malaria_cases', \ 'o5_total_inpatient_all_causes', \ 'o5_total_malaria_inpatient', \ 'o5_total_death_all_causes', \ 'o5_total_malaria_death', \ 'pw_total_consultation_all_causes', \ 'pw_total_suspected_malaria_cases', \ 'pw_total_severe_malaria_cases', \ 'pw_total_tested_malaria_cases', \ 'pw_total_confirmed_malaria_cases', \ 'pw_total_treated_malaria_cases', \ 'pw_total_inpatient_all_causes', \ 'pw_total_malaria_inpatient', \ 'pw_total_death_all_causes', \ 'pw_total_malaria_death', \ 'pw_total_distributed_bednets', \ 'pw_total_anc1', \ 'pw_total_sp1', \ 'pw_total_sp2', \ 'stockout_act_children', 'stockout_act_youth', 'stockout_act_adult', \ 'stockout_artemether', 'stockout_quinine', 'stockout_serum', \ 'stockout_bednet', 'stockout_rdt', 'stockout_sp'] args_values = message.content.strip().lower().split() arguments = dict(zip(args_names, args_values)) except ValueError: # failure to split means we proabably lack a data or more # we can't process it. message.respond(error_start + u" Le format du SMS est incorrect.") return True # convert form-data to int or bool respectively try: for key, value in arguments.items(): if key.split('_')[0] in ('u5', 'o5', 'pw', 'month', 'year'): arguments[key] = int(value) if key.split('_')[0] == 'stockout': arguments[key] = MalariaReport.YES if bool(int(value)) \ else MalariaReport.NO except: raise # failure to convert means non-numeric value which we can't process. message.respond(error_start + u" Les données sont malformées.") return True # check credentials try: provider = Provider.active.get(user__username=arguments['username']) except Provider.DoesNotExist: message.respond(error_start + u"Ce nom d'utilisateur " + u"(%s) n'existe pas." % \ arguments['username']) return True if not provider.check_password(arguments['password']): message.respond(error_start + u"Votre mot de passe est incorrect.") return True # now we have well formed and authenticated data. # let's check for business-logic errors. # create a data holder for validator data_browser = MalariaDataHolder() # feed data holder with sms provided data for key, value in arguments.items(): if key.split('_')[0] in ('u5', 'o5', 'pw', \ 'stockout', 'year', 'month'): data_browser.set(key, value) # feed data holder with guessable data try: hc = entity_for(provider).slug except: hc = None data_browser.set('hc', hc) today = datetime.date.today() data_browser.set('fillin_day', today.day) data_browser.set('fillin_month', today.month) data_browser.set('fillin_year', today.year) data_browser.set('author', provider.name()) # create validator and fire validator = MalariaReportValidator(data_browser) validator.errors.reset() try: validator.validate() except AttributeError as e: message.respond(error_start + e.__str__()) return True errors = validator.errors # return first error to user if errors.count() > 0: message.respond(error_start + errors.all()[0]) return True # create the report try: period = MonthPeriod.find_create_from(year=data_browser.get('year'), \ month=data_browser.get('month')) entity = Entity.objects.get(slug=data_browser.get('hc'), \ type__slug='cscom') report = MalariaReport.start(period, entity, provider, \ type=MalariaReport.TYPE_SOURCE) report.add_underfive_data(*data_browser.data_for_cat('u5')) report.add_overfive_data(*data_browser.data_for_cat('o5')) report.add_pregnantwomen_data(*data_browser.data_for_cat('pw')) report.add_stockout_data(*data_browser.data_for_cat('so')) #report.save() with reversion.create_revision(): report.save() reversion.set_user(provider.user) except Exception as e: message.respond(error_start + u"Une erreur technique s'est " \ u"produite. Reessayez plus tard et " \ u"contactez ANTIM si le probleme persiste.") logger.error(u"Unable to save report to DB. Message: %s | Exp: %r" \ % (message.content, e)) return True message.respond(u"[SUCCES] Le rapport de %(cscom)s pour %(period)s " u"a ete enregistre. " \ u"Le No de recu est #%(receipt)s." \ % {'cscom': report.entity.display_full_name(), \ 'period': report.period, \ 'receipt': report.receipt}) try: to = contact_for(report.entity.parent).phone_number except: to = None if not to: return True send_sms(to, u"[ALERTE] Le CSCom %(cscom)s vient d'envoyer le " \ u"rapport #%(receipt)s pour %(period)s." \ % {'cscom': report.entity.display_full_name(), \ 'period': report.period, \ 'receipt': report.receipt}) return True
def data_browser(request, entity_code=None, period_str=None): context = {'category': 'raw_data'} web_provider = request.user.get_profile() root = web_provider.first_target() period = None entity = None # find period from string or default to current reporting if period_str: try: period = MonthPeriod.find_create_from(year=int(period_str[-4:]), \ month=int(period_str[:2]), \ dont_create=True) except: pass if not period: period = current_reporting_period() # find entity or default to provider target # raise 404 on wrong provided entity code if entity_code: entity = get_object_or_404(Entity, slug=entity_code) if not entity: entity = web_provider.first_target() context.update({'entity': entity}) # check permissions on this entity and raise 403 provider_can_or_403('can_view_raw_data', web_provider, entity) # build entities browser context.update({'root': root, \ 'paths': entities_path(root, entity)}) # build periods list all_periods = raw_data_periods_for(entity) if period_str and not period in all_periods: raise Http404(_(u"No report for that period")) try: # get validated report for that period and location report = MalariaReport.validated.get(entity=entity, period=period) except MalariaReport.DoesNotExist: # district users need to be able to see the generated report # which have been created based on their validations/data. # if a district is looking at its root district and report exist # but not validated, we show it (with period) and no valid flag if web_provider.first_role().slug == 'district' and root == entity: try: report = MalariaReport.unvalidated.get(entity=entity, \ period=period) if not period in all_periods: all_periods.insert(0, period) except: report = None else: report = None # send period variables to template context.update({'periods': [(p.middle().strftime('%m%Y'), p.middle()) \ for p in all_periods], \ 'period': period}) if report: context.update({'report': report}) form = MalariaReportForm(instance=report) context.update({'form': form}) else: context.update({'no_report': True}) return render(request, 'raw_data.html', context)
def indicator_browser(request, entity_code=None, period_str=None, \ section_index='1', sub_section=None): context = {'category': 'indicator_data'} web_provider = request.user.get_profile() root = web_provider.first_target() periods = [] speriod = eperiod = None entity = None #section_index = int(section_index) - 1 # find entity or default to provider target # raise 404 on wrong provided entity code if entity_code: entity = get_object_or_404(Entity, slug=entity_code) if not entity: entity = web_provider.first_target() context.update({'entity': entity}) # define a list of all possible periods. # this is the list of all existing MonthPeriod anterior to current def all_anterior_periods(period): return MonthPeriod.objects\ .filter(start_on__lte=period.start_on)\ .order_by('start_on') all_periods = all_anterior_periods(current_reporting_period()) # retrieve Periods from string # if period_string include innexistant periods -> 404. if period_str: speriod_str, eperiod_str = period_str.split('-') try: speriod = MonthPeriod.find_create_from( year=int(speriod_str[-4:]), month=int(speriod_str[:2]), dont_create=True) eperiod = MonthPeriod.find_create_from( year=int(eperiod_str[-4:]), month=int(eperiod_str[:2]), dont_create=True) # loop on Period.next() from start one to end one. period = speriod while period.middle() <= eperiod.middle(): periods.append(period) period = period.next() except: raise Http404(_(u"Requested period interval (%(period_str)s) " u"includes inexistant periods.") % {'period': period_str}) # in case user did not request a specific interval # default to current_reporting_period if not speriod or not eperiod: speriod = eperiod = current_reporting_period() periods = [speriod] # if end period is before start period, redirect to opposite if eperiod.middle() < speriod.middle(): return redirect('indicator_data', entity_code=entity.slug, period_str='%s-%s' % (eperiod.pid, speriod.pid)) # periods variables context.update({'period_str': '%s-%s' % (speriod.pid, eperiod.pid), 'speriod': speriod, 'eperiod': eperiod}) context.update({'periods': [(p.pid, p.middle()) for p in periods], 'all_periods': [(p.pid, p.middle()) for p in all_periods]}) # check permissions on this entity and raise 403 provider_can_or_403('can_view_indicator_data', web_provider, entity) # build entities browser context.update({'root': root, \ 'paths': entities_path(root, entity)}) # from pnlp_core.indicators import INDICATOR_SECTIONS # context.update({'sections': \ # sorted(INDICATOR_SECTIONS.values(), \ # cmp=lambda a, b: int(a['id'].strip('a').strip('b')) \ # - int(b['id'].strip('a').strip('b')))}) # try: # section = INDICATOR_SECTIONS[section_index] # if not sub_section: # if len(section['sections']): # sub_section = section['sections'].keys()[0] # sname = 'pnlp_core.indicators.section%s' % section_index.__str__() # if sub_section: # sname = '%s_%s' % (sname, sub_section.__str__()) # sm = import_path(sname) # except: # raise # raise Http404(_(u"This section does not exist.")) # section 1 specifics if section_index == '1': context.update({'contact': contact_for(entity)}) # context.update({'section': section, 'sub_section': sub_section}) context.update({'section': {}, 'sub_section': sub_section}) # context.update({'widgets': [widget(entity=entity, periods=periods) \ # for widget in sm.WIDGETS]}) return render(request, 'indicator_data.html', context)
def add_last_period(request): """ Add the last period string """ last_period = MonthPeriod.find_create_by_date(date.today()).previous().middle().strftime('%m-%Y') return {'last_period': last_period}
def current_period(): """ Period of current date """ return MonthPeriod.find_create_by_date(date.today())
def nut_report(message, args, sub_cmd, **kwargs): """ Client sent report for PEC CONS & ORDER Once the PEC MAM/SAM/SAM+ & CONS & ORDER is filled, all the data is sent via one single multipart SMS. SMS is divided in sections and sub sections #P #C #O respectively PEC, CONS and ORDER We don't combine sections in case we'll have to split message in different SMS. SMS can be 1000chars+ Sub sections for capabilities: &MAM, &SAM &SAMP Sub sub sections for age break downs |u6 |u59 |o59 |pw |fu1 |fu12 > nut report rgaudin 89080392890 1111 #P&MAM|u59 6817 7162 2164 1033 6527 5715 6749 2174 4201 3675 8412 2331 4868 4765 1896 2107 3457 6308 6238 6589 2432 5983 3871|pw 6817 7162 2164 1033 6527 5715 6749 2174 4201 3675 8412 2331 4868 4765 1896 2107 3457 6308 6238 6589 2432 5983 3871|fu12 6817 7162 2164 1033 6527 5715 6749 2174 4201 3675 8412 2331 4868 4765 1896 2107 3457 6308 6238 6589 2432 5983 3871&SAM|u59 6817 7162 2164 1033 6527 5715 6749 2174 4201 3675 8412 2331 4868 4765 1896 2107 3457 6308 6238 6589 2432 5983 3871|o59 6817 7162 2164 1033 6527 5715 6749 2174 4201 3675 8412 2331 4868 4765 1896 2107 3457 6308 6238 6589 2432 5983 3871|fu1 6817 7162 2164 1033 6527 5715 6749 2174 4201 3675 8412 2331 4868 4765 1896 2107 3457 6308 6238 6589 2432 5983 3871#C&MAM|csb 1199 1199 1199 1199|unimix 1199 1199 1199 1199|oil 1199 1199 1199 1199|sugar 1199 1199 1199 1199|mil 1199 1199 1199 1199|niebe 1199 1199 1199 1199&SAM|plumpy 1199 1199 1199 1199#O&MAM|csb 1199|unimix 1199|oil 1199|sugar 1199|mil 1199|niebe 1199&SAM|plumpy 1199#T 1 2 3-EOM- T lwb tb hiv < nut report error Error-code | Error Message < nut report ok #P$MAM GA1/gao-343-VO5$SAM GA1/gao-343-VO5#C$MAM GA1/gao-343-VO5$SAM GA1/gao-343-VO5#O$MAM GA1/gao-343-VO5$SAM GA1/gao-343-VO5 """ def resp_error(code, msg): # make sure we cancel whatever addition message.respond(u"nut report error %(code)s|%(msg)s" \ % {'code': code, 'msg': msg}) return True def provider_entity(provider): """ Entity a Provider is attached to """ try: return NUTEntity.objects.get(id=provider.first_access().target.id) except: return None def sub_sections_from_section(section): """ Returns an organised hash from raw string {'mam': {'u6': 'xx xx xx', 'o59': 'xx xx xx'}, 'sam': {}} """ subs = section.split('&') subs = subs[1:] subsh = {} for sub in subs: sub_data = sub.split('|') subh = {} for age_line in sub_data[1:]: age_ls = age_line.split() subh[age_ls[0]] = ' '.join(age_ls[1:]) subsh[sub_data[0]] = subh return subsh def check_capabilities(section, entity): """ return True if section's subs matches entity cap """ for cap in ('mam', 'sam', 'samp'): if getattr(entity, 'is_%s' % cap): if not cap in section.keys(): return False else: if cap in section.keys(): return False return True @reversion.create_revision() @transaction.commit_manually def save_reports(reports, user=None): reversion.set_user(provider.user) reversion.set_comment("SMS transmitted report") # save main first reports['main'].save() for secid, section in reports.items(): if secid == 'main': continue for catid, reports in section.items(): for report in reports: logger.info("%s > %s > %s" \ % (secid, catid, report.__class__)) try: # HACK: write foreign key id if needed if hasattr(report, 'nut_report_id'): report.nut_report_id = report.nut_report.id if hasattr(report, 'cons_report_id'): report.cons_report_id = report.cons_report.id if hasattr(report, 'order_report_id'): report.order_report_id = report.order_report.id report.save() except Exception as e: logger.error(u"Unable to save report to DB. " \ u"Message: %s | Exp: %r" \ % (message.content, e)) transaction.rollback() return False transaction.commit() return True # check that all parts made it together if not args.strip().endswith('-eom-'): return resp_error('BAD_FORM', REPORT_ERRORS['BAD_FORM']) else: args = args.strip()[:-5].strip() # split up sections try: infos, pec_sec, cons_sec, order_sec, other_sec = \ args.strip().lower().split('#') pec_sec = pec_sec[1:] cons_sec = cons_sec[1:] order_sec = order_sec[1:] other_sec = other_sec[1:] except: return resp_error('BAD_FORM', REPORT_ERRORS['BAD_FORM']) # split up infos try: username, pwhash, date_str = infos.strip().split() except: return resp_error('BAD_FORM_INFO', REPORT_ERRORS['BAD_FORM_INFO']) # get Provider based on username try: provider = Provider.objects.get(user__username=username) except Provider.DoesNotExist: return resp_error('NO_ACC', REPORT_ERRORS['NO_ACC']) # check that provider pwhash is good if not provider.check_hash(pwhash): return resp_error('BAD_PASS', REPORT_ERRORS['BAD_PASS']) # check that user is not disabled if not provider.is_active: return resp_error('ACC_DIS', REPORT_ERRORS['ACC_DIS']) # check that user has permission to submit report on entity entity = provider_entity(provider) if not entity: return resp_error('NOT_ENT', REPORT_ERRORS['NOT_ENT']) eentity = Entity.objects.get(id=entity.id) if not provider_can('can_submit_report', provider, eentity): return resp_error('NO_PERM', REPORT_ERRORS['NO_PERM']) # parse date and check if period is valid try: month = int(date_str[0:2]) year = int('%s%s' % ('20', date_str[2:4])) period = MonthPeriod.find_create_from(year=year, month=month) except: return resp_error('BAD_FORM_PERIOD', REPORT_ERRORS['BAD_FORM_PERIOD']) # check period is the one we want if not period == current_reporting_period(): return resp_error('BAD_PERIOD', REPORT_ERRORS['BAD_PERIOD']) # report receipts holder for confirm message #report_receipts = {} # reports holder for delayed database commit reports = {} # global infos infos = {'entity': entity, 'eentity': eentity, 'provider': provider, 'month': month, 'year': year, 'period': period, 'username': username, 'pwhash': pwhash} # UNIQUENESS if NutritionReport.objects.filter(period=infos['period'], entity=infos['entity'], type=Report.TYPE_SOURCE).count() > 0: return resp_error('UNIQ', REPORT_ERRORS['UNIQ']) # create main report try: period = MonthPeriod.find_create_from(year=year, month=month) nut_report = NutritionReport.start(period, entity, provider, type=Report.TYPE_SOURCE) reports['main'] = nut_report except Exception as e: #raise logger.error(u"Unable to save report to DB. Message: %s | Exp: %r" \ % (message.content, e)) return resp_error('SRV', REPORT_ERRORS['SRV']) # SECTIONS for sid, section in {'P': 'pec', 'C': 'cons', 'O': 'order', 'T': 'other'}.items(): logger.info("Processing %s" % section) # extract/split sub sections info from string if sid == 'T': sec = eval('%s_sec' % section) else: sec = sub_sections_from_section(eval('%s_sec' % section)) # check that capabilities correspond to entity if sid != 'T' and not check_capabilities(sec, entity): return resp_error('BAD_CAP', REPORT_ERRORS['BAD_CAP']) # call sub-report section handler sec_succ, sec_data = SUB_REPORTS.get(section)(message, sec, infos, reports, nut_report=nut_report) # cancel if sub report failed. if not sec_succ: logger.warning(u" FAILED.") return resp_error(sec_data[0], sec_data[1]) # add sub-report to list of reports reports[sid] = sec_data logger.info("---- Ended %s" % section) ## DB COMMIT # create the reports in DB # save receipts number logger.info("Saving reports") if not save_reports(reports, user=provider.user): logger.warning("Unable to save reports") return resp_error('SRV', REPORT_ERRORS['SRV']) logger.info("Reports saved") def flatten(iterable): values = [] def add(value): if not isinstance(value, (list, dict)): values.append(value) return True return False if not add(iterable): miterable = iterable.values() if isinstance(iterable, dict) \ else iterable for item in miterable: values += flatten(item) return values # for report in flatten(reports): # with reversion.create_revision(): # reversion.set_user(provider.user) # reversion.set_comment("SMS transmitted report") # report.save() ## CONFIRM RESPONSE confirm = "nut report ok %s" % nut_report.receipt message.respond(confirm) return True ## TRIGGER ALERT """
def data_browser(request, entity_code=None, period_str=None): context = {'category': 'raw_data'} web_provider = request.user.get_profile() root = web_provider.first_target() period = None entity = None # find period from string or default to current reporting if period_str: try: period = MonthPeriod.find_create_from(year=int(period_str[-4:]), month=int(period_str[:2]), dont_create=True) except: pass if not period: period = current_reporting_period() # find entity or default to provider target # raise 404 on wrong provided entity code if entity_code: entity = get_object_or_404(Entity, slug=entity_code) if not entity: entity = web_provider.first_target() context.update({'entity': entity}) # check permissions on this entity and raise 403 provider_can_or_403('can_view_raw_data', web_provider, entity) # build entities browser context.update({'root': root, \ 'paths': entities_path(root, entity)}) # build periods list all_periods = raw_data_periods_for(entity) if period_str and not period in all_periods: raise Http404(_(u"No report for that period")) try: # get validated report for that period and location report = NutritionReport.validated.get(entity=entity, period=period) except NutritionReport.DoesNotExist: # district users need to be able to see the generated report # which have been created based on their validations/data. # if a district is looking at its root district and report exist # but not validated, we show it (with period) and no valid flag if web_provider.first_role().slug == 'district' and root == entity: try: report = NutritionReport.unvalidated.get(entity=entity, period=period) if not period in all_periods: all_periods.insert(0, period) except: report = None else: report = None # send period variables to template context.update({'periods': [(p.middle().strftime('%m%Y'), p.middle()) \ for p in all_periods], \ 'period': period}) if report: context.update({'report': report}) #form = MalariaReportForm(instance=report) form = {} context.update({'form': form}) else: context.update({'no_report': True}) return render(request, 'raw_data.html', context)
except: return resp_error_dob(message) # reccord date try: reccord_date, _reccord_date = parse_age_dob(reccord_date) except: return resp_error_date(message) try: date_is_old(reccord_date) except ValueError, e: message.respond(u"[ERREUR] %s" % e) return True MonthPeriod.find_create_from(year=reccord_date.year, month=reccord_date.month) # Date of Death, YYYY-MM-DD try: dod = parse_age_dob(dod_text, True) except: return resp_error_dod(message) # Place of death, entity code try: death_location = Entity.objects.get(slug=death_location_code) except Entity.DoesNotExist: return resp_error_death_location(message, death_location_code) # Nb of living children try:
def handle(self, *args, **options): current_period = MonthPeriod.find_create_by_date(date.today()) now = datetime.now() # find our date of first report (begining of activities) first_report = date.today() try: child = ChildrenMortalityReport.objects.all().order_by('dod')[0].dod except: child = None try: mat = MaternalMortalityReport.objects.all().order_by('dod')[0].dod except: mat = None try: preg = PregnancyReport.objects.all().order_by('creatd_on')[0].creatd_on except: preg = None try: bir = BirthReport.objects.all().order_by('creatd_on')[0].created_on except: bir = None try: commod = RHCommoditiesReport.objects.all().order_by('period')[0].period.start_on commod = date(commod.year, commod.month, commod.day) except: commod = None if child: first_report = child if mat and mat < first_report: first_report = mat if preg and preg < first_report: first_report = preg if bir and bir < first_report: first_report = bir if commod and commod < first_report: first_report = commod first_period = MonthPeriod.find_create_by_date(first_report) for year in range(first_period.start_on.year, current_period.end_on.year + 1): # create year y = YearPeriod.find_create_from(year) print(y) # create quarter for quarter in y.quarters_: if quarter.start_on > now: break quarter.save() print(u"\t%s" % quarter) # create months: for month in y.months: if month.start_on > now: break month.save() print(u"\t\t%s" % month) # create weeks for week in month.weeks: if week.start_on > now: break week.save() print(u"\t\t\t%s" % week)