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 })
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 })
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:
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)
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
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()
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 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 })
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)
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, })
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()
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)
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