Example #1
0
    def process_xforms_for_cases(xforms, case_db, timing_context=None):
        from casexml.apps.case.xform import process_cases_with_casedb
        from corehq.apps.commtrack.processing import process_stock

        timing_context = timing_context or TimingContext()

        instance = xforms[0]

        with timing_context("process_cases"):
            case_result = process_cases_with_casedb(xforms, case_db)
        with timing_context("process_ledgers"):
            stock_result = process_stock(xforms, case_db)
            stock_result.populate_models()

        modified_on_date = instance.received_on
        if getattr(instance, 'edited_on',
                   None) and instance.edited_on > instance.received_on:
            modified_on_date = instance.edited_on

        with timing_context("check_cases_before_save"):
            cases = case_db.get_cases_for_saving(modified_on_date)

        return CaseStockProcessingResult(
            case_result=case_result,
            case_models=cases,
            stock_result=stock_result,
        )
Example #2
0
 def process_form_unarchived(self, form):
     from corehq.apps.commtrack.processing import process_stock
     from casexml.apps.case.models import CommCareCase
     result = process_stock([form])
     result.populate_models()
     result.commit()
     result.finalize()
     CommCareCase.get_db().bulk_save(result.relevant_cases)
Example #3
0
 def process_form_unarchived(self, form):
     from corehq.apps.commtrack.processing import process_stock
     from casexml.apps.case.models import CommCareCase
     result = process_stock([form])
     result.populate_models()
     result.commit()
     result.finalize()
     CommCareCase.get_db().bulk_save(result.relevant_cases)
Example #4
0
 def create_form_with_duplicate_stock_transaction(self):
     from corehq.apps.commtrack.processing import process_stock
     product = self.make_product()
     form = self.update_stock(product)
     stock_result = process_stock([form])  # create duplicate transaction
     stock_result.populate_models()
     for model in stock_result.models_to_save:
         model.save()
     return product._id
Example #5
0
def reprocess_form(sender, xform, *args, **kwargs):
    from corehq.apps.commtrack.processing import process_stock
    result = process_stock([xform])
    for to_save in result.get_models_to_save():
        if to_save:
            to_save.commit()
    result.finalize()
    # todo: use LedgerProcessor
    CommCareCase.get_db().bulk_save(result.relevant_cases)
Example #6
0
 def create_form_with_duplicate_stock_transaction(self):
     from corehq.apps.commtrack.helpers import make_product
     from corehq.apps.commtrack.processing import process_stock
     thing1 = make_product(self.domain_name, 'thing-1', 'thing-1')
     self.submit_form(LEDGER_FORM.replace("thing-1", thing1._id))
     stock_result = process_stock([self._get_form("ledger-form")])
     stock_result.populate_models()
     for model in stock_result.models_to_save:
         model.save()
     return thing1._id
Example #7
0
def update_case_transactions_for_form(case_cache, live_case_updates,
                                      deprecated_case_updates, live_form,
                                      deprecated_form):
    for case_update in live_case_updates + deprecated_case_updates:
        case_id = case_update.id
        count, _ = CaseTransaction.objects.partitioned_query(case_id)\
            .filter(case_id=case_id, form_id=live_form.form_id).delete()

        rebuild_transactions = CaseTransaction.objects.partitioned_query(
            case_id).filter(case_id=case_id,
                            type=CaseTransaction.TYPE_REBUILD_FORM_EDIT)
        for transaction in rebuild_transactions:
            if transaction.details.get(
                    'deprecated_form_id') == deprecated_form.original_form_id:
                transaction.delete()

    for case_update in live_case_updates:
        case_id = case_update.id
        case = case_cache.get(case_id)
        SqlCaseUpdateStrategy.add_transaction_for_form(case, case_update,
                                                       live_form)

    for case_update in deprecated_case_updates:
        case_id = case_update.id
        case = case_cache.get(case_id)
        SqlCaseUpdateStrategy.add_transaction_for_form(case, case_update,
                                                       deprecated_form)

    stock_result = process_stock([live_form, deprecated_form], case_cache)
    stock_result.populate_models()
    affected_ledgers = set()
    affected_cases = set()
    ledger_transactions = []
    for ledger_value in stock_result.models_to_save:
        affected_ledgers.add(ledger_value.ledger_reference)
        affected_cases.add(ledger_value.case_id)
        for transaction in ledger_value.get_tracked_models_to_create(
                LedgerTransaction):
            ledger_transactions.append(transaction)

    if affected_cases:
        LedgerAccessorSQL.delete_ledger_transactions_for_form(
            affected_cases, live_form.form_id)

    for transaction in ledger_transactions:
        transaction.save()

    for case in case_cache.cache.values():
        affected_cases.add(case.case_id)
        transactions = case.get_tracked_models_to_create(CaseTransaction)
        for transaction in transactions:
            transaction.case = case
            transaction.save()

    return affected_cases, affected_ledgers
