Beispiel #1
0
    def action(self):
        """ Send every reporter with an action left to do a reminder """

        today = date.today()

        level = self.args.level
        if not level:
            return False

        logger.info(u"Level: %s" % level)

        if level == 'cscom':
            message = u"[PNLP] Votre rapport mensuel paludisme est " \
                      u"attendu au plus tard le %(date)s" \
                      % {'date': date(today.year, \
                                      today.month, 5).strftime('%x')}
            for cscom in mobile_entity_gen(cscom_without_report(self.args.period)):
                contact = contact_for(cscom, recursive=False)
                if not contact or not contact.phone_number:
                    continue
                # CSCOM: only cellphone transmiting ones.
                if not cscom.parent.slug in ('nion', 'maci'):
                    continue

                logger.info(u"Sending cscom text to %s" % contact.phone_number)
                send_sms(to=contact.phone_number, text=message)

            # end of CSCom section
            return

        for stat in level_statistics(self.args.period, level).values():

            contact = contact_for(stat['entity'], recursive=False)

            if not contact or not contact.phone_number:
                continue

            # nothing waiting validation.
            if not stat['unval']:
                continue

            logger.info(u"Sending %s text to %s" \
                        % (level, contact.phone_number))

            dom = 15 if level == 'district' else 25

            message = u"[PNLP] Vous avez %(unval)d rapports a valider " \
                      u"au plus tard le %(date)s." \
                      % {'unval': stat['unval'], \
                         'date': date(today.year, \
                                      today.month, dom).strftime('%x')}
            email_title = u"[PNLP] Rapports a valider"
            # send_sms(to=contact.phone_number, text=message)
            if not contact.email:
                continue
            sent, sent_message = send_email(recipients=contact.email,
                       message=message, title=email_title)
Beispiel #2
0
    def action(self):
        """ send SMS to non-sender and to districts

            Non-sending CSCom will receive a message saying they missed.
            District will be reminded they have reports to validate
            and non-sending cscom if applicable """

        # send an SMS to non-reporting CSCOM.
        message = u"[PNLP] Vous n'avez pas envoye votre rapport mensuel." \
                    " Il est desormais trop tard pour l'envoyer. " \
                    "Vos donnees ne seront donc pas integrees."
        for contact in [contact_for(entity, recursive=False) \
                        for entity in mobile_entity_gen(self.get_bad_cscom())]:
            if not contact or not contact.phone_number:
                continue

            send_sms(to=contact.phone_number, text=message)

        # send an SMS to districts:
        # 1. those with non-validated reports.
        # 2. those with non-reporting cscom.
        for dis, e in self.get_all_district().items():

            contact = contact_for(e['entity'], recursive=False)

            if not contact or not contact.phone_number:
                continue

            # already received everything and validated.
            # congrats, we won't bug you buddy.
            if e['unval'] == 0 and e['unsent'] == 0:
                continue

            if e['unval']:
                msg_unval = u"%(nb)s de vos CSCom ont envoye leur " \
                            u"rapport. Vous devez les valider avant le 15." \
                            % {'nb': e['unval']}
            else:
                msg_unval = u""

            if e['unsent']:
                msg_unsent = u"%(nb)s n'ont pas envoye leur rapport " \
                             u"mensuel dans les temps!" % {'nb': e['unsent']}
            else:
                msg_unsent = u""

            # add space before second sentence if both
            if e['unval'] and e['unsent']:
                msg_unsent = u" %s" % msg_unsent

            message = u"[PNLP] %(unval)s%(unsent)s" \
                      % {'unval': msg_unval, 'unsent': msg_unsent}

            send_sms(to=contact.phone_number, text=message)
Beispiel #3
0
def validation_list(request):
    context = {'category': 'validation'}
    web_provider = request.user.get_profile()

    entity = provider_entity(web_provider)
    period = current_reporting_period()

    # check permission or raise 403
    # should never raise as already checked by decorator
    provider_can_or_403('can_validate_report', web_provider, entity)

    not_sent = [(ent, contact_for(ent)) \
                for ent in get_not_received_reports(entity, period)]

    context.update({'not_validated': get_reports_to_validate(entity, period),
                    'validated': get_validated_reports(entity, period),
                    'not_sent': not_sent})

    context.update({'is_complete': context['validated'].__len__() == \
                                   entity.get_children().__len__(),
                    'is_idle': context['not_validated'].__len__() == 0 \
                               and context['not_sent'].__len__() > 0})

    context.update({'time_cscom_over': time_cscom_over(), \
                    'time_district_over': time_district_over(), \
                    'time_region_over': time_region_over()})

    context.update({'validation_over': not time_can_validate(entity)})

    context.update({'current_period': current_period(), \
                    'current_reporting_period': period})

    return render(request, 'validation_list.html', context)
