def testSQLSyncToCouch(self): self.deleteAllLogs() self.assertEqual(self.getCouchCount(), 0) self.assertEqual(self.getSQLCount(), 0) # Test Create sql_obj = ExpectedCallback() self.setRandomSQLObjectValues(sql_obj) sql_obj.save() sleep(1) self.assertEqual(self.getCouchCount(), 1) self.assertEqual(self.getSQLCount(), 1) couch_obj = ExpectedCallbackEventLog.get(sql_obj.couch_id) self.checkFieldValues(couch_obj, sql_obj, ExpectedCallback._migration_get_fields()) self.assertTrue(ExpectedCallbackEventLog.get_db().get_rev(couch_obj._id).startswith('2-')) # Test Update self.setRandomSQLObjectValues(sql_obj) sql_obj.save() sleep(1) self.assertEqual(self.getCouchCount(), 1) self.assertEqual(self.getSQLCount(), 1) couch_obj = ExpectedCallbackEventLog.get(sql_obj.couch_id) self.checkFieldValues(couch_obj, sql_obj, ExpectedCallback._migration_get_fields()) self.assertTrue(ExpectedCallbackEventLog.get_db().get_rev(couch_obj._id).startswith('3-'))
def fire_sms_callback_event(reminder, handler, recipients, verified_numbers, logged_event): current_event = reminder.current_event for recipient in recipients: send_message = False if reminder.callback_try_count > 0: if reminder.event_initiation_timestamp: event = ExpectedCallbackEventLog.view( "sms/expected_callback_event", key=[ reminder.domain, json_format_datetime( reminder.event_initiation_timestamp), recipient.get_id ], include_docs=True, limit=1).one() if not event: continue if event.status == CALLBACK_RECEIVED: continue if CallLog.inbound_entry_exists( recipient.doc_type, recipient.get_id, reminder.event_initiation_timestamp): event.status = CALLBACK_RECEIVED event.save() continue else: continue if (reminder.callback_try_count >= len( current_event.callback_timeout_intervals)): # On the last callback timeout, instead of sending the SMS # again, log the missed callback if event: event.status = CALLBACK_MISSED event.save() else: send_message = True else: # It's the first time sending the sms, so create an expected # callback event send_message = True event = ExpectedCallbackEventLog( domain=reminder.domain, date=reminder.event_initiation_timestamp, couch_recipient_doc_type=recipient.doc_type, couch_recipient=recipient.get_id, status=CALLBACK_PENDING, ) event.save() if send_message: fire_sms_event(reminder, handler, [recipient], verified_numbers, logged_event, workflow=WORKFLOW_CALLBACK)
def fire_sms_callback_event(reminder, handler, recipients, verified_numbers): current_event = reminder.current_event if handler.recipient in [RECIPIENT_CASE, RECIPIENT_USER]: # If there are no recipients, just move to the next reminder event if len(recipients) == 0: return True # If the callback has been received, skip sending the next timeout message if reminder.callback_try_count > 0: # Lookup the expected callback event if reminder.event_initiation_timestamp is None: event = None else: event = ExpectedCallbackEventLog.view( "sms/expected_callback_event", key=[ reminder.domain, json_format_datetime( reminder.event_initiation_timestamp), recipients[0].get_id ], include_docs=True, limit=1).one() # NOTE: If last_fired is None, it means that the reminder fired for the first time on a timeout interval if reminder.last_fired is not None and CallLog.inbound_entry_exists( recipients[0].doc_type, recipients[0].get_id, reminder.last_fired): reminder.skip_remaining_timeouts = True if event is not None: event.status = CALLBACK_RECEIVED event.save() return True elif reminder.callback_try_count >= len( current_event.callback_timeout_intervals): # On the last callback timeout, instead of sending the SMS again, log the missed callback if event is not None: event.status = CALLBACK_MISSED event.save() return True else: # It's the first time sending the sms, so create an expected callback event event = ExpectedCallbackEventLog( domain=reminder.domain, date=reminder.event_initiation_timestamp, couch_recipient_doc_type=recipients[0].doc_type, couch_recipient=recipients[0].get_id, status=CALLBACK_PENDING, ) event.save() return fire_sms_event(reminder, handler, recipients, verified_numbers, workflow=WORKFLOW_CALLBACK) else: # TODO: Implement sms callback for RECIPIENT_OWNER and RECIPIENT_SURVEY_SAMPLE return False
def fire_sms_callback_event(reminder, handler, recipients, verified_numbers): current_event = reminder.current_event for recipient in recipients: send_message = False if reminder.callback_try_count > 0: if reminder.event_initiation_timestamp: event = ExpectedCallbackEventLog.view("sms/expected_callback_event", key=[reminder.domain, json_format_datetime(reminder.event_initiation_timestamp), recipient.get_id], include_docs=True, limit=1).one() if not event: continue if event.status == CALLBACK_RECEIVED: continue if CallLog.inbound_entry_exists(recipient.doc_type, recipient.get_id, reminder.event_initiation_timestamp): event.status = CALLBACK_RECEIVED event.save() continue else: continue if (reminder.callback_try_count >= len(current_event.callback_timeout_intervals)): # On the last callback timeout, instead of sending the SMS # again, log the missed callback if event: event.status = CALLBACK_MISSED event.save() else: send_message = True else: # It's the first time sending the sms, so create an expected # callback event send_message = True event = ExpectedCallbackEventLog( domain=reminder.domain, date=reminder.event_initiation_timestamp, couch_recipient_doc_type=recipient.doc_type, couch_recipient=recipient.get_id, status=CALLBACK_PENDING, ) event.save() if send_message: fire_sms_event(reminder, handler, [recipient], verified_numbers, workflow=WORKFLOW_CALLBACK) return True
def fire_sms_callback_event(reminder, handler, recipients, verified_numbers): current_event = reminder.current_event if handler.recipient in [RECIPIENT_CASE, RECIPIENT_USER]: # If there are no recipients, just move to the next reminder event if len(recipients) == 0: return True # If the callback has been received, skip sending the next timeout message if reminder.callback_try_count > 0: # Lookup the expected callback event if reminder.event_initiation_timestamp is None: event = None else: event = ExpectedCallbackEventLog.view("sms/expected_callback_event", key=[reminder.domain, json_format_datetime(reminder.event_initiation_timestamp), recipients[0].get_id], include_docs=True, limit=1).one() # NOTE: If last_fired is None, it means that the reminder fired for the first time on a timeout interval if reminder.last_fired is not None and CallLog.inbound_entry_exists(recipients[0].doc_type, recipients[0].get_id, reminder.last_fired): reminder.skip_remaining_timeouts = True if event is not None: event.status = CALLBACK_RECEIVED event.save() return True elif reminder.callback_try_count >= len(current_event.callback_timeout_intervals): # On the last callback timeout, instead of sending the SMS again, log the missed callback if event is not None: event.status = CALLBACK_MISSED event.save() return True else: # It's the first time sending the sms, so create an expected callback event event = ExpectedCallbackEventLog( domain = reminder.domain, date = reminder.event_initiation_timestamp, couch_recipient_doc_type = recipients[0].doc_type, couch_recipient = recipients[0].get_id, status = CALLBACK_PENDING, ) event.save() return fire_sms_event(reminder, handler, recipients, verified_numbers, workflow=WORKFLOW_CALLBACK) else: # TODO: Implement sms callback for RECIPIENT_OWNER and RECIPIENT_SURVEY_SAMPLE return False
def getCouchCount(self): result = ExpectedCallbackEventLog.view( 'sms/expected_callback_event', startkey=[self.domain], endkey=[self.domain, {}], include_docs=False, ).all() return len(result)
def rows(self): startdate = json_format_datetime(self.datespan.startdate_utc) enddate = json_format_datetime(self.datespan.enddate_utc) data = ExpectedCallbackEventLog.by_domain(self.domain, startdate, enddate) result = [] status_descriptions = { CALLBACK_PENDING: _("Pending"), CALLBACK_RECEIVED: _("Received"), CALLBACK_MISSED: _("Missed"), } # Store the results of lookups for faster loading username_map = {} for event in data: recipient_id = event.couch_recipient if recipient_id in [None, ""]: username = "******" elif recipient_id in username_map: username = username_map.get(recipient_id) else: username = "******" try: if event.couch_recipient_doc_type == "CommCareCase": username = CommCareCase.get(recipient_id).name else: username = CouchUser.get_by_user_id( recipient_id).username except Exception: pass username_map[recipient_id] = username timestamp = tz_utils.adjust_datetime_to_timezone( event.date, pytz.utc.zone, self.timezone.zone) row = [ self._fmt_timestamp(timestamp), self._fmt(username), self._fmt(status_descriptions.get(event.status, "-")), ] result.append(row) return result
def rows(self): startdate = json_format_datetime(self.datespan.startdate_utc) enddate = json_format_datetime(self.datespan.enddate_utc) data = ExpectedCallbackEventLog.by_domain(self.domain, startdate, enddate) result = [] status_descriptions = { CALLBACK_PENDING : _("Pending"), CALLBACK_RECEIVED : _("Received"), CALLBACK_MISSED : _("Missed"), } # Store the results of lookups for faster loading username_map = {} for event in data: recipient_id = event.couch_recipient if recipient_id in [None, ""]: username = "******" elif recipient_id in username_map: username = username_map.get(recipient_id) else: username = "******" try: if event.couch_recipient_doc_type == "CommCareCase": username = CommCareCase.get(recipient_id).name else: username = CouchUser.get_by_user_id(recipient_id).username except Exception: pass username_map[recipient_id] = username timestamp = tz_utils.adjust_datetime_to_timezone(event.date, pytz.utc.zone, self.timezone.zone) row = [ self._fmt_timestamp(timestamp), self._fmt(username), self._fmt(status_descriptions.get(event.status, "-")), ] result.append(row) return result
def deleteAllLogs(self): for smslog in SMSLog.view( 'sms/by_domain', startkey=[self.domain, 'SMSLog'], endkey=[self.domain, 'SMSLog', {}], include_docs=True, reduce=False, ).all(): smslog.delete() for callog in CallLog.view( 'sms/by_domain', startkey=[self.domain, 'CallLog'], endkey=[self.domain, 'CallLog', {}], include_docs=True, reduce=False, ).all(): callog.delete() for obj in LastReadMessage.view( 'sms/last_read_message', startkey=['by_anyone', self.domain], endkey=['by_anyone', self.domain, {}], include_docs=True, ).all(): obj.delete() for obj in ExpectedCallbackEventLog.view( 'sms/expected_callback_event', startkey=[self.domain], endkey=[self.domain, {}], include_docs=True, ).all(): obj.delete() SMS.objects.filter(domain=self.domain).delete() Call.objects.filter(domain=self.domain).delete() MessagingSubEvent.objects.filter(parent__domain=self.domain).delete() MessagingEvent.objects.filter(domain=self.domain).delete() SQLLastReadMessage.objects.filter(domain=self.domain).delete() ExpectedCallback.objects.filter(domain=self.domain).delete()
def delete_models(self, delete_interval): print 'Deleting SMSLogs...' count = iter_bulk_delete_with_doc_type_verification(SMSLog.get_db(), self.get_sms_couch_ids(), 'SMSLog', wait_time=delete_interval, max_fetch_attempts=5) print 'Deleted %s documents' % count print 'Deleting CallLogs...' count = iter_bulk_delete_with_doc_type_verification(CallLog.get_db(), self.get_call_couch_ids(), 'CallLog', wait_time=delete_interval, max_fetch_attempts=5) print 'Deleted %s documents' % count print 'Deleting ExpectedCallbackEventLogs...' count = iter_bulk_delete_with_doc_type_verification(ExpectedCallbackEventLog.get_db(), self.get_callback_couch_ids(), 'ExpectedCallbackEventLog', wait_time=delete_interval, max_fetch_attempts=5) print 'Deleted %s documents' % count print 'Deleting LastReadMessages...' count = iter_bulk_delete_with_doc_type_verification(LastReadMessage.get_db(), self.get_lastreadmessage_couch_ids(), 'LastReadMessage', wait_time=delete_interval, max_fetch_attempts=5) print 'Deleted %s documents' % count
def delete_models(self, delete_interval): print('Deleting SMSLogs...') count = iter_bulk_delete_with_doc_type_verification(SMSLog.get_db(), self.get_sms_couch_ids(), 'SMSLog', wait_time=delete_interval, max_fetch_attempts=5) print('Deleted %s documents' % count) print('Deleting CallLogs...') count = iter_bulk_delete_with_doc_type_verification(CallLog.get_db(), self.get_call_couch_ids(), 'CallLog', wait_time=delete_interval, max_fetch_attempts=5) print('Deleted %s documents' % count) print('Deleting ExpectedCallbackEventLogs...') count = iter_bulk_delete_with_doc_type_verification(ExpectedCallbackEventLog.get_db(), self.get_callback_couch_ids(), 'ExpectedCallbackEventLog', wait_time=delete_interval, max_fetch_attempts=5) print('Deleted %s documents' % count) print('Deleting LastReadMessages...') count = iter_bulk_delete_with_doc_type_verification(LastReadMessage.get_db(), self.get_lastreadmessage_couch_ids(), 'LastReadMessage', wait_time=delete_interval, max_fetch_attempts=5) print('Deleted %s documents' % count)
def get_callback_couch_ids(self): result = ExpectedCallbackEventLog.view( 'sms/expected_callback_event', include_docs=False, ).all() return [row['id'] for row in result]
def test_ok(self): self.assertEqual(self.handler.get_reminder(self.case), None) # Spawn CaseReminder CaseReminderHandler.now = datetime(year=2011, month=12, day=31, hour=23, minute=0) self.case.set_case_property('start_sending', 'ok') self.case.save() reminder = self.handler.get_reminder(self.case) self.assertNotEqual(reminder, None) self.assertEqual(reminder.next_fire, datetime(year=2012, month=1, day=1, hour=7, minute=0)) self.assertEqual(reminder.start_date, date(year=2012, month=1, day=1)) self.assertEqual(reminder.schedule_iteration_num, 1) self.assertEqual(reminder.current_event_sequence_num, 0) self.assertEqual(reminder.last_fired, None) ###################### # Day1, 10:00 reminder CaseReminderHandler.now = datetime(year=2012, month=1, day=1, hour=7, minute=0) CaseReminderHandler.fire_reminders() reminder = self.handler.get_reminder(self.case) self.assertNotEqual(reminder, None) self.assertEqual(reminder.next_fire, datetime(year=2012, month=1, day=1, hour=8, minute=0)) self.assertEqual(reminder.schedule_iteration_num, 1) self.assertEqual(reminder.current_event_sequence_num, 1) self.assertEqual(reminder.last_fired, CaseReminderHandler.now) # Day1, 11:00 reminder CaseReminderHandler.now = datetime(year=2012, month=1, day=1, hour=8, minute=1) CaseReminderHandler.fire_reminders() reminder = self.handler.get_reminder(self.case) self.assertNotEqual(reminder, None) self.assertEqual(reminder.next_fire, datetime(year=2012, month=1, day=1, hour=8, minute=15)) self.assertEqual(reminder.schedule_iteration_num, 1) self.assertEqual(reminder.current_event_sequence_num, 1) self.assertEqual(reminder.last_fired, CaseReminderHandler.now) event = ExpectedCallbackEventLog.view("sms/expected_callback_event", key=["test", json_format_datetime(datetime(year=2012, month=1, day=1, hour=8, minute=1)), self.user_id], include_docs=True).one() self.assertNotEqual(event, None) self.assertEqual(event.status, CALLBACK_PENDING) # Create a callback c = CallLog( couch_recipient_doc_type = "CommCareUser", couch_recipient = self.user_id, phone_number = "14445551234", direction = "I", date = datetime(year=2012, month=1, day=1, hour=8, minute=5) ) c.save() # Day1, 11:15 timeout (should move on to next event) CaseReminderHandler.now = datetime(year=2012, month=1, day=1, hour=8, minute=15) CaseReminderHandler.fire_reminders() reminder = self.handler.get_reminder(self.case) self.assertNotEqual(reminder, None) self.assertEqual(reminder.next_fire, datetime(year=2012, month=1, day=1, hour=8, minute=45)) self.assertEqual(reminder.schedule_iteration_num, 1) self.assertEqual(reminder.current_event_sequence_num, 1) self.assertEqual(reminder.last_fired, CaseReminderHandler.now) # Day1, 11:45 timeout (should move on to next event) CaseReminderHandler.now = datetime(year=2012, month=1, day=1, hour=8, minute=45) CaseReminderHandler.fire_reminders() reminder = self.handler.get_reminder(self.case) self.assertNotEqual(reminder, None) self.assertEqual(reminder.next_fire, datetime(year=2012, month=1, day=2, hour=7, minute=0)) self.assertEqual(reminder.schedule_iteration_num, 2) self.assertEqual(reminder.current_event_sequence_num, 0) self.assertEqual(reminder.last_fired, CaseReminderHandler.now) event = ExpectedCallbackEventLog.view("sms/expected_callback_event", key=["test", json_format_datetime(datetime(year=2012, month=1, day=1, hour=8, minute=1)), self.user_id], include_docs=True).one() self.assertNotEqual(event, None) self.assertEqual(event.status, CALLBACK_RECEIVED) ###################### # Day2, 10:00 reminder CaseReminderHandler.now = datetime(year=2012, month=1, day=2, hour=7, minute=0) CaseReminderHandler.fire_reminders() reminder = self.handler.get_reminder(self.case) self.assertNotEqual(reminder, None) self.assertEqual(reminder.next_fire, datetime(year=2012, month=1, day=2, hour=8, minute=0)) self.assertEqual(reminder.schedule_iteration_num, 2) self.assertEqual(reminder.current_event_sequence_num, 1) self.assertEqual(reminder.last_fired, CaseReminderHandler.now) # Day2, 11:00 reminder CaseReminderHandler.now = datetime(year=2012, month=1, day=2, hour=8, minute=1) CaseReminderHandler.fire_reminders() reminder = self.handler.get_reminder(self.case) self.assertNotEqual(reminder, None) self.assertEqual(reminder.next_fire, datetime(year=2012, month=1, day=2, hour=8, minute=15)) self.assertEqual(reminder.schedule_iteration_num, 2) self.assertEqual(reminder.current_event_sequence_num, 1) self.assertEqual(reminder.last_fired, CaseReminderHandler.now) event = ExpectedCallbackEventLog.view("sms/expected_callback_event", key=["test", json_format_datetime(datetime(year=2012, month=1, day=2, hour=8, minute=1)), self.user_id], include_docs=True).one() self.assertNotEqual(event, None) self.assertEqual(event.status, CALLBACK_PENDING) # Day2, 11:15 timeout (should move on to next timeout) CaseReminderHandler.now = datetime(year=2012, month=1, day=2, hour=8, minute=15) CaseReminderHandler.fire_reminders() reminder = self.handler.get_reminder(self.case) self.assertNotEqual(reminder, None) self.assertEqual(reminder.next_fire, datetime(year=2012, month=1, day=2, hour=8, minute=45)) self.assertEqual(reminder.schedule_iteration_num, 2) self.assertEqual(reminder.current_event_sequence_num, 1) self.assertEqual(reminder.last_fired, CaseReminderHandler.now) event = ExpectedCallbackEventLog.view("sms/expected_callback_event", key=["test", json_format_datetime(datetime(year=2012, month=1, day=2, hour=8, minute=1)), self.user_id], include_docs=True).one() self.assertNotEqual(event, None) self.assertEqual(event.status, CALLBACK_PENDING) # Day2, 11:45 timeout (should move on to next day) CaseReminderHandler.now = datetime(year=2012, month=1, day=2, hour=8, minute=45) CaseReminderHandler.fire_reminders() reminder = self.handler.get_reminder(self.case) self.assertNotEqual(reminder, None) self.assertEqual(reminder.next_fire, datetime(year=2012, month=1, day=3, hour=7, minute=0)) self.assertEqual(reminder.schedule_iteration_num, 3) self.assertEqual(reminder.current_event_sequence_num, 0) self.assertEqual(reminder.last_fired, CaseReminderHandler.now) event = ExpectedCallbackEventLog.view("sms/expected_callback_event", key=["test", json_format_datetime(datetime(year=2012, month=1, day=2, hour=8, minute=1)), self.user_id], include_docs=True).one() self.assertNotEqual(event, None) self.assertEqual(event.status, CALLBACK_MISSED) ###################### # Day3, 10:00 reminder CaseReminderHandler.now = datetime(year=2012, month=1, day=3, hour=7, minute=0) CaseReminderHandler.fire_reminders() reminder = self.handler.get_reminder(self.case) self.assertNotEqual(reminder, None) self.assertEqual(reminder.next_fire, datetime(year=2012, month=1, day=3, hour=8, minute=0)) self.assertEqual(reminder.schedule_iteration_num, 3) self.assertEqual(reminder.current_event_sequence_num, 1) self.assertEqual(reminder.last_fired, CaseReminderHandler.now) # Day3, 11:00 reminder CaseReminderHandler.now = datetime(year=2012, month=1, day=3, hour=8, minute=1) CaseReminderHandler.fire_reminders() reminder = self.handler.get_reminder(self.case) self.assertNotEqual(reminder, None) self.assertEqual(reminder.next_fire, datetime(year=2012, month=1, day=3, hour=8, minute=15)) self.assertEqual(reminder.schedule_iteration_num, 3) self.assertEqual(reminder.current_event_sequence_num, 1) self.assertEqual(reminder.last_fired, CaseReminderHandler.now) event = ExpectedCallbackEventLog.view("sms/expected_callback_event", key=["test", json_format_datetime(datetime(year=2012, month=1, day=3, hour=8, minute=1)), self.user_id], include_docs=True).one() self.assertNotEqual(event, None) self.assertEqual(event.status, CALLBACK_PENDING) # Day3, 11:15 timeout (should move on to next timeout) CaseReminderHandler.now = datetime(year=2012, month=1, day=3, hour=8, minute=15) CaseReminderHandler.fire_reminders() reminder = self.handler.get_reminder(self.case) self.assertNotEqual(reminder, None) self.assertEqual(reminder.next_fire, datetime(year=2012, month=1, day=3, hour=8, minute=45)) self.assertEqual(reminder.schedule_iteration_num, 3) self.assertEqual(reminder.current_event_sequence_num, 1) self.assertEqual(reminder.last_fired, CaseReminderHandler.now) event = ExpectedCallbackEventLog.view("sms/expected_callback_event", key=["test", json_format_datetime(datetime(year=2012, month=1, day=3, hour=8, minute=1)), self.user_id], include_docs=True).one() self.assertNotEqual(event, None) self.assertEqual(event.status, CALLBACK_PENDING) # Create a callback (with phone_number missing country code) c = CallLog( couch_recipient_doc_type = "CommCareUser", couch_recipient = self.user_id, phone_number = "4445551234", direction = "I", date = datetime(year=2012, month=1, day=3, hour=8, minute=22) ) c.save() # Day3, 11:45 timeout (should deactivate the reminder) CaseReminderHandler.now = datetime(year=2012, month=1, day=3, hour=8, minute=45) CaseReminderHandler.fire_reminders() reminder = self.handler.get_reminder(self.case) self.assertNotEqual(reminder, None) self.assertEqual(reminder.schedule_iteration_num, 4) self.assertEqual(reminder.current_event_sequence_num, 0) self.assertEqual(reminder.last_fired, CaseReminderHandler.now) self.assertEqual(reminder.active, False) event = ExpectedCallbackEventLog.view("sms/expected_callback_event", key=["test", json_format_datetime(datetime(year=2012, month=1, day=3, hour=8, minute=1)), self.user_id], include_docs=True).one() self.assertNotEqual(event, None) self.assertEqual(event.status, CALLBACK_RECEIVED)
def rows(self): group_id = None if self.request.couch_user.is_commcare_user(): group_ids = self.request.couch_user.get_group_ids() if len(group_ids) > 0: group_id = group_ids[0] cases = CommCareCase.view("hqcase/types_by_domain", key=[self.domain, "participant"], reduce=False, include_docs=True).all() data = {} for case in cases: if case.closed: continue # If a site coordinator is viewing the report, only show participants from that site (group) if group_id is None or group_id == case.owner_id: data[case._id] = { "name" : case.name, "time_zone" : case.get_case_property("time_zone"), "dates" : [None for x in range(14)], } dates = self.get_past_two_weeks() date_strings = [date.strftime("%Y-%m-%d") for date in dates] start_date = dates[0] - timedelta(days=1) end_date = dates[-1] + timedelta(days=2) start_utc_timestamp = json_format_datetime(start_date) end_utc_timestamp = json_format_datetime(end_date) expected_callback_events = ExpectedCallbackEventLog.view("sms/expected_callback_event", startkey=[self.domain, start_utc_timestamp], endkey=[self.domain, end_utc_timestamp], include_docs=True).all() for event in expected_callback_events: if event.couch_recipient in data: event_date = tz_utils.adjust_datetime_to_timezone(event.date, pytz.utc.zone, data[event.couch_recipient]["time_zone"]).date() event_date = event_date.strftime("%Y-%m-%d") if event_date in date_strings: data[event.couch_recipient]["dates"][date_strings.index(event_date)] = event.status result = [] for case_id, data_dict in data.items(): row = [ self._fmt(data_dict["name"]), None, None, None, ] total_no_response = 0 total_indicated = 0 total_pending = 0 for date_status in data_dict["dates"]: if date_status == CALLBACK_PENDING: total_indicated += 1 total_pending += 1 row.append(self._fmt(_("pending"))) elif date_status == CALLBACK_RECEIVED: total_indicated += 1 row.append(self._fmt(_("OK"))) elif date_status == CALLBACK_MISSED: total_indicated += 1 total_no_response += 1 row.append(self._fmt_highlight(_("No Response"))) else: row.append(self._fmt(_("not indicated"))) if total_no_response > 0: row[1] = self._fmt_highlight(total_no_response) else: row[1] = self._fmt(total_no_response) row[2] = self._fmt(total_indicated) row[3] = self._fmt(total_pending) result.append(row) return result