Exemplo n.º 1
0
def add_reminder(request,
                 domain,
                 handler_id=None,
                 template="reminders/partial/add_reminder.html"):

    if handler_id:
        handler = CaseReminderHandler.get(handler_id)
        if handler.doc_type != 'CaseReminderHandler' or handler.domain != domain:
            raise Http404
    else:
        handler = None

    if request.method == "POST":
        reminder_form = CaseReminderForm(request.POST)
        if reminder_form.is_valid():
            if not handler:
                handler = CaseReminderHandler(domain=domain)
                handler.ui_type = UI_SIMPLE_FIXED
            for key, value in reminder_form.cleaned_data.items():
                if (key != "frequency") and (key != "message"):
                    handler[key] = value
            handler.max_iteration_count = REPEAT_SCHEDULE_INDEFINITELY
            handler.schedule_length = reminder_form.cleaned_data["frequency"]
            handler.event_interpretation = EVENT_AS_OFFSET
            handler.events = [
                CaseReminderEvent(
                    day_num=0,
                    fire_time=time(hour=0, minute=0, second=0),
                    message=reminder_form.cleaned_data["message"],
                    callback_timeout_intervals=[])
            ]
            handler.save()
            return HttpResponseRedirect(
                reverse('list_reminders', args=[domain]))
    elif handler:
        initial = {}
        for key in handler.to_json():
            if (key !=
                    "max_iteration_count") and (key != "schedule_length") and (
                        key != "events") and (key != "event_interpretation"):
                initial[key] = handler[key]
        initial["message"] = json.dumps(handler.events[0].message)
        initial["frequency"] = handler.schedule_length
        reminder_form = CaseReminderForm(initial=initial)
    else:
        reminder_form = CaseReminderForm()

    return render(request, template, {
        'reminder_form': reminder_form,
        'domain': domain
    })
Exemplo n.º 2
0
def add_reminder(request, domain, handler_id=None, template="reminders/partial/add_reminder.html"):

    if handler_id:
        handler = CaseReminderHandler.get(handler_id)
        if handler.doc_type != 'CaseReminderHandler' or handler.domain != domain:
            raise Http404
    else:
        handler = None
        
    if request.method == "POST":
        reminder_form = CaseReminderForm(request.POST)
        if reminder_form.is_valid():
            if not handler:
                handler = CaseReminderHandler(domain=domain)
                handler.ui_type = UI_SIMPLE_FIXED
            for key, value in reminder_form.cleaned_data.items():
                if (key != "frequency") and (key != "message"):
                    handler[key] = value
            handler.max_iteration_count = REPEAT_SCHEDULE_INDEFINITELY
            handler.schedule_length = reminder_form.cleaned_data["frequency"]
            handler.event_interpretation = EVENT_AS_OFFSET
            handler.events = [
                CaseReminderEvent(
                    day_num = 0
                   ,fire_time = time(hour=0,minute=0,second=0)
                   ,message = reminder_form.cleaned_data["message"]
                   ,callback_timeout_intervals = []
               )
            ]
            handler.save()
            print handler.events[0].message
            return HttpResponseRedirect(reverse('list_reminders', args=[domain]))
    elif handler:
        initial = {}
        for key in handler.to_json():
            if (key != "max_iteration_count") and (key != "schedule_length") and (key != "events") and (key != "event_interpretation"):
                initial[key] = handler[key]
        initial["message"] = json.dumps(handler.events[0].message)
        initial["frequency"] = handler.schedule_length
        reminder_form = CaseReminderForm(initial=initial)
    else:
        reminder_form = CaseReminderForm()

    return render_to_response(request, template, {
        'reminder_form': reminder_form,
        'domain': domain
    })
Exemplo n.º 3
0
                message={'xx': message} if content_type == METHOD_SMS else {},
                callback_timeout_intervals=[],
            )
        ],
        schedule_length=1,
        event_interpretation=EVENT_AS_OFFSET,
        max_iteration_count=1,
        case_id=case_id,
        user_id=contact.get_id if recipient == RECIPIENT_USER else None,
        sample_id=contact.get_id
        if recipient == RECIPIENT_SURVEY_SAMPLE else None,
        user_group_id=contact.get_id
        if recipient == RECIPIENT_USER_GROUP else None,
        messaging_event_id=logged_event.pk if logged_event else None,
    )
    handler.save(send_immediately=True)


def can_use_survey_reminders(request):
    return has_privilege(request, privileges.INBOUND_SMS)


def get_two_way_number_for_recipient(recipient):
    if isinstance(recipient, CommCareMobileContactMixin):
        two_way_numbers = recipient.get_two_way_numbers()
        if len(two_way_numbers) == 1:
            return list(two_way_numbers.values())[0]
        elif len(two_way_numbers) > 1:
            # Retrieve the two-way number that's highest up in the list
            if isinstance(recipient, CouchUser):
                for phone in recipient.phone_numbers:
Exemplo n.º 4
0
def create_immediate_reminder(contact, content_type, reminder_type=None, message=None, form_unique_id=None, case=None):
    """
    contact - the contact to send to
    content_type - METHOD_SMS or METHOD_SMS_SURVEY (see corehq.apps.reminders.models)
    reminder_type - either REMINDER_TYPE_DEFAULT, REMINDER_TYPE_ONE_TIME, or REMINDER_TYPE_KEYWORD_INITIATED
    message - the message to send if content_type == METHOD_SMS
    form_unique_id - the form_unique_id of the form to send if content_type == METHOD_SMS_SURVEY
    case - the case that is associated with this reminder (so that you can embed case properties into the message)
    """
    from corehq.apps.reminders.models import (
        CaseReminderHandler,
        CaseReminderEvent,
        ON_DATETIME,
        EVENT_AS_OFFSET,
        REMINDER_TYPE_DEFAULT,
        METHOD_SMS,
        METHOD_SMS_SURVEY,
        RECIPIENT_CASE,
        RECIPIENT_USER,
        RECIPIENT_SURVEY_SAMPLE,
        RECIPIENT_USER_GROUP,
    )
    if isinstance(contact, CommCareCase):
        recipient = RECIPIENT_CASE
    elif isinstance(contact, CommCareCaseGroup):
        recipient = RECIPIENT_SURVEY_SAMPLE
    elif isinstance(contact, CommCareUser):
        recipient = RECIPIENT_USER
    elif isinstance(contact, Group):
        recipient = RECIPIENT_USER_GROUP
    else:
        raise Exception("Unsupported contact type for %s" % contact._id)

    reminder_type = reminder_type or REMINDER_TYPE_DEFAULT
    if recipient == RECIPIENT_CASE:
        case_id = contact._id
    elif case is not None:
        case_id = case._id
    else:
        case_id = None

    handler = CaseReminderHandler(
        domain = contact.domain,
        reminder_type = reminder_type,
        nickname = "One-time Reminder",
        default_lang = "xx",
        method = content_type,
        recipient = recipient,
        start_condition_type = ON_DATETIME,
        start_datetime = datetime.utcnow(),
        start_offset = 0,
        events = [CaseReminderEvent(
            day_num = 0,
            fire_time = time(0,0),
            form_unique_id = form_unique_id if content_type == METHOD_SMS_SURVEY else None,
            message = {"xx" : message} if content_type == METHOD_SMS else {},
            callback_timeout_intervals = [],
        )],
        schedule_length = 1,
        event_interpretation = EVENT_AS_OFFSET,
        max_iteration_count = 1,
        case_id = case_id,
        user_id = contact._id if recipient == RECIPIENT_USER else None,
        sample_id = contact._id if recipient == RECIPIENT_SURVEY_SAMPLE else None,
        user_group_id = contact._id if recipient == RECIPIENT_USER_GROUP else None,
    )
    handler.save(send_immediately=True)