Example #8
0
    def process_form_unarchived(self, form):
        from corehq.apps.commtrack.processing import process_stock

        result = process_stock([form])
        result.populate_models()
        LedgerAccessorSQL.save_ledger_values(result.models_to_save)
        for ledger_value in result.models_to_save:
            publish_ledger_v2_saved(ledger_value)

        refs_to_rebuild = {ledger_value.ledger_reference for ledger_value in result.models_to_save}
        for ref in refs_to_rebuild:
            self.rebuild_ledger_state(**ref._asdict())

        result.finalize()
Example #9
0
def update_case_transactions_for_form(case_cache, live_case_updates, deprecated_case_updates,
                                      live_form, deprecated_form):
    for case_update in live_case_updates + deprecated_case_updates:
        case_id = case_update.id
        count, _ = CaseTransaction.objects.partitioned_query(case_id)\
            .filter(case_id=case_id, form_id=live_form.form_id).delete()

        rebuild_transactions = CaseTransaction.objects.partitioned_query(case_id).filter(
            case_id=case_id, type=CaseTransaction.TYPE_REBUILD_FORM_EDIT
        )
        for transaction in rebuild_transactions:
            if transaction.details.get('deprecated_form_id') == deprecated_form.original_form_id:
                transaction.delete()

    for case_update in live_case_updates:
        case_id = case_update.id
        case = case_cache.get(case_id)
        SqlCaseUpdateStrategy.add_transaction_for_form(case, case_update, live_form)

    for case_update in deprecated_case_updates:
        case_id = case_update.id
        case = case_cache.get(case_id)
        SqlCaseUpdateStrategy.add_transaction_for_form(case, case_update, deprecated_form)

    stock_result = process_stock([live_form, deprecated_form], case_cache)
    stock_result.populate_models()
    affected_ledgers = set()
    affected_cases = set()
    ledger_transactions = []
    for ledger_value in stock_result.models_to_save:
        affected_ledgers.add(ledger_value.ledger_reference)
        affected_cases.add(ledger_value.case_id)
        for transaction in ledger_value.get_tracked_models_to_create(LedgerTransaction):
            ledger_transactions.append(transaction)

    if affected_cases:
        LedgerAccessorSQL.delete_ledger_transactions_for_form(list(affected_cases), live_form.form_id)

    for transaction in ledger_transactions:
        transaction.save()

    for case in case_cache.cache.values():
        affected_cases.add(case.case_id)
        transactions = case.get_tracked_models_to_create(CaseTransaction)
        for transaction in transactions:
            transaction.case = case
            transaction.save()

    return affected_cases, affected_ledgers
Example #10
0
    def process_form_unarchived(self, form):
        from corehq.apps.commtrack.processing import process_stock
        result = process_stock([form])
        result.populate_models()
        LedgerAccessorSQL.save_ledger_values(result.models_to_save)
        for ledger_value in result.models_to_save:
            publish_ledger_v2_saved(ledger_value)

        refs_to_rebuild = {
            ledger_value.ledger_reference for ledger_value in result.models_to_save
        }
        for ref in refs_to_rebuild:
            self.rebuild_ledger_state(**ref._asdict())

        result.finalize()
