Skip to content

Commit 2d2e5c5

Browse files
authored
jimfuqian/BB2-3887 Added search parameter _tag for EOB (#1332)
* added search param _tag * added unittests coverage. * address feedback, having issue with switch check (WIP) * refactor the custom validator to address error during migration...
1 parent 9426a46 commit 2d2e5c5

File tree

3 files changed

+86
-2
lines changed

3 files changed

+86
-2
lines changed

apps/core/management/commands/create_test_feature_switches.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
("splunk_monitor", False, "This is used in other environments to ensure splunk forwarder is running."),
1717
("testclient_v2", True, "This enables the v2 auth links in the test client"),
1818
("wellknown_applications", True, "This enables the /.well-known/applications end-point. Active in prod, but not in sbx/test."),
19+
("bfd_v3_connectathon", True, "This enables the bfd v3 features for connectathon demo"),
1920
)
2021

2122
WAFFLE_FEATURE_FLAGS = (

apps/fhir/bluebutton/tests/test_fhir_resources_read_search_w_validation.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from django.urls import reverse
55
from httmock import all_requests, HTTMock
66
from oauth2_provider.models import get_access_token_model
7+
from waffle.testutils import override_switch
78

89
from apps.test import BaseApiTest
910

@@ -154,6 +155,67 @@ def catchall(url, req):
154155
for r in response.json()['entry']:
155156
self._assertHasC4BBIdentifier(r['resource'], C4BB_SYSTEM_TYPES['IDTYPE'], v2)
156157

158+
@override_switch('bfd_v3_connectathon', active=True)
159+
def test_search_eob_by_parameter_tag(self):
160+
self._search_eob_by_parameter_tag(False)
161+
162+
@override_switch('bfd_v3_connectathon', active=True)
163+
def test_search_eob_by_parameter_tag_v2(self):
164+
self._search_eob_by_parameter_tag(True)
165+
166+
@override_switch('bfd_v3_connectathon', active=True)
167+
def _search_eob_by_parameter_tag(self, v2=False):
168+
# create the user
169+
first_access_token = self.create_token('John', 'Smith')
170+
ac = AccessToken.objects.get(token=first_access_token)
171+
ac.scope = 'patient/ExplanationOfBenefit.read'
172+
ac.save()
173+
ver = 'v1' if not v2 else 'v2'
174+
175+
@all_requests
176+
def catchall_w_tag_qparam(url, req):
177+
# this is called in case EOB search with good tag
178+
self.assertIn("https://fhir.backend.bluebutton.hhsdevcloud.us/{}/fhir/ExplanationOfBenefit/".format(ver), req.url)
179+
self.assertIn("_format=application%2Fjson%2Bfhir", req.url)
180+
# parameters encoded in prepared request's body
181+
self.assertTrue(("_tag=Adjudicated" in req.body) or ("_tag=PartiallyAdjudicated" in req.body))
182+
183+
return {
184+
'status_code': 200,
185+
'content': get_response_json("eob_search_pt_{}".format(ver)),
186+
}
187+
188+
@all_requests
189+
def catchall(url, req):
190+
self.assertIn("https://fhir.backend.bluebutton.hhsdevcloud.us/{}/fhir/ExplanationOfBenefit/".format(ver), req.url)
191+
self.assertIn("_format=application%2Fjson%2Bfhir", req.url)
192+
193+
return {
194+
'status_code': 200,
195+
'content': get_response_json("eob_search_pt_{}".format(ver)),
196+
}
197+
# Test _tag with valid parameter value e.g. Adjudicated, PartiallyAdjudicated
198+
with HTTMock(catchall_w_tag_qparam):
199+
response = self.client.get(
200+
reverse('bb_oauth_fhir_eob_search' if not v2 else 'bb_oauth_fhir_eob_search_v2'),
201+
{'_tag': 'Adjudicated'},
202+
Authorization="Bearer %s" % (first_access_token))
203+
# just check for 200 is sufficient
204+
self.assertEqual(response.status_code, 200)
205+
206+
# Test _tag with invalid parameter value e.g.: Adjudiacted-Typo
207+
with HTTMock(catchall):
208+
response = self.client.get(
209+
reverse('bb_oauth_fhir_eob_search' if not v2 else 'bb_oauth_fhir_eob_search_v2'),
210+
{'_tag': 'Adjudiacted-Typo'},
211+
Authorization="Bearer %s" % (first_access_token))
212+
213+
content = json.loads(response.content.decode("utf-8"))
214+
self.assertTrue(content['detail'].startswith("Invalid _tag value ("))
215+
self.assertTrue(content['detail'].endswith("'PartiallyAdjudicated' or 'Adjudicated' expected."))
216+
self.assertTrue('Adjudiacted-Typo' in content['detail'])
217+
self.assertEqual(response.status_code, 400)
218+
157219
def test_search_eob_by_parameters_request(self):
158220
self._search_eob_by_parameters_request(False)
159221

apps/fhir/bluebutton/views/search.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import waffle
2+
13
from voluptuous import (
24
Required,
35
All,
46
Match,
57
Range,
68
Coerce,
79
Schema,
10+
Invalid,
811
REMOVE_EXTRA,
912
)
1013
from rest_framework import (permissions)
@@ -105,6 +108,16 @@ def build_parameters(self, request, *args, **kwargs):
105108

106109

107110
class SearchViewExplanationOfBenefit(SearchView):
111+
# customized validator for better error reporting
112+
def validate_tag(self):
113+
def validator(value):
114+
for v in value:
115+
if not (v in ["Adjudicated", "PartiallyAdjudicated"]):
116+
msg = f"Invalid _tag value (='{v}'), 'PartiallyAdjudicated' or 'Adjudicated' expected."
117+
raise Invalid(msg)
118+
return value
119+
return validator
120+
108121
# Class used for ExplanationOfBenefit resource search view
109122
required_scopes = ['patient/ExplanationOfBenefit.read', 'patient/ExplanationOfBenefit.rs', 'patient/ExplanationOfBenefit.s']
110123

@@ -136,7 +149,7 @@ class SearchViewExplanationOfBenefit(SearchView):
136149
# Add type parameter to schema only for EOB
137150
QUERY_SCHEMA = {**SearchView.QUERY_SCHEMA,
138151
'type': Match(REGEX_TYPE_VALUES_LIST, msg="the type parameter value is not valid"),
139-
'service-date': [Match(REGEX_SERVICE_DATE_VALUE, msg="the service-date operator is not valid")]
152+
'service-date': [Match(REGEX_SERVICE_DATE_VALUE, msg="the service-date operator is not valid")],
140153
}
141154

142155
def __init__(self, version=1):
@@ -158,7 +171,15 @@ def filter_parameters(self, request):
158171
if service_dates:
159172
params['service-date'] = service_dates
160173

174+
query_schema = getattr(self, "QUERY_SCHEMA", {})
175+
176+
if waffle.switch_is_active('bfd_v3_connectathon'):
177+
query_schema['_tag'] = self.validate_tag()
178+
# _tag if presents, is a string value
179+
params['_tag'] = request.query_params.getlist('_tag')
180+
161181
schema = Schema(
162-
getattr(self, "QUERY_SCHEMA", {}),
182+
query_schema,
163183
extra=REMOVE_EXTRA)
184+
164185
return schema(params)

0 commit comments

Comments
 (0)