Exemplo n.º 5
0
    def test_cache(self, check_state_mock):
        domain = 'reminder-cache-test'

        # Nothing expected at first
        self.assertEqual(CaseReminderHandler.get_handler_ids(domain), [])

        # Create two reminder definitions of different types
        handler1 = CaseReminderHandler(
            domain=domain,
            reminder_type=REMINDER_TYPE_DEFAULT,
        )
        handler1.save()
        self.addCleanup(handler1.delete)

        handler2 = CaseReminderHandler(
            domain=domain,
            reminder_type=REMINDER_TYPE_ONE_TIME,
        )
        handler2.save()
        self.addCleanup(handler2.delete)

        self.assertEqual(
            CaseReminderHandler.get_handler_ids(
                domain, reminder_type_filter=REMINDER_TYPE_DEFAULT),
            [handler1._id])

        self.assertEqual(
            CaseReminderHandler.get_handler_ids(
                domain, reminder_type_filter=REMINDER_TYPE_ONE_TIME),
            [handler2._id])

        self.assertEqual(sorted(CaseReminderHandler.get_handler_ids(domain)),
                         sorted([handler1._id, handler2._id]))

        # Add another with default type
        handler3 = CaseReminderHandler(
            domain=domain,
            reminder_type=REMINDER_TYPE_DEFAULT,
        )
        handler3.save()
        self.addCleanup(handler3.delete)

        self.assertEqual(
            sorted(
                CaseReminderHandler.get_handler_ids(
                    domain, reminder_type_filter=REMINDER_TYPE_DEFAULT)),
            sorted([handler1._id, handler3._id]))

        self.assertEqual(
            CaseReminderHandler.get_handler_ids(
                domain, reminder_type_filter=REMINDER_TYPE_ONE_TIME),
            [handler2._id])

        self.assertEqual(sorted(CaseReminderHandler.get_handler_ids(domain)),
                         sorted([handler1._id, handler2._id, handler3._id]))

        # Retire the one-time reminder
        handler2.retire()

        self.assertEqual(
            sorted(
                CaseReminderHandler.get_handler_ids(
                    domain, reminder_type_filter=REMINDER_TYPE_DEFAULT)),
            sorted([handler1._id, handler3._id]))

        self.assertEqual(
            CaseReminderHandler.get_handler_ids(
                domain, reminder_type_filter=REMINDER_TYPE_ONE_TIME), [])

        self.assertEqual(sorted(CaseReminderHandler.get_handler_ids(domain)),
                         sorted([handler1._id, handler3._id]))
    def handle(self, *args, **options):
        if len(args) == 0 or len(args) > 1:
            raise CommandError(
                "Usage: manage.py create_definitions_2012_07 <domain>")

        domain = args[0]
        case_type = "participant"
        times_of_day = {
            "0600": time(6, 0, 0),
            "0900": time(9, 0, 0),
            "1700": time(17, 0, 0),
            "2100": time(21, 0, 0)
        }
        days = [
            "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday",
            "Sunday"
        ]

        for time_code, actual_time in times_of_day.items():
            c = CaseReminderHandler(domain=domain,
                                    case_type=case_type,
                                    nickname="Group 1, @ " + time_code,
                                    default_lang="en",
                                    method="survey",
                                    ui_type="COMPLEX",
                                    recipient="CASE",
                                    start_property="send_normal_message",
                                    start_value=time_code,
                                    start_date="normal_result_message_date",
                                    start_offset=0,
                                    start_match_type="EXACT",
                                    events=[
                                        CaseReminderEvent(
                                            day_num=0,
                                            fire_time=actual_time,
                                            message={},
                                            callback_timeout_intervals=[],
                                            form_unique_id="")
                                    ],
                                    schedule_length=1,
                                    event_interpretation="SCHEDULE",
                                    max_iteration_count=1,
                                    until=None)
            c.save()
            print "Created " + c.nickname

            for day in days:
                c = CaseReminderHandler(
                    domain=domain,
                    case_type=case_type,
                    nickname="Group 2 - 4, " + day + ", @ " + time_code,
                    default_lang="en",
                    method="survey",
                    ui_type="COMPLEX",
                    recipient="CASE",
                    start_property="send_" + day.lower(),
                    start_value=time_code,
                    start_date=day.lower() + "_date",
                    start_offset=0,
                    start_match_type="EXACT",
                    events=[
                        CaseReminderEvent(day_num=0,
                                          fire_time=actual_time,
                                          message={},
                                          callback_timeout_intervals=[],
                                          form_unique_id="")
                    ],
                    schedule_length=1,
                    event_interpretation="SCHEDULE",
                    max_iteration_count=1,
                    until=None)
                c.save()
                print "Created " + c.nickname