Beispiel #4
0
def validation_list(request):
    context = {'category': 'validation'}
    web_provider = request.user.get_profile()

    entity = provider_entity(web_provider)
    period = current_reporting_period()

    # check permission or raise 403
    # should never raise as already checked by decorator
    provider_can_or_403('can_validate_report', web_provider, entity)

    not_sent = [(ent, contact_for(ent)) \
                for ent in get_not_received_reports(entity, period)]

    context.update({
        'not_validated': get_reports_to_validate(entity, period),
        'validated': get_validated_reports(entity, period),
        'not_sent': not_sent
    })

    context.update({'is_complete': context['validated'].__len__() == \
                                   entity.get_children().__len__(),
                    'is_idle': context['not_validated'].__len__() == 0 \
                               and context['not_sent'].__len__() > 0})

    context.update({'time_cscom_over': time_cscom_over(), \
                    'time_district_over': time_district_over(), \
                    'time_region_over': time_region_over()})

    context.update({'validation_over': not time_can_validate(entity)})

    context.update({'current_period': current_period(), \
                    'current_reporting_period': period})

    return render(request, 'validation_list.html', context)
Beispiel #5
0
def nb_reports_for(entity, period):
    nb_rec = MalariaReport.objects.filter(entity__parent=entity,
                                          period=period).count()
    next_period = period.next()
    if entity.type.slug == 'district':
        nb_ent = entity.get_children().count()
        incoming_sms = None
        all_sms = None
    else:
        nb_ent = 1
        number = contact_for(entity, True).phone_number
        if not number is None and number.startswith('+223'):
            number = '+223' + number
        incoming_sms = Inbox.objects.filter(receivingdatetime__gte=next_period.start_on,
                                            receivingdatetime__lte=next_period.end_on,
                                            sendernumber=number)
        sent_sms = SentItems.objects.filter(sendingdatetime__gte=next_period.start_on,
                                           sendingdatetime__lte=next_period.end_on,
                                           destinationnumber=number)
        if incoming_sms.count() != sent_sms.count():
            all_sms = list(incoming_sms) + list(sent_sms)
        else:
            all_sms = sent_sms

    percent = float(nb_rec) / nb_ent
    return {'entity': entity, 'nb_received': nb_rec,
            'nb_expected': nb_ent,
            'received_rate': percent,
            'incoming_sms': incoming_sms,
            'all_sms': all_sms}
Beispiel #6
0
def nb_reports_for(entity, period):
    nb_rec = MalariaReport.objects.filter(entity__parent=entity,
                                          period=period).count()
    next_period = period.next()
    if entity.type.slug == 'district':
        nb_ent = entity.get_children().count()
        incoming_sms = None
        all_sms = None
    else:
        nb_ent = 1
        number = contact_for(entity, True).phone_number
        if not number is None and number.startswith('+223'):
            number = '+223' + number
        incoming_sms = Inbox.objects.filter(
            receivingdatetime__gte=next_period.start_on,
            receivingdatetime__lte=next_period.end_on,
            sendernumber=number)
        sent_sms = SentItems.objects.filter(
            sendingdatetime__gte=next_period.start_on,
            sendingdatetime__lte=next_period.end_on,
            destinationnumber=number)
        if incoming_sms.count() != sent_sms.count():
            all_sms = list(incoming_sms) + list(sent_sms)
        else:
            all_sms = sent_sms

    percent = float(nb_rec) / nb_ent
    return {
        'entity': entity,
        'nb_received': nb_rec,
        'nb_expected': nb_ent,
        'received_rate': percent,
        'incoming_sms': incoming_sms,
        'all_sms': all_sms
    }
