def test_withdrawn(self):
        # qbs should halt beyond withdrawal
        crv = self.setup_org_qbs()
        crv_id = crv.id
        # consent 17 months in past
        backdate = datetime.utcnow() - relativedelta(months=17)
        self.test_user = db.session.merge(self.test_user)
        self.test_user.organizations.append(crv)
        self.consent_with_org(org_id=crv_id, setdate=backdate)

        # withdraw user now, which should provide result
        # in QBs prior to 17 months.

        user = db.session.merge(self.test_user)
        withdraw_consent(
            user=user, org_id=crv_id, acting_user=user,
            acceptance_date=datetime.utcnow())
        gen = ordered_qbs(user=user)

        # expect each in order despite overlapping nature
        expect_baseline = next(gen)
        assert visit_name(expect_baseline) == 'Baseline'
        for n in (3, 6, 9, 15):
            assert visit_name(next(gen)) == 'Month {}'.format(n)

        with pytest.raises(StopIteration):
            next(gen)
Exemple #2
0
    def test_withdrawn(self):
        # qbs should halt beyond withdrawal
        crv = self.setup_org_qbs()
        crv_id = crv.id
        # consent 17 months in past
        backdate = datetime.utcnow() - relativedelta(months=17)
        self.test_user.organizations.append(crv)
        self.consent_with_org(org_id=crv_id, setdate=backdate)

        # withdraw user now, which should provide result
        # in QBs prior to 17 months.

        user = db.session.merge(self.test_user)
        withdraw_consent(user=user,
                         org_id=crv_id,
                         acting_user=user,
                         acceptance_date=datetime.utcnow())
        gen = ordered_qbs(user=user)

        # expect each in order despite overlapping nature
        expect_baseline = next(gen)
        assert visit_name(expect_baseline) == 'Baseline'
        for n in (3, 6, 9, 15):
            assert visit_name(next(gen)) == 'Month {}'.format(n)

        with pytest.raises(StopIteration):
            next(gen)
Exemple #3
0
    def test_change_before_start_rp(self):
        now = datetime.utcnow()
        back7, nowish = associative_backdate(now=now,
                                             backdate=relativedelta(months=7))
        back14, nowish = associative_backdate(
            now=now, backdate=relativedelta(months=14))
        org = self.setup_org_qbs(rp_name='v2', retired_as_of=back14)
        org_id = org.id
        self.setup_org_qbs(org=org, rp_name='v3')
        self.consent_with_org(org_id=org_id, setdate=back7)
        user = db.session.merge(self.test_user)
        gen = ordered_qbs(user)

        # expect everything in v3
        expect_baseline = next(gen)
        assert visit_name(expect_baseline) == 'Baseline'
        assert (
            expect_baseline.questionnaire_bank.research_protocol.name == 'v3')
        for n in (3, 6, 9, 15, 18, 21, 30):
            qbd = next(gen)
            assert visit_name(qbd) == 'Month {}'.format(n)
            assert qbd.questionnaire_bank.research_protocol.name == 'v3'

        with pytest.raises(StopIteration):
            next(gen)
    def test_change_before_start_rp_w_result(self):
        now = datetime.utcnow()
        back7, nowish = associative_backdate(
            now=now, backdate=relativedelta(months=7))
        back14, nowish = associative_backdate(
            now=now, backdate=relativedelta(months=14))
        org = self.setup_org_qbs(rp_name='v2', retired_as_of=back14)
        org_id = org.id
        self.setup_org_qbs(org=org, rp_name='v3')
        self.consent_with_org(org_id=org_id, setdate=back7)

        # submit a mock response for baseline QB on old RP
        # which should result in v2 for baseline and v3 thereafter
        qb_name = "CRV Baseline v2"
        baseline = QuestionnaireBank.query.filter(
            QuestionnaireBank.name == qb_name).one()
        mock_qr('epic_26_v2', qb=baseline, iteration=None)

        user = db.session.merge(self.test_user)
        gen = ordered_qbs(user)

        # expect everything in v3 post baseline
        expect_baseline = next(gen)
        assert visit_name(expect_baseline) == 'Baseline'
        assert (
            expect_baseline.questionnaire_bank.research_protocol.name == 'v2')
        for n in (3, 6, 9, 15, 18, 21, 30):
            qbd = next(gen)
            assert visit_name(qbd) == 'Month {}'.format(n)
            assert qbd.questionnaire_bank.research_protocol.name == 'v3'

        with pytest.raises(StopIteration):
            next(gen)
    def test_change_before_start_rp(self):
        now = datetime.utcnow()
        back7, nowish = associative_backdate(
            now=now, backdate=relativedelta(months=7))
        back14, nowish = associative_backdate(
            now=now, backdate=relativedelta(months=14))
        org = self.setup_org_qbs(rp_name='v2', retired_as_of=back14)
        org_id = org.id
        self.setup_org_qbs(org=org, rp_name='v3')
        self.consent_with_org(org_id=org_id, setdate=back7)
        user = db.session.merge(self.test_user)
        gen = ordered_qbs(user)

        # expect everything in v3
        expect_baseline = next(gen)
        assert visit_name(expect_baseline) == 'Baseline'
        assert (
            expect_baseline.questionnaire_bank.research_protocol.name == 'v3')
        for n in (3, 6, 9, 15, 18, 21, 30):
            qbd = next(gen)
            assert visit_name(qbd) == 'Month {}'.format(n)
            assert qbd.questionnaire_bank.research_protocol.name == 'v3'

        with pytest.raises(StopIteration):
            next(gen)