Exemplo n.º 7
0
class KooKooTestCase(TouchformsTestCase):
    """
    Must be run manually (see corehq.apps.sms.tests.util.TouchformsTestCase)
    """
    def setUp(self):
        super(KooKooTestCase, self).setUp()
        self.ivr_backend = MobileBackend(
            _id="MOBILE_BACKEND_KOOKOO",
            outbound_module="corehq.apps.kookoo.api",
            outbound_params={
                "is_test": True,
                "api_key": "xyz"
            },
        )
        self.ivr_backend.save()

        self.user1 = self.create_mobile_worker("user1",
                                               "123",
                                               "91001",
                                               save_vn=False)
        self.user2 = self.create_mobile_worker("user2",
                                               "123",
                                               "91002",
                                               save_vn=False)
        self.create_group("group1", [self.user1, self.user2])

        dirname = os.path.dirname(os.path.abspath(__file__))
        self.load_app("app1.json", dirname)
        self.load_app("app2.json", dirname)

        self.reminder1 = CaseReminderHandler(
            domain=self.domain,
            active=True,
            case_type="participant",
            method=METHOD_IVR_SURVEY,
            recipient=RECIPIENT_CASE,
            sample_id=None,
            user_group_id=None,
            user_id=None,
            case_id=None,
            reminder_type=REMINDER_TYPE_DEFAULT,
            submit_partial_forms=True,
            include_case_side_effects=False,
            max_question_retries=5,
            start_condition_type=CASE_CRITERIA,
            start_property="name",
            start_value="case1",
            start_date=None,
            start_offset=0,
            start_match_type=MATCH_EXACT,
            events=[
                CaseReminderEvent(
                    day_num=0,
                    fire_time=time(12, 0),
                    fire_time_type=FIRE_TIME_DEFAULT,
                    callback_timeout_intervals=[30],
                    form_unique_id=self.apps[0].modules[0].forms[0].unique_id,
                ),
                CaseReminderEvent(
                    day_num=0,
                    fire_time=time(13, 0),
                    fire_time_type=FIRE_TIME_DEFAULT,
                    callback_timeout_intervals=[30],
                    form_unique_id=self.apps[0].modules[0].forms[1].unique_id,
                ),
            ],
            schedule_length=1,
            event_interpretation=EVENT_AS_SCHEDULE,
            max_iteration_count=7,
            until=None,
            force_surveys_to_use_triggered_case=False,
        )
        self.reminder1.save()

        self.reminder2 = CaseReminderHandler(
            domain=self.domain,
            active=True,
            case_type="participant",
            method=METHOD_IVR_SURVEY,
            recipient=RECIPIENT_OWNER,
            sample_id=None,
            user_group_id=None,
            user_id=None,
            case_id=None,
            reminder_type=REMINDER_TYPE_DEFAULT,
            submit_partial_forms=True,
            include_case_side_effects=True,
            max_question_retries=5,
            start_condition_type=CASE_CRITERIA,
            start_property="name",
            start_value="case2",
            start_date=None,
            start_offset=0,
            start_match_type=MATCH_EXACT,
            events=[
                CaseReminderEvent(
                    day_num=0,
                    fire_time=time(12, 0),
                    fire_time_type=FIRE_TIME_DEFAULT,
                    callback_timeout_intervals=[30, 30],
                    form_unique_id=self.apps[1].modules[0].forms[0].unique_id,
                ),
            ],
            schedule_length=1,
            event_interpretation=EVENT_AS_SCHEDULE,
            max_iteration_count=7,
            until=None,
            force_surveys_to_use_triggered_case=False,
        )
        self.reminder2.save()

    def kookoo_in(self, params):
        """
        params should be a dictionary containing:
        event, cid, sid, and (optionally) data
        """
        params = urllib.urlencode(params)
        url = "%s/kookoo/ivr/" % self.live_server_url
        return urllib2.urlopen("%s?%s" % (url, params)).read()

    def kookoo_finished(self, params):
        """
        params should be a dictionary containing:
        sid, status, and duration
        """
        params = urllib.urlencode(params)
        url = "%s/kookoo/ivr_finished/" % self.live_server_url
        return urllib2.urlopen(url, params).read()

    def testOutbound(self):
        # Send an outbound call using self.reminder1 to self.case
        # and answer it
        CaseReminderHandler.now = datetime(2014, 6, 23, 10, 0)
        self.case = CommCareCase.get(
            register_sms_contact(
                self.domain,
                'participant',
                'case1',
                self.user1._id,
                '91000',
                owner_id=self.groups[0]._id,
            ))
        CaseReminderHandler.now = datetime(2014, 6, 23, 12, 0)
        CaseReminderHandler.fire_reminders()
        reminder = self.reminder1.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 23, 12, 30))

        call = self.get_last_outbound_call(self.case)
        self.assertTrue(call.use_precached_first_response)

        kookoo_session_id = call.gateway_session_id[7:]
        resp = self.kookoo_in({
            "cid": "0000",
            "sid": kookoo_session_id,
            "event": "NewCall",
        })
        self.assertEqual(
            resp, '<response sid="%s"><collectdtmf l="1" o="3000">'
            '<playtext>How do you feel today? Press 1 for good, 2 for bad.'
            '</playtext></collectdtmf></response>' % kookoo_session_id)

        resp = self.kookoo_in({
            "cid": "0000",
            "sid": kookoo_session_id,
            "event": "GotDTMF",
            "data": "1",
        })
        self.assertEqual(
            resp, '<response sid="%s"><collectdtmf l="1" o="3000">'
            '<playtext>Did you remember to take your meds today? Press 1 for yes, 2 for no.'
            '</playtext></collectdtmf></response>' % kookoo_session_id)

        resp = self.kookoo_in({
            "cid": "0000",
            "sid": kookoo_session_id,
            "event": "GotDTMF",
            "data": "2",
        })
        self.assertEqual(
            resp,
            '<response sid="%s"><hangup/></response>' % kookoo_session_id)

        self.kookoo_finished({
            "sid": kookoo_session_id,
            "status": "answered",
            "duration": "20",
        })

        call = CallLog.get(call._id)
        self.assertTrue(call.answered)
        self.assertEqual(call.duration, 20)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "how_feel", "1")
        self.assertFormQuestionEquals(form, "take_meds", "2")
        case = CommCareCase.get(self.case._id)
        self.assertCasePropertyEquals(case, "how_feel", "1")
        self.assertCasePropertyEquals(case, "take_meds", "2")

        CaseReminderHandler.now = datetime(2014, 6, 23, 12, 30)
        CaseReminderHandler.fire_reminders()

        reminder = self.reminder1.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 23, 13, 0))

        last_call = self.get_last_outbound_call(self.case)
        self.assertEqual(call._id, last_call._id)

        # Move on to the second event which now uses an all-label form and
        # should not precache the first ivr response
        CaseReminderHandler.now = datetime(2014, 6, 23, 13, 0)
        CaseReminderHandler.fire_reminders()

        reminder = self.reminder1.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 23, 13, 30))

        call = self.get_last_outbound_call(self.case)
        self.assertFalse(call.use_precached_first_response)

        kookoo_session_id = call.gateway_session_id[7:]
        resp = self.kookoo_in({
            "cid": "0000",
            "sid": kookoo_session_id,
            "event": "NewCall",
        })
        self.assertEqual(
            resp, '<response sid="%s">'
            '<playtext>This is just a reminder to take your meds.'
            '</playtext><hangup/></response>' % kookoo_session_id)

        self.kookoo_finished({
            "sid": kookoo_session_id,
            "status": "answered",
            "duration": "5",
        })

        call = CallLog.get(call._id)
        self.assertTrue(call.answered)
        self.assertEqual(call.duration, 5)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "label", "ok")

        CaseReminderHandler.now = datetime(2014, 6, 23, 13, 30)
        CaseReminderHandler.fire_reminders()

        reminder = self.reminder1.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 24, 12, 0))

        last_call = self.get_last_outbound_call(self.case)
        self.assertEqual(call._id, last_call._id)

        # Now test sending outbound calls to a group of users (the owners
        # of the case)

        # Allow sending to unverified numbers
        self.domain_obj = Domain.get(self.domain_obj._id)
        self.domain_obj.send_to_duplicated_case_numbers = True
        self.domain_obj.save()

        CaseReminderHandler.now = datetime(2014, 6, 24, 10, 0)
        self.case = CommCareCase.get(
            register_sms_contact(
                self.domain,
                'participant',
                'case2',
                self.user1._id,
                '91003',
                owner_id=self.groups[0]._id,
            ))
        reminder = self.reminder2.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 24, 12, 0))

        CaseReminderHandler.now = datetime(2014, 6, 24, 12, 0)
        CaseReminderHandler.fire_reminders()
        reminder = self.reminder2.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 24, 12, 30))

        call1 = self.get_last_outbound_call(self.user1)
        self.assertTrue(call1.use_precached_first_response)
        self.assertFalse(call1.answered)

        call2 = self.get_last_outbound_call(self.user2)
        self.assertTrue(call2.use_precached_first_response)
        self.assertFalse(call2.answered)

        old_call1 = call1
        old_call2 = call2

        CaseReminderHandler.now = datetime(2014, 6, 24, 12, 30)
        CaseReminderHandler.fire_reminders()
        reminder = self.reminder2.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 24, 13, 0))

        call1 = self.get_last_outbound_call(self.user1)
        self.assertTrue(call1.use_precached_first_response)
        self.assertNotEqual(call1._id, old_call1._id)

        call2 = self.get_last_outbound_call(self.user2)
        self.assertTrue(call2.use_precached_first_response)
        self.assertFalse(call2.answered)
        self.assertNotEqual(call2._id, old_call2._id)

        kookoo_session_id = call1.gateway_session_id[7:]
        resp = self.kookoo_in({
            "cid": "0001",
            "sid": kookoo_session_id,
            "event": "NewCall",
        })
        self.assertEqual(
            resp, '<response sid="%s"><collectdtmf l="1" o="3000">'
            '<playtext>How do you feel today? Press 1 for good, 2 for bad.'
            '</playtext></collectdtmf></response>' % kookoo_session_id)

        resp = self.kookoo_in({
            "cid": "0001",
            "sid": kookoo_session_id,
            "event": "GotDTMF",
            "data": "2",
        })
        self.assertEqual(
            resp, '<response sid="%s"><collectdtmf l="1" o="3000">'
            '<playtext>Did you remember to take your meds today? Press 1 for yes, 2 for no.'
            '</playtext></collectdtmf></response>' % kookoo_session_id)

        resp = self.kookoo_in({
            "cid": "0001",
            "sid": kookoo_session_id,
            "event": "GotDTMF",
            "data": "1",
        })
        self.assertEqual(
            resp,
            '<response sid="%s"><hangup/></response>' % kookoo_session_id)

        self.kookoo_finished({
            "sid": kookoo_session_id,
            "status": "answered",
            "duration": "20",
        })
        call1 = CallLog.get(call1._id)
        self.assertTrue(call1.answered)
        self.assertEqual(call1.duration, 20)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "how_feel", "2")
        self.assertFormQuestionEquals(form, "take_meds", "1")
        self.assertEqual(form.form["meta"]["userID"], self.user1._id)
        case = CommCareCase.get(self.case._id)
        self.assertCasePropertyEquals(case, "how_feel", "2")
        self.assertCasePropertyEquals(case, "take_meds", "1")
        self.assertEqual(case.user_id, self.user1._id)

        old_call1 = call1
        old_call2 = call2

        CaseReminderHandler.now = datetime(2014, 6, 24, 13, 0)
        CaseReminderHandler.fire_reminders()
        reminder = self.reminder2.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 25, 12, 0))

        call1 = self.get_last_outbound_call(self.user1)
        # No new call for user1 since it was already answered
        self.assertEqual(call1._id, old_call1._id)

        call2 = self.get_last_outbound_call(self.user2)
        self.assertTrue(call2.use_precached_first_response)
        self.assertNotEqual(call2._id, old_call2._id)

        kookoo_session_id = call2.gateway_session_id[7:]
        resp = self.kookoo_in({
            "cid": "0002",
            "sid": kookoo_session_id,
            "event": "NewCall",
        })
        self.assertEqual(
            resp, '<response sid="%s"><collectdtmf l="1" o="3000">'
            '<playtext>How do you feel today? Press 1 for good, 2 for bad.'
            '</playtext></collectdtmf></response>' % kookoo_session_id)

        resp = self.kookoo_in({
            "cid": "0002",
            "sid": kookoo_session_id,
            "event": "GotDTMF",
            "data": "1",
        })
        self.assertEqual(
            resp, '<response sid="%s"><collectdtmf l="1" o="3000">'
            '<playtext>Did you remember to take your meds today? Press 1 for yes, 2 for no.'
            '</playtext></collectdtmf></response>' % kookoo_session_id)

        resp = self.kookoo_in({
            "cid": "0002",
            "sid": kookoo_session_id,
            "event": "GotDTMF",
            "data": "2",
        })
        self.assertEqual(
            resp,
            '<response sid="%s"><hangup/></response>' % kookoo_session_id)

        self.kookoo_finished({
            "sid": kookoo_session_id,
            "status": "answered",
            "duration": "20",
        })
        call2 = CallLog.get(call2._id)
        self.assertTrue(call2.answered)
        self.assertEqual(call2.duration, 20)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "how_feel", "1")
        self.assertFormQuestionEquals(form, "take_meds", "2")
        self.assertEqual(form.form["meta"]["userID"], self.user2._id)
        case = CommCareCase.get(self.case._id)
        self.assertCasePropertyEquals(case, "how_feel", "1")
        self.assertCasePropertyEquals(case, "take_meds", "2")
        self.assertEqual(case.user_id, self.user2._id)

    def tearDown(self):
        self.ivr_backend.delete()
        super(KooKooTestCase, self).tearDown()
