Exemplo n.º 1
0
    def setUp(self):
        super(TestApp, self).setUp()
        type, _ = LocationType.objects.get_or_create(singular="clinic", 
                                                     plural="clinics", 
                                                     slug="clinics")
        clinic = Location.objects.create(type=type, name="demo", slug="demo") 
        self.clinic_zone= Location.objects.create(type=get_zone_type(), name="child", 
                                             slug="child", parent=clinic) 
        clinic_worker = self.create_contact(name="clinic_worker", location=clinic, 
                                            types=[get_clinic_worker_type()])
        clinic_worker2 = self.create_contact(name="clinic_worker2", location=self.clinic_zone,
                                             types=[get_clinic_worker_type()])
        
#        script = "help_admin > hello world"
#        self.runScript(script)
#        connection = Connection.objects.get(identity="help_admin")
#        help_admin = Contact.objects.create(alias='help_admin', is_active = True, name="help_admin",
#                                         location=clinic_zone,is_help_admin = True)
#        help_admin.types.add(const.get_clinic_worker_type())
#                                
#        connection.contact = help_admin
#        connection.save()
        
        cba = self.create_contact(name="cba", location=clinic,
                                  types=[get_cba_type()])
        cba2 = self.create_contact(name="cba2", location=self.clinic_zone,
                                   types=[get_cba_type()])
        active_contacts = Contact.active.all()
        
        self.all = [clinic_worker, clinic_worker2, cba, cba2]
        self.expected_keyword_to_groups = \
            {"ALL":    [clinic_worker, clinic_worker2, cba, cba2],
             "CLINIC": [clinic_worker, clinic_worker2],
             "CBA":    [cba, cba2],
             }
Exemplo n.º 2
0
    def setUp(self):
        super(TestApp, self).setUp()
        type, _ = LocationType.objects.get_or_create(singular="clinic",
                                                     plural="clinics",
                                                     slug="clinics")
        district_type, _ = LocationType.objects.get_or_create(
            singular="district", plural="districts", slug="districts")
        self.district = Location.objects.create(type=district_type,
                                                name="Mansa",
                                                slug="403000")
        self.district2 = Location.objects.create(type=district_type,
                                                 name="Lusaka",
                                                 slug="402000")
        clinic = Location.objects.create(type=type,
                                         name="Central Clinic",
                                         slug="403020")
        clinic.parent = self.district
        clinic.save()
        self.clinic2 = Location.objects.create(type=type,
                                               name="Other Clinic",
                                               slug="402020")
        self.clinic2.parent = self.district2
        self.clinic2.save()

        self.clinic_zone = Location.objects.create(type=get_zone_type(),
                                                   name="child",
                                                   slug="child",
                                                   parent=clinic)

        clinic_worker = self.create_contact(name="clinic_worker",
                                            location=clinic,
                                            types=[get_clinic_worker_type()])
        clinic_worker2 = self.create_contact(name="clinic_worker2",
                                             location=clinic,
                                             types=[get_clinic_worker_type()])

        cba = self.create_contact(name="cba",
                                  location=self.clinic_zone,
                                  types=[get_cba_type()])
        cba2 = self.create_contact(name="cba2",
                                   location=self.clinic_zone,
                                   types=[get_cba_type()])
        active_contacts = Contact.active.all()

        self.all = [clinic_worker, clinic_worker2, cba, cba2]
        self.expected_keyword_to_groups = \
            {"ALL":    [clinic_worker, clinic_worker2, cba, cba2],
             "CLINIC": [clinic_worker, clinic_worker2],
             "CBA":    [cba, cba2],
             }
Exemplo n.º 3
0
 def _get_or_create_zone(self, clinic, name):
     # create the zone if it doesn't already exist
     zone_type = const.get_zone_type()
     try:
         # get_or_create does not work with iexact
         zone = Location.objects.get(name__iexact=name,
                                     parent=clinic,
                                     type=zone_type)
     except Location.DoesNotExist:
         zone = Location.objects.create(name=name,
                                        parent=clinic,
                                        slug=get_unique_value(Location.objects, "slug", name),
                                        type=zone_type)
     return zone
