Esempio n. 1
0
 def test_dict_exceptions(self):
     fhir = SimpleFhirR4Reader({'a': 'foo'})
     with self.assertRaises(AttributeError):
         fhir.b
     with self.assertRaises(KeyError):
         fhir['b']
     with self.assertRaises(KeyError):
         fhir[0]
     with self.assertRaises(KeyError):
         fhir[-1]
     with self.assertRaises(TypeError):
         fhir[1:]
 def test_looks_up_deep_references(self):
     fhir = SimpleFhirR4Reader({
         'contained': [{
             'id': 'some-foo',
             'value': 123
         }],
         'bar': {
             'foo': {
                 'reference': '#some-foo'
             }
         }
     })
     self.assertEqual(fhir.bar.foo.value, 123)
Esempio n. 3
0
    def _post_supply_delivery(self, resource):
        try:
            fhir = SimpleFhirR4Reader(resource)
            patient = fhir.patient
            pid = patient.identifier
            p_id = from_client_participant_id(pid.value)
            bo_id = fhir.basedOn[0].identifier.value
            _id = self.dao.get_id(
                ObjDict({
                    'participantId': p_id,
                    'order_id': int(bo_id)
                }))
            tracking_status = fhir.extension.get(
                url=DV_FHIR_URL + 'tracking-status').valueString.lower()
        except AttributeError as e:
            raise BadRequest(e.message)
        except Exception as e:
            raise BadRequest(e.message)

        if not _id:
            raise Conflict(
                'Existing SupplyRequest for order required for SupplyDelivery')
        dvo = self.dao.get(_id)
        if not dvo:
            raise Conflict(
                'Existing SupplyRequest for order required for SupplyDelivery')

        merged_resource = None
        # Note: POST tracking status should be either 'enroute/in_transit'. PUT should only be 'delivered'.
        if tracking_status in [
                'in_transit', 'enroute', 'delivered'
        ] and self._to_mayo(fhir) and not dvo.biobankOrderId:
            # Send to mayolink and create internal biobank order
            response = self.dao.send_order(resource, p_id)
            merged_resource = merge_dicts(response, resource)
            merged_resource['id'] = _id
            logging.info(
                'Sending salivary order to biobank for participant: %s', p_id)
            self.dao.insert_biobank_order(p_id, merged_resource)

        response = super(DvOrderApi, self).put(bo_id,
                                               participant_id=p_id,
                                               skip_etag=True,
                                               resource=merged_resource)
        response[2]['Location'] = '/rdr/v1/SupplyDelivery/{}'.format(bo_id)
        response[2]['auth_user'] = resource['auth_user']
        if response[1] == 200:
            created_response = list(response)
            created_response[1] = 201
            return tuple(created_response)
        return response
 def _post_supply_request(self, resource):
     fhir_resource = SimpleFhirR4Reader(resource)
     patient = fhir_resource.contained.get(resourceType='Patient')
     pid = patient.identifier.get(system=VIBRENT_FHIR_URL +
                                  'participantId').value
     p_id = from_client_participant_id(pid)
     response = super(DvOrderApi, self).post(participant_id=p_id)
     order_id = fhir_resource.identifier.get(system=VIBRENT_FHIR_URL +
                                             'orderId').value
     response[2]['Location'] = '/rdr/v1/SupplyRequest/{}'.format(order_id)
     if response[1] == 200:
         created_response = list(response)
         created_response[1] = 201
         return tuple(created_response)
     return response
    def _put_supply_request(self, resource, bo_id):

        # handle invalid FHIR documents
        try:
            fhir_resource = SimpleFhirR4Reader(resource)
            barcode_url = None
            if fhir_resource.extension.get(
                    url=VIBRENT_FULFILLMENT_URL).valueString == 'shipped':
                barcode_url = fhir_resource.extension.get(
                    url=VIBRENT_BARCODE_URL).url
            pid = fhir_resource.contained.get(
                resourceType='Patient').identifier.get(
                    system=VIBRENT_FHIR_URL + 'participantId')
            p_id = from_client_participant_id(pid.value)
        except AttributeError as e:
            raise BadRequest(e.message)
        except Exception as e:
            raise BadRequest(e.message)

        merged_resource = None
        if not p_id:
            raise BadRequest(
                'Request must include participant id and must be of type int')
        if str(barcode_url) == VIBRENT_BARCODE_URL:
            _id = self.dao.get_id(
                ObjDict({
                    'participantId': p_id,
                    'order_id': int(bo_id)
                }))
            ex_obj = self.dao.get(_id)
            if not ex_obj.barcode:
                # Send to mayolink and create internal biobank order
                response = self.dao.send_order(resource, p_id)
                merged_resource = merge_dicts(response, resource)
                merged_resource['id'] = _id
                self.dao.insert_biobank_order(p_id, merged_resource)

        if merged_resource:
            response = super(DvOrderApi, self).put(bo_id,
                                                   participant_id=p_id,
                                                   skip_etag=True,
                                                   resource=merged_resource)
        else:
            response = super(DvOrderApi, self).put(bo_id,
                                                   participant_id=p_id,
                                                   skip_etag=True)

        return response
    def _post_supply_delivery(self, resource):
        fhir_resource = SimpleFhirR4Reader(resource)
        patient = fhir_resource.patient
        pid = patient.identifier
        p_id = from_client_participant_id(pid.value)
        bo_id = fhir_resource.basedOn[0].identifier.value
        pk = {'participantId': p_id, 'order_id': bo_id}
        obj = ObjDict(pk)
        if not self.dao.get_id(obj):
            raise Conflict(
                'Existing SupplyRequest for order required for SupplyDelivery')

        response = super(DvOrderApi, self).put(bo_id,
                                               participant_id=p_id,
                                               skip_etag=True)
        response[2]['Location'] = '/rdr/v1/SupplyDelivery/{}'.format(bo_id)
        if response[1] == 200:
            created_response = list(response)
            created_response[1] = 201
            return tuple(created_response)
        return response