Exemplo n.º 8
0
    def test_cache(self, check_state_mock):
        domain = 'reminder-cache-test'

        # Nothing expected at first
        self.assertEqual(
            CaseReminderHandler.get_handler_ids(domain),
            []
        )

        # Create two reminder definitions of different types
        handler1 = CaseReminderHandler(
            domain=domain,
            reminder_type=REMINDER_TYPE_DEFAULT,
        )
        handler1.save()
        self.addCleanup(handler1.delete)

        handler2 = CaseReminderHandler(
            domain=domain,
            reminder_type=REMINDER_TYPE_ONE_TIME,
        )
        handler2.save()
        self.addCleanup(handler2.delete)

        self.assertEqual(
            CaseReminderHandler.get_handler_ids(domain, reminder_type_filter=REMINDER_TYPE_DEFAULT),
            [handler1._id]
        )

        self.assertEqual(
            CaseReminderHandler.get_handler_ids(domain, reminder_type_filter=REMINDER_TYPE_ONE_TIME),
            [handler2._id]
        )

        self.assertEqual(
            sorted(CaseReminderHandler.get_handler_ids(domain)),
            sorted([handler1._id, handler2._id])
        )

        # Add another with default type
        handler3 = CaseReminderHandler(
            domain=domain,
            reminder_type=REMINDER_TYPE_DEFAULT,
        )
        handler3.save()
        self.addCleanup(handler3.delete)

        self.assertEqual(
            sorted(CaseReminderHandler.get_handler_ids(domain, reminder_type_filter=REMINDER_TYPE_DEFAULT)),
            sorted([handler1._id, handler3._id])
        )

        self.assertEqual(
            CaseReminderHandler.get_handler_ids(domain, reminder_type_filter=REMINDER_TYPE_ONE_TIME),
            [handler2._id]
        )

        self.assertEqual(
            sorted(CaseReminderHandler.get_handler_ids(domain)),
            sorted([handler1._id, handler2._id, handler3._id])
        )

        # Retire the one-time reminder
        handler2.retire()

        self.assertEqual(
            sorted(CaseReminderHandler.get_handler_ids(domain, reminder_type_filter=REMINDER_TYPE_DEFAULT)),
            sorted([handler1._id, handler3._id])
        )

        self.assertEqual(
            CaseReminderHandler.get_handler_ids(domain, reminder_type_filter=REMINDER_TYPE_ONE_TIME),
            []
        )

        self.assertEqual(
            sorted(CaseReminderHandler.get_handler_ids(domain)),
            sorted([handler1._id, handler3._id])
        )
Exemplo n.º 9
0
def add_complex_reminder_schedule(request, domain, handler_id=None):
    if handler_id:
        h = CaseReminderHandler.get(handler_id)
        if h.doc_type != 'CaseReminderHandler' or h.domain != domain:
            raise Http404
    else:
        h = None
    
    form_list = get_form_list(domain)
    
    if request.method == "POST":
        form = ComplexCaseReminderForm(request.POST)
        if form.is_valid():
            if h is None:
                h = CaseReminderHandler(domain=domain)
                h.ui_type = UI_COMPLEX
            h.case_type = form.cleaned_data["case_type"]
            h.nickname = form.cleaned_data["nickname"]
            h.default_lang = form.cleaned_data["default_lang"]
            h.method = form.cleaned_data["method"]
            h.recipient = form.cleaned_data["recipient"]
            h.start_property = form.cleaned_data["start_property"]
            h.start_value = form.cleaned_data["start_value"]
            h.start_date = form.cleaned_data["start_date"]
            h.start_offset = form.cleaned_data["start_offset"]
            h.start_match_type = form.cleaned_data["start_match_type"]
            h.schedule_length = form.cleaned_data["schedule_length"]
            h.event_interpretation = form.cleaned_data["event_interpretation"]
            h.max_iteration_count = form.cleaned_data["max_iteration_count"]
            h.until = form.cleaned_data["until"]
            h.events = form.cleaned_data["events"]
            h.save()
            return HttpResponseRedirect(reverse('list_reminders', args=[domain]))
    else:
        if h is not None:
            initial = {
                "case_type"             : h.case_type
               ,"nickname"              : h.nickname
               ,"default_lang"          : h.default_lang
               ,"method"                : h.method
               ,"recipient"             : h.recipient
               ,"start_property"        : h.start_property
               ,"start_value"           : h.start_value
               ,"start_date"            : h.start_date
               ,"start_match_type"      : h.start_match_type
               ,"start_offset"          : h.start_offset
               ,"schedule_length"       : h.schedule_length
               ,"event_interpretation"  : h.event_interpretation
               ,"max_iteration_count"   : h.max_iteration_count
               ,"until"                 : h.until
               ,"events"                : h.events
            }
        else:
            initial = {}
        
        form = ComplexCaseReminderForm(initial=initial)
    
    return render_to_response(request, "reminders/partial/add_complex_reminder.html", {
        "domain":       domain
       ,"form":         form
       ,"form_list":    form_list
    })
Exemplo n.º 10
0
def add_survey(request, domain, survey_id=None):
    survey = None
    
    if survey_id is not None:
        survey = Survey.get(survey_id)
    
    if request.method == "POST":
        form = SurveyForm(request.POST)
        if form.is_valid():
            name = form.cleaned_data.get("name")
            waves = form.cleaned_data.get("waves")
            followups = form.cleaned_data.get("followups")
            samples = form.cleaned_data.get("samples")
            send_automatically = form.cleaned_data.get("send_automatically")
            send_followup = form.cleaned_data.get("send_followup")
            
            sample_data = {}
            for sample in samples:
                sample_data[sample["sample_id"]] = sample
            
            if send_followup:
                timeout_intervals = [int(followup["interval"]) * 1440 for followup in followups]
            else:
                timeout_intervals = []
            
            timeout_duration = sum(timeout_intervals) / 1440
            final_timeout = lambda wave : [((wave.end_date - wave.date).days - timeout_duration) * 1440]
            
            if survey is None:
                wave_list = []
                for wave in waves:
                    wave_list.append(SurveyWave(
                        date=parse(wave["date"]).date(),
                        time=parse(wave["time"]).time(),
                        end_date=parse(wave["end_date"]).date(),
                        form_id=wave["form_id"],
                        reminder_definitions={},
                        delegation_tasks={},
                    ))
                
                if send_automatically:
                    for wave in wave_list:
                        for sample in samples:
                            if sample["method"] == "SMS":
                                handler = CaseReminderHandler(
                                    domain = domain,
                                    nickname = "Survey '%s'" % name,
                                    default_lang = "en",
                                    method = "survey",
                                    recipient = RECIPIENT_SURVEY_SAMPLE,
                                    start_condition_type = ON_DATETIME,
                                    start_datetime = datetime.combine(wave.date, time(0,0)),
                                    start_offset = 0,
                                    events = [CaseReminderEvent(
                                        day_num = 0,
                                        fire_time = wave.time,
                                        form_unique_id = wave.form_id,
                                        callback_timeout_intervals = timeout_intervals + final_timeout(wave),
                                    )],
                                    schedule_length = 1,
                                    event_interpretation = EVENT_AS_SCHEDULE,
                                    max_iteration_count = 1,
                                    sample_id = sample["sample_id"],
                                    survey_incentive = sample["incentive"],
                                    submit_partial_forms = True,
                                )
                                handler.save()
                                wave.reminder_definitions[sample["sample_id"]] = handler._id
                
                survey = Survey (
                    domain = domain,
                    name = name,
                    waves = wave_list,
                    followups = followups,
                    samples = samples,
                    send_automatically = send_automatically,
                    send_followup = send_followup
                )
            else:
                current_waves = survey.waves
                survey.waves = []
                unchanged_wave_json = []
                
                # Keep any waves that didn't change in case the surveys are in progress
                for wave in current_waves:
                    for wave_json in waves:
                        parsed_date = parse(wave_json["date"]).date()
                        parsed_time = parse(wave_json["time"]).time()
                        if parsed_date == wave.date and parsed_time == wave.time and wave_json["form_id"] == wave.form_id:
                            wave.end_date = parse(wave_json["end_date"]).date()
                            survey.waves.append(wave)
                            unchanged_wave_json.append(wave_json)
                            continue
                
                for wave in survey.waves:
                    current_waves.remove(wave)
                
                for wave_json in unchanged_wave_json:
                    waves.remove(wave_json)
                
                # Retire reminder definitions / close delegation tasks for old waves
                for wave in current_waves:
                    for sample_id, handler_id in wave.reminder_definitions.items():
                        handler = CaseReminderHandler.get(handler_id)
                        handler.retire()
                    for sample_id, delegation_data in wave.delegation_tasks.items():
                        for case_id, delegation_case_id in delegation_data.items():
                            close_task(domain, delegation_case_id, request.couch_user.get_id)
                
                # Add in new waves
                for wave_json in waves:
                    survey.waves.append(SurveyWave(
                        date=parse(wave_json["date"]).date(),
                        time=parse(wave_json["time"]).time(),
                        end_date=parse(wave_json["end_date"]).date(),
                        form_id=wave_json["form_id"],
                        reminder_definitions={},
                        delegation_tasks={},
                    ))
                
                # Retire reminder definitions that are no longer needed
                if send_automatically:
                    new_sample_ids = [sample_json["sample_id"] for sample_json in samples if sample_json["method"] == "SMS"]
                else:
                    new_sample_ids = []
                
                for wave in survey.waves:
                    for sample_id, handler_id in wave.reminder_definitions.items():
                        if sample_id not in new_sample_ids:
                            handler = CaseReminderHandler.get(handler_id)
                            handler.retire()
                            del wave.reminder_definitions[sample_id]
                
                # Update existing reminder definitions
                for wave in survey.waves:
                    for sample_id, handler_id in wave.reminder_definitions.items():
                        handler = CaseReminderHandler.get(handler_id)
                        handler.events[0].callback_timeout_intervals = timeout_intervals + final_timeout(wave)
                        handler.nickname = "Survey '%s'" % name
                        handler.survey_incentive = sample_data[sample_id]["incentive"]
                        handler.save()
                
                # Create additional reminder definitions as necessary
                for wave in survey.waves:
                    for sample_id in new_sample_ids:
                        if sample_id not in wave.reminder_definitions:
                            handler = CaseReminderHandler(
                                domain = domain,
                                nickname = "Survey '%s'" % name,
                                default_lang = "en",
                                method = "survey",
                                recipient = RECIPIENT_SURVEY_SAMPLE,
                                start_condition_type = ON_DATETIME,
                                start_datetime = datetime.combine(wave.date, time(0,0)),
                                start_offset = 0,
                                events = [CaseReminderEvent(
                                    day_num = 0,
                                    fire_time = wave.time,
                                    form_unique_id = wave.form_id,
                                    callback_timeout_intervals = timeout_intervals + final_timeout(wave),
                                )],
                                schedule_length = 1,
                                event_interpretation = EVENT_AS_SCHEDULE,
                                max_iteration_count = 1,
                                sample_id = sample_id,
                                survey_incentive = sample_data[sample_id]["incentive"],
                                submit_partial_forms = True,
                            )
                            handler.save()
                            wave.reminder_definitions[sample_id] = handler._id
                
                # Set the rest of the survey info
                survey.name = name
                survey.followups = followups
                survey.samples = samples
                survey.send_automatically = send_automatically
                survey.send_followup = send_followup
            
            # Sort the questionnaire waves by date and time
            survey.waves = sorted(survey.waves, key = lambda wave : datetime.combine(wave.date, wave.time))
            
            # Create / Close delegation tasks as necessary for samples with method "CATI"
            survey.update_delegation_tasks(request.couch_user.get_id)
            
            survey.save()
            return HttpResponseRedirect(reverse("survey_list", args=[domain]))
    else:
        initial = {}
        if survey is not None:
            waves = []
            samples = [SurveySample.get(sample["sample_id"]) for sample in survey.samples]
            utcnow = datetime.utcnow()
            for wave in survey.waves:
                wave_json = {
                    "date" : str(wave.date),
                    "form_id" : wave.form_id,
                    "time" : str(wave.time),
                    "ignore" : wave.has_started(survey),
                    "end_date" : str(wave.end_date),
                }
                
                waves.append(wave_json)
            
            initial["name"] = survey.name
            initial["waves"] = waves
            initial["followups"] = survey.followups
            initial["samples"] = survey.samples
            initial["send_automatically"] = survey.send_automatically
            initial["send_followup"] = survey.send_followup
            
        form = SurveyForm(initial=initial)
    
    form_list = get_form_list(domain)
    form_list.insert(0, {"code":"--choose--", "name":"-- Choose --"})
    sample_list = get_sample_list(domain)
    sample_list.insert(0, {"code":"--choose--", "name":"-- Choose --"})
    
    context = {
        "domain" : domain,
        "survey_id" : survey_id,
        "form" : form,
        "form_list" : form_list,
        "sample_list" : sample_list,
        "method_list" : SURVEY_METHOD_LIST,
        "user_list" : CommCareUser.by_domain(domain),
        "started" : survey.has_started() if survey is not None else False,
    }
    return render(request, "reminders/partial/add_survey.html", context)