Exemplo n.º 4
0
 def _get_or_create_zone(self, clinic, name):
     # create the zone if it doesn't already exist
     zone_type = const.get_zone_type()
     try:
         # get_or_create does not work with iexact
         zone = Location.objects.get(name__iexact=name,
                                     parent=clinic,
                                     type=zone_type)
     except Location.DoesNotExist:
         zone = Location.objects.create(name=name,
                                        parent=clinic,
                                        slug=get_unique_value(
                                            Location.objects, "slug", name),
                                        type=zone_type)
     return zone
Exemplo n.º 5
0
def get_clinic_or_default(contact):
    """Gets a clinic associated with the contact"""
    
    if contact is None:   return None
    
    # implementation-wise this is a mess because of the list 
    # of possible clinic types.  For now we just return the
    # first parent that is not a zone type or the location
    # associated with the contact directly, if no non-zone
    # parents are found 
    location = contact.location
    while location:
        if location.type != get_zone_type():
            return location
        location = location.parent
    return contact.location
Exemplo n.º 6
0
def send_appointment_reminder(patient, default_conn=None, pronouns=None):
    if pronouns is None:
        pronouns = {}
    logger.info('Sending appointment reminder for %s' % patient)
    if patient.location:
        logger.debug('using patient location (%s) to find CBAs' %
                      patient.location)
        # if the cba was registered, we'll have a location on
        # the patient and can use that information to find the CBAs to whom
        # we should send the appointment reminders
        # TODO: also check child locations?
        connections = list(Connection.objects.filter(
                                         contact__types__slug=const.CBA_SLUG,
                                         contact__location=patient.location,
                                         contact__is_active=True))
        logger.debug('found %d CBAs to deliver reminders to' %
                      len(connections))
    elif default_conn:
        logger.debug('no patient location; using default_conn')
        # if the CBA was not registered, just send the notification to the
        # CBA who logged the event
        connections = [default_conn]
    else:
        logger.debug('no patient location or default_conn; not sending any '
                      'reminders')

    for connection in connections:
        if connection.contact:
            cba_name = ' %s' % connection.contact.name
        else:
            cba_name = ''
        if patient.location:
            if patient.location.type == const.get_zone_type() and\
               patient.location.parent:
                clinic_name = patient.location.parent.name
            else:
                clinic_name = patient.location.name
        else:
            clinic_name = 'the clinic'
        msg = OutgoingMessage(connection, _("Hello%(cba)s. %(patient)s is due "
                              "for their next clinic appointment. Please "
                              "deliver a reminder to this person and ensure "
                              "they visit %(clinic)s within 3 days."),
                              cba=cba_name, patient=patient.name,
                              clinic=clinic_name)
        msg.send()
    return connections
Exemplo n.º 7
0
    def setUp(self):
        super(TestApp, self).setUp()
        type, _ = LocationType.objects.get_or_create(singular="clinic", 
                                                     plural="clinics", 
                                                     slug="clinics")
        district_type, _ = LocationType.objects.get_or_create(singular="district",
                                                     plural="districts",
                                                     slug="districts")
        self.district = Location.objects.create(type=district_type, name="Mansa", slug="403000")
        self.district2 = Location.objects.create(type=district_type, name="Lusaka", slug="402000")
        clinic = Location.objects.create(type=type, name="Central Clinic", slug="403020")
        clinic.parent = self.district
        clinic.save()
        self.clinic2 = Location.objects.create(type=type, name="Other Clinic", slug="402020")
        self.clinic2.parent = self.district2
        self.clinic2.save()

        self.clinic_zone= Location.objects.create(type=get_zone_type(), name="child", 
                                             slug="child", parent=clinic) 
        
        clinic_worker = self.create_contact(name="clinic_worker", location=clinic,
                                            types=[get_clinic_worker_type()])
        clinic_worker2 = self.create_contact(name="clinic_worker2", location=clinic,
                                             types=[get_clinic_worker_type()])
        

        
        cba = self.create_contact(name="cba", location=self.clinic_zone,
                                  types=[get_cba_type()])
        cba2 = self.create_contact(name="cba2", location=self.clinic_zone,
                                   types=[get_cba_type()])
        active_contacts = Contact.active.all()
        
        self.all = [clinic_worker, clinic_worker2, cba, cba2]
        self.expected_keyword_to_groups = \
            {"ALL":    [clinic_worker, clinic_worker2, cba, cba2],
             "CLINIC": [clinic_worker, clinic_worker2],
             "CBA":    [cba, cba2],
             }