Example #11
0
def _get_case_and_ledger_updates(domain, sql_form):
    """
    Get a CaseStockProcessingResult with the appropriate cases and ledgers to
    be saved.

    See SubmissionPost.process_xforms_for_cases and methods it calls for the equivalent
    section of the form-processing code.
    """
    from corehq.apps.commtrack.processing import process_stock

    interface = FormProcessorInterface(domain)

    assert sql_form.domain
    xforms = [sql_form]

    with interface.casedb_cache(
            domain=domain,
            lock=False,
            deleted_ok=True,
            xforms=xforms,
            load_src="couchsqlmigration",
    ) as case_db:
        touched_cases = FormProcessorInterface(domain).get_cases_from_forms(
            case_db, xforms)
        extensions_to_close = get_all_extensions_to_close(
            domain, list(touched_cases.values()))
        case_result = CaseProcessingResult(
            domain,
            [update.case for update in touched_cases.values()],
            [],  # ignore dirtiness_flags,
            extensions_to_close)
        for case in case_result.cases:
            case_db.post_process_case(case, sql_form)
            case_db.mark_changed(case)
        cases = case_result.cases

        try:
            stock_result = process_stock(xforms, case_db)
            cases = case_db.get_cases_for_saving(sql_form.received_on)
            stock_result.populate_models()
        except MissingFormXml:
            stock_result = None

    return CaseStockProcessingResult(
        case_result=case_result,
        case_models=cases,
        stock_result=stock_result,
    )
Example #12
0
    def process_xforms_for_cases(xforms, case_db):
        from casexml.apps.case.xform import process_cases_with_casedb
        from corehq.apps.commtrack.processing import process_stock

        instance = xforms[0]

        case_result = process_cases_with_casedb(xforms, case_db)
        stock_result = process_stock(xforms, case_db)

        cases = case_db.get_cases_for_saving(instance.received_on)
        stock_result.populate_models()

        return CaseStockProcessingResult(
            case_result=case_result,
            case_models=cases,
            stock_result=stock_result,
        )
Example #13
0
def _get_case_and_ledger_updates(domain, sql_form):
    """
    Get a CaseStockProcessingResult with the appropriate cases and ledgers to
    be saved.

    See SubmissionPost.process_xforms_for_cases and methods it calls for the equivalent
    section of the form-processing code.
    """
    from casexml.apps.case.xform import get_and_check_xform_domain
    from corehq.apps.commtrack.processing import process_stock

    interface = FormProcessorInterface(domain)

    get_and_check_xform_domain(sql_form)
    xforms = [sql_form]

    # todo: I think this can be changed to lock=False
    with interface.casedb_cache(domain=domain,
                                lock=True,
                                deleted_ok=True,
                                xforms=xforms) as case_db:
        touched_cases = FormProcessorInterface(domain).get_cases_from_forms(
            case_db, xforms)
        extensions_to_close = get_all_extensions_to_close(
            domain, touched_cases.values())
        case_result = CaseProcessingResult(
            domain,
            [update.case for update in touched_cases.values()],
            [],  # ignore dirtiness_flags,
            extensions_to_close)
        # todo: is this necessary?
        for case in case_result.cases:
            case_db.mark_changed(case)

        stock_result = process_stock(xforms, case_db)
        cases = case_db.get_cases_for_saving(sql_form.received_on)
        stock_result.populate_models()

    return CaseStockProcessingResult(
        case_result=case_result,
        case_models=cases,
        stock_result=stock_result,
    )
Example #14
0
    def process_xforms_for_cases(xforms, case_db):
        from casexml.apps.case.xform import process_cases_with_casedb
        from corehq.apps.commtrack.processing import process_stock

        instance = xforms[0]

        case_result = process_cases_with_casedb(xforms, case_db)
        stock_result = process_stock(xforms, case_db)

        modified_on_date = instance.received_on
        if getattr(instance, 'edited_on', None) and instance.edited_on > instance.received_on:
            modified_on_date = instance.edited_on
        cases = case_db.get_cases_for_saving(modified_on_date)
        stock_result.populate_models()

        return CaseStockProcessingResult(
            case_result=case_result,
            case_models=cases,
            stock_result=stock_result,
        )
Example #15
0
    def process_xforms_for_cases(xforms, case_db):
        from casexml.apps.case.xform import process_cases_with_casedb
        from corehq.apps.commtrack.processing import process_stock

        instance = xforms[0]

        case_result = process_cases_with_casedb(xforms, case_db)
        stock_result = process_stock(xforms, case_db)

        modified_on_date = instance.received_on
        if getattr(instance, 'edited_on', None) and instance.edited_on > instance.received_on:
            modified_on_date = instance.edited_on
        cases = case_db.get_cases_for_saving(modified_on_date)
        stock_result.populate_models()

        return CaseStockProcessingResult(
            case_result=case_result,
            case_models=cases,
            stock_result=stock_result,
        )
