def test_amending_biobank_order_distinct_visit_count(self):
    self.participant = self._insert(Participant(participantId=9, biobankId=13))
    with clock.FakeClock(TIME_5):
      order = self.order_dao.insert(self._make_biobank_order(biobankOrderId='2', identifiers=[
        BiobankOrderIdentifier(system='b', value='d')], samples=[BiobankOrderedSample(
                                                        biobankOrderId='2',
                                                        finalized=TIME_5,
                                                        test=BIOBANK_TESTS[0],
                                                        description='description',
                                                        processingRequired=True)]))

      summary = self.dao.get(self.participant.participantId)
      self.assertEquals(summary.numberDistinctVisits, 1)

    with clock.FakeClock(TIME_7):
      amend_order = self._get_amended_info(order)
      with self.order_dao.session() as session:
        self.order_dao._do_update(session, amend_order, order)

      # Shouldn't change on a simple amendment (unless finalized time on samples change)
      summary = self.dao.get(self.participant.participantId)
      self.assertEquals(summary.numberDistinctVisits, 1)

    with clock.FakeClock(TIME_7_5):
      cancel_request = cancel_biobank_order()
      order = self.order_dao.update_with_patch(order.biobankOrderId, cancel_request, order.version)

    # A cancelled order (even after amending) should reduce count (unless some other valid order on same day)
    summary = self.dao.get(self.participant.participantId)
    self.assertEquals(summary.numberDistinctVisits, 0)
  def test_cancelled_order_removes_from_participant_summary(self):
    ParticipantSummaryDao().insert(self.participant_summary(self.participant))
    samples = [BiobankOrderedSample(
      test=self._B_TEST, processingRequired=True, description=u'new sample')]
    biobank_order_id = 2
    with clock.FakeClock(self.TIME_1):
      order_1 = self.dao.insert(self._make_biobank_order())

    with clock.FakeClock(self.TIME_2):
      self.dao.insert(self._make_biobank_order(samples=samples,
                                               biobankOrderId=biobank_order_id,
                                               identifiers=[
                                                           BiobankOrderIdentifier(system='z',
                                                                                  value='x')]))
    cancelled_request = self._get_cancel_patch()
    ps_dao = ParticipantSummaryDao().get(self.participant.participantId)

    self.assertEqual(ps_dao.sampleOrderStatus1ED10, OrderStatus.FINALIZED)
    self.assertEqual(ps_dao.sampleOrderStatus1ED10Time, self.TIME_2)
    self.assertEqual(ps_dao.sampleOrderStatus2ED10, OrderStatus.CREATED)
    self.assertEqual(ps_dao.sampleOrderStatus2ED10Time, self.TIME_2)

    self.dao.update_with_patch(order_1.biobankOrderId, cancelled_request,
                               order_1.version)
    ps_dao = ParticipantSummaryDao().get(self.participant.participantId)

    self.assertEqual(ps_dao.sampleOrderStatus1ED10, None)
    self.assertEqual(ps_dao.sampleOrderStatus1ED10Time, None)
    # should not remove the other order
    self.assertEqual(ps_dao.sampleOrderStatus2ED10, OrderStatus.CREATED)
    self.assertEqual(ps_dao.sampleOrderStatus2ED10Time, self.TIME_2)
    self.assertEqual(ps_dao.biospecimenCollectedSiteId, 1)
    self.assertEqual(ps_dao.biospecimenFinalizedSiteId, 2)
    self.assertEqual(ps_dao.biospecimenProcessedSiteId, 1)
    self.assertEqual(ps_dao.biospecimenStatus, OrderStatus.FINALIZED)
  def test_pm_restore_cancel_biobank_restore_cancel(self):
    self.participant = self._insert(Participant(participantId=9, biobankId=13))
    self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId,
                                                             TIME_4.isoformat()))
    measurement = self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=669,
                                                                 finalized=TIME_4))
    summary = self.dao.get(self.participant.participantId)
    self.assertEquals(summary.numberDistinctVisits, 1)

    with clock.FakeClock(TIME_5):
      order = self.order_dao.insert(self._make_biobank_order(biobankOrderId='2', identifiers=[
        BiobankOrderIdentifier(system='b', value='d')], samples=[BiobankOrderedSample(
                                                        biobankOrderId='2',
                                                        finalized=TIME_5,
                                                        test=BIOBANK_TESTS[0],
                                                        description='description',
                                                        processingRequired=True)]))


    with clock.FakeClock(TIME_7):
      summary = self.dao.get(self.participant.participantId)
      # distinct count should be 2
      self.assertEquals(summary.numberDistinctVisits, 2)

      # cancel the measurement
      cancel_measurement = get_restore_or_cancel_info()
      with self.measurement_dao.session() as session:
        self.measurement_dao.update_with_patch(measurement.physicalMeasurementsId, session,
                                               cancel_measurement)

      summary = self.dao.get(self.participant.participantId)
      self.assertEquals(summary.numberDistinctVisits, 1)

    with clock.FakeClock(TIME_7):
      restore_measurement = get_restore_or_cancel_info(status='restored')
      with self.measurement_dao.session() as session:
        self.measurement_dao.update_with_patch(measurement.physicalMeasurementsId, session,
                                               restore_measurement)

      summary = self.dao.get(self.participant.participantId)
      self.assertEquals(summary.numberDistinctVisits, 2)


      cancel_request = cancel_biobank_order()
      order = self.order_dao.update_with_patch(order.biobankOrderId, cancel_request, order.version)

      summary = self.dao.get(self.participant.participantId)
      self.assertEquals(summary.numberDistinctVisits, 1)

      restore_order = get_restore_or_cancel_info(status='restored')
      restore_order['amendedReason'] = 'some reason'
      self.order_dao.update_with_patch(order.biobankOrderId, restore_order, order.version)
      summary = self.dao.get(self.participant.participantId)
      self.assertEquals(summary.numberDistinctVisits, 2)