Exemple #6
0
    def test_change_before_start_rp_w_result(self):
        now = datetime.utcnow()
        back7, nowish = associative_backdate(now=now,
                                             backdate=relativedelta(months=7))
        back14, nowish = associative_backdate(
            now=now, backdate=relativedelta(months=14))
        org = self.setup_org_qbs(rp_name='v2', retired_as_of=back14)
        org_id = org.id
        self.setup_org_qbs(org=org, rp_name='v3')
        self.consent_with_org(org_id=org_id, setdate=back7)

        # submit a mock response for baseline QB on old RP
        # which should result in v2 for baseline and v3 thereafter
        qb_name = "CRV Baseline v2"
        baseline = QuestionnaireBank.query.filter(
            QuestionnaireBank.name == qb_name).one()
        mock_qr('epic_26_v2', qb=baseline, iteration=None)

        user = db.session.merge(self.test_user)
        gen = ordered_qbs(user)

        # expect everything in v3 post baseline
        expect_baseline = next(gen)
        assert visit_name(expect_baseline) == 'Baseline'
        assert (
            expect_baseline.questionnaire_bank.research_protocol.name == 'v2')
        for n in (3, 6, 9, 15, 18, 21, 30):
            qbd = next(gen)
            assert visit_name(qbd) == 'Month {}'.format(n)
            assert qbd.questionnaire_bank.research_protocol.name == 'v3'

        with pytest.raises(StopIteration):
            next(gen)
Exemple #7
0
    def test_visit_6mo(self):
        crv = self.setup_qbs()
        backdate, nowish = associative_backdate(
            now=now, backdate=relativedelta(months=6))
        self.bless_with_basics(setdate=backdate)
        self.test_user.organizations.append(crv)
        self.test_user = db.session.merge(self.test_user)

        qbd = QuestionnaireBank.most_current_qb(self.test_user,
                                                as_of_date=nowish +
                                                timedelta(hours=1))
        self.assertEqual("Month 6", visit_name(qbd))

        qbd_i2 = qbd._replace(iteration=1)
        self.assertEqual("Month 18", visit_name(qbd_i2))