Example #16
0
    def process_xforms_for_cases(self, xforms):
        from casexml.apps.case.xform import get_and_check_xform_domain
        from casexml.apps.case.xform import process_cases_with_casedb
        from corehq.apps.commtrack.processing import process_stock

        instance = xforms[0]

        domain = get_and_check_xform_domain(instance)
        with self.interface.casedb_cache(domain=domain, lock=True, deleted_ok=True, xforms=xforms) as case_db:
            case_result = process_cases_with_casedb(xforms, case_db)
            stock_result = process_stock(xforms, case_db)

            cases = case_db.get_cases_for_saving(instance.received_on)
            stock_result.populate_models()

        return CaseStockProcessingResult(
            case_result=case_result,
            case_models=cases,
            stock_result=stock_result,
        )
Example #17
0
    def process_xforms_for_cases(self, xforms):
        from casexml.apps.case.xform import get_and_check_xform_domain
        from casexml.apps.case.xform import process_cases_with_casedb
        from corehq.apps.commtrack.processing import process_stock

        instance = xforms[0]

        domain = get_and_check_xform_domain(instance)
        with self.interface.casedb_cache(domain=domain, lock=True, deleted_ok=True, xforms=xforms) as case_db:
            case_result = process_cases_with_casedb(xforms, case_db)
            stock_result = process_stock(xforms, case_db)

            cases = case_db.get_cases_for_saving(instance.received_on)
            stock_result.populate_models()

        return CaseStockProcessingResult(
            case_result=case_result,
            case_models=cases,
            stock_result=stock_result,
        )
Example #18
0
def _get_case_and_ledger_updates(domain, sql_form):
    """
    Get a CaseStockProcessingResult with the appropriate cases and ledgers to
    be saved.

    See SubmissionPost.process_xforms_for_cases and methods it calls for the equivalent
    section of the form-processing code.
    """
    from corehq.apps.commtrack.processing import process_stock

    interface = FormProcessorInterface(domain)

    assert sql_form.domain
    xforms = [sql_form]

    with interface.casedb_cache(
        domain=domain, lock=False, deleted_ok=True, xforms=xforms,
        load_src="couchsqlmigration",
    ) as case_db:
        touched_cases = FormProcessorInterface(domain).get_cases_from_forms(case_db, xforms)
        extensions_to_close = get_all_extensions_to_close(domain, list(touched_cases.values()))
        case_result = CaseProcessingResult(
            domain,
            [update.case for update in touched_cases.values()],
            [],  # ignore dirtiness_flags,
            extensions_to_close
        )
        for case in case_result.cases:
            case_db.post_process_case(case, sql_form)
            case_db.mark_changed(case)

        stock_result = process_stock(xforms, case_db)
        cases = case_db.get_cases_for_saving(sql_form.received_on)
        stock_result.populate_models()

    return CaseStockProcessingResult(
        case_result=case_result,
        case_models=cases,
        stock_result=stock_result,
    )
Example #19
0
    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.models import CommCareCase
            from casexml.apps.case.xform import (
                get_and_check_xform_domain, CaseDbCache, process_cases_with_casedb
            )
            from casexml.apps.case.signals import case_post_save
            from casexml.apps.case.exceptions import IllegalCaseId, UsesReferrals
            from corehq.apps.commtrack.processing import process_stock

            cases = []
            responses = []
            errors = []
            with lock_manager as xforms:
                instance = xforms[0]
                if instance.doc_type == 'XFormInstance':
                    if len(xforms) > 1:
                        assert len(xforms) == 2
                        assert is_deprecation(xforms[1])
                    domain = get_and_check_xform_domain(instance)
                    with CaseDbCache(domain=domain, lock=True, deleted_ok=True, xforms=xforms) as case_db:
                        try:
                            case_result = process_cases_with_casedb(xforms, case_db)
                            process_stock(instance, case_db)
                        except (IllegalCaseId, UsesReferrals) as e:
                            # errors we know about related to the content of the form
                            # log the error and respond with a success code so that the phone doesn't
                            # keep trying to send the form
                            instance = _handle_known_error(e, instance)
                            response = self._get_open_rosa_response(instance,
                                                                    None, None)
                            return response, instance, cases
                        except Exception as e:
                            # handle / log the error and reraise so the phone knows to resubmit
                            _handle_unexpected_error(e, instance)
                            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:
                            # save both the forms and cases
                            XFormInstance.get_db().bulk_save(docs)
                        except BulkSaveError as e:
                            logging.error('BulkSaveError saving forms', exc_info=1,
                                          extra={'details': {'errors': e.errors}})
                            raise
                        unfinished_submission_stub.saved = True
                        unfinished_submission_stub.save()
                        for case in cases:
                            case_post_save.send(CommCareCase, case=case)

                        case_result.commit_dirtiness_flags()

                    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