Beispiel #7
0
def malitel_list(request):
    context = {'category': 'malitel'}
    entities = []
    for entity in Entity.objects.filter(Q(parent__slug='maci') | Q(parent__slug='nion')):
        pn = contact_for(entity).phone_number
        if '624175' in pn:
            entities.append({'name': entity, 'contact': pn})
    entities.sort(key=lambda x: x['contact'])
    context.update({'entities': entities})

    return render(request, 'malitel.html', context)
Beispiel #8
0
def malitel_list(request):
    context = {'category': 'malitel'}
    entities = []
    for entity in Entity.objects.filter(
            Q(parent__slug='maci') | Q(parent__slug='nion')):
        pn = contact_for(entity).phone_number
        if '624175' in pn:
            entities.append({'name': entity, 'contact': pn})
    entities.sort(key=lambda x: x['contact'])
    context.update({'entities': entities})

    return render(request, 'malitel.html', context)
Beispiel #9
0
 def entities_autoreports(level):
     districts_missed_report = {}
     auto_validated_cscom_reports = \
         MalariaReport.validated\
                      .filter(entity__type__slug=level, \
                              modified_by__user__username='******')
     for report in auto_validated_cscom_reports:
         if not report.entity.parent.slug in districts_missed_report:
             districts_missed_report[report.entity.parent.slug] = \
                 {'entity': report.entity.parent, \
                  'nbauto': 0, \
                  'contact': contact_for(report.entity.parent, False)}
         districts_missed_report[report.entity.parent.slug]['nbauto'] += 1
     return districts_missed_report
Beispiel #10
0
 def entities_autoreports(level):
     districts_missed_report = {}
     auto_validated_cscom_reports = \
         MalariaReport.validated\
                      .filter(entity__type__slug=level, \
                              modified_by__user__username='******')
     for report in auto_validated_cscom_reports:
         if not report.entity.parent.slug in districts_missed_report:
             districts_missed_report[report.entity.parent.slug] = \
                 {'entity': report.entity.parent, \
                  'nbauto': 0, \
                  'contact': contact_for(report.entity.parent, False)}
         districts_missed_report[report.entity.parent.slug]['nbauto'] += 1
     return districts_missed_report
Beispiel #11
0
    def action(self):
        """ send SMS to district/region for each new report """

        report = self.args.report

        # we have a district/cscom report
        logger.info(u"Report %s found." % report)

        contact = contact_for(report.entity.parent)

        message = u"[PNLP] Le rapport %(receipt)s de %(entity)s " \
                  u"a ete recu. Vous devez le valider." \
                  % {'receipt': report.receipt, 'entity': report.entity}

        # if contact.phone_number:
        #     send_sms(contact.phone_number, message)
        if contact.email:
            send_email(recipients=contact.email, message=message, \
                       title=u"[PNLP] Nouveau rapport recu!")
        else:
            send_email(settings.HOTLINE_EMAIL, message, \
                       u"[PNLP] Unable to send report notification " \
                       u"to %(contact)s" \
                       % {'contact': contact.name_access()})