Exemple #8
0
    def test_visit_6mo(self):
        crv = self.setup_org_qbs()
        backdate, nowish = associative_backdate(
            now=now, backdate=relativedelta(months=6))
        self.bless_with_basics(setdate=backdate)
        self.test_user = db.session.merge(self.test_user)
        self.test_user.organizations.append(crv)

        qstats = QB_Status(self.test_user,
                           as_of_date=nowish + timedelta(hours=1))
        qbd = qstats.current_qbd()
        assert visit_name(qbd) == "Month 6"

        qbd.iteration = 1
        assert visit_name(qbd) == "Month 18"
    def test_visit_6mo(self):
        crv = self.setup_org_qbs()
        backdate, nowish = associative_backdate(
            now=now, backdate=relativedelta(months=6))
        self.bless_with_basics(setdate=backdate)
        self.test_user = db.session.merge(self.test_user)
        self.test_user.organizations.append(crv)

        qstats = QB_Status(
            self.test_user, as_of_date=nowish + timedelta(hours=1))
        qbd = qstats.current_qbd()
        assert visit_name(qbd) == "Month 6"

        qbd.iteration = 1
        assert visit_name(qbd) == "Month 18"
    def test_full_list(self):
        crv = self.setup_org_qbs()
        self.bless_with_basics()  # pick up a consent, etc.
        self.test_user = db.session.merge(self.test_user)
        self.test_user.organizations.append(crv)

        gen = ordered_qbs(user=self.test_user)

        # expect each in order despite overlapping nature
        expect_baseline = next(gen)
        assert visit_name(expect_baseline) == 'Baseline'
        for n in (3, 6, 9, 15, 18, 21, 30):
            assert visit_name(next(gen)) == 'Month {}'.format(n)

        with pytest.raises(StopIteration):
            next(gen)
Exemple #11
0
    def test_full_list(self):
        crv = self.setup_org_qbs()
        self.bless_with_basics()  # pick up a consent, etc.
        self.test_user = db.session.merge(self.test_user)
        self.test_user.organizations.append(crv)

        gen = ordered_qbs(user=self.test_user)

        # expect each in order despite overlapping nature
        expect_baseline = next(gen)
        assert visit_name(expect_baseline) == 'Baseline'
        for n in (3, 6, 9, 15, 18, 21, 30):
            assert visit_name(next(gen)) == 'Month {}'.format(n)

        with pytest.raises(StopIteration):
            next(gen)
Exemple #12
0
    def test_recurring_starts(self):
        # should get full list of QBDs for recurring qb
        self.setup_org_qbs()
        td = datetime.utcnow().replace(month=1, day=1)

        sixMoQB = QuestionnaireBank.query.filter(
            QuestionnaireBank.name == 'CRV_recurring_6mo_period v2').one()
        results = sixMoQB.recurring_starts(trigger_date=td)
        # Expect in order, 6mo, 18mo, 30mo
        expect6 = next(results)
        assert visit_name(expect6) == 'Month 6'
        expect18 = next(results)
        assert visit_name(expect18) == 'Month 18'
        expect30 = next(results)
        assert visit_name(expect30) == 'Month 30'
        with pytest.raises(StopIteration):
            next(results)
    def test_recurring_starts(self):
        # should get full list of QBDs for recurring qb
        self.setup_org_qbs()
        td = datetime.utcnow().replace(month=1, day=1)

        sixMoQB = QuestionnaireBank.query.filter(
            QuestionnaireBank.name == 'CRV_recurring_6mo_period v2').one()
        results = sixMoQB.recurring_starts(trigger_date=td)
        # Expect in order, 6mo, 18mo, 30mo
        expect6 = next(results)
        assert visit_name(expect6) == 'Month 6'
        expect18 = next(results)
        assert visit_name(expect18) == 'Month 18'
        expect30 = next(results)
        assert visit_name(expect30) == 'Month 30'
        with pytest.raises(StopIteration):
            next(results)
Exemple #14
0
    def test_visit_baseline(self):
        crv = self.setup_qbs()
        self.bless_with_basics()  # pick up a consent, etc.
        self.test_user.organizations.append(crv)
        self.test_user = db.session.merge(self.test_user)

        qbd = QuestionnaireBank.most_current_qb(self.test_user, as_of_date=now)
        self.assertEqual("Baseline", visit_name(qbd))
    def test_visit_baseline(self):
        crv = self.setup_org_qbs()
        self.bless_with_basics(setdate=now)  # pick up a consent, etc.
        self.test_user = db.session.merge(self.test_user)
        self.test_user.organizations.append(crv)

        qstats = QB_Status(self.test_user, now)
        qbd = qstats.current_qbd()
        assert visit_name(qbd) == "Baseline"
