def test_lookup_for_user(self): crv, rp, rp_id = self.setup_org_n_rp(org_name='CRV') epic26 = self.add_questionnaire(name='epic26') eproms_add = self.add_questionnaire(name='eproms_add') comorb = self.add_questionnaire(name='comorb') crv, epic26, eproms_add, comorb = map( db.session.merge, (crv, epic26, eproms_add, comorb)) bank = QuestionnaireBank(name='CRV', research_protocol_id=rp_id, start='{"days": 7}', expired='{"days": 90}') for rank, q in enumerate((epic26, eproms_add, comorb)): qbq = QuestionnaireBankQuestionnaire(questionnaire_id=q.id, rank=rank) bank.questionnaires.append(qbq) self.test_user.organizations.append(crv) self.consent_with_org(org_id=crv.id) with SessionScope(db): db.session.add(bank) db.session.commit() # User associated with CRV org should generate appropriate # questionnaires self.test_user = db.session.merge(self.test_user) qb = QuestionnaireBank.most_current_qb( self.test_user, as_of_date=now).questionnaire_bank results = list(qb.questionnaires) self.assertEqual(3, len(results)) # confirm rank sticks self.assertEqual(results[0].name, 'epic26') self.assertEqual(results[2].name, 'comorb')
def test_lookup_with_intervention(self): intv = Intervention(name='TEST', description='Test Intervention') epic26 = self.add_questionnaire(name='epic26') eproms_add = self.add_questionnaire(name='eproms_add') with SessionScope(db): db.session.add(intv) db.session.commit() intv, epic26, eproms_add = map(db.session.merge, (intv, epic26, eproms_add)) bank = QuestionnaireBank(name='CRV', intervention_id=intv.id, start='{"days": 7}', expired='{"days": 90}') for rank, q in enumerate((epic26, eproms_add)): qbq = QuestionnaireBankQuestionnaire(questionnaire_id=q.id, rank=rank) bank.questionnaires.append(qbq) self.test_user.interventions.append(intv) self.login() self.add_required_clinical_data() with SessionScope(db): db.session.add(bank) db.session.commit() # User associated with INTV intervention should generate appropriate # questionnaires self.test_user = db.session.merge(self.test_user) qb = QuestionnaireBank.most_current_qb( self.test_user, as_of_date=now).questionnaire_bank results = list(qb.questionnaires) self.assertEqual(2, len(results))
def test_serialize(self): q1 = Questionnaire(name='q1') q2 = Questionnaire(name='q2') org = Organization(name='org') with SessionScope(db): db.session.add(q1) db.session.add(q2) db.session.add(org) db.session.commit() q1, q2, org = map(db.session.merge, (q1, q2, org)) qb = QuestionnaireBank(name='qb', organization_id=org.id, classification='baseline') for rank, q in enumerate((q1, q2)): qbq = QuestionnaireBankQuestionnaire(days_till_due=5, days_till_overdue=30, rank=rank, questionnaire=q) qb.questionnaires.append(qbq) with SessionScope(db): db.session.add(qb) db.session.commit() qb = db.session.merge(qb) data = qb.as_json() self.assertEquals('QuestionnaireBank', data.get('resourceType')) self.assertEquals(2, len(data['questionnaires']))
def test_questionnaire_banks_recurs(self): # set up a few recurring instances initial_recur = Recur(days_to_start=90, days_in_cycle=90, days_till_termination=720) every_six_thereafter = Recur(days_to_start=720, days_in_cycle=180) metastatic_org = Organization(name='metastatic') questionnaire = Questionnaire(name='test_q') with SessionScope(db): db.session.add(initial_recur) db.session.add(every_six_thereafter) db.session.add(metastatic_org) db.session.add(questionnaire) db.session.commit() initial_recur = db.session.merge(initial_recur) every_six_thereafter = db.session.merge(every_six_thereafter) metastatic_org_id = db.session.merge(metastatic_org).id # with bits in place, setup a recurring QB mr_qb = QuestionnaireBank(name='metastatic_recurring', classification='recurring', organization_id=metastatic_org_id) questionnaire = db.session.merge(questionnaire) recurs = [initial_recur, every_six_thereafter] qbq = QuestionnaireBankQuestionnaire(questionnaire=questionnaire, days_till_due=1, days_till_overdue=30, rank=1, recurs=recurs) mr_qb.questionnaires.append(qbq) # confirm persistence of this questionnaire bank includes the bits # added above results = mr_qb.as_json() copy = QuestionnaireBank.from_json(results) self.assertEquals(copy.name, mr_qb.name) copy_q = copy.questionnaires[0] self.assertEquals(copy_q.recurs, [initial_recur, every_six_thereafter]) # now, modify the persisted form, remove one recur and add another new_recur = Recur(days_to_start=900, days_in_cycle=180, days_till_termination=1800) results['questionnaires'][0]['recurs'] = [ initial_recur.as_json(), new_recur.as_json() ] updated_copy = QuestionnaireBank.from_json(results) self.assertEquals( [r.as_json() for r in updated_copy.questionnaires[0].recurs], [r.as_json() for r in (initial_recur, new_recur)])
def setup_intervention_qbs(self, intervention=None): if not intervention: intervention = Intervention(name='symptom tracker', description='test') with SessionScope(db): db.session.add(intervention) db.session.commit() eq5d = self.add_questionnaire(name='eq5d') epic26 = self.add_questionnaire(name='epic26') recur6 = Recur(start='{"months": 3, "weeks": -2}', cycle_length='{"months": 6}', termination='{"months": 27}') exists = Recur.query.filter_by(start=recur6.start, cycle_length=recur6.cycle_length, termination=recur6.termination).first() if exists: recur6 = exists with SessionScope(db): db.session.add(eq5d) db.session.add(epic26) db.session.add(recur6) db.session.commit() intervention, eq5d, epic26, recur6 = map( db.session.merge, (intervention, eq5d, epic26, recur6)) qb_base = QuestionnaireBank(name='Symptom Tracker Baseline', classification='baseline', intervention_id=intervention.id, start='{"days": 0}', expired='{"months": 3, "days": -14}') qbq = QuestionnaireBankQuestionnaire(questionnaire=epic26, rank=0) qbq2 = QuestionnaireBankQuestionnaire(questionnaire=eq5d, rank=1) qb_base.questionnaires.append(qbq) qb_base.questionnaires.append(qbq2) qb_r6 = QuestionnaireBank(name='Symptom Tracker Recurring', classification='recurring', intervention_id=intervention.id, start='{"days": 0}', expired='{"months": 3}', recurs=[recur6]) qbq = QuestionnaireBankQuestionnaire(questionnaire=epic26, rank=0) qbq2 = QuestionnaireBankQuestionnaire(questionnaire=eq5d, rank=1) qb_r6.questionnaires.append(qbq) qb_r6.questionnaires.append(qbq2) with SessionScope(db): db.session.add(qb_base) db.session.add(qb_r6) db.session.commit() return db.session.merge(intervention)
def test_qb_pre_retired(self): # Confirm backdating returns the correct QB weekago = now - timedelta(days=7) org, rpv3, rpv3_id = self.setup_org_n_rp(rp_name='v3') org, rpv2, rpv2_id = self.setup_org_n_rp(org=org, rp_name='v2', retired_as_of=weekago) qn3 = self.add_questionnaire(name='epic26-v3') qn2 = self.add_questionnaire(name='epic26-v2') qb3 = QuestionnaireBank(name='Test Questionnaire Bank v3', classification='baseline', research_protocol_id=rpv3_id, start='{"days": 0}', overdue='{"days": 7}', expired='{"days": 90}') qbq3 = QuestionnaireBankQuestionnaire(questionnaire=qn3, rank=0) qb3.questionnaires.append(qbq3) qb2 = QuestionnaireBank(name='Test Questionnaire Bank v2', classification='baseline', research_protocol_id=rpv2_id, start='{"days": 0}', overdue='{"days": 7}', expired='{"days": 90}') qbq2 = QuestionnaireBankQuestionnaire(questionnaire=qn2, rank=0) qb2.questionnaires.append(qbq2) self.test_user.organizations.append(org) audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID) uc = UserConsent(user_id=TEST_USER_ID, organization=org, audit=audit, agreement_url='http://no.com') with SessionScope(db): map(db.session.add, (qb2, qb3)) db.session.add(audit) db.session.add(uc) db.session.commit() user, org, qb2, qb3 = map(db.session.merge, (self.test_user, org, qb2, qb3)) # w/o backdating, should get current QB self.assertEqual( qb3, QuestionnaireBank.most_current_qb( user, as_of_date=now).questionnaire_bank) # backdate prior to retirement of previous, should get the previous QB pre_retirement = weekago - timedelta(days=1) self.assertEqual( qb2, QuestionnaireBank.most_current_qb( user, as_of_date=pre_retirement).questionnaire_bank)
def test_lookup_with_intervention(self): intv = Intervention(name='TEST', description='Test Intervention') epic26 = Questionnaire(name='epic26') eproms_add = Questionnaire(name='eproms_add') with SessionScope(db): db.session.add(intv) db.session.add(epic26) db.session.add(eproms_add) db.session.commit() intv, epic26, eproms_add = map(db.session.merge, (intv, epic26, eproms_add)) bank = QuestionnaireBank(name='CRV', intervention_id=intv.id) for rank, q in enumerate((epic26, eproms_add)): qbq = QuestionnaireBankQuestionnaire(questionnaire_id=q.id, days_till_due=7, days_till_overdue=90, rank=rank) bank.questionnaires.append(qbq) self.test_user.interventions.append(intv) with SessionScope(db): db.session.add(bank) db.session.commit() # User associated with INTV intervention should generate appropriate # questionnaires self.test_user = db.session.merge(self.test_user) qd = QuestionnaireDetails(self.test_user, datetime.utcnow()) results = list(qd.baseline()) self.assertEquals(2, len(results)) # confirm rank sticks self.assertEquals(results[0]['name'], 'epic26') self.assertEquals(results[1]['name'], 'eproms_add')
def test_org_trigger_date(self): # testing org-based QBs org, rp, rp_id = self.setup_org_n_rp() q = self.add_questionnaire(name='q') q, org, self.test_user = map(db.session.merge, (q, org, self.test_user)) qb = QuestionnaireBank(name='qb', research_protocol_id=rp_id, classification='baseline', start='{"days": 1}', expired='{"days": 2}') qbq = QuestionnaireBankQuestionnaire(rank=0, questionnaire=q) qb.questionnaires.append(qbq) # user without consents or TX date should return None assert not trigger_date(self.test_user) # user with consent should return consent date self.consent_with_org(org.id, setdate=now) self.test_user = db.session.merge(self.test_user) assert trigger_date(self.test_user) == now assert trigger_date(self.test_user, qb) == now # user with consent and TX date should return TX date (if qb.recurs) tx_date = datetime(2017, 6, 10, 20, 00, 00, 000000) self.add_procedure(code='7', display='Focal therapy', system=ICHOM, setdate=tx_date) self.test_user = db.session.merge(self.test_user) recur = Recur(start='{"months": 3}', cycle_length='{"months": 6}', termination='{"months": 24}') qb.recurs.append(recur) assert trigger_date(self.test_user, qb) == tx_date
def test_lookup_with_intervention(self): intv = Intervention(name='TEST', description='Test Intervention') epic26 = self.add_questionnaire(name='epic26') eproms_add = self.add_questionnaire(name='eproms_add') with SessionScope(db): db.session.add(intv) db.session.commit() intv, epic26, eproms_add = map(db.session.merge, (intv, epic26, eproms_add)) bank = QuestionnaireBank(name='CRV', intervention_id=intv.id, start='{"days": 7}', expired='{"days": 90}') for rank, q in enumerate((epic26, eproms_add)): qbq = QuestionnaireBankQuestionnaire(questionnaire_id=q.id, rank=rank) bank.questionnaires.append(qbq) self.test_user.interventions.append(intv) self.login() self.add_required_clinical_data() with SessionScope(db): db.session.add(bank) db.session.commit() # Patient associated with INTV intervention should generate appropriate # questionnaires as of start date self.promote_user(role_name=ROLE.PATIENT.value) self.test_user = db.session.merge(self.test_user) qb_status = QB_Status(self.test_user, as_of_date=now + relativedelta(days=8)) qb = qb_status.current_qbd().questionnaire_bank results = list(qb.questionnaires) assert len(results) == 2
def setup_qb(self, questionnaire_name, qb_name, classification, rp_id, expired=None): """Shortcut to setup a testing QB with given values Sets up a single qb with a single questionnaire for given classification and research_protocol """ if expired is None: expired = '{"days": 90}' qn = self.add_questionnaire(questionnaire_name) qb = QuestionnaireBank(name=qb_name, classification=classification, research_protocol_id=rp_id, start='{"days": 0}', expired=expired) qbq = QuestionnaireBankQuestionnaire(questionnaire=qn, rank=0) qb.questionnaires.append(qbq) with SessionScope(db): db.session.add(qb) db.session.commit() return db.session.merge(qb)
def test_import(self): org, rp, rp_id = self.setup_org_n_rp() rp_name = rp.name q1 = self.add_questionnaire(name='q1') q2 = self.add_questionnaire(name='q2') org, q1, q2 = map(db.session.merge, (org, q1, q2)) data = { 'resourceType': 'QuestionnaireBank', 'research_protocol': {'reference': ('api/research_protocol/' '{}').format(rp_name)}, 'start': '{"days": 0}', 'overdue': '{"weeks": 1}', 'expired': '{"days": 30}', 'questionnaires': [ { 'rank': 2, 'questionnaire': { 'reference': 'api/questionnaire/{}?system={}'.format( q1.name, TRUENTH_QUESTIONNAIRE_CODE_SYSTEM)} }, { 'rank': 1, 'questionnaire': { 'reference': 'api/questionnaire/{}?system={}'.format( q2.name, TRUENTH_QUESTIONNAIRE_CODE_SYSTEM)} } ], 'id': 1, 'name': 'bank', 'classification': 'baseline' } qb = QuestionnaireBank.from_json(data) assert len(qb.questionnaires) == 2 assert qb.research_protocol_id == rp_id
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_overdue_stats(self): self.promote_user(user=self.test_user, role_name=ROLE.PATIENT.value) rp = ResearchProtocol(name='proto') with SessionScope(db): db.session.add(rp) db.session.commit() rp = db.session.merge(rp) rp_id = rp.id crv = Organization(name='CRV') crv.research_protocols.append(rp) epic26 = self.add_questionnaire(name='epic26') with SessionScope(db): db.session.add(crv) db.session.commit() crv, epic26 = map(db.session.merge, (crv, epic26)) crv_id = crv.id bank = QuestionnaireBank(name='CRV', research_protocol_id=rp_id, start='{"days": 1}', overdue='{"days": 2}', expired='{"days": 90}') qbq = QuestionnaireBankQuestionnaire(questionnaire_id=epic26.id, rank=0) bank.questionnaires.append(qbq) with SessionScope(db): db.session.add(bank) db.session.commit() self.test_user = db.session.merge(self.test_user) self.test_user.organizations.append(crv) self.consent_with_org(org_id=crv_id) self.test_user = db.session.merge(self.test_user) # test user with status = 'Expired' (should not show up) a_s = QB_Status(self.test_user, as_of_date=datetime.utcnow()) assert a_s.overall_status == OverallStatus.expired ostats = self.get_ostats() assert len(ostats) == 0 # test user with status = 'Overdue' (should show up) self.consent_with_org(org_id=crv_id, backdate=relativedelta(days=18)) with SessionScope(db): db.session.add(bank) db.session.commit() crv, self.test_user = map(db.session.merge, (crv, self.test_user)) invalidate_users_QBT(self.test_user.id) a_s = QB_Status(self.test_user, as_of_date=datetime.utcnow()) assert a_s.overall_status == OverallStatus.overdue ostats = self.get_ostats() assert len(ostats) == 1 assert ostats[(crv.id, crv.name)] == [(15, TEST_USER_ID)]
def test_submit_assessment_for_qb(self): swagger_spec = swagger(self.app) data = swagger_spec['definitions']['QuestionnaireResponse']['example'] rp = ResearchProtocol(name='proto') with SessionScope(db): db.session.add(rp) db.session.commit() rp = db.session.merge(rp) rp_id = rp.id qn = self.add_questionnaire(name='epic26') org = Organization(name="testorg") org.research_protocols.append(rp) with SessionScope(db): db.session.add(qn) db.session.add(org) db.session.commit() qn, org = map(db.session.merge, (qn, org)) qb = QuestionnaireBank(name='Test Questionnaire Bank', classification='baseline', research_protocol_id=rp_id, start='{"days": 0}', overdue='{"days": 7}', expired='{"days": 90}') qbq = QuestionnaireBankQuestionnaire(questionnaire=qn, rank=0) qb.questionnaires.append(qbq) test_user = get_user(TEST_USER_ID) test_user.organizations.append(org) audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID) uc = UserConsent(user_id=TEST_USER_ID, organization=org, audit=audit, agreement_url='http://no.com') with SessionScope(db): db.session.add(qb) db.session.add(test_user) db.session.add(audit) db.session.add(uc) db.session.commit() qb = db.session.merge(qb) self.login() response = self.client.post( '/api/patient/{}/assessment'.format(TEST_USER_ID), content_type='application/json', data=json.dumps(data), ) assert response.status_code == 200 test_user = get_user(TEST_USER_ID) assert test_user.questionnaire_responses.count() == 1 assert test_user.questionnaire_responses[0].questionnaire_bank_id ==\ qb.id
def test_start(self): org, rp, rp_id = self.setup_org_n_rp() q = self.add_questionnaire('q') q, org = map(db.session.merge, (q, org)) qb = QuestionnaireBank( name='qb', research_protocol_id=rp_id, classification='baseline', start='{"days": 1}', expired='{"days": 2}') qbq = QuestionnaireBankQuestionnaire(rank=0, questionnaire=q) qb.questionnaires.append(qbq) trigger_date = datetime.strptime('2000-01-01', '%Y-%m-%d') start = qb.calculated_start(trigger_date).relative_start assert start > trigger_date assert start == datetime.strptime('2000-01-02', '%Y-%m-%d') end = qb.calculated_expiry(start) expected_expiry = datetime.strptime('2000-01-04', '%Y-%m-%d') assert end == expected_expiry
def mock_tnth_questionnairebanks(): for name in (symptom_tracker_instruments): TestCase.add_questionnaire(name=name) # Symptom Tracker Baseline self_management = INTERVENTION.SELF_MANAGEMENT st_qb = QuestionnaireBank( name='symptom_tracker', classification='baseline', intervention_id=self_management.id, start='{"days": 0}', expired='{"months": 3}' ) for rank, instrument in enumerate(symptom_tracker_instruments): q = Questionnaire.find_by_name(name=instrument) qbq = QuestionnaireBankQuestionnaire(questionnaire=q, rank=rank) st_qb.questionnaires.append(qbq) # Symptom Tracker Recurrence st_recur = Recur( start='{"months": 3}', cycle_length='{"months": 3}', termination='{"months": 27}') with SessionScope(db): db.session.add(st_qb) db.session.add(st_recur) db.session.commit() self_management = INTERVENTION.SELF_MANAGEMENT st_recur_qb = QuestionnaireBank( name='symptom_tracker_recurring', classification='recurring', intervention_id=self_management.id, start='{"days": 0}', expired='{"months": 3}', recurs=[st_recur] ) for rank, instrument in enumerate(symptom_tracker_instruments): q = Questionnaire.find_by_name(name=instrument) qbq = QuestionnaireBankQuestionnaire(questionnaire=q, rank=rank) st_recur_qb.questionnaires.append(qbq) with SessionScope(db): db.session.add(st_recur_qb) db.session.commit()
def test_completed_older_rp(self): """If current qb completed on older rp, should show as done""" fourmonthsago = now - timedelta(days=120) weekago = now - timedelta(weeks=1) twoweeksago = now - timedelta(weeks=2) org = self.setup_qbs(rp_name='v2', retired_as_of=weekago) org_id = org.id self.setup_qbs(org=org, rp_name='v3') self.test_user.organizations.append(org) audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID) uc = UserConsent(user_id=TEST_USER_ID, organization_id=org_id, audit=audit, agreement_url='http://no.com', acceptance_date=fourmonthsago) with SessionScope(db): db.session.add(audit) db.session.add(uc) db.session.commit() # Two weeks ago, still on rp v2, should be in 3mo recurrence user = db.session.merge(self.test_user) a_s = AssessmentStatus(user=user, as_of_date=twoweeksago) v2qb = a_s.qb_data.qbd.questionnaire_bank self.assertEqual('CRV_recurring_3mo_period v2', a_s.qb_data.qbd.questionnaire_bank.name) self.assertEqual('CRV_recurring_3mo_period v2', a_s.qb_name) self.assertEqual(['epic26_v2'], a_s.instruments_needing_full_assessment()) # Now, should still be rp v3, 3mo recurrence a_s = AssessmentStatus(user=user, as_of_date=now) self.assertEqual('CRV_recurring_3mo_period v3', a_s.qb_data.qbd.questionnaire_bank.name) self.assertEqual(['epic26_v3'], a_s.instruments_needing_full_assessment()) # Complete the questionnaire from the 3mo v2 QB mock_qr('epic26_v2', timestamp=twoweeksago, qb=v2qb, iteration=0) # Two weeks ago, should be completed user = db.session.merge(user) a_s = AssessmentStatus(user=user, as_of_date=twoweeksago) self.assertEqual('Completed', a_s.overall_status) # Current should also be completed, even tho protocol changed a_s = AssessmentStatus(user=user, as_of_date=now) self.assertEqual('Completed', a_s.overall_status) # Should see both as candidates qbds = QuestionnaireBank.qbs_for_user(user, classification='recurring', as_of_date=now) self.assertEqual(len(qbds), 2)
def test_start(self): org, rp, rp_id = self.setup_org_n_rp() q = self.add_questionnaire('q') q, org = map(db.session.merge, (q, org)) qb = QuestionnaireBank(name='qb', research_protocol_id=rp_id, classification='baseline', start='{"days": 1}', expired='{"days": 2}') qbq = QuestionnaireBankQuestionnaire(rank=0, questionnaire=q) qb.questionnaires.append(qbq) trigger_date = datetime.strptime('2000-01-01', '%Y-%m-%d') start = qb.calculated_start(trigger_date).relative_start assert start > trigger_date assert start == datetime.strptime('2000-01-02', '%Y-%m-%d') end = qb.calculated_expiry(start) expected_expiry = datetime.strptime('2000-01-04', '%Y-%m-%d') assert end == expected_expiry
def test_visit_9mo(self): crv = self.setup_qbs() backdate, nowish = associative_backdate( now=now, backdate=relativedelta(months=9)) 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 9", visit_name(qbd))
def test_serialize(self): org, rp, rp_id = self.setup_org_n_rp() q1 = self.add_questionnaire(name='q1') q2 = self.add_questionnaire(name='q2') q1, q2, org = map(db.session.merge, (q1, q2, org)) qb = QuestionnaireBank( name='qb', research_protocol_id=rp_id, classification='baseline', start='{"days": 0}', overdue='{"days": 5}', expired='{"days": 30}') for rank, q in enumerate((q1, q2)): qbq = QuestionnaireBankQuestionnaire( rank=rank, questionnaire=q) qb.questionnaires.append(qbq) with SessionScope(db): db.session.add(qb) db.session.commit() qb = db.session.merge(qb) data = qb.as_json() assert 'QuestionnaireBank' == data.get('resourceType') assert len(data['questionnaires']) == 2
def test_serialize(self): org, rp, rp_id = self.setup_org_n_rp() q1 = self.add_questionnaire(name='q1') q2 = self.add_questionnaire(name='q2') q1, q2, org = map(db.session.merge, (q1, q2, org)) qb = QuestionnaireBank(name='qb', research_protocol_id=rp_id, classification='baseline', start='{"days": 0}', overdue='{"days": 5}', expired='{"days": 30}') for rank, q in enumerate((q1, q2)): qbq = QuestionnaireBankQuestionnaire(rank=rank, questionnaire=q) qb.questionnaires.append(qbq) with SessionScope(db): db.session.add(qb) db.session.commit() qb = db.session.merge(qb) data = qb.as_json() assert 'QuestionnaireBank' == data.get('resourceType') assert len(data['questionnaires']) == 2
def test_due(self): org, rp, rp_id = self.setup_org_n_rp() q = self.add_questionnaire('q') q, org = map(db.session.merge, (q, org)) qb = QuestionnaireBank(name='qb', research_protocol_id=rp_id, classification='baseline', start='{"days": 1}', due='{"days": 2}') qbq = QuestionnaireBankQuestionnaire(rank=0, questionnaire=q) qb.questionnaires.append(qbq) trigger_date = datetime.strptime('2000-01-01', '%Y-%m-%d') now = datetime.now() start = qb.calculated_start(trigger_date, as_of_date=now).relative_start self.assertTrue(start > trigger_date) self.assertEqual(start, datetime.strptime('2000-01-02', '%Y-%m-%d')) due = qb.calculated_due(trigger_date, as_of_date=now) expected_due = datetime.strptime('2000-01-04', '%Y-%m-%d') self.assertEqual(due, expected_due)
def test_overdue_stats(self): self.promote_user(user=self.test_user, role_name=ROLE.PATIENT.value) rp = ResearchProtocol(name='proto') with SessionScope(db): db.session.add(rp) db.session.commit() rp = db.session.merge(rp) rp_id = rp.id crv = Organization(name='CRV') crv.research_protocols.append(rp) epic26 = self.add_questionnaire(name='epic26') with SessionScope(db): db.session.add(crv) db.session.commit() crv, epic26 = map(db.session.merge, (crv, epic26)) bank = QuestionnaireBank(name='CRV', research_protocol_id=rp_id, start='{"days": 1}', overdue='{"days": 2}', expired='{"days": 90}') qbq = QuestionnaireBankQuestionnaire(questionnaire_id=epic26.id, rank=0) bank.questionnaires.append(qbq) self.test_user = db.session.merge(self.test_user) # test user with status = 'Expired' (should not show up) a_s = AssessmentStatus(self.test_user, as_of_date=datetime.utcnow()) self.assertEqual(a_s.overall_status, 'Expired') ostats = self.get_ostats() self.assertEqual(len(ostats), 0) # test user with status = 'Overdue' (should show up) self.test_user.organizations.append(crv) self.consent_with_org(org_id=crv.id, backdate=relativedelta(days=18)) with SessionScope(db): db.session.add(bank) db.session.commit() crv, self.test_user = map(db.session.merge, (crv, self.test_user)) a_s = AssessmentStatus(self.test_user, as_of_date=datetime.utcnow()) self.assertEqual(a_s.overall_status, 'Overdue') ostats = self.get_ostats() self.assertEqual(len(ostats), 1) self.assertEqual(ostats[crv], [15])
def test_no_start_date(self): # W/O a biopsy (i.e. event start date), no questionnaries self.promote_user(role_name=ROLE.PATIENT.value) # toggle default setup - set biopsy false for test user self.login() self.test_user = db.session.merge(self.test_user) self.test_user.save_observation(codeable_concept=CC.BIOPSY, value_quantity=CC.FALSE_VALUE, audit=Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID), status='final', issued=None) assert not QuestionnaireBank.qbs_for_user( self.test_user, 'baseline', as_of_date=now)
def test_intervention_in_progress(self): # testing intervention-based QBs q = self.add_questionnaire('q') interv = Intervention(name='interv', description='test') with SessionScope(db): db.session.add(interv) db.session.commit() q, interv, self.test_user = map(db.session.merge, (q, interv, self.test_user)) qb = QuestionnaireBank(name='qb', intervention_id=interv.id, classification='baseline', start='{"days": 0}', expired='{"days": 2}') qbq = QuestionnaireBankQuestionnaire(rank=0, questionnaire=q) qb.questionnaires.append(qbq) # user with biopsy should return biopsy date self.login() self.test_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) self.test_user = db.session.merge(self.test_user) obs = self.test_user.observations.first() self.assertEqual(obs.codeable_concept.codings[0].display, 'biopsy') self.assertEqual(qb.trigger_date(self.test_user), obs.issued) # add mock in-process QB - confirm most_current_qb still returns one mock_qr('q', 'in-progress', qb=qb) self.test_user, qb = map(db.session.merge, (self.test_user, qb)) self.assertEqual( qb.most_current_qb(self.test_user, as_of_date=now).questionnaire_bank, qb)
def mock_qr(instrument_id, status='completed', timestamp=None, qb=None, doc_id=None, iteration=None): if not doc_id: doc_id = ''.join(choice(ascii_letters) for _ in range(10)) timestamp = timestamp or datetime.utcnow() qr_document = { "questionnaire": { "display": "Additional questions", "reference": "https://{}/api/questionnaires/{}".format('SERVER_NAME', instrument_id) }, "identifier": { "use": "official", "label": "cPRO survey session ID", "value": doc_id, "system": "https://stg-ae.us.truenth.org/eproms-demo" } } enc = Encounter(status='planned', auth_method='url_authenticated', user_id=TEST_USER_ID, start_time=timestamp) with SessionScope(db): db.session.add(enc) db.session.commit() enc = db.session.merge(enc) qb = qb or QuestionnaireBank.most_current_qb(get_user(TEST_USER_ID), timestamp).questionnaire_bank qr = QuestionnaireResponse(subject_id=TEST_USER_ID, status=status, authored=timestamp, document=qr_document, encounter_id=enc.id, questionnaire_bank=qb, qb_iteration=iteration) with SessionScope(db): db.session.add(qr) db.session.commit() invalidate_assessment_status_cache(TEST_USER_ID)
def test_import(self): org, rp, rp_id = self.setup_org_n_rp() rp_name = rp.name q1 = self.add_questionnaire(name='q1') q2 = self.add_questionnaire(name='q2') org, q1, q2 = map(db.session.merge, (org, q1, q2)) data = { 'resourceType': 'QuestionnaireBank', 'research_protocol': { 'reference': ('api/research_protocol/' '{}').format(rp_name) }, 'start': '{"days": 0}', 'overdue': '{"weeks": 1}', 'expired': '{"days": 30}', 'questionnaires': [{ 'rank': 2, 'questionnaire': { 'reference': 'api/questionnaire/{}?system={}'.format( q1.name, TRUENTH_QUESTIONNAIRE_CODE_SYSTEM) } }, { 'rank': 1, 'questionnaire': { 'reference': 'api/questionnaire/{}?system={}'.format( q2.name, TRUENTH_QUESTIONNAIRE_CODE_SYSTEM) } }], 'id': 1, 'name': 'bank', 'classification': 'baseline' } qb = QuestionnaireBank.from_json(data) assert len(qb.questionnaires) == 2 assert qb.research_protocol_id == rp_id
def test_early(self): # Prior to days passing, no message should be generated mock_communication_request('symptom_tracker', '{"days": 90}') self.promote_user(role_name=ROLE.PATIENT.value) self.login() self.add_required_clinical_data(backdate=relativedelta(days=89)) self.test_user = db.session.merge(self.test_user) # Confirm test user qualifies for ST QB assert QuestionnaireBank.qbs_for_user(self.test_user, 'baseline', as_of_date=datetime.utcnow()) # Being a day short, shouldn't fire update_patient_loop(update_cache=False, queue_messages=True) expected = Communication.query.first() assert not expected
def test_import_followup(self): intervention = Intervention(name='testy', description='simple') q1 = self.add_questionnaire(name='q1') q2 = self.add_questionnaire(name='q2') with SessionScope(db): db.session.add(intervention) db.session.commit() intervention, q1, q2 = map(db.session.merge, (intervention, q1, q2)) data = { 'resourceType': 'QuestionnaireBank', 'intervention': { 'reference': 'api/intervention/{}'.format(intervention.name) }, 'expired': '{"days": 104}', 'start': '{"days": 76}', 'questionnaires': [{ 'rank': 2, 'questionnaire': { 'reference': 'api/questionnaire/{}?system={}'.format( q1.name, TRUENTH_QUESTIONNAIRE_CODE_SYSTEM) } }, { 'rank': 1, 'questionnaire': { 'reference': 'api/questionnaire/{}?system={}'.format( q2.name, TRUENTH_QUESTIONNAIRE_CODE_SYSTEM) } }], 'id': 1, 'name': u'bank', 'classification': 'followup' } qb = QuestionnaireBank.from_json(data) self.assertEqual(2, len(qb.questionnaires))
def test_import(self): org = Organization(name='org') q1 = Questionnaire(name='q1') q2 = Questionnaire(name='q2') with SessionScope(db): db.session.add(org) db.session.add(q1) db.session.add(q2) db.session.commit() org, q1, q2 = map(db.session.merge, (org, q1, q2)) q2_id = q2.id data = { 'resourceType': 'QuestionnaireBank', 'organization': { 'reference': 'api/organization/{}'.format(org.id) }, 'questionnaires': [{ 'days_till_overdue': 30, 'days_till_due': 5, 'rank': 2, 'questionnaire': { 'reference': 'api/questionnaire/{}'.format(q1.name) } }, { 'days_till_overdue': 30, 'days_till_due': 5, 'rank': 1, 'questionnaire': { 'reference': 'api/questionnaire/{}'.format(q2.name) } }], 'id': 1, 'name': u'bank', 'classification': 'baseline' } qb = QuestionnaireBank.from_json(data) self.assertEquals(2, len(qb.questionnaires))
def test_intervention_trigger_date(self): # testing intervention-based QBs q = self.add_questionnaire('q') interv = Intervention(name='interv', description='test') with SessionScope(db): db.session.add(interv) db.session.commit() q, interv, self.test_user = map(db.session.merge, (q, interv, self.test_user)) qb = QuestionnaireBank(name='qb', intervention_id=interv.id, classification='baseline', start='{"days": 1}', expired='{"days": 2}') qbq = QuestionnaireBankQuestionnaire(rank=0, questionnaire=q) qb.questionnaires.append(qbq) # user without biopsy or TX date should return None assert not trigger_date(self.test_user) # user with biopsy should return biopsy date self.login() self.test_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) self.test_user = db.session.merge(self.test_user) obs = self.test_user.observations.first() assert obs.codeable_concept.codings[0].display == 'biopsy' assert trigger_date(self.test_user) == obs.issued # user with biopsy and TX date should return TX date tx_date = datetime.utcnow() self.add_procedure(code='7', display='Focal therapy', system=ICHOM, setdate=tx_date) self.test_user = db.session.merge(self.test_user) assert trigger_date(self.test_user) == tx_date
def test_questionnaire_gets(self): crv, rp, rp_id = self.setup_org_n_rp(org_name='CRV') epic26 = self.add_questionnaire(name='epic26') eproms_add = self.add_questionnaire(name='eproms_add') comorb = self.add_questionnaire(name='comorb') crv, epic26, eproms_add, comorb = map( db.session.merge, (crv, epic26, eproms_add, comorb)) resp = self.client.get('/api/questionnaire') assert resp.status_code == 200 assert len(resp.json['entry']) == 3 assert all(('resource' in entry for entry in resp.json['entry'])) resp = self.client.get('/api/questionnaire/{}?system={}'.format( 'epic26', TRUENTH_QUESTIONNAIRE_CODE_SYSTEM)) assert resp.status_code == 200 q_ids = [ ident for ident in resp.json['identifier'] if ident['system'] == TRUENTH_QUESTIONNAIRE_CODE_SYSTEM ] assert len(q_ids) == 1 assert q_ids[0]['value'] == 'epic26' bank = QuestionnaireBank(name='CRV', research_protocol_id=rp_id, start='{"days": 7}', expired='{"days": 90}') for rank, q in enumerate((epic26, eproms_add, comorb)): qbq = QuestionnaireBankQuestionnaire(questionnaire_id=q.id, rank=rank) bank.questionnaires.append(qbq) self.test_user = db.session.merge(self.test_user) self.test_user.organizations.append(crv) with SessionScope(db): db.session.add(bank) db.session.commit() resp = self.client.get('/api/questionnaire_bank') assert resp.status_code == 200 assert len(resp.json['entry'][0]['resource']['questionnaires']) == 3
def test_lookup_for_user(self): crv, rp, rp_id = self.setup_org_n_rp(org_name='CRV') epic26 = self.add_questionnaire(name='epic26') eproms_add = self.add_questionnaire(name='eproms_add') comorb = self.add_questionnaire(name='comorb') crv, epic26, eproms_add, comorb = map( db.session.merge, (crv, epic26, eproms_add, comorb)) bank = QuestionnaireBank(name='CRV', research_protocol_id=rp_id, start='{"days": 7}', expired='{"days": 90}') for rank, q in enumerate((epic26, eproms_add, comorb)): qbq = QuestionnaireBankQuestionnaire(questionnaire_id=q.id, rank=rank) bank.questionnaires.append(qbq) self.test_user = db.session.merge(self.test_user) self.test_user.organizations.append(crv) self.consent_with_org(org_id=crv.id, setdate=now) self.promote_user(role_name=ROLE.PATIENT.value) with SessionScope(db): db.session.add(bank) db.session.commit() # User associated with CRV org should generate appropriate # questionnaires self.test_user = db.session.merge(self.test_user) # Doesn't start for 7 days, initially shouldn't get any qb_stat = QB_Status(user=self.test_user, as_of_date=now) assert qb_stat.current_qbd() is None qb_stat = QB_Status(user=self.test_user, as_of_date=now + relativedelta(days=7)) qb = qb_stat.current_qbd().questionnaire_bank results = list(qb.questionnaires) assert len(results) == 3 # confirm rank sticks assert results[0].name == 'epic26' assert results[2].name == 'comorb'
def upgrade(): bind = op.get_bind() session = Session(bind=bind) for qnr in QuestionnaireResponse.query.all(): if ("questionnaire" in qnr.document) and qnr.subject: qn_ref = qnr.document.get("questionnaire").get("reference") qn_name = qn_ref.split("/")[-1] if qn_ref else None qn = Questionnaire.query.filter_by(name=qn_name).first() qbd = QuestionnaireBank.most_current_qb( qnr.subject, as_of_date=qnr.authored) qb = qbd.questionnaire_bank ic = qbd.iteration if qb and qn and (qn.id in [qbq.questionnaire.id for qbq in qb.questionnaires]): ic = ic or 'NULL' session.execute( 'UPDATE questionnaire_responses SET ' 'questionnaire_bank_id = {}, qb_iteration = {} WHERE ' 'id = {}'.format(qb.id, ic, qnr.id))
def test_questionnaire_banks_recurs(self): # only one recurrence per qb allowed at this time initial_recur = Recur( start='{"days": 90}', cycle_length='{"days": 90}', termination='{"days": 720}') every_six_thereafter = Recur( start='{"days": 720}', cycle_length='{"days": 180}') rp = ResearchProtocol(name='proto') with SessionScope(db): db.session.add(rp) db.session.commit() rp = db.session.merge(rp) rp_id = rp.id metastatic_org = Organization(name='metastatic') metastatic_org.research_protocols.append(rp) questionnaire = self.add_questionnaire(name='test_q') with SessionScope(db): db.session.add(initial_recur) db.session.add(every_six_thereafter) db.session.add(metastatic_org) db.session.add(questionnaire) db.session.commit() initial_recur = db.session.merge(initial_recur) every_six_thereafter = db.session.merge(every_six_thereafter) # with bits in place, setup a recurring QB recurs = [initial_recur, every_six_thereafter] mr_qb = QuestionnaireBank( name='metastatic_recurring', classification='recurring', research_protocol_id=rp_id, start='{"days": 0}', overdue='{"days": 1}', expired='{"days": 30}', recurs=recurs) questionnaire = db.session.merge(questionnaire) qbq = QuestionnaireBankQuestionnaire( questionnaire=questionnaire, rank=1) mr_qb.questionnaires.append(qbq) with SessionScope(db): db.session.add(mr_qb) db.session.commit() mr_qb, initial_recur, every_six_thereafter = map( db.session.merge, (mr_qb, initial_recur, every_six_thereafter)) # confirm persistence of this questionnaire bank includes the bits # added above results = mr_qb.as_json() copy = QuestionnaireBank.from_json(results) assert copy.name == mr_qb.name assert copy.recurs == [initial_recur, every_six_thereafter] # now, modify the persisted form, remove one recur and add another new_recur = Recur( start='{"days": 900}', cycle_length='{"days": 180}', termination='{"days": 1800}') results['recurs'] = [ initial_recur.as_json(), new_recur.as_json()] updated_copy = QuestionnaireBank.from_json(results) assert ([r.as_json() for r in updated_copy.recurs] == [r.as_json() for r in (initial_recur, new_recur)])