Exemplo n.º 11
0
def add_complex_reminder_schedule(request, domain, handler_id=None):
    if handler_id:
        h = CaseReminderHandler.get(handler_id)
        if h.doc_type != 'CaseReminderHandler' or h.domain != domain:
            raise Http404
    else:
        h = None
    
    form_list = get_form_list(domain)
    sample_list = get_sample_list(domain)
    
    if request.method == "POST":
        form = ComplexCaseReminderForm(request.POST)
        if form.is_valid():
            if h is None:
                h = CaseReminderHandler(domain=domain)
                h.ui_type = UI_COMPLEX
            else:
                if h.start_condition_type != form.cleaned_data["start_condition_type"]:
                    for reminder in h.get_reminders():
                        reminder.retire()
            h.active = form.cleaned_data["active"]
            h.case_type = form.cleaned_data["case_type"]
            h.nickname = form.cleaned_data["nickname"]
            h.default_lang = form.cleaned_data["default_lang"]
            h.method = form.cleaned_data["method"]
            h.recipient = form.cleaned_data["recipient"]
            h.start_property = form.cleaned_data["start_property"]
            h.start_value = form.cleaned_data["start_value"]
            h.start_date = form.cleaned_data["start_date"]
            h.start_offset = form.cleaned_data["start_offset"]
            h.start_match_type = form.cleaned_data["start_match_type"]
            h.schedule_length = form.cleaned_data["schedule_length"]
            h.event_interpretation = form.cleaned_data["event_interpretation"]
            h.max_iteration_count = form.cleaned_data["max_iteration_count"]
            h.until = form.cleaned_data["until"]
            h.events = form.cleaned_data["events"]
            h.submit_partial_forms = form.cleaned_data["submit_partial_forms"]
            h.include_case_side_effects = form.cleaned_data["include_case_side_effects"]
            h.ui_frequency = form.cleaned_data["frequency"]
            h.start_condition_type = form.cleaned_data["start_condition_type"]
            h.max_question_retries = form.cleaned_data["max_question_retries"]
            if form.cleaned_data["start_condition_type"] == "ON_DATETIME":
                dt = parse(form.cleaned_data["start_datetime_date"]).date()
                tm = parse(form.cleaned_data["start_datetime_time"]).time()
                h.start_datetime = datetime.combine(dt, tm)
            else:
                h.start_datetime = None
            h.sample_id = form.cleaned_data["sample_id"]
            h.save()
            return HttpResponseRedirect(reverse('list_reminders', args=[domain]))
    else:
        if h is not None:
            initial = {
                "active"                : h.active,
                "case_type"             : h.case_type,
                "nickname"              : h.nickname,
                "default_lang"          : h.default_lang,
                "method"                : h.method,
                "recipient"             : h.recipient,
                "start_property"        : h.start_property,
                "start_value"           : h.start_value,
                "start_date"            : h.start_date,
                "start_match_type"      : h.start_match_type,
                "start_offset"          : h.start_offset,
                "schedule_length"       : h.schedule_length,
                "event_interpretation"  : h.event_interpretation,
                "max_iteration_count"   : h.max_iteration_count,
                "until"                 : h.until,
                "events"                : h.events,
                "submit_partial_forms"  : h.submit_partial_forms,
                "include_case_side_effects" : h.include_case_side_effects,
                "start_condition_type"  : h.start_condition_type,
                "start_datetime_date"   : str(h.start_datetime.date()) if isinstance(h.start_datetime, datetime) else None,
                "start_datetime_time"   : str(h.start_datetime.time()) if isinstance(h.start_datetime, datetime) else None,
                "frequency"             : h.ui_frequency,
                "sample_id"             : h.sample_id,
                "use_until"             : "Y" if h.until is not None else "N",
                "max_question_retries"  : h.max_question_retries,
            }
        else:
            initial = {
                "events"    : [CaseReminderEvent(day_num=0, fire_time=time(0,0), message={"":""}, callback_timeout_intervals=[], form_unique_id=None)],
                "use_until" : "N",
                "max_question_retries" : QUESTION_RETRY_CHOICES[-1],
                "active" : True,
            }
        
        form = ComplexCaseReminderForm(initial=initial)
    
    return render(request, "reminders/partial/add_complex_reminder.html", {
        "domain":       domain,
        "form":         form,
        "form_list":    form_list,
        "handler_id":   handler_id,
        "sample_list":  sample_list,
    })