Exemple #16
0
    def test_visit_baseline(self):
        crv = self.setup_org_qbs()
        self.bless_with_basics(setdate=now)  # pick up a consent, etc.
        self.test_user = db.session.merge(self.test_user)
        self.test_user.organizations.append(crv)

        qstats = QB_Status(self.test_user, now)
        qbd = qstats.current_qbd()
        assert visit_name(qbd) == "Baseline"
    def test_intervention_list(self):
        self.setup_intervention_qbs()
        self.bless_with_basics()  # pick up a consent, etc.
        # user with biopsy should return biopsy date
        self.login()
        user = db.session.merge(self.test_user)
        user.save_observation(
            codeable_concept=CC.BIOPSY, value_quantity=CC.TRUE_VALUE,
            audit=Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID),
            status='', issued=None)
        user = db.session.merge(self.test_user)

        gen = ordered_qbs(user=user)

        # expect all intervention QBs - baseline then every 3mos
        expect_baseline = next(gen)
        assert visit_name(expect_baseline) == 'Baseline'
        for n in (3, 9, 15, 21, 27):
            assert visit_name(next(gen)) == 'Month {}'.format(n)

        with pytest.raises(StopIteration):
            next(gen)
    def test_change_midstream_results_rp(self):
        now = datetime.utcnow()
        back1, nowish = associative_backdate(
            now=now, backdate=relativedelta(months=1))
        back10, nowish = associative_backdate(
            now=now, backdate=relativedelta(months=10))
        org = self.setup_org_qbs(rp_name='v2', retired_as_of=back1)
        org_id = org.id
        self.setup_org_qbs(org=org, rp_name='v3')
        self.consent_with_org(org_id=org_id, setdate=back10)

        # submit a mock response for 9 month QB on old RP
        # which should result in v2 for up to 9 month and v3 thereafter
        qb_name = "CRV_recurring_3mo_period v2"
        nineMo = QuestionnaireBank.query.filter(
            QuestionnaireBank.name == qb_name).one()
        mock_qr('epic_26_v2', qb=nineMo, iteration=1)

        user = db.session.merge(self.test_user)
        gen = ordered_qbs(user)

        # expect baseline and 3 month in v2, rest in v3
        expect_baseline = next(gen)
        assert visit_name(expect_baseline) == 'Baseline'
        assert (
            expect_baseline.questionnaire_bank.research_protocol.name == 'v2')
        for n in (3, 6, 9):
            qbd = next(gen)
            assert visit_name(qbd) == 'Month {}'.format(n)
            assert qbd.questionnaire_bank.research_protocol.name == 'v2'
        for n in (15, 18, 21, 30):
            qbd = next(gen)
            assert visit_name(qbd) == 'Month {}'.format(n)
            assert qbd.questionnaire_bank.research_protocol.name == 'v3'

        with pytest.raises(StopIteration):
            next(gen)
Exemple #19
0
    def test_change_midstream_results_rp(self):
        now = datetime.utcnow()
        back1, nowish = associative_backdate(now=now,
                                             backdate=relativedelta(months=1))
        back10, nowish = associative_backdate(
            now=now, backdate=relativedelta(months=10))
        org = self.setup_org_qbs(rp_name='v2', retired_as_of=back1)
        org_id = org.id
        self.setup_org_qbs(org=org, rp_name='v3')
        self.consent_with_org(org_id=org_id, setdate=back10)

        # submit a mock response for 9 month QB on old RP
        # which should result in v2 for up to 9 month and v3 thereafter
        qb_name = "CRV_recurring_3mo_period v2"
        nineMo = QuestionnaireBank.query.filter(
            QuestionnaireBank.name == qb_name).one()
        mock_qr('epic_26_v2', qb=nineMo, iteration=1)

        user = db.session.merge(self.test_user)
        gen = ordered_qbs(user)

        # expect baseline and 3 month in v2, rest in v3
        expect_baseline = next(gen)
        assert visit_name(expect_baseline) == 'Baseline'
        assert (
            expect_baseline.questionnaire_bank.research_protocol.name == 'v2')
        for n in (3, 6, 9):
            qbd = next(gen)
            assert visit_name(qbd) == 'Month {}'.format(n)
            assert qbd.questionnaire_bank.research_protocol.name == 'v2'
        for n in (15, 18, 21, 30):
            qbd = next(gen)
            assert visit_name(qbd) == 'Month {}'.format(n)
            assert qbd.questionnaire_bank.research_protocol.name == 'v3'

        with pytest.raises(StopIteration):
            next(gen)
