def handle_sms_form_complete(sender, session_id, form, **kwargs): from corehq.apps.smsforms.models import XFormsSession session = XFormsSession.by_session_id(session_id) if session: resp = submit_form_locally(form, session.domain, app_id=session.app_id) xform_id = resp['X-CommCareHQ-FormID'] session.end(completed=True) session.submission_id = xform_id session.save() xform = XFormInstance.get(xform_id) xform.survey_incentive = session.survey_incentive xform.save()
def handle_sms_form_complete(sender, session_id, form, **kwargs): from corehq.apps.smsforms.models import XFormsSession session = XFormsSession.by_session_id(session_id) if session: resp = submit_form_locally(form, session.domain, app_id=session.app_id) xform_id = resp['X-CommCareHQ-FormID'] session.end(completed=True) session.submission_id = xform_id session.save() xform = XFormInstance.get(xform_id) xform.survey_incentive = session.survey_incentive xform.save()
def fire_sms_survey_event(reminder, handler, recipients, verified_numbers): if reminder.callback_try_count > 0: # Handle timeouts if handler.submit_partial_forms and ( reminder.callback_try_count == len( reminder.current_event.callback_timeout_intervals)): # Submit partial form completions for session_id in reminder.xforms_session_ids: submit_unfinished_form(session_id, handler.include_case_side_effects) else: # Resend current question for session_id in reminder.xforms_session_ids: session = XFormsSession.by_session_id(session_id) if session.end_time is None: vn = VerifiedNumber.view("sms/verified_number_by_owner_id", key=session.connection_id, include_docs=True).first() if vn is not None: metadata = MessageMetadata( workflow=get_workflow(handler), reminder_id=reminder._id, xforms_session_couch_id=session._id, ) resp = current_question(session_id) send_sms_to_verified_number(vn, resp.event.text_prompt, metadata) return True else: reminder.xforms_session_ids = [] # Get the app, module, and form try: form_unique_id = reminder.current_event.form_unique_id form = Form.get_form(form_unique_id) app = form.get_app() module = form.get_module() except Exception as e: raise_error(reminder, ERROR_FORM) return False # Start a touchforms session for each recipient for recipient in recipients: verified_number, unverified_number = get_recipient_phone_number( reminder, recipient, verified_numbers) domain_obj = Domain.get_by_name(reminder.domain, strict=True) no_verified_number = verified_number is None cant_use_unverified_number = ( unverified_number is None or not domain_obj.send_to_duplicated_case_numbers or form_requires_input(form)) if no_verified_number and cant_use_unverified_number: if len(recipients) == 1: raise_error(reminder, ERROR_NO_VERIFIED_NUMBER) return False else: continue # Close all currently open sessions XFormsSession.close_all_open_sms_sessions(reminder.domain, recipient.get_id) # Start the new session if isinstance( recipient, CommCareCase ) and not handler.force_surveys_to_use_triggered_case: case_id = recipient.get_id else: case_id = reminder.case_id session, responses = start_session( reminder.domain, recipient, app, module, form, case_id, case_for_case_submission=handler. force_surveys_to_use_triggered_case) session.survey_incentive = handler.survey_incentive session.workflow = get_workflow(handler) session.reminder_id = reminder._id session.save() reminder.xforms_session_ids.append(session.session_id) # Send out first message if len(responses) > 0: message = format_message_list(responses) metadata = MessageMetadata( workflow=get_workflow(handler), reminder_id=reminder._id, xforms_session_couch_id=session._id, ) if verified_number: result = send_sms_to_verified_number( verified_number, message, metadata) else: result = send_sms(reminder.domain, recipient, unverified_number, message, metadata) if len(recipients) == 1: return result return True
def fire_sms_survey_event(reminder, handler, recipients, verified_numbers): if reminder.callback_try_count > 0: # Handle timeouts if handler.submit_partial_forms and (reminder.callback_try_count == len(reminder.current_event.callback_timeout_intervals)): # Submit partial form completions for session_id in reminder.xforms_session_ids: submit_unfinished_form(session_id, handler.include_case_side_effects) else: # Resend current question for session_id in reminder.xforms_session_ids: session = XFormsSession.by_session_id(session_id) if session.end_time is None: vn = VerifiedNumber.view("sms/verified_number_by_owner_id", key=session.connection_id, include_docs=True).first() if vn is not None: metadata = MessageMetadata( workflow=get_workflow(handler), reminder_id=reminder._id, xforms_session_couch_id=session._id, ) resp = current_question(session_id) send_sms_to_verified_number(vn, resp.event.text_prompt, metadata) return True else: reminder.xforms_session_ids = [] # Get the app, module, and form try: form_unique_id = reminder.current_event.form_unique_id form = Form.get_form(form_unique_id) app = form.get_app() module = form.get_module() except Exception as e: raise_error(reminder, ERROR_FORM) return False # Start a touchforms session for each recipient for recipient in recipients: verified_number, unverified_number = get_recipient_phone_number( reminder, recipient, verified_numbers) domain_obj = Domain.get_by_name(reminder.domain, strict=True) no_verified_number = verified_number is None cant_use_unverified_number = (unverified_number is None or not domain_obj.send_to_duplicated_case_numbers or form_requires_input(form)) if no_verified_number and cant_use_unverified_number: if len(recipients) == 1: raise_error(reminder, ERROR_NO_VERIFIED_NUMBER) return False else: continue key = "start-sms-survey-for-contact-%s" % recipient.get_id with CriticalSection([key], timeout=60): # Close all currently open sessions XFormsSession.close_all_open_sms_sessions(reminder.domain, recipient.get_id) # Start the new session if (isinstance(recipient, CommCareCase) and not handler.force_surveys_to_use_triggered_case): case_id = recipient.get_id else: case_id = reminder.case_id session, responses = start_session(reminder.domain, recipient, app, module, form, case_id, case_for_case_submission= handler.force_surveys_to_use_triggered_case) session.survey_incentive = handler.survey_incentive session.workflow = get_workflow(handler) session.reminder_id = reminder._id session.save() reminder.xforms_session_ids.append(session.session_id) # Send out first message if len(responses) > 0: message = format_message_list(responses) metadata = MessageMetadata( workflow=get_workflow(handler), reminder_id=reminder._id, xforms_session_couch_id=session._id, ) if verified_number: result = send_sms_to_verified_number(verified_number, message, metadata) else: result = send_sms(reminder.domain, recipient, unverified_number, message, metadata) if len(recipients) == 1: return result return True
def incoming(phone_number, backend_module, gateway_session_id, ivr_event, input_data=None): # Look up the call if one already exists call_log_entry = CallLog.view("sms/call_by_session", startkey=[gateway_session_id, {}], endkey=[gateway_session_id], descending=True, include_docs=True, limit=1).one() answer_is_valid = False # This will be set to True if IVR validation passes error_occurred = False # This will be set to False if touchforms validation passes (i.e., no form constraints fail) if call_log_entry is not None and backend_module: if ivr_event == IVR_EVENT_NEW_CALL and call_log_entry.use_precached_first_response: return HttpResponse(call_log_entry.first_response) form = Form.get_form(call_log_entry.form_unique_id) app = form.get_app() module = form.get_module() recipient = call_log_entry.recipient if ivr_event == IVR_EVENT_NEW_CALL: case_id = call_log_entry.case_id case_for_case_submission = call_log_entry.case_for_case_submission session, responses = start_session(recipient.domain, recipient, app, module, form, case_id, yield_responses=True, session_type=XFORMS_SESSION_IVR, case_for_case_submission=case_for_case_submission) call_log_entry.xforms_session_id = session.session_id elif ivr_event == IVR_EVENT_INPUT: if call_log_entry.xforms_session_id is not None: current_q = current_question(call_log_entry.xforms_session_id) if validate_answer(input_data, current_q): answer_is_valid = True responses = _get_responses(recipient.domain, recipient._id, input_data, yield_responses=True, session_id=call_log_entry.xforms_session_id) else: call_log_entry.current_question_retry_count += 1 responses = [current_q] else: responses = [] else: responses = [] ivr_responses = [] hang_up = False for response in responses: if response.is_error: error_occurred = True call_log_entry.current_question_retry_count += 1 if response.text_prompt is None: ivr_responses = [] break else: ivr_responses.append(format_ivr_response(response.text_prompt, app)) elif response.event.type == "question": ivr_responses.append(format_ivr_response(response.event.caption, app)) elif response.event.type == "form-complete": hang_up = True if answer_is_valid and not error_occurred: call_log_entry.current_question_retry_count = 0 if call_log_entry.max_question_retries is not None and call_log_entry.current_question_retry_count > call_log_entry.max_question_retries: # Force hang-up ivr_responses = [] if len(ivr_responses) == 0: hang_up = True input_length = None if hang_up: if call_log_entry.xforms_session_id is not None: # Process disconnect session = XFormsSession.by_session_id(call_log_entry.xforms_session_id) if session.end_time is None: if call_log_entry.submit_partial_form: submit_unfinished_form(session.session_id, call_log_entry.include_case_side_effects) else: session.end(completed=False) session.save() else: # Set input_length to let the ivr gateway know how many digits we need to collect. # Have to get the current question again, since the last XFormsResponse in responses # may not have an event if it was a response to a constraint error. if error_occurred: current_q = current_question(call_log_entry.xforms_session_id) else: current_q = responses[-1] input_length = get_input_length(current_q) call_log_entry.save() return HttpResponse(backend_module.get_http_response_string(gateway_session_id, ivr_responses, collect_input=(not hang_up), hang_up=hang_up, input_length=input_length)) # If not processed, just log the call if call_log_entry: # No need to log, already exists return HttpResponse("") cleaned_number = phone_number if cleaned_number is not None and len(cleaned_number) > 0 and cleaned_number[0] == "+": cleaned_number = cleaned_number[1:] # Try to look up the verified number entry v = VerifiedNumber.view("sms/verified_number_by_number", key=cleaned_number, include_docs=True ).one() # If none was found, try to match only the last digits of numbers in the database if v is None: v = VerifiedNumber.view("sms/verified_number_by_suffix", key=cleaned_number, include_docs=True ).one() # Save the call entry msg = CallLog( phone_number=cleaned_number, direction=INCOMING, date=datetime.utcnow(), backend_api=backend_module.API_ID if backend_module else None, gateway_session_id=gateway_session_id, ) if v is not None: msg.domain = v.domain msg.couch_recipient_doc_type = v.owner_doc_type msg.couch_recipient = v.owner_id msg.save() return HttpResponse("")