def reprocess_form_cases(form, config=None, case_db=None): """ For a given form, reprocess all case elements inside it. This operation should be a no-op if the form was sucessfully processed, but should correctly inject the update into the case history if the form was NOT successfully processed. """ from casexml.apps.case import process_cases, process_cases_with_casedb if case_db: process_cases_with_casedb(form, case_db, config=config) else: process_cases(form, config) # mark cleaned up now that we've reprocessed it if form.doc_type != 'XFormInstance': form = XFormInstance.get(form._id) form.doc_type = 'XFormInstance' form.save()
def run(self): if not self.auth_context.is_valid(): return self.failed_auth_response, None, [] if isinstance(self.instance, const.BadRequest): return HttpResponseBadRequest(self.instance.message), None, [] def process(xform): self._attach_shared_props(xform) scrub_meta(xform) try: lock_manager = process_xform(self.instance, attachments=self.attachments, process=process, domain=self.domain) except SubmissionError as e: logging.exception( u"Problem receiving submission to %s. %s" % ( self.path, unicode(e), ) ) return self.get_exception_response(e.error_log), None, [] else: from casexml.apps.case import process_cases_with_casedb from casexml.apps.case.models import CommCareCase from casexml.apps.case.xform import get_and_check_xform_domain, CaseDbCache from casexml.apps.case.signals import case_post_save from casexml.apps.case.exceptions import IllegalCaseId from corehq.apps.commtrack.processing import process_stock cases = [] responses = [] errors = [] with lock_manager as xforms: instance = xforms[0] if instance.doc_type == "XFormInstance": domain = get_and_check_xform_domain(instance) with CaseDbCache(domain=domain, lock=True, deleted_ok=True) as case_db: try: process_cases_with_casedb(instance, case_db) process_stock(instance, case_db) except IllegalCaseId as e: error_message = '{}: {}'.format( type(e).__name__, unicode(e)) logging.exception(( u"Warning in case or stock processing " u"for form {}: {}." ).format(instance._id, error_message)) instance.__class__ = XFormError instance.problem = error_message instance.save() response = self._get_open_rosa_response(instance, None, None) return response, instance, cases except Exception as e: # Some things to consider here # The following code saves the xform instance # as an XFormError, with a different ID. # That's because if you save with the original ID # and then resubmit, the new submission never has a # chance to get reprocessed; it'll just get saved as # a duplicate. error_message = '{}: {}'.format( type(e).__name__, unicode(e)) new_id = XFormError.get_db().server.next_uuid() logging.exception(( u"Error in case or stock processing " u"for form {}: {}.\n" u"Error saved as {}" ).format(instance._id, error_message, new_id)) instance.__class__ = XFormError instance.orig_id = instance._id instance._id = new_id instance.problem = error_message instance.save() raise now = datetime.datetime.utcnow() unfinished_submission_stub = UnfinishedSubmissionStub( xform_id=instance.get_id, timestamp=now, saved=False, domain=domain, ) unfinished_submission_stub.save() cases = case_db.get_changed() # todo: this property is useless now instance.initial_processing_complete = True assert XFormInstance.get_db().uri == CommCareCase.get_db().uri docs = xforms + cases # in saving the cases, we have to do all the things # done in CommCareCase.save() for case in cases: case.initial_processing_complete = True case.server_modified_on = now try: rev = CommCareCase.get_db().get_rev(case.case_id) except ResourceNotFound: pass else: assert rev == case.get_rev, ( "Aborting because there would have been " "a document update conflict. {} {} {}".format( case.get_id, case.get_rev, rev ) ) try: XFormInstance.get_db().bulk_save(docs) except BulkSaveError as e: logging.exception('BulkSaveError saving forms', extra={'errors': e.errors}) raise unfinished_submission_stub.saved = True unfinished_submission_stub.save() for case in cases: case_post_save.send(CommCareCase, case=case) responses, errors = self.process_signals(instance) if errors: # .problems was added to instance instance.save() unfinished_submission_stub.delete() elif instance.doc_type == 'XFormDuplicate': assert len(xforms) == 1 instance.save() response = self._get_open_rosa_response(instance, responses, errors) return response, instance, cases