Example #20
0
    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
Example #21
0
    def run(self):
        if timezone_migration_in_progress(self.domain):
            # keep submissions on the phone
            # until ready to start accepting again
            return HttpResponse(status=503), None, []

        if not self.auth_context.is_valid():
            return self.failed_auth_response, None, []

        if isinstance(self.instance, BadRequest):
            return HttpResponseBadRequest(self.instance.message), None, []

        def process(xform):
            self._attach_shared_props(xform)
            if xform.doc_type != 'SubmissionErrorLog':
                found_old = scrub_meta(xform)
                legacy_soft_assert(not found_old, 'Form with old metadata submitted', xform._id)

        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.models import CommCareCase
            from casexml.apps.case.xform import (
                get_and_check_xform_domain, CaseDbCache, process_cases_with_casedb
            )
            from casexml.apps.case.signals import case_post_save
            from casexml.apps.case.exceptions import IllegalCaseId, UsesReferrals
            from corehq.apps.commtrack.processing import process_stock
            from corehq.apps.commtrack.exceptions import MissingProductId

            cases = []
            responses = []
            errors = []
            known_errors = (IllegalCaseId, UsesReferrals, MissingProductId,
                            PhoneDateValueError)
            with lock_manager as xforms:
                instance = xforms[0]
                if instance.doc_type == 'XFormInstance':
                    if len(xforms) > 1:
                        assert len(xforms) == 2
                        assert is_deprecation(xforms[1])
                    domain = get_and_check_xform_domain(instance)
                    with CaseDbCache(domain=domain, lock=True, deleted_ok=True, xforms=xforms) as case_db:
                        try:
                            case_result = process_cases_with_casedb(xforms, case_db)
                            stock_result = process_stock(xforms, case_db)
                        except known_errors as e:
                            # errors we know about related to the content of the form
                            # log the error and respond with a success code so that the phone doesn't
                            # keep trying to send the form
                            instance = _handle_known_error(e, instance)
                            xforms[0] = instance
                            # this is usually just one document, but if an edit errored we want
                            # to save the deprecated form as well
                            XFormInstance.get_db().bulk_save(xforms)
                            response = self._get_open_rosa_response(
                                instance, None)
                            return response, instance, cases
                        except Exception as e:
                            # handle / log the error and reraise so the phone knows to resubmit
                            # note that in the case of edit submissions this won't flag the previous
                            # submission as having been edited. this is intentional, since we should treat
                            # this use case as if the edit "failed"
                            error_message = u'{}: {}'.format(type(e).__name__, unicode(e))
                            instance = _handle_unexpected_error(instance, 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 only used by the MVPFormIndicatorPillow
                        instance.initial_processing_complete = True

                        # in saving the cases, we have to do all the things
                        # done in CommCareCase.save()
                        for case in cases:
                            legacy_soft_assert(case.version == "2.0", "v1.0 case updated", case.case_id)
                            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
                                    )
                                )

                        # verify that these DB's are the same so that we can save them with one call to bulk_save
                        assert XFormInstance.get_db().uri == CommCareCase.get_db().uri
                        docs = xforms + cases
                        try:
                            XFormInstance.get_db().bulk_save(docs)
                        except BulkSaveError as e:
                            logging.error('BulkSaveError saving forms', exc_info=1,
                                          extra={'details': {'errors': e.errors}})
                            raise
                        except Exception as e:
                            docs_being_saved = [doc['_id'] for doc in docs]
                            error_message = u'Unexpected error bulk saving docs {}: {}, doc_ids: {}'.format(
                                type(e).__name__,
                                unicode(e),
                                ', '.join(docs_being_saved)
                            )
                            instance = _handle_unexpected_error(instance, error_message)
                            instance.save()
                            raise
                        unfinished_submission_stub.saved = True
                        unfinished_submission_stub.save()
                        case_result.commit_dirtiness_flags()
                        stock_result.commit()
                        for case in cases:
                            case_post_save.send(CommCareCase, case=case)

                    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, errors)
            return response, instance, cases