Beispiel #4
0
    def test_replace_history(self):
        fake_clock = clock.FakeClock(datetime.datetime.utcnow())
        orig_config = self.send_get('Config')

        # Replace some data in the current config.
        test_key = 'testing_config_key'
        new_config_1 = copy.deepcopy(orig_config)
        new_config_1[test_key] = ['initially', 'injected', 'values']
        with fake_clock:
            self.send_request('PUT', 'Config', request_data=new_config_1)

        # Make sure the replacements show up when re-fetching the config.
        with fake_clock:
            response = self.send_get('Config')
        self.assertEquals(new_config_1, response)

        fake_clock.advance()
        between_updates = fake_clock.now
        fake_clock.advance()

        # Make sure another replacement takes effect.
        new_config_2 = copy.deepcopy(orig_config)
        new_config_2[test_key] = ['afterwards', 'replaced', 'values']
        with fake_clock:
            self.send_request('PUT', 'Config', new_config_2)
            response = self.send_get('Config')
        self.assertEquals(new_config_2, response)

        # Make sure we get the the first replacement config when we query by time.
        with fake_clock:
            response = self.send_get('Config?date={}'.format(
                between_updates.isoformat()))
        self.assertEquals(new_config_1, response)
Beispiel #5
0
 def test_ny_zip_code(self):
     participant_a = self.make_participant()
     self.make_summary(participant_a, zipCode=None)
     participant_b = self.make_participant()
     self.make_summary(participant_b, zipCode='')
     participant_c = self.make_participant()
     self.make_summary(participant_c, zipCode='12345')
     genomic_set = self.make_genomic_set()
     member_a = self.make_genomic_member(genomic_set, participant_a)
     member_b = self.make_genomic_member(genomic_set, participant_b)
     member_c = self.make_genomic_member(genomic_set, participant_c)
     with clock.FakeClock(datetime.datetime(2019, 1, 1)):
         validate_and_update_genomic_set_by_id(genomic_set.id)
     current_member_a = self.genomic_member_dao.get(member_a.id)
     current_member_b = self.genomic_member_dao.get(member_b.id)
     current_member_c = self.genomic_member_dao.get(member_c.id)
     self.assertEqual(current_member_a.validationStatus,
                      GenomicSetMemberStatus.INVALID)
     self.assertIn(GenomicValidationFlag.INVALID_NY_ZIPCODE,
                   current_member_a.validationFlags)
     self.assertEqual(current_member_b.validationStatus,
                      GenomicSetMemberStatus.INVALID)
     self.assertIn(GenomicValidationFlag.INVALID_NY_ZIPCODE,
                   current_member_a.validationFlags)
     self.assertEqual(current_member_c.validationStatus,
                      GenomicSetMemberStatus.VALID)
     current_set = self.genomic_set_dao.get(genomic_set.id)
     self.assertEqual(current_set.genomicSetStatus,
                      GenomicSetStatus.INVALID)
