Skip to content

Commit 3941a55

Browse files
NIAD-3301: Update MedicationRequest.medication datatype support. (#1250)
* NIAD-3301: Update MedicationRequest.medication datatype support * Add test and test file where the `MedicationRequest` contains a `medicationCodableConcept` and not a `medication.reference` to ensure that this is used if it is provided. * Ensure existing tests still pass using the original functionality * Update `MedicationStatementMapper` to implement this. * Added new test file and new addition to the bundle to account for codeable concept * Implemented new implementation to print medication codeable concept in output for supporting info * * Refactor `RequestStatementMapperTest` for readability. * Fix Checkstyle issues. * * Update CHANGELOG.md --------- Co-authored-by: Chiara <[email protected]>
1 parent ff874f7 commit 3941a55

9 files changed

+176
-41
lines changed

CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88

99
### Added
1010
* The GP2GP Adaptor now adds the EhrComposition / confidentialityCode field when Encounter.meta.security contains NOPAT security entry
11-
* The GP2GP Adaptor now populates the ObservationStatement / confidentialityCode field when the .meta.security field of an Uncategorised Data Observation contains NOPAT
11+
* The GP2GP Adaptor now populates the ObservationStatement / confidentialityCode field when the .meta.security field of an Uncategorized Data Observation contains NOPAT
1212
* When List.meta.security field contains NOPAT, the GP2GP Adaptor will now populate the CompoundStatement.confidentialityCode
1313

1414
### Update
15-
* The GP2GP Adaptor is now able to identify e-referrals by using either `https://fhir.nhs.uk/Id/ubr-number` or `https://fhir.nhs.uk/Id/UBRN` when provided as an identifier system URL.
15+
16+
* [GP Connect 1.6.1] The GP2GP Adaptor is now able to identify e-referrals by using either `https://fhir.nhs.uk/Id/ubr-number` or `https://fhir.nhs.uk/Id/UBRN` when provided as an identifier system URL.
17+
* [GP Connect 1.6.2] In a `MedicationRequest` the `Medication` can be provided as a reference to a `Medication` (using `Medication.medicationReference`) or, in the case that only a single resource references this medication, a `Medication.medicationCodeableConcept` can be used instead.)
1618

1719

1820
## [2.4.0] - 2025-04-02

service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/MedicationStatementMapper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ private String buildStatusCode(MedicationRequest medicationRequest) {
148148
}
149149