Exemplo n.º 8
0
    def handle(self, text):
        b = InputCleaner()
        if not is_eligible_for_results(self.msg.connection):
            # essentially checking for an active clinic_worker
            self.respond(self.INELIGIBLE)
            return

        text = text.strip()
        text = b.remove_double_spaces(text)
        location = self.msg.contact.location
        if location.type == const.get_zone_type():
            location = location.parent
        cba = None

        if text[1:].isdigit() and len(text) >= self.MIN_PHONE_LENGTH:
            try:
                cba = \
                Contact.active.get(connection__identity__icontains=text,
                                   location__parent=location,
                                   types=const.get_cba_type())
            except Contact.DoesNotExist:
                self.respond('The phone number %(phone)s does not belong to any'
                             + ' CBA at %(clinic)s. Make sure you typed it '
                             + 'correctly', phone=text, clinic=location)
            except Contact.MultipleObjectsReturned:
                logger.warning("Bug. phone number %s is used by multiple cba's "
                +"at same clinic" % text)
                return

        if not cba:
            cbas = \
            Contact.active.filter(name__icontains=text,
                                  location__parent=location,
                                  types=const.get_cba_type())
            if not cbas:
                self.respond('The name %(name)s does not belong to any'
                             + ' CBA at %(clinic)s. Make sure you typed it '
                             + 'correctly', name=text,
                             clinic=location)
                return
            if len(cbas) == 1:
                cba = cbas[0]
            elif len(cbas) < 5:
                self.respond("Try sending DEREGISTER <CBA_PHONE_NUMBER>. Which "
                             + "CBA did you mean? %(cbas)s", cbas=' or '.join(
                             cba.name + ":" + cba.default_connection.identity
                             for cba in cbas))
                return
            else:
                self.respond("There are %(len)s CBA's who's names match %(name)s"
                             + " at %(clinic)s. Try to use the phone number "
                             + "instead", len=len(cbas), name=text,
                             clinic=location.name)
                return
        if cba:
            cba.is_active = False
            cba.save()
            self.respond("You have successfully deregistered %(name)s:"
                         + "%(phone)s of zone %(zone)s at %(clinic)s",
                         name=cba.name, phone=cba.default_connection.identity,
                         zone=cba.location.name, clinic=location.name)
            worker = self.msg.contact
            for help_admin in Contact.active.filter(is_help_admin=True):
                OutgoingMessage(
                                help_admin.default_connection,
                                "%s:%s has deregistered %s:%s of zone %s at %s" %
                                (worker.name,
                                worker.default_connection.identity,
                                cba.name,
                                cba.default_connection.identity,
                                cba.location.name,
                                location.name
                                )).send()
