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") if survey is None: survey = Survey ( domain = domain, name = name, waves = waves, followups = followups, samples = samples, send_automatically = send_automatically, send_followup = send_followup ) else: survey.name = name survey.waves = waves survey.followups = followups survey.samples = samples survey.send_automatically = send_automatically survey.send_followup = send_followup survey.save() return HttpResponseRedirect(reverse("survey_list", args=[domain])) else: initial = {} if survey is not None: initial["name"] = survey.name initial["waves"] = survey.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), } return render_to_response(request, "reminders/partial/add_survey.html", context)
def get_surveys_in_domain(domain): from corehq.apps.reminders.models import Survey return sorted(Survey.view( 'domain/docs', startkey=[domain, 'Survey'], endkey=[domain, 'Survey', {}], include_docs=True, reduce=False, ), key=lambda survey: survey.name)
def survey_list(request, domain): context = { "domain" : domain, "surveys" : Survey.get_all(domain) } return render_to_response(request, "reminders/partial/survey_list.html", context)
def add_sample(request, domain, sample_id=None): sample = None if sample_id is not None: sample = SurveySample.get(sample_id) if request.method == "POST": form = SurveySampleForm(request.POST, request.FILES) if form.is_valid(): name = form.cleaned_data.get("name") sample_contacts = form.cleaned_data.get("sample_contacts") time_zone = form.cleaned_data.get("time_zone") use_contact_upload_file = form.cleaned_data.get("use_contact_upload_file") contact_upload_file = form.cleaned_data.get("contact_upload_file") if sample is None: sample = SurveySample ( domain = domain, name = name, time_zone = time_zone.zone ) else: sample.name = name sample.time_zone = time_zone.zone errors = [] phone_numbers = [] if use_contact_upload_file == "Y": for contact in contact_upload_file: phone_numbers.append(contact["phone_number"]) else: for contact in sample_contacts: phone_numbers.append(contact["phone_number"]) existing_number_entries = VerifiedNumber.view('sms/verified_number_by_number', keys=phone_numbers, include_docs=True ).all() for entry in existing_number_entries: if entry.domain != domain or entry.owner_doc_type != "CommCareCase": errors.append("Cannot use phone number %s" % entry.phone_number) if len(errors) > 0: if use_contact_upload_file == "Y": form._errors["contact_upload_file"] = form.error_class(errors) else: form._errors["sample_contacts"] = form.error_class(errors) else: existing_numbers = [v.phone_number for v in existing_number_entries] nonexisting_numbers = list(set(phone_numbers).difference(existing_numbers)) id_range = DomainCounter.increment(domain, "survey_contact_id", len(nonexisting_numbers)) ids = iter(range(id_range[0], id_range[1] + 1)) for phone_number in nonexisting_numbers: register_sms_contact(domain, "participant", str(ids.next()), request.couch_user.get_id, phone_number, contact_phone_number_is_verified="1", contact_backend_id="MOBILE_BACKEND_TROPO_US", language_code="en", time_zone=time_zone.zone) newly_registered_entries = VerifiedNumber.view('sms/verified_number_by_number', keys=nonexisting_numbers, include_docs=True ).all() sample.contacts = [v.owner_id for v in existing_number_entries] + [v.owner_id for v in newly_registered_entries] sample.save() # Update delegation tasks for surveys using this sample surveys = Survey.view("reminders/sample_to_survey", key=[domain, sample._id, "CATI"], include_docs=True).all() for survey in surveys: survey.update_delegation_tasks(request.couch_user.get_id) survey.save() return HttpResponseRedirect(reverse("sample_list", args=[domain])) else: initial = {} if sample is not None: initial["name"] = sample.name initial["time_zone"] = sample.time_zone contact_info = [] for case_id in sample.contacts: case = CommCareCase.get(case_id) contact_info.append({"id":case.name, "phone_number":case.contact_phone_number, "case_id" : case_id}) initial["sample_contacts"] = contact_info form = SurveySampleForm(initial=initial) context = { "domain" : domain, "form" : form, "sample_id" : sample_id } return render(request, "reminders/partial/add_sample.html", context)
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_sample(request, domain, sample_id=None): sample = None if sample_id is not None: sample = SurveySample.get(sample_id) if request.method == "POST": form = SurveySampleForm(request.POST, request.FILES) if form.is_valid(): name = form.cleaned_data.get("name") sample_contacts = form.cleaned_data.get("sample_contacts") time_zone = form.cleaned_data.get("time_zone") use_contact_upload_file = form.cleaned_data.get( "use_contact_upload_file") contact_upload_file = form.cleaned_data.get("contact_upload_file") if sample is None: sample = SurveySample(domain=domain, name=name, time_zone=time_zone.zone) else: sample.name = name sample.time_zone = time_zone.zone errors = [] phone_numbers = [] if use_contact_upload_file == "Y": for contact in contact_upload_file: phone_numbers.append(contact["phone_number"]) else: for contact in sample_contacts: phone_numbers.append(contact["phone_number"]) existing_number_entries = VerifiedNumber.view( 'sms/verified_number_by_number', keys=phone_numbers, include_docs=True).all() for entry in existing_number_entries: if entry.domain != domain or entry.owner_doc_type != "CommCareCase": errors.append("Cannot use phone number %s" % entry.phone_number) if len(errors) > 0: if use_contact_upload_file == "Y": form._errors["contact_upload_file"] = form.error_class( errors) else: form._errors["sample_contacts"] = form.error_class(errors) else: existing_numbers = [ v.phone_number for v in existing_number_entries ] nonexisting_numbers = list( set(phone_numbers).difference(existing_numbers)) id_range = DomainCounter.increment(domain, "survey_contact_id", len(nonexisting_numbers)) ids = iter(range(id_range[0], id_range[1] + 1)) for phone_number in nonexisting_numbers: register_sms_contact( domain, "participant", str(ids.next()), request.couch_user.get_id, phone_number, contact_phone_number_is_verified="1", contact_backend_id="MOBILE_BACKEND_TROPO_US", language_code="en", time_zone=time_zone.zone) newly_registered_entries = VerifiedNumber.view( 'sms/verified_number_by_number', keys=nonexisting_numbers, include_docs=True).all() sample.contacts = [ v.owner_id for v in existing_number_entries ] + [v.owner_id for v in newly_registered_entries] sample.save() # Update delegation tasks for surveys using this sample surveys = Survey.view("reminders/sample_to_survey", key=[domain, sample._id, "CATI"], include_docs=True).all() for survey in surveys: survey.update_delegation_tasks(request.couch_user.get_id) survey.save() return HttpResponseRedirect( reverse("sample_list", args=[domain])) else: initial = {} if sample is not None: initial["name"] = sample.name initial["time_zone"] = sample.time_zone contact_info = [] for case_id in sample.contacts: case = CommCareCase.get(case_id) contact_info.append({ "id": case.name, "phone_number": case.contact_phone_number, "case_id": case_id }) initial["sample_contacts"] = contact_info form = SurveySampleForm(initial=initial)
def survey_list(request, domain): context = {"domain": domain, "surveys": Survey.get_all(domain)} return render(request, "reminders/partial/survey_list.html", context)
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)