150150
private String buildMedicationReferenceCode(MedicationRequest medicationRequest) {
151+
if (medicationRequest.hasMedicationCodeableConcept()) {
152+
return codeableConceptCdMapper.mapCodeableConceptForMedication(medicationRequest.getMedicationCodeableConcept());
153+
}
154+
151155
IIdType reference = medicationRequest.getMedicationReference().getReferenceElement();
152156
return messageContext.getInputBundleHolder()
153157
.getResource(reference)

service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/utils/SupportingInfoResourceExtractor.java

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public static String extractReferralRequest(MessageContext messageContext, Refer
122122
}
123123

124124
if (referralRequest.hasReasonCode()) {
125-
CodeableConceptMappingUtils.extractTextOrCoding(referralRequest.getReasonCode().get(0)).ifPresent(
125+
CodeableConceptMappingUtils.extractTextOrCoding(referralRequest.getReasonCode().getFirst()).ifPresent(
126126
reasonCode -> stringBuilder
127127
.append(" ")
128128
.append(reasonCode)
@@ -170,47 +170,61 @@ public static String extractDiagnosticReport(MessageContext messageContext, Refe
170170
return stringBuilder.toString();
171171
}
172172

173+
private static String buildDispenseRequestText(MedicationRequest medicationRequest) {
174+
if (medicationRequest.hasDispenseRequest() && medicationRequest.getDispenseRequest().getValidityPeriod().hasStart()) {
175+
return " " + formatDateUsingDayPrecision(medicationRequest.getDispenseRequest().getValidityPeriod().getStartElement());
176+
}
177+
return "";
178+
}
179+
173180
public static String extractMedicationRequest(MessageContext messageContext, Reference reference) {
174-
var medicationRequestOptional = messageContext
181+
return messageContext
175182
.getInputBundleHolder()
176183
.getResource(reference.getReferenceElement())
177-
.map(MedicationRequest.class::cast);
178-
179-
if (medicationRequestOptional.isEmpty()) {
180-
return "";
181-
}
182-
183-
var stringBuilder = new StringBuilder();
184-
stringBuilder.append("{ Medication:");
184+
.map(MedicationRequest.class::cast)
185+
.map(medicationRequest -> buildMedicationRequestText(messageContext, medicationRequest))
186+
.orElse(StringUtils.EMPTY);
187+
}
185188

186-
var medicationRequest = medicationRequestOptional.get();
189+
private static String buildMedicationRequestText(MessageContext messageContext, MedicationRequest medicationRequest) {
190+
return new StringBuilder()
191+
.append("{ Medication:")
192+
.append(buildDispenseRequestText(medicationRequest))
193+
.append(buildCodeableConceptText(messageContext, medicationRequest))
194+
.append(" }")
195+
.toString();
196+
}
187197

188-
if (medicationRequest.hasDispenseRequest()) {
189-
if (medicationRequest.getDispenseRequest().getValidityPeriod().hasStart()) {
190-
stringBuilder
191-
.append(" ")
192-
.append(
193-
formatDateUsingDayPrecision(
194-
medicationRequest.getDispenseRequest().getValidityPeriod().getStartElement()
195-
)
196-
);
197-
}
198+
private static String buildCodeableConceptText(
199+
MessageContext messageContext,
200+
MedicationRequest medicationRequest
201+
) {
202+
if (medicationRequest.hasMedicationCodeableConcept()) {
203+
return buildCodeableConceptTextFromMedicationCodableConcept(medicationRequest);
204+
} else if (medicationRequest.hasMedicationReference()) {
205+
return buildCodeableConceptFromMedicationReference(messageContext, medicationRequest);
198206
}
207+
return "";
208+
}
199209

200-
if (medicationRequest.hasMedicationReference()) {
201-
messageContext
202-
.getInputBundleHolder()
203-
.getResource(medicationRequest.getMedicationReference().getReferenceElement())
204-
.map(Medication.class::cast)
205-
.flatMap(medication -> CodeableConceptMappingUtils.extractTextOrCoding(medication.getCode()))
206-
.ifPresent(code -> stringBuilder
207-
.append(" ")
208-
.append(code)
209-
);
210-
}
211-
stringBuilder.append(" }");
210+
private static String buildCodeableConceptFromMedicationReference(
211+
MessageContext messageContext,
212+
MedicationRequest medicationRequest
213+
) {
214+
return messageContext
215+
.getInputBundleHolder()
216+
.getResource(medicationRequest.getMedicationReference().getReferenceElement())
217+
.map(Medication.class::cast)
218+
.flatMap(medication -> CodeableConceptMappingUtils.extractTextOrCoding(medication.getCode()))
219+
.map(code -> " " + code)
220+
.orElse("");
221+
}
212222

213-
return stringBuilder.toString();
223+
private static String buildCodeableConceptTextFromMedicationCodableConcept(
224+
MedicationRequest medicationRequest
225+
) {
226+
return " " + CodeableConceptMappingUtils.extractTextOrCoding(medicationRequest.getMedicationCodeableConcept())
227+
.orElse("");
214228
}
215229

216230
private static String formatDateUsingDayPrecision(BaseDateTimeType baseDateTimeType) {

service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/MedicationStatementMapperTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ public void When_MappingObservationJson_Expect_NarrativeStatementXmlOutput(Strin
107107
private static Stream<Arguments> resourceFileParams() {
108108
return Stream.of(
109109
Arguments.of("mr-with-order-no-optional-fields.json", "medication-statement-with-prescribe-no-optional-fields.xml"),
110+
Arguments.of(
111+
"mr-with-order-no-optional-fields-with-medication-codeable-concept.json",
112+
"medication-statement-with-prescribe-no-optional-fields.xml"
113+
),
110114
Arguments.of("mr-with-order-optional-fields.json", "medication-statement-with-prescribe-optional-fields.xml"),
111115
Arguments.of("mr-with-complete-status.json", "medication-statement-with-complete-status.xml"),
112116
Arguments.of("mr-with-active-status.json", "medication-statement-with-active-status.xml"),

service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/RequestStatementMapperTest.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ public class RequestStatementMapperTest {
119119
+ "example-referral-request-supportingInfo-with-medication-request.json";
120120
private static final String INPUT_JSON_WITH_SUPPORTINGINFO_MEDICATIONREQUEST_NO_DATE = TEST_FILE_DIRECTORY
121121
+ "example-referral-request-supportingInfo-with-medication-request-no-date.json";
122+
private static final String INPUT_JSON_WITH_SUPPORTINGINFO_MEDICATION_REQUEST_WITH_MEDICATION_CODEABLE_CONCEPT = TEST_FILE_DIRECTORY
123+
+ "example-referral-request-supportingInfo-medication-request-with-medication-codeable-concept.json";
122124
private static final String INPUT_JSON_WITH_SUPPORTINGINFO_IGNORED_RESOURCES = TEST_FILE_DIRECTORY
123125
+ "example-referral-request-supportingInfo-with-ignored-resources.json";
124126
private static final String INPUT_JSON_WITH_NO_AUTHOR_AND_TIME = TEST_FILE_DIRECTORY
@@ -189,6 +191,8 @@ public class RequestStatementMapperTest {
189191
+ "expected-output-request-statement-supportingInfo-with-medication-request.xml";
190192
private static final String OUTPUT_XML_WITH_SUPPORTINGINFO_MEDICATIONREQUEST_NO_DATE = TEST_FILE_DIRECTORY
191193
+ "expected-output-request-statement-supportingInfo-with-medication-request-no-date.xml";
194+
private static final String OUTPUT_XML_WITH_SUPPORTINGINFO_FROM_MEDICATION_CODEABLE_CONCEPT_DISPLAY = TEST_FILE_DIRECTORY
195+
+ "expected-output-request-statement-supportingInfo-from-medication-codeable-concept-display.xml";
192196
private static final String OUTPUT_XML_WITH_NO_SUPPORTINGINFO = TEST_FILE_DIRECTORY
193197
+ "expected-output-request-statement-no-supportingInfo.xml";
194198
private static final String OUTPUT_XML_WITH_NO_AUTHOR_AND_TIME = TEST_FILE_DIRECTORY
@@ -207,8 +211,6 @@ public class RequestStatementMapperTest {
207211
@Mock
208212
private ConfidentialityService confidentialityService;
209213

210-
private InputBundle inputBundle;
211-
212214
private RequestStatementMapper requestStatementMapper;
213215

214216
private static Stream<Arguments> resourceFileParams() {
@@ -257,9 +259,11 @@ private static Stream<Arguments> resourceFileParams() {
257259
OUTPUT_XML_WITH_SUPPORTINGINFO_MEDICATIONREQUEST_NO_DATE),
258260
arguments(INPUT_JSON_WITH_SUPPORTINGINFO_IGNORED_RESOURCES,
259261
OUTPUT_XML_WITH_NO_SUPPORTINGINFO),
262+
arguments(INPUT_JSON_WITH_WITH_UBRN_SYSTEM_URL, OUTPUT_XML_WITH_SYSTEM_URL),
263+
arguments(INPUT_JSON_WITH_SUPPORTINGINFO_MEDICATION_REQUEST_WITH_MEDICATION_CODEABLE_CONCEPT,
264+
OUTPUT_XML_WITH_SUPPORTINGINFO_FROM_MEDICATION_CODEABLE_CONCEPT_DISPLAY),
260265
arguments(INPUT_JSON_WITH_NO_AUTHOR_AND_TIME, OUTPUT_XML_WITH_NO_AUTHOR_AND_TIME),
261-
arguments(INPUT_JSON_WITH_WITH_UBR_NUMBER_SYSTEM_URL, OUTPUT_XML_WITH_SYSTEM_URL),
262-
arguments(INPUT_JSON_WITH_WITH_UBRN_SYSTEM_URL, OUTPUT_XML_WITH_SYSTEM_URL)
266+
arguments(INPUT_JSON_WITH_WITH_UBR_NUMBER_SYSTEM_URL, OUTPUT_XML_WITH_SYSTEM_URL)
263267
);
264268
}
265269

@@ -286,7 +290,7 @@ private static Stream<Arguments> resourceFileParamsWithInvalidData() {
286290
public void setUp() {
287291
var bundleInput = ResourceTestFileUtils.getFileContent(INPUT_JSON_BUNDLE);
288292
Bundle bundle = new FhirParseService().parseResource(bundleInput, Bundle.class);
289-
inputBundle = new InputBundle(bundle);
293+
var inputBundle = new InputBundle(bundle);
290294

291295
lenient().when(messageContext.getIdMapper()).thenReturn(idMapper);
292296
lenient().when(messageContext.getAgentDirectory()).thenReturn(agentDirectory);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"resourceType":"MedicationRequest",
3+
"id":"3377543D-5B1B-4C4F-BFF6-9F7BC3A1C3B8",
4+
"meta":{
5+
"profile":[
6+
"https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-MedicationRequest-1"
7+
]
8+
},
9+
"extension":[
10+
{
11+
"url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-MedicationRepeatInformation-1",
12+
"extension": [
13+
{
14+
"url": "numberOfRepeatPrescriptionsAllowed",
15+
"valuePositiveInt": 12
16+
},
17+
{
18+
"url": "numberOfRepeatPrescriptionsIssued",
19+
"valuePositiveInt": 11
20+
}
21+
]
22+
}
23+
],
24+
"identifier":[
25+
{
26+
"system":"https://fhir.nhs.uk/Id/cross-care-setting-identifier",
27+
"value":"f2489066-7082-11eb-bb13-00505692d4aa"
28+
}
29+
],
30+
"status":"active",
31+
"intent":"order",
32+
"medicationCodeableConcept": {
33+
"coding": [
34+
{
35+
"system": "http://snomed.info/sct",
36+
"code": "430127000",
37+
"display": "Oral Form Oxycodone (product)"
38+
}
39+
]
40+
},
41+
"subject":{
42+
"reference":"Patient/2"
43+
},
44+
"authoredOn":"2017-11-10T00:00:00+00:00",
45+
"recorder":{
46+
"reference":"Practitioner/1"
47+
},
48+
"dosageInstruction":[
49+
{
50+
"text":"1 tablet once a day",
51+
"patientInstruction":"Take in morning"
52+
}
53+
],
54+
"dispenseRequest":{
55+
"validityPeriod":{
56+
"start":"2017-11-10T00:00:00+00:00",
57+
"end":"2018-08-15T00:00:00+01:00"
58+
}
59+
},
60+
"basedOn": [
61+
{
62+
"reference": "MedicationRequest/D66D84C9-C073-4EDF-8C2C-F309A83C3DC7"
63+
}
64+
]
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"resourceType": "ReferralRequest",
3+
"id": "2FB2C828-F8EC-11EB-9A03-0242AC139999",
4+
"supportingInfo": [
5+
{
6+
"reference": "MedicationRequest/2F40AD96-F910-11EB-9A03-0242AC139999"
7+
}
8+
]
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<component typeCode="COMP" >
2+
<RequestStatement classCode="OBS" moodCode="RQO">
3+
<id root="II-for-ReferralRequest-2FB2C828-F8EC-11EB-9A03-0242AC139999" />
4+
<code code="3457005" displayName="Patient referral" codeSystem="2.16.840.1.113883.2.1.3.2.4.15"/>
5+
<text>Supporting Information: { Medication: 2021-01-01 Oral Form Oxycodone (product) } </text>
6+
<statusCode code="COMPLETE"/>
7+
<effectiveTime>
8+
<center nullFlavor="NI"/>
9+
</effectiveTime>
10+
<availabilityTime nullFlavor="UNK"/>
11+
</RequestStatement>
12+
</component>

service/src/test/resources/ehr/mapper/referral/fhir-bundle.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,27 @@
489489
}
490490
}
491491
},
492+
{
493+
"resource": {
494+
"resourceType": "MedicationRequest",
495+
"id": "2F40AD96-F910-11EB-9A03-0242AC139999",
496+
"dispenseRequest": {
497+
"validityPeriod": {
498+
"start": "2021-01-01T00:00:00+00:00",
499+
"end": "2021-02-01T00:00:00+01:00"
500+
}
501+
},
502+
"medicationCodeableConcept": {
503+
"coding": [
504+
{
505+
"system": "http://snomed.info/sct",
506+
"code": "430127000",
507+
"display": "Oral Form Oxycodone (product)"
508+
}
509+
]
510+
}
511+
}
512+
},
492513
{
493514
"resource": {
494515
"resourceType": "Medication",

0 commit comments

Comments
 (0)