Exemple #20
0
    def test_intervention_list(self):
        self.setup_intervention_qbs()
        self.bless_with_basics()  # pick up a consent, etc.
        # user with biopsy should return biopsy date
        self.login()
        user = db.session.merge(self.test_user)
        user.save_observation(codeable_concept=CC.BIOPSY,
                              value_quantity=CC.TRUE_VALUE,
                              audit=Audit(user_id=TEST_USER_ID,
                                          subject_id=TEST_USER_ID),
                              status='',
                              issued=None)
        user = db.session.merge(self.test_user)

        gen = ordered_qbs(user=user)

        # expect all intervention QBs - baseline then every 3mos
        expect_baseline = next(gen)
        assert visit_name(expect_baseline) == 'Baseline'
        for n in (3, 9, 15, 21, 27):
            assert visit_name(next(gen)) == 'Month {}'.format(n)

        with pytest.raises(StopIteration):
            next(gen)
def upgrade():
    # Tricky task to locate the errors.  One time expensive process,
    # loop through patients identifying problems.

    admin = admin_id()
    qb_map = qb_pairs_by_rp()
    if not qb_map:
        return  # nothing to do on systems w/o RP changes
    fix_map = dict()

    raise RuntimeError(
        "Unsupported migration; code has changed - not maintained")
    for patient in active_patients(include_test_role=True).order_by(User.id):
        qnrs = QuestionnaireResponse.query.filter(
            QuestionnaireResponse.subject_id == patient.id).order_by(
            QuestionnaireResponse.authored)
        if not qnrs.count():
            # Only care if the user submitted QNRs:
            continue

        for qnr in qnrs:

            # Obtain qb_timeline row at the time of QNR.authored
            as_of_date = qnr.authored
            qbt = QBT.query.filter(QBT.user_id == patient.id).filter(
                QBT.at <= as_of_date).order_by(
                QBT.at.desc(), QBT.id.desc()).first()

            if qnr.questionnaire_bank_id is None:
                print(
                    "qnr {} user_id {} authored {} {}"
                    " with NO qb_id set".format(
                        qnr.id, patient.id, as_of_date,
                        qnr.document['questionnaire']['reference']))
                continue

            if qbt and qbt.status != OverallStatus.withdrawn:
                recorded_qb = QuestionnaireBank.query.get(
                    qnr.questionnaire_bank_id)
                qbd = qbt.qbd()
                expected_qb = qbd.questionnaire_bank
                if recorded_qb.classification == 'indefinite':
                    # indefinite case is handled differently...
                    qb_status = QB_Status(patient, as_of_date)
                    expected_qb = QuestionnaireBank.query.get(
                        qb_status._current_indef.qb_id)

                if recorded_qb != expected_qb:
                    replacement = qb_map.get(recorded_qb.id)
                    if replacement == expected_qb.id:
                        # retain the change request, as altering it inline
                        # interrupts the iteration
                        patched_qbd = QBD(
                            relative_start=qbd.relative_start, iteration=qbd.iteration,
                            recur=qbd.recur, qb_id=replacement)
                        fix_map[qnr.id] = (expected_qb.id, visit_name(patched_qbd))
                        print(
                            "qnr {} replacing incorrect qb_id {} with {} "
                            "for user {}".format(
                                qnr.id, recorded_qb.id, expected_qb.id,
                                patient.id))

                    else:
                        print(
                            "qnr {} PROBLEM: recorded qb_id {}, "
                            "expected {} doesn't match replacement {} "
                            "for user_id {}".format(
                                qnr.id, recorded_qb.id, expected_qb.id,
                                replacement, patient.id))

    for qnr_id, row in fix_map.items():
        qb_id, visit = row
        qnr = QuestionnaireResponse.query.get(qnr_id)
        comment = (
            "Migration correct qnr.id {} ({}) questionnaire_bank_id"
            " from {} to {}".format(
                qnr.id, visit, qnr.questionnaire_bank_id, qb_id))
        audit = Audit(
            user_id=admin, subject_id=qnr.subject_id,
            context='assessment', comment=comment)
        db.session.add(audit)
        qnr.questionnaire_bank_id = qb_id

        # clear out cached qb_timeline data for user as it
        # needs to be recalculated given the change
        invalidate_users_QBT(qnr.subject_id)

    db.session.commit()