Exemplo n.º 9
0
 def testSendReminders(self):
     birth = reminders.Event.objects.create(name="Birth", slug="birth",
                                            gender="f")
     birth.appointments.create(name='2 day', num_days=2)
     birth.appointments.create(name='3 day', num_days=3)
     birth.appointments.create(name='4 day', num_days=4)
     clinic = LocationType.objects.create(slug=const.CLINIC_SLUGS[0])
     zone = const.get_zone_type()
     central = Location.objects.create(name='Central Clinic', type=clinic)
     zone1 = Location.objects.create(name='Zone 1', type=zone,
                                     parent=central, slug='zone1')
     zone2 = Location.objects.create(name='Zone 2', type=zone,
                                     parent=central, slug='zone2')
     patient1 = Contact.objects.create(name='patient 1', location=zone1)
     patient2 = Contact.objects.create(name='patient 2', location=zone1)
     patient3 = Contact.objects.create(name='patient 3', location=zone2)
     
     # this gets the backend and connection in the db
     self.runScript("""
     cba1 > hello world
     cba2 > hello world
     """)
     # take a break to allow the router thread to catch up; otherwise we
     # get some bogus messages when they're retrieved below
     time.sleep(.1)
     cba_t = const.get_cba_type()
     cba1_conn = Connection.objects.get(identity="cba1")
     cba1 = Contact.objects.create(name='cba1', location=zone1)
     cba1.types.add(cba_t)
     cba1_conn.contact = cba1
     cba1_conn.save()
     cba2_conn = Connection.objects.get(identity="cba2")
     cba2 = Contact.objects.create(name='cba2', location=zone2)
     cba2.types.add(cba_t)
     cba2_conn.contact = cba2
     cba2_conn.save()
     birth.patient_events.create(patient=patient1, cba_conn=cba1_conn,
                                 date=datetime.datetime.today())
     birth.patient_events.create(patient=patient2, cba_conn=cba1_conn,
                                 date=datetime.datetime.today())
     birth.patient_events.create(patient=patient3, cba_conn=cba2_conn,
                                 date=datetime.datetime.today())
     self.startRouter()
     tasks.send_notifications(self.router)
     # just the 1 and two day notifications should go out;
     # 3 patients x 2 notifications = 6 messages
     messages = self.receiveAllMessages()
     expected_messages =\
         ['Hello cba1. patient 1 is due for their 2 day clinic appointment. '
          'Please remind this person and ensure they '
          'visit Central Clinic within 3 days.',
          'Hello cba1. patient 2 is due for their 2 day clinic appointment. '
          'Please remind this person and ensure they '
          'visit Central Clinic within 3 days.',
          'Hello cba2. patient 3 is due for their 2 day clinic appointment. '
          'Please remind this person and ensure they '
          'visit Central Clinic within 3 days.']
     self.assertEqual(len(messages), len(expected_messages))
     for msg in messages:
         self.assertTrue(msg.text in expected_messages, msg)
     sent_notifications = reminders.SentNotification.objects.all()
     self.assertEqual(sent_notifications.count(), len(expected_messages))