Example #22
0
def reprocess_form(sender, xform, *args, **kwargs):
    from corehq.apps.commtrack.processing import process_stock
    for case in process_stock(xform):
        case.save()
Example #23
0
 def process_stock(cls, xforms, case_db):
     from corehq.apps.commtrack.processing import process_stock
     return process_stock(xforms, case_db)
Example #24
0
def reprocess_form(sender, xform, *args, **kwargs):
    from corehq.apps.commtrack.processing import process_stock
    result = process_stock(xform)
    result.commit()
    CommCareCase.get_db().bulk_save(result.relevant_cases)
Example #25
0
def reprocess_form(sender, xform, *args, **kwargs):
    from corehq.apps.commtrack.processing import process_stock
    result = process_stock(xform)
    result.commit()
    CommCareCase.get_db().bulk_save(result.relevant_cases)
Example #26
0
    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.models import CommCareCase
            from casexml.apps.case.xform import (
                get_and_check_xform_domain, CaseDbCache, process_cases_with_casedb
            )
            from casexml.apps.case.signals import case_post_save
            from casexml.apps.case.exceptions import IllegalCaseId, UsesReferrals
            from corehq.apps.commtrack.processing import process_stock
            from corehq.apps.commtrack.exceptions import MissingProductId

            cases = []
            responses = []
            errors = []
            known_errors = (IllegalCaseId, UsesReferrals, MissingProductId,
                            PhoneDateValueError)
            with lock_manager as xforms:
                instance = xforms[0]
                if instance.doc_type == 'XFormInstance':
                    if len(xforms) > 1:
                        assert len(xforms) == 2
                        assert is_deprecation(xforms[1])
                    domain = get_and_check_xform_domain(instance)
                    with CaseDbCache(domain=domain, lock=True, deleted_ok=True, xforms=xforms) as case_db:
                        try:
                            case_result = process_cases_with_casedb(xforms, case_db)
                            stock_result = process_stock(instance, case_db)
                        except known_errors as e:
                            # errors we know about related to the content of the form
                            # log the error and respond with a success code so that the phone doesn't
                            # keep trying to send the form
                            instance = _handle_known_error(e, instance)
                            xforms[0] = instance
                            # this is usually just one document, but if an edit errored we want
                            # to save the deprecated form as well
                            XFormInstance.get_db().bulk_save(xforms)
                            response = self._get_open_rosa_response(instance,
                                                                    None, None)
                            return response, instance, cases
                        except Exception as e:
                            # handle / log the error and reraise so the phone knows to resubmit
                            # note that in the case of edit submissions this won't flag the previous
                            # submission as having been edited. this is intentional, since we should treat
                            # this use case as if the edit "failed"
                            error_message = u'{}: {}'.format(type(e).__name__, unicode(e))
                            instance = _handle_unexpected_error(instance, 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:
                            # save both the forms and cases
                            XFormInstance.get_db().bulk_save(docs)
                        except BulkSaveError as e:
                            logging.error('BulkSaveError saving forms', exc_info=1,
                                          extra={'details': {'errors': e.errors}})
                            raise
                        except Exception as e:
                            docs_being_saved = [doc['_id'] for doc in docs]
                            error_message = u'Unexpected error bulk saving docs {}: {}, doc_ids: {}'.format(
                                type(e).__name__,
                                unicode(e),
                                ', '.join(docs_being_saved)
                            )
                            instance = _handle_unexpected_error(instance, error_message)
                            instance.save()
                            raise
                        unfinished_submission_stub.saved = True
                        unfinished_submission_stub.save()
                        case_result.commit_dirtiness_flags()
                        stock_result.commit()
                        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()