Beispiel #6
0
 def test_age(self):
     now = datetime.datetime(2019, 1, 1)
     valid_date_of_birth = datetime.datetime(now.year - 18, now.month,
                                             now.day)
     invalid_date_of_birth = datetime.datetime(now.year - 17, now.month,
                                               now.day)
     participant_a = self.make_participant()
     self.make_summary(participant_a, dateOfBirth=valid_date_of_birth)
     participant_b = self.make_participant()
     self.make_summary(participant_b, dateOfBirth=invalid_date_of_birth)
     genomic_set = self.make_genomic_set()
     member_a = self.make_genomic_member(genomic_set, participant_a)
     member_b = self.make_genomic_member(genomic_set, participant_b)
     with clock.FakeClock(datetime.datetime(2019, 1, 1)):
         validate_and_update_genomic_set_by_id(genomic_set.id)
     current_member_a = self.genomic_member_dao.get(member_a.id)
     current_member_b = self.genomic_member_dao.get(member_b.id)
     self.assertEqual(current_member_a.validationStatus,
                      GenomicSetMemberStatus.VALID)
     self.assertEqual(current_member_b.validationStatus,
                      GenomicSetMemberStatus.INVALID)
     self.assertIn(GenomicValidationFlag.INVALID_AGE,
                   current_member_b.validationFlags)
     current_set = self.genomic_set_dao.get(genomic_set.id)
     self.assertEqual(current_set.genomicSetStatus,
                      GenomicSetStatus.INVALID)
    def test_date_header(self):
        response = lambda: None  # Dummy object; functions can have arbitrary attrs set on them.
        setattr(response, 'headers', {})

        with clock.FakeClock(datetime.datetime(1994, 11, 6, 8, 49, 37)):
            app_util.add_headers(response)

        self.assertEquals(response.headers['Date'],
                          'Sun, 06 Nov 1994 08:49:37 GMT')
Beispiel #8
0
 def test_valid_does_update_validated_time(self):
     participant = self.make_participant()
     self.make_summary(participant)
     genomic_set = self.make_genomic_set()
     member = self.make_genomic_member(genomic_set, participant)
     now = datetime.datetime(2019, 1, 1)
     with clock.FakeClock(now):
         validate_and_update_genomic_set_by_id(genomic_set.id)
     current_member = self.genomic_member_dao.get(member.id)
     self.assertEqual(current_member.validatedTime, now)
     current_set = self.genomic_set_dao.get(genomic_set.id)
     self.assertEqual(current_set.validatedTime, now)