Exemplo n.º 12
0
class KooKooTestCase(TouchformsTestCase):
    """
    Must be run manually (see corehq.apps.sms.tests.util.TouchformsTestCase)
    """

    def setUp(self):
        super(KooKooTestCase, self).setUp()
        self.ivr_backend = SQLKooKooBackend(
            backend_type=SQLKooKooBackend.IVR,
            name="MOBILE_BACKEND_KOOKOO",
            is_global=True,
            hq_api_id=SQLKooKooBackend.get_api_id()
        )
        self.ivr_backend.set_extra_fields(api_key="xyz")
        self.ivr_backend.save()

        self.user1 = self.create_mobile_worker("user1", "123", "91001", save_vn=False)
        self.user2 = self.create_mobile_worker("user2", "123", "91002", save_vn=False)
        self.create_group("group1", [self.user1, self.user2])

        dirname = os.path.dirname(os.path.abspath(__file__))
        self.load_app("app1.json", dirname)
        self.load_app("app2.json", dirname)

        self.reminder1 = CaseReminderHandler(
            domain=self.domain,
            active=True,
            case_type="participant",
            method=METHOD_IVR_SURVEY,
            recipient=RECIPIENT_CASE,
            sample_id=None,
            user_group_id=None,
            user_id=None,
            case_id=None,
            reminder_type=REMINDER_TYPE_DEFAULT,
            submit_partial_forms=True,
            include_case_side_effects=False,
            max_question_retries=5,
            start_condition_type=CASE_CRITERIA,
            start_property="name",
            start_value="case1",
            start_date=None,
            start_offset=0,
            start_match_type=MATCH_EXACT,
            events=[
                CaseReminderEvent(
                    day_num=0,
                    fire_time=time(12,0),
                    fire_time_type=FIRE_TIME_DEFAULT,
                    callback_timeout_intervals=[30],
                    form_unique_id=self.apps[0].modules[0].forms[0].unique_id,
                ),
                CaseReminderEvent(
                    day_num=0,
                    fire_time=time(13,0),
                    fire_time_type=FIRE_TIME_DEFAULT,
                    callback_timeout_intervals=[30],
                    form_unique_id=self.apps[0].modules[0].forms[1].unique_id,
                ),
            ],
            schedule_length=1,
            event_interpretation=EVENT_AS_SCHEDULE,
            max_iteration_count=7,
            until=None,
            force_surveys_to_use_triggered_case=False,
        )
        self.reminder1.save()

        self.reminder2 = CaseReminderHandler(
            domain=self.domain,
            active=True,
            case_type="participant",
            method=METHOD_IVR_SURVEY,
            recipient=RECIPIENT_OWNER,
            sample_id=None,
            user_group_id=None,
            user_id=None,
            case_id=None,
            reminder_type=REMINDER_TYPE_DEFAULT,
            submit_partial_forms=True,
            include_case_side_effects=True,
            max_question_retries=5,
            start_condition_type=CASE_CRITERIA,
            start_property="name",
            start_value="case2",
            start_date=None,
            start_offset=0,
            start_match_type=MATCH_EXACT,
            events=[
                CaseReminderEvent(
                    day_num=0,
                    fire_time=time(12,0),
                    fire_time_type=FIRE_TIME_DEFAULT,
                    callback_timeout_intervals=[30, 30],
                    form_unique_id=self.apps[1].modules[0].forms[0].unique_id,
                ),
            ],
            schedule_length=1,
            event_interpretation=EVENT_AS_SCHEDULE,
            max_iteration_count=7,
            until=None,
            force_surveys_to_use_triggered_case=False,
        )
        self.reminder2.save()

    def kookoo_in(self, params):
        """
        params should be a dictionary containing:
        event, cid, sid, and (optionally) data
        """
        params = urllib.urlencode(params)
        url = "%s/kookoo/ivr/" % self.live_server_url
        return urllib2.urlopen("%s?%s" % (url, params)).read()

    def kookoo_finished(self, params):
        """
        params should be a dictionary containing:
        sid, status, and duration
        """
        params = urllib.urlencode(params)
        url = "%s/kookoo/ivr_finished/" % self.live_server_url
        return urllib2.urlopen(url, params).read()

    def testOutbound(self):
        # Send an outbound call using self.reminder1 to self.case
        # and answer it
        CaseReminderHandler.now = datetime(2014, 6, 23, 10, 0)
        self.case = CommCareCase.get(register_sms_contact(
            self.domain,
            'participant',
            'case1',
            self.user1._id,
            '91000',
            owner_id=self.groups[0]._id,
            contact_ivr_backend_id='MOBILE_BACKEND_KOOKOO'
        ))
        CaseReminderHandler.now = datetime(2014, 6, 23, 12, 0)
        CaseReminderHandler.fire_reminders()
        reminder = self.reminder1.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 23, 12, 30))

        call = self.get_last_outbound_call(self.case)
        self.assertTrue(call.use_precached_first_response)

        kookoo_session_id = call.gateway_session_id[7:]
        resp = self.kookoo_in({
            "cid": "0000",
            "sid": kookoo_session_id,
            "event": "NewCall",
        })
        self.assertEqual(resp, '<response sid="%s"><collectdtmf l="1" o="3000">'
            '<playtext>How do you feel today? Press 1 for good, 2 for bad.'
            '</playtext></collectdtmf></response>' % kookoo_session_id)

        resp = self.kookoo_in({
            "cid": "0000",
            "sid": kookoo_session_id,
            "event": "GotDTMF",
            "data": "1",
        })
        self.assertEqual(resp, '<response sid="%s"><collectdtmf l="1" o="3000">'
            '<playtext>Did you remember to take your meds today? Press 1 for yes, 2 for no.'
            '</playtext></collectdtmf></response>' % kookoo_session_id)

        resp = self.kookoo_in({
            "cid": "0000",
            "sid": kookoo_session_id,
            "event": "GotDTMF",
            "data": "2",
        })
        self.assertEqual(resp, '<response sid="%s"><hangup/></response>' % kookoo_session_id)

        self.kookoo_finished({
            "sid": kookoo_session_id,
            "status": "answered",
            "duration": "20",
        })

        call = CallLog.get(call._id)
        self.assertTrue(call.answered)
        self.assertEqual(call.duration, 20)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "how_feel", "1")
        self.assertFormQuestionEquals(form, "take_meds", "2")
        case = CommCareCase.get(self.case._id)
        self.assertCasePropertyEquals(case, "how_feel", "1")
        self.assertCasePropertyEquals(case, "take_meds", "2")

        CaseReminderHandler.now = datetime(2014, 6, 23, 12, 30)
        CaseReminderHandler.fire_reminders()

        reminder = self.reminder1.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 23, 13, 0))

        last_call = self.get_last_outbound_call(self.case)
        self.assertEqual(call._id, last_call._id)

        # Move on to the second event which now uses an all-label form and
        # should not precache the first ivr response
        CaseReminderHandler.now = datetime(2014, 6, 23, 13, 0)
        CaseReminderHandler.fire_reminders()

        reminder = self.reminder1.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 23, 13, 30))

        call = self.get_last_outbound_call(self.case)
        self.assertFalse(call.use_precached_first_response)

        kookoo_session_id = call.gateway_session_id[7:]
        resp = self.kookoo_in({
            "cid": "0000",
            "sid": kookoo_session_id,
            "event": "NewCall",
        })
        self.assertEqual(resp, '<response sid="%s">'
            '<playtext>This is just a reminder to take your meds.'
            '</playtext><hangup/></response>' % kookoo_session_id)

        self.kookoo_finished({
            "sid": kookoo_session_id,
            "status": "answered",
            "duration": "5",
        })

        call = CallLog.get(call._id)
        self.assertTrue(call.answered)
        self.assertEqual(call.duration, 5)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "label", "ok")

        CaseReminderHandler.now = datetime(2014, 6, 23, 13, 30)
        CaseReminderHandler.fire_reminders()

        reminder = self.reminder1.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 24, 12, 0))

        last_call = self.get_last_outbound_call(self.case)
        self.assertEqual(call._id, last_call._id)

        # Now test sending outbound calls to a group of users (the owners
        # of the case)

        # Allow sending to unverified numbers
        self.domain_obj = Domain.get(self.domain_obj._id)
        self.domain_obj.send_to_duplicated_case_numbers = True
        self.domain_obj.save()

        CaseReminderHandler.now = datetime(2014, 6, 24, 10, 0)
        self.case = CommCareCase.get(register_sms_contact(
            self.domain,
            'participant',
            'case2',
            self.user1._id,
            '91003',
            owner_id=self.groups[0]._id,
        ))
        reminder = self.reminder2.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 24, 12, 0))

        CaseReminderHandler.now = datetime(2014, 6, 24, 12, 0)
        CaseReminderHandler.fire_reminders()
        reminder = self.reminder2.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 24, 12, 30))

        call1 = self.get_last_outbound_call(self.user1)
        self.assertTrue(call1.use_precached_first_response)
        self.assertFalse(call1.answered)

        call2 = self.get_last_outbound_call(self.user2)
        self.assertTrue(call2.use_precached_first_response)
        self.assertFalse(call2.answered)

        old_call1 = call1
        old_call2 = call2

        CaseReminderHandler.now = datetime(2014, 6, 24, 12, 30)
        CaseReminderHandler.fire_reminders()
        reminder = self.reminder2.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 24, 13, 0))

        call1 = self.get_last_outbound_call(self.user1)
        self.assertTrue(call1.use_precached_first_response)
        self.assertNotEqual(call1._id, old_call1._id)

        call2 = self.get_last_outbound_call(self.user2)
        self.assertTrue(call2.use_precached_first_response)
        self.assertFalse(call2.answered)
        self.assertNotEqual(call2._id, old_call2._id)

        kookoo_session_id = call1.gateway_session_id[7:]
        resp = self.kookoo_in({
            "cid": "0001",
            "sid": kookoo_session_id,
            "event": "NewCall",
        })
        self.assertEqual(resp, '<response sid="%s"><collectdtmf l="1" o="3000">'
            '<playtext>How do you feel today? Press 1 for good, 2 for bad.'
            '</playtext></collectdtmf></response>' % kookoo_session_id)

        resp = self.kookoo_in({
            "cid": "0001",
            "sid": kookoo_session_id,
            "event": "GotDTMF",
            "data": "2",
        })
        self.assertEqual(resp, '<response sid="%s"><collectdtmf l="1" o="3000">'
            '<playtext>Did you remember to take your meds today? Press 1 for yes, 2 for no.'
            '</playtext></collectdtmf></response>' % kookoo_session_id)

        resp = self.kookoo_in({
            "cid": "0001",
            "sid": kookoo_session_id,
            "event": "GotDTMF",
            "data": "1",
        })
        self.assertEqual(resp, '<response sid="%s"><hangup/></response>' % kookoo_session_id)

        self.kookoo_finished({
            "sid": kookoo_session_id,
            "status": "answered",
            "duration": "20",
        })
        call1 = CallLog.get(call1._id)
        self.assertTrue(call1.answered)
        self.assertEqual(call1.duration, 20)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "how_feel", "2")
        self.assertFormQuestionEquals(form, "take_meds", "1")
        self.assertEqual(form.form["meta"]["userID"], self.user1._id)
        case = CommCareCase.get(self.case._id)
        self.assertCasePropertyEquals(case, "how_feel", "2")
        self.assertCasePropertyEquals(case, "take_meds", "1")
        self.assertEqual(case.user_id, self.user1._id)

        old_call1 = call1
        old_call2 = call2

        CaseReminderHandler.now = datetime(2014, 6, 24, 13, 0)
        CaseReminderHandler.fire_reminders()
        reminder = self.reminder2.get_reminder(self.case)
        self.assertEquals(reminder.next_fire, datetime(2014, 6, 25, 12, 0))

        call1 = self.get_last_outbound_call(self.user1)
        # No new call for user1 since it was already answered
        self.assertEqual(call1._id, old_call1._id)

        call2 = self.get_last_outbound_call(self.user2)
        self.assertTrue(call2.use_precached_first_response)
        self.assertNotEqual(call2._id, old_call2._id)

        kookoo_session_id = call2.gateway_session_id[7:]
        resp = self.kookoo_in({
            "cid": "0002",
            "sid": kookoo_session_id,
            "event": "NewCall",
        })
        self.assertEqual(resp, '<response sid="%s"><collectdtmf l="1" o="3000">'
            '<playtext>How do you feel today? Press 1 for good, 2 for bad.'
            '</playtext></collectdtmf></response>' % kookoo_session_id)

        resp = self.kookoo_in({
            "cid": "0002",
            "sid": kookoo_session_id,
            "event": "GotDTMF",
            "data": "1",
        })
        self.assertEqual(resp, '<response sid="%s"><collectdtmf l="1" o="3000">'
            '<playtext>Did you remember to take your meds today? Press 1 for yes, 2 for no.'
            '</playtext></collectdtmf></response>' % kookoo_session_id)

        resp = self.kookoo_in({
            "cid": "0002",
            "sid": kookoo_session_id,
            "event": "GotDTMF",
            "data": "2",
        })
        self.assertEqual(resp, '<response sid="%s"><hangup/></response>' % kookoo_session_id)

        self.kookoo_finished({
            "sid": kookoo_session_id,
            "status": "answered",
            "duration": "20",
        })
        call2 = CallLog.get(call2._id)
        self.assertTrue(call2.answered)
        self.assertEqual(call2.duration, 20)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "how_feel", "1")
        self.assertFormQuestionEquals(form, "take_meds", "2")
        self.assertEqual(form.form["meta"]["userID"], self.user2._id)
        case = CommCareCase.get(self.case._id)
        self.assertCasePropertyEquals(case, "how_feel", "1")
        self.assertCasePropertyEquals(case, "take_meds", "2")
        self.assertEqual(case.user_id, self.user2._id)

    def tearDown(self):
        self.ivr_backend.delete()
        super(KooKooTestCase, self).tearDown()