Exemplo n.º 10
0
    def testSendReminders(self):
        birth = reminders.Event.objects.create(name="Birth",
                                               slug="birth",
                                               gender="f")
        birth.appointments.create(name='2 day', num_days=2)
        birth.appointments.create(name='3 day', num_days=3)
        birth.appointments.create(name='4 day', num_days=4)
        clinic = LocationType.objects.create(slug=const.CLINIC_SLUGS[0])
        zone = const.get_zone_type()
        central = Location.objects.create(name='Central Clinic', type=clinic)
        zone1 = Location.objects.create(name='Zone 1',
                                        type=zone,
                                        parent=central,
                                        slug='zone1')
        zone2 = Location.objects.create(name='Zone 2',
                                        type=zone,
                                        parent=central,
                                        slug='zone2')
        patient1 = Contact.objects.create(name='patient 1', location=zone1)
        patient2 = Contact.objects.create(name='patient 2', location=zone1)
        patient3 = Contact.objects.create(name='patient 3', location=zone2)

        # this gets the backend and connection in the db
        self.runScript("""
        cba1 > hello world
        cba2 > hello world
        """)
        # take a break to allow the router thread to catch up; otherwise we
        # get some bogus messages when they're retrieved below
        time.sleep(.1)
        cba_t = const.get_cba_type()
        cba1_conn = Connection.objects.get(identity="cba1")
        cba1 = Contact.objects.create(name='cba1', location=zone1)
        cba1.types.add(cba_t)
        cba1_conn.contact = cba1
        cba1_conn.save()
        cba2_conn = Connection.objects.get(identity="cba2")
        cba2 = Contact.objects.create(name='cba2', location=zone2)
        cba2.types.add(cba_t)
        cba2_conn.contact = cba2
        cba2_conn.save()
        birth.patient_events.create(patient=patient1,
                                    cba_conn=cba1_conn,
                                    date=datetime.datetime.today())
        birth.patient_events.create(patient=patient2,
                                    cba_conn=cba1_conn,
                                    date=datetime.datetime.today())
        birth.patient_events.create(patient=patient3,
                                    cba_conn=cba2_conn,
                                    date=datetime.datetime.today())
        self.startRouter()
        tasks.send_notifications(self.router)
        # just the 1 and two day notifications should go out;
        # 3 patients x 2 notifications = 6 messages
        messages = self.receiveAllMessages()
        expected_messages =\
            ['Hello cba1. patient 1 is due for their 2 day clinic appointment. '
             'Please remind this person and ensure they '
             'visit Central Clinic within 3 days.',
             'Hello cba1. patient 2 is due for their 2 day clinic appointment. '
             'Please remind this person and ensure they '
             'visit Central Clinic within 3 days.',
             'Hello cba2. patient 3 is due for their 2 day clinic appointment. '
             'Please remind this person and ensure they '
             'visit Central Clinic within 3 days.']
        self.assertEqual(len(messages), len(expected_messages))
        for msg in messages:
            self.assertTrue(msg.text in expected_messages, msg)
        sent_notifications = reminders.SentNotification.objects.all()
        self.assertEqual(sent_notifications.count(), len(expected_messages))
Exemplo n.º 11
0
    def handle(self, text):
        b = InputCleaner()
        if not is_eligible_for_results(self.msg.connection):
            # essentially checking for an active clinic_worker
            self.respond(self.INELIGIBLE)
            return

        text = text.strip()
        text = b.remove_double_spaces(text)
        worker = self.msg.contact
        location = worker.location
        if location.type == const.get_zone_type():
            location = location.parent
        cba = None

        # we expect phone numbers like +260977123456, 0977123456, 977123456
        # (a phone number is unique to each cba at a clinic)
        if text[1:].isdigit() and len(text) >= self.MIN_PHONE_LENGTH:
            try:
                cba = \
                Contact.active.get(connection__identity__endswith=text,
                                   location__parent=location,
                                   types=const.get_cba_type())
            except Contact.DoesNotExist:
                self.respond('The phone number %(phone)s does not belong to any'
                             ' CBA at %(clinic)s. Make sure you typed it '
                             'correctly', phone=text, clinic=location)
            # we do not expect this to happen. phone number is excpected to be
            # unique (>=9 chars) project wide
            except Contact.MultipleObjectsReturned:
                logger.warning("Bug. phone number %s is used by multiple cba's "
                               "at same clinic" % text)

                self.respond("Sorry %(name)s, the CBA with phone number %(phone)s"
                             " could not be deregistered. This matter will be"
                             " followed up by Support Staff immediately",
                             name=worker.name, phone=text)

                msg = (self.FOLLOWUP_MESSAGE % (text, worker.name,
                       worker.default_connection.identity,
                       location.name))
                self.notify_help_admins(msg)
                return

        if not cba:
            cbas = \
            Contact.active.filter(name__icontains=text,
                                  location__parent=location,
                                  types=const.get_cba_type())
            if not cbas:
                self.respond('The name %(name)s does not belong to any'
                             ' CBA at %(clinic)s. Make sure you typed it '
                             'correctly', name=text,
                             clinic=location)
                return
            if len(cbas) == 1:
                cba = cbas[0]
            elif len(cbas) < 5:
                self.respond("Try sending REMOVE <CBA_PHONE_NUMBER>. Which "
                             + "CBA did you mean? %(cbas)s", cbas=' or '.join(
                             cba.name + ":" + cba.default_connection.identity
                             for cba in cbas))
                return
            else:
                self.respond("There are %(len)s CBA's who's names match %(name)s"
                             + " at %(clinic)s. Try to use the phone number "
                             + "instead", len=len(cbas), name=text,
                             clinic=location.name)
                return
        if cba:
            cba.is_active = False
            cba.save()
            self.respond("You have successfully deregistered %(name)s:"
                         + "%(phone)s of zone %(zone)s at %(clinic)s",
                         name=cba.name, phone=cba.default_connection.identity,
                         zone=cba.location.name, clinic=location.name)
            msg = ("%s:%s has deregistered %s:%s of zone %s at %s" %
                   (worker.name,
                   worker.default_connection.identity,
                   cba.name,
                   cba.default_connection.identity,
                   cba.location.name,
                   location.name))
            self.notify_help_admins(msg)