Beispiel #9
0
    def setUp(self):

        super(BigQuerySyncDaoTest, self).setUp(use_mysql=True,
                                               with_consent_codes=True)
        self.dao = ParticipantDao()

        with self.dao.session() as session:
            self.site = session.query(Site).filter(
                Site.googleGroup == 'hpo-site-monroeville').first()
            self.hpo = session.query(HPO).filter(HPO.name == 'PITT').first()

        with clock.FakeClock(self.TIME_1):
            self.participant = Participant(participantId=123, biobankId=555)
            self.participant.hpoId = self.hpo.hpoId
            self.participant.siteId = self.site.siteId
            self.dao.insert(self.participant)

            ps = ParticipantSummary(
                participantId=123,
                biobankId=555,
                firstName='john',
                lastName='doe',
                withdrawalStatus=WithdrawalStatus.NOT_WITHDRAWN,
                suspensionStatus=SuspensionStatus.NOT_SUSPENDED)
            ps.hpoId = self.hpo.hpoId
            ps.siteId = self.site.siteId
            self.summary = ParticipantSummaryDao().insert(ps)

        self.pm_json = json.dumps(
            load_measurement_json(self.participant.participantId,
                                  self.TIME_1.isoformat()))
        self.pm = PhysicalMeasurementsDao().insert(
            self._make_physical_measurements())

        with clock.FakeClock(self.TIME_2):
            self.dao = BiobankOrderDao()
            self.bio_order = BiobankOrderDao().insert(
                self._make_biobank_order(
                    participantId=self.participant.participantId))
