def dashboard(request, entity_uuid=None, indicator_slug=None, period_str=None, *args, **kwargs): context = {'page': 'dashboard'} # entity context.update(process_entity_filter(request, entity_uuid)) root = context['entity'] if context['entity'] else Entity.get_root() context.update(process_period_filter(request, period_str, 'period')) if context['period'] is None: context['period'] = MonthPeriod.current().previous() all_indicators = Indicator.get_all_sorted() # Indicator.get_all_routine() indicator = Indicator.get_or_none(indicator_slug) context.update({ 'root': root, 'completeness': OrderedDict([ (child, get_cached_data('completeness', dps=child, period=context['period'], indicator=indicator)) for child in root.get_children() ]), 'indicators': all_indicators, 'indicator': indicator, 'lineage': [Entity.PROVINCE] }) # totals context.update({ 'mean_completeness': numpy.mean( [e['completeness'] for e in context['completeness'].values()]), 'mean_promptness': numpy.mean( [e['promptness'] for e in context['completeness'].values()]), }) # evolution of pw_anc_receiving_sp3 pwsp3 = get_timed_records(Indicator.get_by_number(59), root, context['all_periods']) perioda = context['all_periods'][0] periodb = context['all_periods'][-1] context.update({ 'sp3_title': "{num} : {name} entre {pa} et {pb}" .format(num=pwsp3['indicator'].number, name=pwsp3['indicator'].name, pa=perioda.strid, pb=periodb.strid), 'sp3_fname': "palu-evol-sp3-_{pa}_{pb}" .format(pa=perioda.strid, pb=periodb.strid), 'sp3_categories': [p[1].name for p in pwsp3['periods']], 'sp3_series': [{'name': pwsp3['indicator'].name, 'data': pwsp3['points']} ], }) return render(request, kwargs.get('template_name', 'dashboard.html'), context)
def png_map_for(request, perioda_str, periodb_str, entity_name, indicator_number, with_title=True, with_legend=True): entity = Entity.get_by_short_name(entity_name) if entity is None: raise Http404( _("Unknown entity with name `{u}`").format(u=entity_name)) if perioda_str is None and periodb_str is None \ and indicator_number is None: periods = None indicator = None with_title = False fname = "initial.png" else: with_title = True perioda = process_period_filter(request, perioda_str, 'perioda').get('perioda') periodb = process_period_filter(request, periodb_str, 'periodb').get('periodb') periods = MonthPeriod.all_from(perioda, periodb) if not len(periods): raise Http404( _("Unknown period interval `{pa}` `{pb}`").format( pa=perioda_str, pb=periodb_str)) indicator = Indicator.get_by_number(indicator_number) if indicator is None: raise Http404( _("Unknown indicator `{s}`").format(s=indicator_number)) fname = fname_for(entity, periods, indicator) fpath = os.path.join('png_map', fname) abspath = os.path.join(settings.EXPORT_REPOSITORY, fpath) if not os.path.exists(abspath): try: gen_map_for(entity, periods, indicator, save_as=abspath, with_title=with_title, with_index=with_title) except IOError: logger.error("Missing map png folder in exports.") raise # return redirect('export', fpath=fpath) return serve_exported_files(request, fpath=fpath)
def png_map_for(request, perioda_str, periodb_str, entity_name, indicator_number, with_title=True, with_legend=True): entity = Entity.get_by_short_name(entity_name) if entity is None: raise Http404(_("Unknown entity with name `{u}`") .format(u=entity_name)) if perioda_str is None and periodb_str is None \ and indicator_number is None: periods = None indicator = None with_title = False fname = "initial.png" else: with_title = True perioda = process_period_filter( request, perioda_str, 'perioda').get('perioda') periodb = process_period_filter( request, periodb_str, 'periodb').get('periodb') periods = MonthPeriod.all_from(perioda, periodb) if not len(periods): raise Http404(_("Unknown period interval `{pa}` `{pb}`") .format(pa=perioda_str, pb=periodb_str)) indicator = Indicator.get_by_number(indicator_number) if indicator is None: raise Http404(_("Unknown indicator `{s}`") .format(s=indicator_number)) fname = fname_for(entity, periods, indicator) fpath = os.path.join('png_map', fname) abspath = os.path.join(settings.EXPORT_REPOSITORY, fpath) if not os.path.exists(abspath): try: gen_map_for(entity, periods, indicator, save_as=abspath, with_title=with_title, with_index=with_title) except IOError: logger.error("Missing map png folder in exports.") raise # return redirect('export', fpath=fpath) return serve_exported_files(request, fpath=fpath)
def read_xls(filepath, partner): if not partner.can_upload: raise UploadPermissionDenied(_("{user} is not allowed to submit data") .format(user=partner)) try: wb = load_workbook(filepath, data_only=True) except InvalidFileException: raise IncorrectExcelFile(_("Not a proper XLSX Template.")) ws = wb.active nb_rows = len(ws.rows) cd = lambda row, column: ws.cell(row=row, column=column).value # data holder data = { 'errors': [], } # record now's time to compare with delays submited_on = timezone.now() def add_error(row, column=None, indicator=None, error=None, text=None): data['errors'].append({ 'row': row, 'column': column, 'indicator': Indicator.get_or_none(indicator.slug) if indicator else None, 'slug': error, 'text': text, }) # retrieve and store default year/month default_year_addr = "=$C$4" default_month_addr = "=$D$4" try: default_year = int(float(cd(4, 3))) except: default_year = None try: default_month = int(float(cd(4, 4))) except: default_month = None for row in range(5, nb_rows + 1): row_has_data = sum([1 for x in ws.rows[row - 1][4:] if x.value]) if not row_has_data: continue rdc = Entity.get_root() dps = Entity.find_by_stdname(cd(row, 1), parent=rdc) if dps is None: logger.warning("No DPS for row #{}".format(row)) continue # no DPS, no data zs = Entity.find_by_stdname(cd(row, 2), parent=dps) if zs is None: if cd(row, 2).lower().strip() != "-": logger.warning("No ZS for row #{}".format(row)) continue # no ZS, no data else: entity = dps else: entity = zs # check upload location authorization if partner.upload_location not in entity.get_ancestors(): add_error(row, error='permission_denied', text=_("You can't submit data for " "that location ({entity})") .format(entity=entity)) continue # retrieve period year_str = cd(row, 3) if year_str == default_year_addr: year = default_year else: try: year = int(float(year_str)) except: year = None month_str = cd(row, 4) if month_str == default_month_addr: month = default_month else: try: month = int(float(month_str)) except: month = None if year is None or month is None: logger.warning("No year or month for row #{}".format(row)) add_error(row, error='incorrect_period', text=_("Missing year or month at row {row}") .format(row)) continue try: period = MonthPeriod.get_or_create(year, month) except ValueError as e: logger.warning("Unable to retrieve period: {}".format(e)) add_error(row, error='incorrect_period', text=_("Unable to retrieve period for {y}/{m}") .format(y=year, m=month)) continue for idx, cell in enumerate(ws.rows[2][4:]): if idx % 3 != 0: continue # skip empty merged cols column = letter_to_column(cell.column) try: number = cell.value.split('-')[0].strip() except: # the header doesn't respect the format # better fail everything raise IncorrectExcelFile(_("Not a proper XLSX Template.")) num = cd(row, column) denom = cd(row, column + 1) # skip if missing numerator if num is None: # logger.debug("No numerator for indic #{}".format(number)) continue indicator = Indicator.get_by_number(number) # not an expected number if indicator is None: logger.warning("No indicator found at col #{}".format(column)) add_error(row, column=cell.column, error='incorrect_indicator', text=_("Unable to match an Indicator at col {col}") .format(col=cell.column)) continue # ensure level of data submitted depending on type if indicator.collection_type == indicator.SURVEY: # data must be DPS if not entity.is_dps: logger.warning("Data for Survey Indic on non-DPS #{}" .format(cell.coordinate)) add_error(row, column=cell.column, error='incorect_level', text=_("Survey indicator require DPS data")) continue elif indicator.collection_type == indicator.ROUTINE: # data must be ZS if not entity.is_zs: logger.warning("Data for Routine Indic on non-ZS #{}" .format(cell.coordinate)) add_error(row, column=cell.column, error='incorect_level', text=_("Routine indicator require ZS data")) continue # check submission period for that Indicator if not indicator.can_submit_on(on=submited_on, period=period): logger.warning("{on} is not a valid submission time " "for {ind} {period}" .format(on=submited_on, ind=indicator, period=period)) add_error(row, column=cell.column, indicator=indicator, error='outside_submussion_delay', text=_("{on} is outside submission period " "for Indicator #{ind} at {period}") .format(on=submited_on.strftime('%d-%m-%Y'), ind=indicator.number, period=period)) continue if not indicator.is_number and denom is None: logger.warning("No denominator for indic #{}".format(number)) add_error(row, column=cell.column, error='missing_denominator', text=_("Missing denominator on " "non-number Indicator")) continue elif indicator.is_number: denom = 1 try: num = float(num) denom = float(denom) except: add_error(row, column=cell.column, error='incorrect_value', indicator=indicator, text=_("Incorrect value for numerator " "or denominator `{num} / {denom}`") .format(num=num, denom=denom)) continue data.update({data_ident_for(indicator, period, entity): { 'slug': indicator.slug, 'period': period, 'entity': entity, 'numerator': num, 'denominator': denom}}) return data
def dashboard(request, entity_uuid=None, indicator_slug=None, period_str=None, *args, **kwargs): context = {'page': 'dashboard'} # entity context.update(process_entity_filter(request, entity_uuid)) root = context['entity'] if context['entity'] else Entity.get_root() context.update(process_period_filter(request, period_str, 'period')) if context['period'] is None: context['period'] = MonthPeriod.current().previous() all_indicators = Indicator.get_all_sorted() # Indicator.get_all_routine() indicator = Indicator.get_or_none(indicator_slug) context.update({ 'root': root, 'completeness': OrderedDict([(child, get_cached_data('completeness', dps=child, period=context['period'], indicator=indicator)) for child in root.get_children()]), 'indicators': all_indicators, 'indicator': indicator, 'lineage': [Entity.PROVINCE] }) # totals context.update({ 'mean_completeness': numpy.mean( [e['completeness'] for e in context['completeness'].values()]), 'mean_promptness': numpy.mean([e['promptness'] for e in context['completeness'].values()]), }) # evolution of pw_anc_receiving_sp3 pwsp3 = get_timed_records(Indicator.get_by_number(59), root, context['all_periods']) perioda = context['all_periods'][0] periodb = context['all_periods'][-1] context.update({ 'sp3_title': "{num} : {name} entre {pa} et {pb}".format( num=pwsp3['indicator'].number, name=pwsp3['indicator'].name, pa=perioda.strid, pb=periodb.strid), 'sp3_fname': "palu-evol-sp3-_{pa}_{pb}".format(pa=perioda.strid, pb=periodb.strid), 'sp3_categories': [p[1].name for p in pwsp3['periods']], 'sp3_series': [{ 'name': pwsp3['indicator'].name, 'data': pwsp3['points'] }], }) return render(request, kwargs.get('template_name', 'dashboard.html'), context)