1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.healthconnect.cts.phr.utils; 18 19 import org.json.JSONArray; 20 import org.json.JSONException; 21 import org.json.JSONObject; 22 23 import java.util.Iterator; 24 import java.util.List; 25 import java.util.Map; 26 27 /** 28 * Test helper class for making medication related FHIR data, including <a 29 * href="https://www.hl7.org/fhir/medication.html">Medication</a>, <a 30 * href="https://www.hl7.org/fhir/medicationrequest.html">MedicationRequest</a> and <a 31 * href="https://www.hl7.org/fhir/medicationstatement.html">MedicationStatement</a>. 32 */ 33 public final class MedicationsBuilder { 34 35 /** 36 * Builder class for creating FHIR <a 37 * href="https://www.hl7.org/fhir/medication.html">Medications</a> 38 */ 39 public static class MedicationBuilder extends FhirResourceBuilder<MedicationBuilder> { 40 41 private static final String DEFAULT_MEDICATION_JSON = 42 "{" 43 + " \"resourceType\": \"Medication\"," 44 + " \"id\": \"med0311\"," 45 + " \"code\": {" 46 + " \"coding\": [" 47 + " {" 48 + " \"system\": \"http://snomed.info/sct\"," 49 + " \"code\": \"373994007\"," 50 + " \"display\": \"Prednisone 5mg tablet (Product)\"" 51 + " }" 52 + " ]" 53 + " }," 54 + " \"form\": {" 55 + " \"coding\": [" 56 + " {" 57 + " \"system\": \"http://snomed.info/sct\"," 58 + " \"code\": \"385055001\"," 59 + " \"display\": \"Tablet dose form (qualifier value)\"" 60 + " }" 61 + " ]" 62 + " }," 63 + " \"ingredient\": [" 64 + " {" 65 + " \"itemReference\": {" 66 + " \"reference\": \"#sub03\"" 67 + " }," 68 + " \"strength\": {" 69 + " \"numerator\": {" 70 + " \"value\": 5," 71 + " \"system\": \"http://unitsofmeasure.org\"," 72 + " \"code\": \"mg\"" 73 + " }," 74 + " \"denominator\": {" 75 + " \"value\": 1," 76 + " \"system\":" 77 + "\"http://terminology.hl7.org/CodeSystem/v3-orderableDrugForm\"," 78 + " \"code\": \"TAB\"" 79 + " }" 80 + " }" 81 + " }" 82 + " ]" 83 + "}"; 84 85 private static final String TYLENOL = 86 "{" 87 + " \"resourceType\": \"Medication\"," 88 + " \"id\": \"med0309\"," 89 + " \"code\": {" 90 + " \"coding\": [" 91 + " {" 92 + " \"system\": \"http://hl7.org/fhir/sid/ndc\"," 93 + " \"code\": \"50580-506-02\"," 94 + " \"display\": \"Tylenol PM\"" 95 + " }" 96 + " ]" 97 + " }," 98 + " \"manufacturer\": {" 99 + " \"reference\": \"#org2\"" 100 + " }," 101 + " \"form\": {" 102 + " \"coding\": [" 103 + " {" 104 + " \"system\": \"http://snomed.info/sct\"," 105 + " \"code\": \"385057009\"," 106 + " \"display\": \"Film-coated tablet (qualifier value)\"" 107 + " }" 108 + " ]" 109 + " }," 110 + " \"ingredient\": [" 111 + " {" 112 + " \"itemCodeableConcept\": {" 113 + " \"coding\": [" 114 + " {" 115 + " \"system\": \"http://www.nlm.nih.gov/research/umls/rxnorm\"," 116 + " \"code\": \"315266\"," 117 + " \"display\": \"Acetaminophen 500 MG\"" 118 + " }" 119 + " ]" 120 + " }," 121 + " \"strength\": {" 122 + " \"numerator\": {" 123 + " \"value\": 500," 124 + " \"system\": \"http://unitsofmeasure.org\"," 125 + " \"code\": \"mg\"" 126 + " }," 127 + " \"denominator\": {" 128 + " \"value\": 1," 129 + " \"system\":" 130 + "\"http://terminology.hl7.org/CodeSystem/v3-orderableDrugForm\"," 131 + " \"code\": \"Tab\"" 132 + " }" 133 + " }" 134 + " }," 135 + " {" 136 + " \"itemCodeableConcept\": {" 137 + " \"coding\": [" 138 + " {" 139 + " \"system\": \"http://www.nlm.nih.gov/research/umls/rxnorm\"," 140 + " \"code\": \"901813\"," 141 + " \"display\": \"Diphenhydramine Hydrochloride 25 mg\"" 142 + " }" 143 + " ]" 144 + " }," 145 + " \"strength\": {" 146 + " \"numerator\": {" 147 + " \"value\": 25," 148 + " \"system\": \"http://unitsofmeasure.org\"," 149 + " \"code\": \"mg\"" 150 + " }," 151 + " \"denominator\": {" 152 + " \"value\": 1," 153 + " \"system\":" 154 + "\"http://terminology.hl7.org/CodeSystem/v3-orderableDrugForm\"," 155 + " \"code\": \"Tab\"" 156 + " }" 157 + " }" 158 + " }" 159 + " ]," 160 + " \"batch\": {" 161 + " \"lotNumber\": \"9494788\"," 162 + " \"expirationDate\": \"2017-05-22\"" 163 + " }" 164 + "}"; 165 MedicationBuilder()166 public MedicationBuilder() { 167 super(DEFAULT_MEDICATION_JSON); 168 } 169 170 /** 171 * Set this medication to be Tylenol. 172 * 173 * @return this builder 174 */ setTylenol()175 public MedicationBuilder setTylenol() { 176 try { 177 JSONObject tylenol = new JSONObject(TYLENOL); 178 Iterator<String> keys = tylenol.keys(); 179 while (keys.hasNext()) { 180 String key = keys.next(); 181 set(key, tylenol.get(key)); 182 } 183 } catch (JSONException e) { 184 throw new IllegalStateException(e); 185 } 186 return this; 187 } 188 189 @Override returnThis()190 protected MedicationBuilder returnThis() { 191 return this; 192 } 193 } 194 195 /** 196 * Builder class for creating FHIR <a 197 * href="https://www.hl7.org/fhir/medicationstatement.html">MedicationStatements</a> 198 */ 199 public static class MedicationStatementR4Builder 200 extends FhirResourceBuilder<MedicationStatementR4Builder> { 201 private static final String DEFAULT_MEDICATION_STATEMENT_JSON = 202 "{" 203 + " \"resourceType\": \"MedicationStatement\"," 204 + " \"id\": \"example001\"," 205 + " \"identifier\": [" 206 + " {" 207 + " \"use\": \"official\"," 208 + " \"system\": \"http://www.bmc.nl/portal/medstatements\"," 209 + " \"value\": \"12345689\"" 210 + " }" 211 + " ]," 212 + " \"status\": \"active\"," 213 + " \"category\": {" 214 + " \"coding\": [" 215 + " {" 216 + " \"system\": " 217 + "\"http://terminology.hl7.org/CodeSystem/medication-statement-category\"," 218 + " \"code\": \"inpatient\"," 219 + " \"display\": \"Inpatient\"" 220 + " }" 221 + " ]" 222 + " }," 223 + " \"medicationReference\": {" 224 + " \"reference\": \"#med0309\"" 225 + " }," 226 + " \"subject\": {" 227 + " \"reference\": \"Patient/pat1\"," 228 + " \"display\": \"Donald Duck\"" 229 + " }," 230 + " \"effectiveDateTime\": \"2015-01-23\"," 231 + " \"dateAsserted\": \"2015-02-22\"," 232 + " \"informationSource\": {" 233 + " \"reference\": \"Patient/pat1\"," 234 + " \"display\": \"Donald Duck\"" 235 + " }," 236 + " \"derivedFrom\": [" 237 + " {" 238 + " \"reference\": \"MedicationRequest/medrx002\"" 239 + " }" 240 + " ]," 241 + " \"reasonCode\": [" 242 + " {" 243 + " \"coding\": [" 244 + " {" 245 + " \"system\": \"http://snomed.info/sct\"," 246 + " \"code\": \"32914008\"," 247 + " \"display\": \"Restless Legs\"" 248 + " }" 249 + " ]" 250 + " }" 251 + " ]," 252 + " \"note\": [" 253 + " {" 254 + " \"text\": \"Patient indicates they miss the occasional dose\"" 255 + " }" 256 + " ]," 257 + " \"dosage\": [" 258 + " {" 259 + " \"sequence\": 1," 260 + " \"text\": \"1-2 tablets once daily at bedtime as needed\"," 261 + " \"additionalInstruction\": [" 262 + " {" 263 + " \"text\": \"Taking at bedtime\"" 264 + " }" 265 + " ]," 266 + " \"timing\": {" 267 + " \"repeat\": {" 268 + " \"frequency\": 1," 269 + " \"period\": 1," 270 + " \"periodUnit\": \"d\"" 271 + " }" 272 + " }," 273 + " \"asNeededCodeableConcept\": {" 274 + " \"coding\": [" 275 + " {" 276 + " \"system\": \"http://snomed.info/sct\"," 277 + " \"code\": \"32914008\"," 278 + " \"display\": \"Restless Legs\"" 279 + " }" 280 + " ]" 281 + " }," 282 + " \"route\": {" 283 + " \"coding\": [" 284 + " {" 285 + " \"system\": \"http://snomed.info/sct\"," 286 + " \"code\": \"26643006\"," 287 + " \"display\": \"Oral Route\"" 288 + " }" 289 + " ]" 290 + " }," 291 + " \"doseAndRate\": [" 292 + " {" 293 + " \"type\": {" 294 + " \"coding\": [" 295 + " {" 296 + " \"system\": " 297 + "\"http://terminology.hl7.org/CodeSystem/dose-rate-type\"," 298 + " \"code\": \"ordered\"," 299 + " \"display\": \"Ordered\"" 300 + " }" 301 + " ]" 302 + " }," 303 + " \"doseRange\": {" 304 + " \"low\": {" 305 + " \"value\": 1," 306 + " \"unit\": \"TAB\"," 307 + " \"system\": " 308 + "\"http://terminology.hl7.org/CodeSystem/v3-orderableDrugForm\"," 309 + " \"code\": \"TAB\"" 310 + " }," 311 + " \"high\": {" 312 + " \"value\": 2," 313 + " \"unit\": \"TAB\"," 314 + " \"system\": " 315 + "\"http://terminology.hl7.org/CodeSystem/v3-orderableDrugForm\"," 316 + " \"code\": \"TAB\"" 317 + " }" 318 + " }" 319 + " }" 320 + " ]" 321 + " }" 322 + " ]" 323 + "}"; 324 MedicationStatementR4Builder()325 public MedicationStatementR4Builder() { 326 super(DEFAULT_MEDICATION_STATEMENT_JSON); 327 } 328 329 /** 330 * Set this medication statement to contain the given medication. 331 * 332 * @param medication the medication to be contained (may be modified). 333 * @return this builder 334 */ setContainedMedication(MedicationBuilder medication)335 public MedicationStatementR4Builder setContainedMedication(MedicationBuilder medication) { 336 String containedId = "med123"; 337 try { 338 set( 339 "contained", 340 new JSONArray( 341 List.of(new JSONObject(medication.setId(containedId).toJson())))); 342 set("medicationReference", new JSONObject(Map.of("reference", "#" + containedId))); 343 } catch (JSONException e) { 344 throw new IllegalArgumentException(e); 345 } 346 return this; 347 } 348 349 @Override returnThis()350 protected MedicationStatementR4Builder returnThis() { 351 return this; 352 } 353 } 354 355 public static class MedicationRequestBuilder 356 extends FhirResourceBuilder<MedicationRequestBuilder> { 357 358 private static final String DEFAULT_REQUEST_JSON = 359 "{" 360 + " \"resourceType\": \"MedicationRequest\"," 361 + " \"id\": \"medrx0331\"," 362 + " \"identifier\": [" 363 + " {" 364 + " \"use\": \"official\"," 365 + " \"system\": \"http://www.bmc.nl/portal/prescriptions\"," 366 + " \"value\": \"12345689\"" 367 + " }" 368 + " ]," 369 + " \"status\": \"active\"," 370 + " \"intent\": \"order\"," 371 + " \"medicationReference\": {" 372 + " \"reference\": \"#med0350\"" 373 + " }," 374 + " \"subject\": {" 375 + " \"reference\": \"Patient/pat1\"," 376 + " \"display\": \"Donald Duck\"" 377 + " }," 378 + " \"authoredOn\": \"2015-01-15\"," 379 + " \"requester\": {" 380 + " \"reference\": \"Practitioner/f007\"," 381 + " \"display\": \"Patrick Pump\"" 382 + " }," 383 + " \"dosageInstruction\": [" 384 + " {" 385 + " \"sequence\": 1," 386 + " \"text\": \"7mg once daily\"," 387 + " \"timing\": {" 388 + " \"repeat\": {" 389 + " \"frequency\": 1," 390 + " \"period\": 1," 391 + " \"periodUnit\": \"d\"" 392 + " }" 393 + " }," 394 + " \"doseAndRate\": [" 395 + " {" 396 + " \"type\": {" 397 + " \"coding\": [" 398 + " {" 399 + " \"system\":" 400 + "\"http://terminology.hl7.org/CodeSystem/dose-rate-type\"," 401 + " \"code\": \"ordered\"," 402 + " \"display\": \"Ordered\"" 403 + " }" 404 + " ]" 405 + " }," 406 + " \"doseQuantity\": {" 407 + " \"value\": 7," 408 + " \"unit\": \"mg\"," 409 + " \"system\": \"http://unitsofmeasure.org\"," 410 + " \"code\": \"mg\"" 411 + " }" 412 + " }" 413 + " ]" 414 + " }" 415 + " ]," 416 + " \"dispenseRequest\": {" 417 + " \"validityPeriod\": {" 418 + " \"start\": \"2015-01-15\"," 419 + " \"end\": \"2016-01-15\"" 420 + " }," 421 + " \"numberOfRepeatsAllowed\": 3," 422 + " \"quantity\": {" 423 + " \"value\": 30," 424 + " \"unit\": \"TAB\"," 425 + " \"system\":" 426 + "\"http://terminology.hl7.org/CodeSystem/v3-orderableDrugForm\"," 427 + " \"code\": \"TAB\"" 428 + " }," 429 + " \"expectedSupplyDuration\": {" 430 + " \"value\": 30," 431 + " \"unit\": \"days\"," 432 + " \"system\": \"http://unitsofmeasure.org\"," 433 + " \"code\": \"d\"" 434 + " }" 435 + " }," 436 + " \"substitution\": {" 437 + " \"allowedBoolean\": true," 438 + " \"reason\": {" 439 + " \"coding\": [" 440 + " {" 441 + " \"system\":" 442 + "\"http://terminology.hl7.org/CodeSystem/v3-ActReason\"," 443 + " \"code\": \"FP\"," 444 + " \"display\": \"formulary policy\"" 445 + " }" 446 + " ]" 447 + " }" 448 + " }" 449 + "}"; 450 MedicationRequestBuilder()451 public MedicationRequestBuilder() { 452 super(DEFAULT_REQUEST_JSON); 453 } 454 455 @Override returnThis()456 protected MedicationRequestBuilder returnThis() { 457 return this; 458 } 459 } 460 461 /** 462 * Returns a builder class that will help build <a 463 * href="https://www.hl7.org/fhir/medication.html">Medication</a> FHIR JSON. 464 */ medication()465 public static MedicationBuilder medication() { 466 return new MedicationBuilder(); 467 } 468 469 /** 470 * Returns a builder class that will help build <a 471 * href="https://www.hl7.org/fhir/medication.html">Medication</a> FHIR JSON, in FHIR version R4 472 * format. 473 */ statementR4()474 public static MedicationStatementR4Builder statementR4() { 475 return new MedicationStatementR4Builder(); 476 } 477 478 /** 479 * Returns a builder class that will help build <a 480 * href="https://www.hl7.org/fhir/medicationrequest.html">MedicationRequest</a> FHIR JSON. 481 */ request()482 public static MedicationRequestBuilder request() { 483 return new MedicationRequestBuilder(); 484 } 485 } 486