Beispiel #12
0
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
Beispiel #13
0
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 = list(all_anterior_periods(current_reporting_period()).all())
    if not MalariaReport.validated.filter(entity=entity,
                                          period=current_reporting_period()) \
                                  .count():
        all_periods.remove(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({'widgets': [widget(entity=entity, periods=periods) \
                                for widget in sm.WIDGETS]})

    return render(request, 'indicator_data.html', context)
Beispiel #14
0
def dashboard(request):
    category = 'dashboard'
    context = {'category': category}

    from bolibana.models import Entity
    from pnlp_core.data import (current_period, current_stage, \
                                time_cscom_over, time_district_over, \
                                time_region_over)

    def sms_received_sent_by_period(period):
        received = Inbox.objects.filter(receivingdatetime__gte=period.start_on,
                                        receivingdatetime__lte=period.end_on) \
                                .count()
        sent = SentItems.objects.filter(sendingdatetime__gte=period.start_on,
                                        sendingdatetime__lte=period.end_on) \
                                .count()
        return (received, sent)

    def received_reports(period, type_):
        return MalariaReport.objects.filter(period=period, \
                                            entity__type__slug=type_)

    def reports_validated(period, type_):
        return MalariaReport.validated.filter(period=period, \
                                       entity__type__slug=type_)

    def reporting_rate(period, entity):
        return float(MalariaReport.validated.filter(period=period, \
                 entity__parent=entity).count()) \
        / Entity.objects.filter(parent__slug=entity.slug).count()

    current_period = current_period()
    period = current_reporting_period()

    context.update({'current_period': current_period,
                    'current_reporting_period': period,
                    'current_stage': current_stage(),
                    'current_sms': sms_received_sent_by_period(current_period),
                    'current_reporting_sms': \
                         sms_received_sent_by_period(period),
                    'total_cscom': Entity.objects\
                                         .filter(type__slug='cscom').count(),
                    'time_cscom_over': time_cscom_over(period),
                    'time_district_over': time_district_over(period),
                    'time_region_over': time_region_over(period)})

    received_cscom_reports = received_reports(period, 'cscom')
    cscom_reports_validated = reports_validated(period, 'cscom')
    district_reports_validated = reports_validated(period, 'district')
    reporting_rate = \
        float(MalariaReport.validated.filter(period=period).count()) \
        / Entity.objects.count()

    cscom_missed_report = \
        Entity.objects.filter(type__slug='cscom')\
                      .exclude(id__in=[r.entity.id \
                                       for r \
                                       in received_cscom_reports])\
                      .order_by('name')

    def entities_autoreports(level):
        districts_missed_report = {}
        auto_validated_cscom_reports = \
            MalariaReport.validated\
                         .filter(entity__type__slug=level, \
                                 modified_by__user__username='******')
        for report in auto_validated_cscom_reports:
            if not report.entity.parent.slug in districts_missed_report:
                districts_missed_report[report.entity.parent.slug] = \
                    {'entity': report.entity.parent, \
                     'nbauto': 0, \
                     'contact': contact_for(report.entity.parent, False)}
            districts_missed_report[report.entity.parent.slug]['nbauto'] += 1
        return districts_missed_report

    districts_missed_report = entities_autoreports('cscom')
    regions_missed_report = entities_autoreports('district')

    context.update({'received_cscom_reports': received_cscom_reports.count(),
                'cscom_reports_validated': cscom_reports_validated.count(),
              'district_reports_validated': district_reports_validated.count(),
                'reporting_rate': reporting_rate,
                'cscom_missed_report_count': cscom_missed_report.count(),
                'cscom_missed_report': [(e, contact_for(e, True)) \
                                        for e in cscom_missed_report[:20]],
                'districts_missed_report': districts_missed_report,
                'regions_missed_report': regions_missed_report})

    return render(request, 'dashboard.html', context)
Beispiel #15
0
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
Beispiel #16
0
    def action(self):
        """ Validate remaining reports and inform region """

        # retrieve autobot provider if possible
        try:
            author = Provider.active.get(user__username='******')
        except:
            author = None

        if self.args.is_district:
            validate_level = 'cscom'
            aggregate_level = 'district'
        else:
            validate_level = 'district'
            aggregate_level = 'region'

        # validate non-validated reports
        for report in MalariaReport.unvalidated\
                                   .filter(period=self.args.period, \
                                           entity__type__slug=validate_level):
            report._status = MalariaReport.STATUS_VALIDATED
            if author:
                report.modified_by = author
            report.modified_on = datetime.now()
            with reversion.create_revision():
                report.save()
                if author:
                    reversion.set_user(author.user)
                else:
                    reversion.set_user(get_autobot().user)
                #report.save()

        # create aggregated reports
        for entity in Entity.objects.filter(type__slug=aggregate_level):
            if entity.pnlp_core_malariareport_reports\
                     .filter(period=self.args.period).count() > 0:
                continue
            rauthor = contact_for(entity) if not author else author
            logger.info(u"Creating Aggregated report for %s" % entity)
            report = MalariaReport.create_aggregated(self.args.period, \
                                                     entity, rauthor)
            # region auto-validates their reports
            if not self.args.is_district:
                report._status = MalariaReport.STATUS_VALIDATED
                #report.save()
                with reversion.create_revision():
                    report.save()
                    reversion.set_user(rauthor.user)

        # region-only section
        # create national report
        mali = Entity.objects.get(slug='mali')
        if not self.args.is_district \
           and mali.pnlp_core_malariareport_reports\
                   .filter(period=self.args.period).count() == 0:
            rauthor = author if author else get_autobot()
            logger.info(u"Creating National report")
            report = MalariaReport.create_aggregated(self.args.period, \
                                                     mali, rauthor)

            # following only applies to districts (warn regions).
            return

        # district-only section
        # let region know there are reports to validate
        for region in Entity.objects.filter(type__slug='region'):
            contact = contact_for(region, recursive=False)

            # skip if not recipient
            if not contact or not contact.phone_number:
                continue

            nb_reports = MalariaReport.unvalidated\
                                   .filter(period=self.args.period, \
                                           entity__type__slug='district', \
                                           entity__parent=region).count()

            message = u"[PNLP] La periode de validation CSRef est " \
                      u"terminee. Vous avez %(nb)d rapports de " \
                      u"CSRef a valider." % {'nb': nb_reports}
            email_title = u"[PNLP] Fin de la periode de validation CSRef"

            if not contact.email:
                continue
            send_email(contact.email, message=message, title=email_title)
Beispiel #17
0
def dashboard(request):
    category = 'dashboard'
    context = {'category': category}

    from bolibana.models import Entity
    from pnlp_core.data import (current_period, current_stage, \
                                time_cscom_over, time_district_over, \
                                time_region_over)

    def sms_received_sent_by_period(period):
        received = Inbox.objects.filter(receivingdatetime__gte=period.start_on,
                                        receivingdatetime__lte=period.end_on) \
                                .count()
        sent = SentItems.objects.filter(sendingdatetime__gte=period.start_on,
                                        sendingdatetime__lte=period.end_on) \
                                .count()
        return (received, sent)

    def received_reports(period, type_):
        return MalariaReport.objects.filter(period=period, \
                                            entity__type__slug=type_)

    def reports_validated(period, type_):
        return MalariaReport.validated.filter(period=period, \
                                       entity__type__slug=type_)

    def reporting_rate(period, entity):
        return float(MalariaReport.validated.filter(period=period, \
                 entity__parent=entity).count()) \
        / Entity.objects.filter(parent__slug=entity.slug).count()

    current_period = current_period()
    period = current_reporting_period()

    context.update({'current_period': current_period,
                    'current_reporting_period': period,
                    'current_stage': current_stage(),
                    'current_sms': sms_received_sent_by_period(current_period),
                    'current_reporting_sms': \
                         sms_received_sent_by_period(period),
                    'total_cscom': Entity.objects\
                                         .filter(type__slug='cscom').count(),
                    'time_cscom_over': time_cscom_over(period),
                    'time_district_over': time_district_over(period),
                    'time_region_over': time_region_over(period)})

    received_cscom_reports = received_reports(period, 'cscom')
    cscom_reports_validated = reports_validated(period, 'cscom')
    district_reports_validated = reports_validated(period, 'district')
    reporting_rate = \
        float(MalariaReport.validated.filter(period=period).count()) \
        / Entity.objects.count()

    cscom_missed_report = \
        Entity.objects.filter(type__slug='cscom')\
                      .exclude(id__in=[r.entity.id \
                                       for r \
                                       in received_cscom_reports])\
                      .order_by('name')

    def entities_autoreports(level):
        districts_missed_report = {}
        auto_validated_cscom_reports = \
            MalariaReport.validated\
                         .filter(entity__type__slug=level, \
                                 modified_by__user__username='******')
        for report in auto_validated_cscom_reports:
            if not report.entity.parent.slug in districts_missed_report:
                districts_missed_report[report.entity.parent.slug] = \
                    {'entity': report.entity.parent, \
                     'nbauto': 0, \
                     'contact': contact_for(report.entity.parent, False)}
            districts_missed_report[report.entity.parent.slug]['nbauto'] += 1
        return districts_missed_report

    districts_missed_report = entities_autoreports('cscom')
    regions_missed_report = entities_autoreports('district')

    context.update({'received_cscom_reports': received_cscom_reports.count(),
                'cscom_reports_validated': cscom_reports_validated.count(),
              'district_reports_validated': district_reports_validated.count(),
                'reporting_rate': reporting_rate,
                'cscom_missed_report_count': cscom_missed_report.count(),
                'cscom_missed_report': [(e, contact_for(e, True)) \
                                        for e in cscom_missed_report[:20]],
                'districts_missed_report': districts_missed_report,
                'regions_missed_report': regions_missed_report})

    return render(request, 'dashboard.html', context)