Exemplo n.º 12
0
    def handle(self, text):
        b = InputCleaner()
        if not is_eligible_for_results(self.msg.connection):
            # essentially checking for an active clinic_worker
            self.respond(self.INELIGIBLE)
            return

        text = text.strip()
        text = b.remove_double_spaces(text)
        worker = self.msg.contact
        location = worker.location
        if location.type == const.get_zone_type():
            location = location.parent
        cba = None

        # we expect phone numbers like +260977123456, 0977123456, 977123456
        # (a phone number is unique to each cba at a clinic)
        if text[1:].isdigit() and len(text) >= self.MIN_PHONE_LENGTH:
            try:
                cba = \
                Contact.active.get(connection__identity__endswith=text,
                                   location__parent=location,
                                   types=const.get_cba_type())
            except Contact.DoesNotExist:
                self.respond(
                    'The phone number %(phone)s does not belong to any'
                    ' CBA at %(clinic)s. Make sure you typed it '
                    'correctly',
                    phone=text,
                    clinic=location)
            # we do not expect this to happen. phone number is excpected to be
            # unique (>=9 chars) project wide
            except Contact.MultipleObjectsReturned:
                logger.warning(
                    "Bug. phone number %s is used by multiple cba's "
                    "at same clinic" % text)

                self.respond(
                    "Sorry %(name)s, the CBA with phone number %(phone)s"
                    " could not be deregistered. This matter will be"
                    " followed up by Support Staff immediately",
                    name=worker.name,
                    phone=text)

                msg = (self.FOLLOWUP_MESSAGE %
                       (text, worker.name, worker.default_connection.identity,
                        location.name))
                self.notify_help_admins(msg)
                return

        if not cba:
            cbas = \
            Contact.active.filter(name__icontains=text,
                                  location__parent=location,
                                  types=const.get_cba_type())
            if not cbas:
                self.respond(
                    'The name %(name)s does not belong to any'
                    ' CBA at %(clinic)s. Make sure you typed it '
                    'correctly',
                    name=text,
                    clinic=location)
                return
            if len(cbas) == 1:
                cba = cbas[0]
            elif len(cbas) < 5:
                self.respond("Try sending REMOVE <CBA_PHONE_NUMBER>. Which " +
                             "CBA did you mean? %(cbas)s",
                             cbas=' or '.join(cba.name + ":" +
                                              cba.default_connection.identity
                                              for cba in cbas))
                return
            else:
                self.respond(
                    "There are %(len)s CBA's who's names match %(name)s" +
                    " at %(clinic)s. Try to use the phone number " + "instead",
                    len=len(cbas),
                    name=text,
                    clinic=location.name)
                return
        if cba:
            cba.is_active = False
            cba.save()
            self.respond("You have successfully deregistered %(name)s:" +
                         "%(phone)s of zone %(zone)s at %(clinic)s",
                         name=cba.name,
                         phone=cba.default_connection.identity,
                         zone=cba.location.name,
                         clinic=location.name)
            msg = ("%s:%s has deregistered %s:%s of zone %s at %s" %
                   (worker.name, worker.default_connection.identity, cba.name,
                    cba.default_connection.identity, cba.location.name,
                    location.name))
            self.notify_help_admins(msg)