Exemplo n.º 13
0
def add_survey(request, domain, survey_id=None):
    survey = None

    if survey_id is not None:
        survey = Survey.get(survey_id)

    if request.method == "POST":
        form = SurveyForm(request.POST)
        if form.is_valid():
            name = form.cleaned_data.get("name")
            waves = form.cleaned_data.get("waves")
            followups = form.cleaned_data.get("followups")
            samples = form.cleaned_data.get("samples")
            send_automatically = form.cleaned_data.get("send_automatically")
            send_followup = form.cleaned_data.get("send_followup")

            sample_data = {}
            for sample in samples:
                sample_data[sample["sample_id"]] = sample

            if send_followup:
                timeout_intervals = [
                    int(followup["interval"]) * 1440 for followup in followups
                ]
            else:
                timeout_intervals = []

            timeout_duration = sum(timeout_intervals) / 1440
            final_timeout = lambda wave: [(
                (wave.end_date - wave.date).days - timeout_duration) * 1440]

            if survey is None:
                wave_list = []
                for wave in waves:
                    wave_list.append(
                        SurveyWave(
                            date=parse(wave["date"]).date(),
                            time=parse(wave["time"]).time(),
                            end_date=parse(wave["end_date"]).date(),
                            form_id=wave["form_id"],
                            reminder_definitions={},
                            delegation_tasks={},
                        ))

                if send_automatically:
                    for wave in wave_list:
                        for sample in samples:
                            if sample["method"] == "SMS":
                                handler = CaseReminderHandler(
                                    domain=domain,
                                    nickname="Survey '%s'" % name,
                                    default_lang="en",
                                    method="survey",
                                    recipient=RECIPIENT_SURVEY_SAMPLE,
                                    start_condition_type=ON_DATETIME,
                                    start_datetime=datetime.combine(
                                        wave.date, time(0, 0)),
                                    start_offset=0,
                                    events=[
                                        CaseReminderEvent(
                                            day_num=0,
                                            fire_time=wave.time,
                                            form_unique_id=wave.form_id,
                                            callback_timeout_intervals=
                                            timeout_intervals +
                                            final_timeout(wave),
                                        )
                                    ],
                                    schedule_length=1,
                                    event_interpretation=EVENT_AS_SCHEDULE,
                                    max_iteration_count=1,
                                    sample_id=sample["sample_id"],
                                    survey_incentive=sample["incentive"],
                                    submit_partial_forms=True,
                                )
                                handler.save()
                                wave.reminder_definitions[
                                    sample["sample_id"]] = handler._id

                survey = Survey(domain=domain,
                                name=name,
                                waves=wave_list,
                                followups=followups,
                                samples=samples,
                                send_automatically=send_automatically,
                                send_followup=send_followup)
            else:
                current_waves = survey.waves
                survey.waves = []
                unchanged_wave_json = []

                # Keep any waves that didn't change in case the surveys are in progress
                for wave in current_waves:
                    for wave_json in waves:
                        parsed_date = parse(wave_json["date"]).date()
                        parsed_time = parse(wave_json["time"]).time()
                        if parsed_date == wave.date and parsed_time == wave.time and wave_json[
                                "form_id"] == wave.form_id:
                            wave.end_date = parse(wave_json["end_date"]).date()
                            survey.waves.append(wave)
                            unchanged_wave_json.append(wave_json)
                            continue

                for wave in survey.waves:
                    current_waves.remove(wave)

                for wave_json in unchanged_wave_json:
                    waves.remove(wave_json)

                # Retire reminder definitions / close delegation tasks for old waves
                for wave in current_waves:
                    for sample_id, handler_id in wave.reminder_definitions.items(
                    ):
                        handler = CaseReminderHandler.get(handler_id)
                        handler.retire()
                    for sample_id, delegation_data in wave.delegation_tasks.items(
                    ):
                        for case_id, delegation_case_id in delegation_data.items(
                        ):
                            close_task(domain, delegation_case_id,
                                       request.couch_user.get_id)

                # Add in new waves
                for wave_json in waves:
                    survey.waves.append(
                        SurveyWave(
                            date=parse(wave_json["date"]).date(),
                            time=parse(wave_json["time"]).time(),
                            end_date=parse(wave_json["end_date"]).date(),
                            form_id=wave_json["form_id"],
                            reminder_definitions={},
                            delegation_tasks={},
                        ))

                # Retire reminder definitions that are no longer needed
                if send_automatically:
                    new_sample_ids = [
                        sample_json["sample_id"] for sample_json in samples
                        if sample_json["method"] == "SMS"
                    ]
                else:
                    new_sample_ids = []

                for wave in survey.waves:
                    for sample_id, handler_id in wave.reminder_definitions.items(
                    ):
                        if sample_id not in new_sample_ids:
                            handler = CaseReminderHandler.get(handler_id)
                            handler.retire()
                            del wave.reminder_definitions[sample_id]

                # Update existing reminder definitions
                for wave in survey.waves:
                    for sample_id, handler_id in wave.reminder_definitions.items(
                    ):
                        handler = CaseReminderHandler.get(handler_id)
                        handler.events[
                            0].callback_timeout_intervals = timeout_intervals + final_timeout(
                                wave)
                        handler.nickname = "Survey '%s'" % name
                        handler.survey_incentive = sample_data[sample_id][
                            "incentive"]
                        handler.save()

                # Create additional reminder definitions as necessary
                for wave in survey.waves:
                    for sample_id in new_sample_ids:
                        if sample_id not in wave.reminder_definitions:
                            handler = CaseReminderHandler(
                                domain=domain,
                                nickname="Survey '%s'" % name,
                                default_lang="en",
                                method="survey",
                                recipient=RECIPIENT_SURVEY_SAMPLE,
                                start_condition_type=ON_DATETIME,
                                start_datetime=datetime.combine(
                                    wave.date, time(0, 0)),
                                start_offset=0,
                                events=[
                                    CaseReminderEvent(
                                        day_num=0,
                                        fire_time=wave.time,
                                        form_unique_id=wave.form_id,
                                        callback_timeout_intervals=
                                        timeout_intervals +
                                        final_timeout(wave),
                                    )
                                ],
                                schedule_length=1,
                                event_interpretation=EVENT_AS_SCHEDULE,
                                max_iteration_count=1,
                                sample_id=sample_id,
                                survey_incentive=sample_data[sample_id]
                                ["incentive"],
                                submit_partial_forms=True,
                            )
                            handler.save()
                            wave.reminder_definitions[sample_id] = handler._id

                # Set the rest of the survey info
                survey.name = name
                survey.followups = followups
                survey.samples = samples
                survey.send_automatically = send_automatically
                survey.send_followup = send_followup

            # Sort the questionnaire waves by date and time
            survey.waves = sorted(
                survey.waves,
                key=lambda wave: datetime.combine(wave.date, wave.time))

            # Create / Close delegation tasks as necessary for samples with method "CATI"
            survey.update_delegation_tasks(request.couch_user.get_id)

            survey.save()
            return HttpResponseRedirect(reverse("survey_list", args=[domain]))
    else:
        initial = {}
        if survey is not None:
            waves = []
            samples = [
                SurveySample.get(sample["sample_id"])
                for sample in survey.samples
            ]
            utcnow = datetime.utcnow()
            for wave in survey.waves:
                wave_json = {
                    "date": str(wave.date),
                    "form_id": wave.form_id,
                    "time": str(wave.time),
                    "ignore": wave.has_started(survey),
                    "end_date": str(wave.end_date),
                }

                waves.append(wave_json)

            initial["name"] = survey.name
            initial["waves"] = waves
            initial["followups"] = survey.followups
            initial["samples"] = survey.samples
            initial["send_automatically"] = survey.send_automatically
            initial["send_followup"] = survey.send_followup

        form = SurveyForm(initial=initial)

    form_list = get_form_list(domain)
    form_list.insert(0, {"code": "--choose--", "name": "-- Choose --"})
    sample_list = get_sample_list(domain)
    sample_list.insert(0, {"code": "--choose--", "name": "-- Choose --"})

    context = {
        "domain": domain,
        "survey_id": survey_id,
        "form": form,
        "form_list": form_list,
        "sample_list": sample_list,
        "method_list": SURVEY_METHOD_LIST,
        "user_list": CommCareUser.by_domain(domain),
        "started": survey.has_started() if survey is not None else False,
    }
    return render(request, "reminders/partial/add_survey.html", context)