Beispiel #10
0
 def test_transaction(self):
     participant = self.make_participant()
     self.make_summary(participant)
     genomic_set = self.make_genomic_set()
     member = self.make_genomic_member(genomic_set, participant)
     with mock.patch('genomic.validation.GenomicSetDao.update_with_session'
                     ) as mocked_set_update:
         mocked_set_update.side_effect = Exception('baz')
         with clock.FakeClock(datetime.datetime(2019, 1, 1)):
             with self.assertRaises(Exception):
                 validate_and_update_genomic_set_by_id(genomic_set.id)
     current_member = self.genomic_member_dao.get(member.id)
     self.assertEqual(current_member.validationStatus, None)
     current_set = self.genomic_set_dao.get(genomic_set.id)
     self.assertEqual(current_set.genomicSetStatus, None)
    def run(self):
        """
    Main program process
    :param args: program arguments
    :return: Exit code value
    """
        # load participant spreadsheet from bucket or local file.
        csv_data = self._local_csv_data(
            self.args.src_csv) or self._gdoc_csv_data(self.args.src_csv)
        if not csv_data:
            _logger.error(
                'unable to fetch participant source spreadsheet [{0}].'.format(
                    self.args.src_csv))
            return 1

        _logger.info('processing source data.')
        count = 0

        # Loop through each column and generate data.
        for column in range(0, len(csv_data[0]) - 1):

            p_data = self._convert_csv_column_to_dict(csv_data, column)

            hpo = self._get_dict_data_by_key(p_data, '_HPO')
            pm = self._get_dict_data_by_key(p_data, '_PM')
            site_id = self._get_dict_data_by_key(p_data, '_HPOSite')
            bio_orders = self._get_dict_data_by_key(p_data, '_BIOOrder')
            bio_orders_mayo = self._get_dict_data_by_key(
                p_data, '_BIOOrderMayo')
            ppi_modules = self._get_dict_data_by_key(p_data, '_PPIModule')

            # choose a random starting date, timestamps of all other activities feed off this value.
            start_dt = self._random_date()
            #
            # Create a new participant
            #
            count += 1
            _logger.info('participant [{0}].'.format(count))
            with clock.FakeClock(start_dt):
                p_obj, hpo_site = self.create_participant(site_id=site_id,
                                                          hpo_id=hpo)

                if not p_obj or 'participantId' not in p_obj.__dict__:
                    _logger.error('failed to create participant.')
                    continue

                _logger.info('  created [{0}].'.format(p_obj.participantId))
            #
            # process any questionnaire modules
            #
            if ppi_modules:

                # submit the first module pretty close to the start date. Assumes the first
                # module is ConsentPII.
                mod_dt = self._increment_date(start_dt, minute_range=60)

                modules = ppi_modules.split('|')
                for module in modules:
                    with clock.FakeClock(mod_dt):
                        mod_obj = self.submit_module_response(
                            module, p_obj.participantId, p_data.items())
                        if mod_obj:
                            _logger.info(
                                '  module: [{0}]: submitted.'.format(module))
                        else:
                            _logger.info(
                                '  module: [{0}]: failed.'.format(module))
                    #
                    # see if we need to submit physical measurements.
                    #
                    if module == 'ConsentPII' and pm and pm.lower() == 'yes':

                        mod_dt = self._random_date(
                            mod_dt, datetime.timedelta(minutes=90))
                        with clock.FakeClock(mod_dt):
                            pm_obj = self.submit_physical_measurements(
                                p_obj.participantId, hpo_site)
                            if pm_obj:
                                _logger.info('  pm: submitted.')
                            else:
                                _logger.info('  pm: failed.')
                    # choose a new random date between mod_dt and mod_dt + 15 days.
                    mod_dt = self._random_date(mod_dt,
                                               datetime.timedelta(days=15))
            #
            # process biobank samples
            #
            if bio_orders:
                sample_dt = self._increment_date(start_dt, day_range=10)

                samples = bio_orders.split('|')
                for sample in samples:
                    with clock.FakeClock(sample_dt):
                        bio_obj = self.submit_biobank_order(
                            p_obj.participantId, sample, hpo_site)
                        if bio_obj:
                            _logger.info(
                                '  biobank order: [{0}] submitted.'.format(
                                    sample))
                        else:
                            _logger.info(
                                '  biobank order: [{0}] failed.'.format(
                                    sample))

                    sample_dt = self._random_date(sample_dt,
                                                  datetime.timedelta(days=30))
            #
            # process biobank samples that also need to be sent to Mayolink.
            #
            if bio_orders_mayo:
                sample_dt = self._increment_date(start_dt, day_range=10)

                samples = bio_orders_mayo.split('|')
                for sample in samples:
                    with clock.FakeClock(sample_dt):
                        bio_obj = self.submit_biobank_order(
                            p_obj.participantId,
                            sample,
                            hpo_site,
                            to_mayo=True)
                        if bio_obj:
                            _logger.info(
                                '  biobank order w/mayo: {0} submitted.'.
                                format(sample))
                        else:
                            _logger.info(
                                '  biobank order w/mayo: {0} failed.'.format(
                                    sample))

                    sample_dt = self._random_date(sample_dt,
                                                  datetime.timedelta(days=30))

                # TODO: Add code for sending orders to mayo here, in a new ticket.

        return 0
  def test_qa_scenarios_for_pmb_visits(self):
    """ PDR at https://docs.google.com/document/d/1sL54f-I91RvhjIprrdbwD8TlR9Jq91MX2ELf1EtJdxc/edit#heading=h.bqo8kt3igsrw<Paste> """
    self.participant = self._insert(Participant(participantId=6, biobankId=66))

    # test scenario 1
    with clock.FakeClock(TIME_4):
      self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId,
                                                               TIME_4.isoformat()))
      self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=666,
                                                                   participantId=self.participant.participantId,
                                                                   finalized=TIME_4))
      summary = self.dao.get(self.participant.participantId)
      self.assertEquals(summary.numberDistinctVisits, 1)

    with clock.FakeClock(TIME_5):
      self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId,
                                                               TIME_5.isoformat()))
      self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=669,
                                                                   finalized=TIME_5))
      summary = self.dao.get(self.participant.participantId)
      self.assertEquals(summary.numberDistinctVisits, 2)

    # test scenario 2
    with clock.FakeClock(TIME_6):
      self.participant = self._insert(Participant(participantId=9, biobankId=13))
      self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId,
                                                               TIME_6.isoformat()))
      self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=8,
                                                                   finalized=TIME_6))
      self.order_dao.insert(self._make_biobank_order(biobankOrderId='2', identifiers=[
        BiobankOrderIdentifier(system='b', value='d')], samples=[BiobankOrderedSample(
                                                        biobankOrderId='2',
                                                        finalized=TIME_7,
                                                        test=BIOBANK_TESTS[0],
                                                        description='description',
                                                        processingRequired=True)]))


      summary = self.dao.get(self.participant.participantId)
      # distinct count should be 2
      self.assertEquals(summary.numberDistinctVisits, 2)

    # test scenario 3
    with clock.FakeClock(TIME_6):
      self.participant = self._insert(Participant(participantId=66, biobankId=42))
      self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId,
                                                               TIME_6.isoformat()))
      self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=12,
                                                                   createdSiteId=2,
                                                                   finalized=TIME_6))

      self.order_dao.insert(self._make_biobank_order(biobankOrderId='18', finalizedSiteId=1, identifiers=[
          BiobankOrderIdentifier(system='x', value='y')], samples=[BiobankOrderedSample(
              biobankOrderId='18',
              finalized=TIME_6,
              test=BIOBANK_TESTS[0],
              description='description',
              processingRequired=True)]))


      summary = self.dao.get(self.participant.participantId)
      # distinct count should be 1
      self.assertEquals(summary.numberDistinctVisits, 1)

    # test scenario 4
    with clock.FakeClock(TIME_8):
      self.participant = self._insert(Participant(participantId=6613, biobankId=142))
      self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId,
                                                               TIME_8.isoformat()))
      self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=129,
                                                                   finalized=TIME_8))

      order = self.order_dao.insert(self._make_biobank_order(biobankOrderId='999', identifiers=[
          BiobankOrderIdentifier(system='s', value='s')], samples=[BiobankOrderedSample(
              biobankOrderId='999',
              finalized=TIME_8,
              test=BIOBANK_TESTS[1],
              description='description',
              processingRequired=True)]))
      summary = self.dao.get(self.participant.participantId)
      # distinct count should be 1
      self.assertEquals(summary.numberDistinctVisits, 1)

     # change finalized time, recalculating count
      with self.order_dao.session() as session:
        existing_order = copy.deepcopy(order)
        order.samples[0].finalized = TIME_9
        self.order_dao._do_update(session, order, existing_order)

      summary = self.dao.get(self.participant.participantId)
      self.assertEquals(summary.numberDistinctVisits, 1)

     # change test, should not change count.
      with self.order_dao.session() as session:
        existing_order = copy.deepcopy(order)
        order.samples[0].test = BIOBANK_TESTS[0]
        self.order_dao._do_update(session, order, existing_order)

      summary = self.dao.get(self.participant.participantId)
      self.assertEquals(summary.numberDistinctVisits, 1)

    # test scenario 5
    with clock.FakeClock(TIME_12):
      self.participant = self._insert(Participant(participantId=3000, biobankId=2019))

      self.order_dao.insert(self._make_biobank_order(biobankOrderId='700', identifiers=[
          BiobankOrderIdentifier(system='n', value='s')], samples=[BiobankOrderedSample(
              biobankOrderId='700',
              finalized=TIME_10,
              test=BIOBANK_TESTS[1],
              description='description',
              processingRequired=True)]))
      summary = self.dao.get(self.participant.participantId)
      # distinct count should be 1
      self.assertEquals(summary.numberDistinctVisits, 1)

      other_order = self.order_dao.insert(self._make_biobank_order(biobankOrderId='701', identifiers=[
          BiobankOrderIdentifier(system='n', value='t')], samples=[BiobankOrderedSample(
              biobankOrderId='701',
              finalized=TIME_11,
              test=BIOBANK_TESTS[1],
              description='description',
              processingRequired=True)]))
      summary = self.dao.get(self.participant.participantId)
      # distinct count should be 2
      self.assertEquals(summary.numberDistinctVisits, 2)

      order = self.order_dao.insert(self._make_biobank_order(biobankOrderId='702', identifiers=[
          BiobankOrderIdentifier(system='n', value='u')], samples=[BiobankOrderedSample(
              biobankOrderId='702',
              finalized=TIME_12,
              test=BIOBANK_TESTS[1],
              description='description',
              processingRequired=True)]))
      summary = self.dao.get(self.participant.participantId)
      # distinct count should be 3
      self.assertEquals(summary.numberDistinctVisits, 3)

      self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId,
                                                               TIME_12.isoformat()))
      self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=120,
                                                                   finalized=TIME_12))

      summary = self.dao.get(self.participant.participantId)
      # distinct count should be 3
      self.assertEquals(summary.numberDistinctVisits, 3)
      cancel_request = cancel_biobank_order()
      # cancel biobank order with PM on same day
      self.order_dao.update_with_patch(order.biobankOrderId, cancel_request, order.version)
      summary = self.dao.get(self.participant.participantId)
      # distinct count should be 3 (the PM on same day still counts)
      self.assertEquals(summary.numberDistinctVisits, 3)

      self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId,
                                                               TIME_1.isoformat()))
      self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=150,
                                                                   finalized=TIME_1))
      summary = self.dao.get(self.participant.participantId)
      # distinct count should be 4
      self.assertEquals(summary.numberDistinctVisits, 4)
      # cancel order with pm on different day
      self.order_dao.update_with_patch(other_order.biobankOrderId, cancel_request, order.version)
      summary = self.dao.get(self.participant.participantId)
      # distinct count should be 3
      self.assertEquals(summary.numberDistinctVisits, 3)
  def testNumberDistinctVisitsCounts(self):
    self.participant = self._insert(Participant(participantId=7, biobankId=77))
    # insert biobank order
    order = self.order_dao.insert(self._make_biobank_order())
    summary = self.dao.get(self.participant.participantId)
    self.assertEquals(summary.numberDistinctVisits, 1)
    cancel_request = cancel_biobank_order()
    # cancel biobank order
    self.order_dao.update_with_patch(order.biobankOrderId, cancel_request, order.version)
    summary = self.dao.get(self.participant.participantId)
    # distinct count should be 0
    self.assertEquals(summary.numberDistinctVisits, 0)

    self.measurement_json = json.dumps(load_measurement_json(self.participant.participantId,
                                                             TIME_1.isoformat()))
    # insert physical measurement
    measurement = self.measurement_dao.insert(self._make_physical_measurements())
    summary = self.dao.get(self.participant.participantId)
    # count should be 1
    self.assertEquals(summary.numberDistinctVisits, 1)

    # cancel the measurement
    cancel_measurement = get_restore_or_cancel_info()
    with self.measurement_dao.session() as session:
      self.measurement_dao.update_with_patch(measurement.physicalMeasurementsId, session,
                                             cancel_measurement)

    summary = self.dao.get(self.participant.participantId)
    # count should be 0
    self.assertEquals(summary.numberDistinctVisits, 0)

    with clock.FakeClock(TIME_1):
      self.order_dao.insert(self._make_biobank_order(biobankOrderId='2', identifiers=[
        BiobankOrderIdentifier(system='b', value='d')], samples=[BiobankOrderedSample(
                                                        biobankOrderId='2',
                                                        test=BIOBANK_TESTS[0],
                                                        description='description',
                                                        processingRequired=True)]))
    with clock.FakeClock(TIME_2):
      self.measurement_dao.insert(self._make_physical_measurements(
        physicalMeasurementsId=2))
      summary = self.dao.get(self.participant.participantId)

      # A PM on another day should add a new distinct count.
      self.assertEquals(summary.numberDistinctVisits, 2)

    with clock.FakeClock(TIME_3):
      self.order_dao.insert(self._make_biobank_order(biobankOrderId='3', identifiers=[
        BiobankOrderIdentifier(system='s', value='s')], samples=[BiobankOrderedSample(
        biobankOrderId ='3',
        finalized=TIME_3,
        test=BIOBANK_TESTS[1],
        description='another description',
        processingRequired=False)]))

      # a physical measurement on same day as biobank order does not add distinct visit.
      self.measurement_dao.insert(self._make_physical_measurements(physicalMeasurementsId=6))

      # another biobank order on the same day should also not add a distinct visit
      self.order_dao.insert(self._make_biobank_order(biobankOrderId='7', identifiers=[
          BiobankOrderIdentifier(system='x', value='x')], samples=[BiobankOrderedSample(
              biobankOrderId ='7',
              finalized=TIME_3,
              test=BIOBANK_TESTS[1],
              description='another description',
              processingRequired=False)]))

      summary = self.dao.get(self.participant.participantId)
      # 1 from each of TIME_1 TIME_2 TIME_3
      self.assertEquals(summary.numberDistinctVisits, 3)