Esempio n. 7
0
    def _put_supply_request(self, resource, bo_id):

        # handle invalid FHIR documents
        try:
            fhir_resource = SimpleFhirR4Reader(resource)
            pid = fhir_resource.contained.get(
                resourceType='Patient').identifier.get(system=DV_FHIR_URL +
                                                       'participantId')
            p_id = from_client_participant_id(pid.value)
        except AttributeError as e:
            raise BadRequest(e.message)
        except Exception as e:
            raise BadRequest(e.message)

        if not p_id:
            raise BadRequest('Request must include participant id')
        response = super(DvOrderApi, self).put(bo_id,
                                               participant_id=p_id,
                                               skip_etag=True)

        return response
    def _put_supply_delivery(self, resource, bo_id):

        # handle invalid FHIR documents
        try:
            fhir = SimpleFhirR4Reader(resource)
            participant_id = fhir.patient.identifier.value
            p_id = from_client_participant_id(participant_id)
            update_time = dateutil.parser.parse(fhir.occurrenceDateTime)
            carrier_name = fhir.extension.get(url=VIBRENT_FHIR_URL +
                                              'carrier').valueString
            eta = dateutil.parser.parse(
                fhir.extension.get(url=VIBRENT_FHIR_URL +
                                   "expected-delivery-date").valueDateTime)
            tracking_status = fhir.extension.get(url=VIBRENT_FHIR_URL +
                                                 'tracking-status').valueString
        except AttributeError as e:
            raise BadRequest(e.message)
        except Exception as e:
            raise BadRequest(e.message)

        tracking_status_enum = getattr(OrderShipmentTrackingStatus,
                                       tracking_status.upper(),
                                       OrderShipmentTrackingStatus.UNSET)

        biobank_dv_order_id = self.dao.get_id(
            ObjDict({
                'participantId': p_id,
                'order_id': int(bo_id)
            }))
        order = self.dao.get(biobank_dv_order_id)
        order.shipmentLastUpdate = update_time.date()
        order.shipmentCarrier = carrier_name
        order.shipmentEstArrival = eta.date()
        order.shipmentStatus = tracking_status_enum

        response = super(DvOrderApi, self).put(bo_id,
                                               participant_id=p_id,
                                               skip_etag=True)
        return response