Exemplo n.º 14
0
def add_complex_reminder_schedule(request, domain, handler_id=None):
    if handler_id:
        h = CaseReminderHandler.get(handler_id)
        if h.doc_type != 'CaseReminderHandler' or h.domain != domain:
            raise Http404
    else:
        h = None

    form_list = get_form_list(domain)
    sample_list = get_sample_list(domain)

    if request.method == "POST":
        form = ComplexCaseReminderForm(request.POST)
        if form.is_valid():
            if h is None:
                h = CaseReminderHandler(domain=domain)
                h.ui_type = UI_COMPLEX
            else:
                if h.start_condition_type != form.cleaned_data[
                        "start_condition_type"]:
                    for reminder in h.get_reminders():
                        reminder.retire()
            h.active = form.cleaned_data["active"]
            h.case_type = form.cleaned_data["case_type"]
            h.nickname = form.cleaned_data["nickname"]
            h.default_lang = form.cleaned_data["default_lang"]
            h.method = form.cleaned_data["method"]
            h.recipient = form.cleaned_data["recipient"]
            h.start_property = form.cleaned_data["start_property"]
            h.start_value = form.cleaned_data["start_value"]
            h.start_date = form.cleaned_data["start_date"]
            h.start_offset = form.cleaned_data["start_offset"]
            h.start_match_type = form.cleaned_data["start_match_type"]
            h.schedule_length = form.cleaned_data["schedule_length"]
            h.event_interpretation = form.cleaned_data["event_interpretation"]
            h.max_iteration_count = form.cleaned_data["max_iteration_count"]
            h.until = form.cleaned_data["until"]
            h.events = form.cleaned_data["events"]
            h.submit_partial_forms = form.cleaned_data["submit_partial_forms"]
            h.include_case_side_effects = form.cleaned_data[
                "include_case_side_effects"]
            h.ui_frequency = form.cleaned_data["frequency"]
            h.start_condition_type = form.cleaned_data["start_condition_type"]
            h.max_question_retries = form.cleaned_data["max_question_retries"]
            h.recipient_case_match_property = form.cleaned_data[
                "recipient_case_match_property"]
            h.recipient_case_match_type = form.cleaned_data[
                "recipient_case_match_type"]
            h.recipient_case_match_value = form.cleaned_data[
                "recipient_case_match_value"]
            if form.cleaned_data["start_condition_type"] == "ON_DATETIME":
                dt = parse(form.cleaned_data["start_datetime_date"]).date()
                tm = parse(form.cleaned_data["start_datetime_time"]).time()
                h.start_datetime = datetime.combine(dt, tm)
            else:
                h.start_datetime = None
            h.sample_id = form.cleaned_data["sample_id"]
            h.save()
            return HttpResponseRedirect(
                reverse('list_reminders', args=[domain]))
    else:
        if h is not None:
            initial = {
                "active":
                h.active,
                "case_type":
                h.case_type,
                "nickname":
                h.nickname,
                "default_lang":
                h.default_lang,
                "method":
                h.method,
                "recipient":
                h.recipient,
                "start_property":
                h.start_property,
                "start_value":
                h.start_value,
                "start_date":
                h.start_date,
                "start_match_type":
                h.start_match_type,
                "start_offset":
                h.start_offset,
                "schedule_length":
                h.schedule_length,
                "event_interpretation":
                h.event_interpretation,
                "max_iteration_count":
                h.max_iteration_count,
                "until":
                h.until,
                "events":
                h.events,
                "submit_partial_forms":
                h.submit_partial_forms,
                "include_case_side_effects":
                h.include_case_side_effects,
                "start_condition_type":
                h.start_condition_type,
                "start_datetime_date":
                str(h.start_datetime.date()) if isinstance(
                    h.start_datetime, datetime) else None,
                "start_datetime_time":
                str(h.start_datetime.time()) if isinstance(
                    h.start_datetime, datetime) else None,
                "frequency":
                h.ui_frequency,
                "sample_id":
                h.sample_id,
                "use_until":
                "Y" if h.until is not None else "N",
                "max_question_retries":
                h.max_question_retries,
                "recipient_case_match_property":
                h.recipient_case_match_property,
                "recipient_case_match_type":
                h.recipient_case_match_type,
                "recipient_case_match_value":
                h.recipient_case_match_value,
            }
        else:
            initial = {
                "events": [
                    CaseReminderEvent(day_num=0,
                                      fire_time=time(0, 0),
                                      message={"": ""},
                                      callback_timeout_intervals=[],
                                      form_unique_id=None)
                ],
                "use_until":
                "N",
                "max_question_retries":
                QUESTION_RETRY_CHOICES[-1],
                "active":
                True,
            }

        form = ComplexCaseReminderForm(initial=initial)

    return render(
        request, "reminders/partial/add_complex_reminder.html", {
            "domain": domain,
            "form": form,
            "form_list": form_list,
            "handler_id": handler_id,
            "sample_list": sample_list,
        })
    def handle(self, *args, **options):
        if len(args) == 0 or len(args) > 1:
            raise CommandError("Usage: manage.py create_definitions_2012_07 <domain>")

        domain = args[0]
        case_type = "participant"
        times_of_day = {"0600": time(6, 0, 0), "0900": time(9, 0, 0), "1700": time(17, 0, 0), "2100": time(21, 0, 0)}
        days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]

        for time_code, actual_time in times_of_day.items():
            c = CaseReminderHandler(
                domain=domain,
                case_type=case_type,
                nickname="Group 1, @ " + time_code,
                default_lang="en",
                method="survey",
                ui_type="COMPLEX",
                recipient="CASE",
                start_property="send_normal_message",
                start_value=time_code,
                start_date="normal_result_message_date",
                start_offset=0,
                start_match_type="EXACT",
                events=[
                    CaseReminderEvent(
                        day_num=0, fire_time=actual_time, message={}, callback_timeout_intervals=[], form_unique_id=""
                    )
                ],
                schedule_length=1,
                event_interpretation="SCHEDULE",
                max_iteration_count=1,
                until=None,
            )
            c.save()
            print "Created " + c.nickname

            for day in days:
                c = CaseReminderHandler(
                    domain=domain,
                    case_type=case_type,
                    nickname="Group 2 - 4, " + day + ", @ " + time_code,
                    default_lang="en",
                    method="survey",
                    ui_type="COMPLEX",
                    recipient="CASE",
                    start_property="send_" + day.lower(),
                    start_value=time_code,
                    start_date=day.lower() + "_date",
                    start_offset=0,
                    start_match_type="EXACT",
                    events=[
                        CaseReminderEvent(
                            day_num=0,
                            fire_time=actual_time,
                            message={},
                            callback_timeout_intervals=[],
                            form_unique_id="",
                        )
                    ],
                    schedule_length=1,
                    event_interpretation="SCHEDULE",
                    max_iteration_count=1,
                    until=None,
                )
                c.save()
                print "Created " + c.nickname