def upgrade():
    # Tricky task to locate the errors.  One time expensive process,
    # loop through patients identifying problems.

    admin = admin_id()
    qb_map = qb_pairs_by_rp()
    if not qb_map:
        return  # nothing to do on systems w/o RP changes
    fix_map = dict()

    for patient in active_patients(include_test_role=True).order_by(User.id):
        qnrs = QuestionnaireResponse.query.filter(
            QuestionnaireResponse.subject_id == patient.id).order_by(
            QuestionnaireResponse.authored)
        if not qnrs.count():
            # Only care if the user submitted QNRs:
            continue

        for qnr in qnrs:

            # Obtain qb_timeline row at the time of QNR.authored
            as_of_date = qnr.authored
            qbt = QBT.query.filter(QBT.user_id == patient.id).filter(
                QBT.at <= as_of_date).order_by(
                QBT.at.desc(), QBT.id.desc()).first()

            if qnr.questionnaire_bank_id is None:
                print(
                    "qnr {} user_id {} authored {} {}"
                    " with NO qb_id set".format(
                        qnr.id, patient.id, as_of_date,
                        qnr.document['questionnaire']['reference']))
                continue

            if qbt and qbt.status != OverallStatus.withdrawn:
                recorded_qb = QuestionnaireBank.query.get(
                    qnr.questionnaire_bank_id)
                qbd = qbt.qbd()
                expected_qb = qbd.questionnaire_bank
                if recorded_qb.classification == 'indefinite':
                    # indefinite case is handled differently...
                    qb_status = QB_Status(patient, as_of_date)
                    expected_qb = QuestionnaireBank.query.get(
                        qb_status._current_indef.qb_id)

                if recorded_qb != expected_qb:
                    replacement = qb_map.get(recorded_qb.id)
                    if replacement == expected_qb.id:
                        # retain the change request, as altering it inline
                        # interrupts the iteration
                        patched_qbd = QBD(
                            relative_start=qbd.relative_start, iteration=qbd.iteration,
                            recur=qbd.recur, qb_id=replacement)
                        fix_map[qnr.id] = (expected_qb.id, visit_name(patched_qbd))
                        print(
                            "qnr {} replacing incorrect qb_id {} with {} "
                            "for user {}".format(
                                qnr.id, recorded_qb.id, expected_qb.id,
                                patient.id))

                    else:
                        print(
                            "qnr {} PROBLEM: recorded qb_id {}, "
                            "expected {} doesn't match replacement {} "
                            "for user_id {}".format(
                                qnr.id, recorded_qb.id, expected_qb.id,
                                replacement, patient.id))

    for qnr_id, row in fix_map.items():
        qb_id, visit = row
        qnr = QuestionnaireResponse.query.get(qnr_id)
        comment = (
            "Migration correct qnr.id {} ({}) questionnaire_bank_id"
            " from {} to {}".format(
                qnr.id, visit, qnr.questionnaire_bank_id, qb_id))
        audit = Audit(
            user_id=admin, subject_id=qnr.subject_id,
            context='assessment', comment=comment)
        db.session.add(audit)
        qnr.questionnaire_bank_id = qb_id

        # clear out cached qb_timeline data for user as it
        # needs to be recalculated given the change
        invalidate_users_QBT(qnr.subject_id)

    db.session.commit()