Esempio n. 9
0
    def _put_supply_delivery(self, resource, bo_id):
        # handle invalid FHIR documents
        try:
            fhir = SimpleFhirR4Reader(resource)
            participant_id = fhir.patient.identifier.value
            p_id = from_client_participant_id(participant_id)
            update_time = dateutil.parser.parse(fhir.occurrenceDateTime)
            carrier_name = fhir.extension.get(url=DV_FHIR_URL +
                                              'carrier').valueString

            eta = None
            if hasattr(fhir['extension'],
                       DV_FHIR_URL + 'expected-delivery-date'):
                eta = dateutil.parser.parse(
                    fhir.extension.get(url=DV_FHIR_URL +
                                       "expected-delivery-date").valueDateTime)

            tracking_status = fhir.extension.get(url=DV_FHIR_URL +
                                                 'tracking-status').valueString
            if tracking_status:
                tracking_status = tracking_status.lower()
        except AttributeError as e:
            raise BadRequest(e.message)
        except Exception as e:
            raise BadRequest(e.message)

        _id = self.dao.get_id(
            ObjDict({
                'participantId': p_id,
                'order_id': int(bo_id)
            }))
        if not _id:
            raise Conflict(
                'Existing SupplyRequest for order required for SupplyDelivery')
        dvo = self.dao.get(_id)
        if not dvo:
            raise Conflict(
                'Existing SupplyRequest for order required for SupplyDelivery')

        tracking_status_enum = \
          getattr(OrderShipmentTrackingStatus, tracking_status.upper(), OrderShipmentTrackingStatus.UNSET)

        dvo.shipmentLastUpdate = update_time.date()
        dvo.shipmentCarrier = carrier_name
        if eta:
            dvo.shipmentEstArrival = eta.date()
        dvo.shipmentStatus = tracking_status_enum
        if not p_id:
            raise BadRequest('Request must include participant id')

        merged_resource = None
        # Note: PUT tracking status should only be 'delivered'. POST should be either 'enroute/in_transit'.
        if tracking_status in [
                'in_transit', 'enroute', 'delivered'
        ] and self._to_mayo(fhir) and not dvo.biobankOrderId:
            # Send to mayolink and create internal biobank order
            response = self.dao.send_order(resource, p_id)
            merged_resource = merge_dicts(response, resource)
            merged_resource['id'] = _id
            logging.info(
                'Sending salivary order to biobank for participant: %s', p_id)
            self.dao.insert_biobank_order(p_id, merged_resource)

        response = super(DvOrderApi, self).put(bo_id,
                                               participant_id=p_id,
                                               skip_etag=True,
                                               resource=merged_resource)
        return response
    def build_expected_resource_type_data(self, resource_type):
        """Helper function to build the data we are expecting from the test-data file."""
        fhir_resource = SimpleFhirR4Reader(resource_type)

        test_fields = {}
        fhir_address = {}

        # fields to test with the same structure in both payloads
        fhir_device = fhir_resource.contained.get(resourceType="Device")
        test_fields.update({
            'itemName':
            fhir_device.deviceName.get(type="manufacturer-name").name,
            'orderType':
            fhir_resource.extension.get(url=DV_ORDER_URL).valueString
        })

        # add the fields to test for each resource type (SupplyRequest, SupplyDelivery)
        if resource_type == self.post_request:
            test_fields.update({
                'order_id':
                int(
                    fhir_resource.identifier.get(system=DV_FHIR_URL +
                                                 "orderId").value),
                'supplier':
                fhir_resource.contained.get(resourceType="Organization").id,
                'supplierStatus':
                fhir_resource.extension.get(
                    url=DV_FULFILLMENT_URL).valueString,
                'itemQuantity':
                fhir_resource.quantity.value,
                'itemSKUCode':
                fhir_device.identifier.get(system=DV_FHIR_URL + "SKU").value,
            })
            # Address Handling
            fhir_address = fhir_resource.contained.get(
                resourceType="Patient").address[0]

        if resource_type == self.post_delivery:
            test_fields.update({
                'order_id':
                int(fhir_resource.basedOn[0].identifier.value),
                'shipmentEstArrival':
                parse_date(
                    fhir_resource.extension.get(
                        url=DV_FHIR_URL +
                        "expected-delivery-date").valueDateTime),
                'shipmentCarrier':
                fhir_resource.extension.get(url=DV_FHIR_URL +
                                            "carrier").valueString,
                'trackingId':
                fhir_resource.identifier.get(system=DV_FHIR_URL +
                                             "trackingId").value,
                'shipmentLastUpdate':
                parse_date(fhir_resource.occurrenceDateTime),
            })
            # Address Handling
            fhir_address = fhir_resource.contained.get(
                resourceType="Location").get("address")

        address_fields = {
            "streetAddress1": fhir_address.line[0],
            "streetAddress2": '',
            "city": fhir_address.city,
            "stateId": get_code_id(fhir_address, self.code_dao, "state",
                                   "State_"),
            "zipCode": fhir_address.postalCode,
        }

        # street address 2
        if len(list(fhir_address.line)) > 1:
            address_fields['streetAddress2'] = fhir_address.line[1]

        test_fields.update(address_fields)

        Supply = namedtuple('Supply', test_fields.keys())
        expected_data = Supply(**test_fields)

        return expected_data
 def test_list_filter_function_key(self):
     fhir = SimpleFhirR4Reader(list(range(10)))
     odds_only_filter = lambda x: x % 2
     self.assertEqual(list(fhir.get(odds_only_filter)), [1, 3, 5, 7, 9])
 def test_enumerate_shipping_status(self):
     fhir_resource = SimpleFhirR4Reader(self.post_request)
     status = self.dao._enumerate_order_shipping_status(
         fhir_resource.status)
     self.assertEquals(status, OrderShipmentStatus.SHIPPED)
 def test_enumerate_tracking_status(self):
     fhir_resource = SimpleFhirR4Reader(self.post_delivery)
     status = self.dao._enumerate_order_tracking_status(
         fhir_resource.extension.get(url=DV_FHIR_URL +
                                     'tracking-status').valueString)
     self.assertEquals(status, OrderShipmentTrackingStatus.IN_TRANSIT)
    def from_client_json(self,
                         resource_json,
                         id_=None,
                         expected_version=None,
                         participant_id=None,
                         client_id=None):  #pylint: disable=unused-argument
        """Initial loading of the DV order table does not include all attributes."""
        fhir_resource = SimpleFhirR4Reader(resource_json)
        order = BiobankDVOrder(participantId=participant_id)
        order.participantId = participant_id

        if resource_json['resourceType'].lower() == 'supplydelivery':
            order.order_id = int(fhir_resource.basedOn[0].identifier.value)
            existing_obj = self.get(self.get_id(order))
            if not existing_obj:
                raise NotFound('existing order record not found')

            # handling of biobankStatus from Mayolink API
            try:
                existing_obj.biobankStatus = resource_json['biobankStatus']
            except KeyError:
                # resource will only have biobankStatus on a PUT
                pass

            existing_obj.shipmentStatus = self._enumerate_order_tracking_status(
                fhir_resource.extension.get(url=DV_FHIR_URL +
                                            'tracking-status').valueString)
            existing_obj.shipmentCarrier = fhir_resource.extension.get(
                url=DV_FHIR_URL + 'carrier').valueString

            # shipmentEstArrival
            # The fhir_resource.get() method
            # will raise an exception on "expected-delivery-date"
            # if the resource doesn't have that path
            delivery_date_url = [
                extension.url for extension in fhir_resource["extension"]
                if extension.url == DV_FHIR_URL + "expected-delivery-date"
            ]
            if delivery_date_url:
                existing_obj.shipmentEstArrival = parse_date(
                    fhir_resource.extension.get(
                        url=DV_FHIR_URL +
                        "expected-delivery-date").valueDateTime)

            existing_obj.trackingId = fhir_resource.identifier.get(
                system=DV_FHIR_URL + 'trackingId').value
            # USPS status
            existing_obj.orderStatus = self._enumerate_order_shipping_status(
                fhir_resource.status)
            # USPS status time
            existing_obj.shipmentLastUpdate = parse_date(
                fhir_resource.occurrenceDateTime)
            order_address = fhir_resource.contained.get(
                resourceType='Location').get('address')
            address_use = fhir_resource.contained.get(
                resourceType='Location').get('address').get('use')
            order_address.stateId = get_code_id(order_address, self.code_dao,
                                                'state', 'State_')
            existing_obj.address = {
                'city': existing_obj.city,
                'state': existing_obj.stateId,
                'postalCode': existing_obj.zipCode,
                'line': [existing_obj.streetAddress1]
            }

            if existing_obj.streetAddress2 is not None and existing_obj.streetAddress2 != '':
                existing_obj.address['line'].append(
                    existing_obj.streetAddress2)

            if address_use.lower() == 'home':
                existing_obj.city = order_address.city
                existing_obj.stateId = order_address.stateId
                existing_obj.streetAddress1 = order_address.line[0]
                existing_obj.zipCode = order_address.postalCode

                if len(order_address._obj['line'][0]) > 1:
                    try:
                        existing_obj.streetAddress2 = order_address._obj[
                            'line'][1]
                    except IndexError:
                        pass

            elif address_use.lower() == 'work':
                existing_obj.biobankCity = order_address.city
                existing_obj.biobankStateId = order_address.stateId
                existing_obj.biobankStreetAddress1 = order_address.line[0]
                existing_obj.biobankZipCode = order_address.postalCode

            if hasattr(fhir_resource, 'biobankTrackingId'):
                existing_obj.biobankTrackingId = fhir_resource.biobankTrackingId
                existing_obj.biobankReceived = parse_date(
                    fhir_resource.received)

            return existing_obj

        if resource_json['resourceType'].lower() == 'supplyrequest':
            order.order_id = int(
                fhir_resource.identifier.get(system=DV_FHIR_URL +
                                             'orderId').value)
            if id_ and int(id_) != order.order_id:
                raise Conflict(
                    'url order id param does not match document order id')

            if hasattr(fhir_resource, 'authoredOn'):
                order.order_date = parse_date(fhir_resource.authoredOn)

            order.supplier = fhir_resource.contained.get(
                resourceType='Organization').id
            order.created = clock.CLOCK.now()
            order.supplierStatus = fhir_resource.extension.get(
                url=DV_FULFILLMENT_URL).valueString

            fhir_device = fhir_resource.contained.get(resourceType='Device')
            order.itemName = fhir_device.deviceName.get(
                type='manufacturer-name').name
            order.itemSKUCode = fhir_device.identifier.get(system=DV_FHIR_URL +
                                                           'SKU').value
            order.itemQuantity = fhir_resource.quantity.value

            fhir_patient = fhir_resource.contained.get(resourceType='Patient')
            fhir_address = fhir_patient.address[0]
            order.streetAddress1 = fhir_address.line[0]
            order.streetAddress2 = '\n'.join(fhir_address.line[1:])
            order.city = fhir_address.city
            order.stateId = get_code_id(fhir_address, self.code_dao, 'state',
                                        'State_')
            order.zipCode = fhir_address.postalCode

            order.orderType = fhir_resource.extension.get(
                url=DV_ORDER_URL).valueString
            if id_ is None:
                order.version = 1
            else:
                # A put request may add new attributes
                existing_obj = self.get(self.get_id(order))
                if not existing_obj:
                    raise NotFound('existing order record not found')

                order.id = existing_obj.id
                order.version = expected_version
                order.biobankStatus = fhir_resource.biobankStatus if hasattr(
                    fhir_resource, 'biobankStatus') else None
                try:
                    order.barcode = fhir_resource.extension.get(
                        url=DV_BARCODE_URL).valueString
                except ValueError:
                    order.barcode = None

        return order
    def _filter_order_fields(self, resource, pid):
        fhir_resource = SimpleFhirR4Reader(resource)
        summary = ParticipantSummaryDao().get(pid)
        if not summary:
            raise BadRequest('No summary for participant id: {}'.format(pid))
        code_dict = summary.asdict()
        format_json_code(code_dict, self.code_dao, 'genderIdentityId')
        format_json_code(code_dict, self.code_dao, 'stateId')
        if 'genderIdentity' in code_dict and code_dict['genderIdentity']:
            if code_dict['genderIdentity'] == 'GenderIdentity_Woman':
                gender_val = 'F'
            elif code_dict['genderIdentity'] == 'GenderIdentity_Man':
                gender_val = 'M'
            else:
                gender_val = 'U'
        else:
            gender_val = 'U'

        order_id = int(fhir_resource.basedOn[0].identifier.value)
        with self.session() as session:
            result = session.query(BiobankDVOrder.barcode).filter(
                BiobankDVOrder.order_id == order_id).first()
            barcode = None if not result else result if isinstance(
                result, str) else result.barcode

        # MayoLink api has strong opinions on what should be sent and the order of elements. Dont touch.
        order = {
            'order': {
                'collected': fhir_resource.occurrenceDateTime,
                'account': '',
                'number': barcode,
                'patient': {
                    'medical_record_number':
                    str(to_client_biobank_id(summary.biobankId)),
                    'first_name':
                    '*',
                    'last_name':
                    str(to_client_biobank_id(summary.biobankId)),
                    'middle_name':
                    '',
                    'birth_date':
                    '3/3/1933',
                    'gender':
                    gender_val,
                    'address1':
                    summary.streetAddress,
                    'address2':
                    summary.streetAddress2,
                    'city':
                    summary.city,
                    'state':
                    code_dict['state'],
                    'postal_code':
                    str(summary.zipCode),
                    'phone':
                    str(summary.phoneNumber),
                    'account_number':
                    None,
                    'race':
                    summary.race,
                    'ethnic_group':
                    None
                },
                'physician': {
                    'name': 'None',  # must be a string value, not None.
                    'phone': None,
                    'npi': None
                },
                'report_notes':
                fhir_resource.extension.get(url=DV_ORDER_URL).valueString,
                'tests': {
                    'test': {
                        'code': '1SAL2',
                        'name': 'PMI Saliva, FDA Kit',
                        'comments': None
                    }
                },
                'comments': 'Salivary Kit Order, direct from participant'
            }
        }
        return order
 def test_dict_filter_function_key(self):
     fhir = SimpleFhirR4Reader({'a': 0, 'b': 1, 'c': 2, 'd': 3})
     odd_values_only_filter = lambda x: x[1] % 2
     self.assertEqual(list(fhir.get(odd_values_only_filter)), [('b', 1),
                                                               ('d', 3)])
 def test_list_key_range(self):
     fhir = SimpleFhirR4Reader(['foo', 'bar', 'baz'])
     self.assertEqual(fhir[1:], ['bar', 'baz'])
     self.assertEqual(fhir[:-1], ['foo', 'bar'])
 def test_attribute_lookup(self):
     fhir = SimpleFhirR4Reader({'foo': {'bar': {'baz': 123}}})
     self.assertEqual(fhir.foo.bar.baz, 123)
 def test_nested_dict_lookup(self):
     fhir = SimpleFhirR4Reader({'a': {'b': 'bar'}})
     self.assertEqual(fhir.get('a', 'b'), 'bar')
 def test_dict_lookup(self):
     fhir = SimpleFhirR4Reader({'a': 'foo'})
     self.assertEqual(fhir.get('a'), 'foo')
 def setUp(self):
     self.fhir = SimpleFhirR4Reader(EXAMPLE_SUPPLY_REQUEST)
 def test_dict_key_lookup(self):
     fhir = SimpleFhirR4Reader({'a': 'foo'})
     self.assertEqual(fhir['a'], 'foo')
 def test_list_item_at_index(self):
     fhir = SimpleFhirR4Reader({'a': [2, 4, 6, 8]})
     self.assertEqual(fhir.get('a', 1), 4)
 def test_list_key_lookup(self):
     fhir = SimpleFhirR4Reader(['foo', 'bar', 'baz'])
     self.assertEqual(fhir[1], 'bar')
     self.assertEqual(fhir[-1], 'baz')