@ampath/esm-dispensing-app 1.10.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/.editorconfig +12 -0
  2. package/.eslintignore +2 -0
  3. package/.eslintrc +80 -0
  4. package/.husky/pre-commit +7 -0
  5. package/.husky/pre-push +6 -0
  6. package/.prettierignore +12 -0
  7. package/.tx/config +11 -0
  8. package/.yarn/versions/1c40b9b6.yml +0 -0
  9. package/.yarn/versions/ff162597.yml +0 -0
  10. package/LICENSE +401 -0
  11. package/README.md +124 -0
  12. package/__mocks__/react-i18next.js +51 -0
  13. package/dist/1043.js +1 -0
  14. package/dist/1043.js.map +1 -0
  15. package/dist/1119.js +1 -0
  16. package/dist/1197.js +1 -0
  17. package/dist/2146.js +1 -0
  18. package/dist/2177.js +2 -0
  19. package/dist/2177.js.LICENSE.txt +9 -0
  20. package/dist/2177.js.map +1 -0
  21. package/dist/2690.js +1 -0
  22. package/dist/2890.js +2 -0
  23. package/dist/2890.js.LICENSE.txt +14 -0
  24. package/dist/2890.js.map +1 -0
  25. package/dist/2898.js +1 -0
  26. package/dist/2898.js.map +1 -0
  27. package/dist/3041.js +1 -0
  28. package/dist/3041.js.map +1 -0
  29. package/dist/3099.js +1 -0
  30. package/dist/3184.js +2 -0
  31. package/dist/3184.js.LICENSE.txt +14 -0
  32. package/dist/3184.js.map +1 -0
  33. package/dist/3568.js +1 -0
  34. package/dist/3568.js.map +1 -0
  35. package/dist/3584.js +1 -0
  36. package/dist/4055.js +1 -0
  37. package/dist/4099.js +1 -0
  38. package/dist/4099.js.map +1 -0
  39. package/dist/4132.js +1 -0
  40. package/dist/4225.js +1 -0
  41. package/dist/4225.js.map +1 -0
  42. package/dist/4300.js +1 -0
  43. package/dist/4335.js +1 -0
  44. package/dist/4353.js +1 -0
  45. package/dist/4353.js.map +1 -0
  46. package/dist/439.js +1 -0
  47. package/dist/4618.js +1 -0
  48. package/dist/4652.js +1 -0
  49. package/dist/4944.js +1 -0
  50. package/dist/5173.js +1 -0
  51. package/dist/5241.js +1 -0
  52. package/dist/5422.js +1 -0
  53. package/dist/5422.js.map +1 -0
  54. package/dist/5442.js +1 -0
  55. package/dist/5661.js +1 -0
  56. package/dist/5897.js +1 -0
  57. package/dist/5897.js.map +1 -0
  58. package/dist/6022.js +1 -0
  59. package/dist/609.js +1 -0
  60. package/dist/609.js.map +1 -0
  61. package/dist/6468.js +1 -0
  62. package/dist/6540.js +2 -0
  63. package/dist/6540.js.LICENSE.txt +9 -0
  64. package/dist/6540.js.map +1 -0
  65. package/dist/6589.js +1 -0
  66. package/dist/6606.js +1 -0
  67. package/dist/6606.js.map +1 -0
  68. package/dist/6679.js +1 -0
  69. package/dist/6825.js +1 -0
  70. package/dist/6825.js.map +1 -0
  71. package/dist/6840.js +1 -0
  72. package/dist/6841.js +1 -0
  73. package/dist/6841.js.map +1 -0
  74. package/dist/6859.js +1 -0
  75. package/dist/7097.js +1 -0
  76. package/dist/7159.js +1 -0
  77. package/dist/723.js +1 -0
  78. package/dist/7240.js +1 -0
  79. package/dist/7240.js.map +1 -0
  80. package/dist/7255.js +1 -0
  81. package/dist/7255.js.map +1 -0
  82. package/dist/7617.js +1 -0
  83. package/dist/795.js +1 -0
  84. package/dist/8163.js +1 -0
  85. package/dist/8349.js +1 -0
  86. package/dist/8371.js +1 -0
  87. package/dist/8569.js +2 -0
  88. package/dist/8569.js.LICENSE.txt +41 -0
  89. package/dist/8569.js.map +1 -0
  90. package/dist/8600.js +1 -0
  91. package/dist/8600.js.map +1 -0
  92. package/dist/8618.js +1 -0
  93. package/dist/8885.js +1 -0
  94. package/dist/8885.js.map +1 -0
  95. package/dist/890.js +1 -0
  96. package/dist/9214.js +1 -0
  97. package/dist/9538.js +1 -0
  98. package/dist/9569.js +1 -0
  99. package/dist/961.js +2 -0
  100. package/dist/961.js.LICENSE.txt +19 -0
  101. package/dist/961.js.map +1 -0
  102. package/dist/963.js +1 -0
  103. package/dist/963.js.map +1 -0
  104. package/dist/986.js +1 -0
  105. package/dist/9879.js +1 -0
  106. package/dist/9895.js +1 -0
  107. package/dist/9900.js +1 -0
  108. package/dist/9913.js +1 -0
  109. package/dist/main.js +2 -0
  110. package/dist/main.js.LICENSE.txt +51 -0
  111. package/dist/main.js.map +1 -0
  112. package/dist/openmrs-esm-dispensing-app.js +1 -0
  113. package/dist/openmrs-esm-dispensing-app.js.buildmanifest.json +1645 -0
  114. package/dist/openmrs-esm-dispensing-app.js.map +1 -0
  115. package/dist/routes.json +1 -0
  116. package/e2e/README.md +119 -0
  117. package/e2e/commands/drug-order-operations.ts +43 -0
  118. package/e2e/commands/encounter-operations.ts +60 -0
  119. package/e2e/commands/index.ts +5 -0
  120. package/e2e/commands/patient-operations.ts +109 -0
  121. package/e2e/commands/provider-operations.ts +9 -0
  122. package/e2e/commands/types/index.ts +157 -0
  123. package/e2e/commands/visit-operations.ts +38 -0
  124. package/e2e/core/global-setup.ts +32 -0
  125. package/e2e/core/index.ts +1 -0
  126. package/e2e/core/test.ts +31 -0
  127. package/e2e/fixtures/api.ts +27 -0
  128. package/e2e/fixtures/index.ts +1 -0
  129. package/e2e/pages/dispensing-page.ts +9 -0
  130. package/e2e/pages/index.ts +1 -0
  131. package/e2e/specs/active-prescriptions.spec.ts +72 -0
  132. package/e2e/specs/close-prescription.spec.ts +71 -0
  133. package/e2e/specs/dispense-medication.spec.ts +71 -0
  134. package/e2e/specs/pause-prescription.spec.ts +72 -0
  135. package/e2e/support/github/Dockerfile +34 -0
  136. package/e2e/support/github/docker-compose.yml +24 -0
  137. package/e2e/support/github/run-e2e-docker-env.sh +42 -0
  138. package/e2e/types/index.ts +157 -0
  139. package/example.env +7 -0
  140. package/jest.config.js +24 -0
  141. package/package.json +110 -0
  142. package/playwright.config.ts +36 -0
  143. package/prettier.config.js +8 -0
  144. package/src/components/action-buttons.component.tsx +87 -0
  145. package/src/components/action-buttons.scss +16 -0
  146. package/src/components/action-buttons.test.tsx +217 -0
  147. package/src/components/medication-card.component.tsx +37 -0
  148. package/src/components/medication-card.scss +20 -0
  149. package/src/components/medication-card.test.tsx +36 -0
  150. package/src/components/medication-dispense-review.scss +108 -0
  151. package/src/components/medication-event.component.tsx +96 -0
  152. package/src/components/medication-event.scss +44 -0
  153. package/src/components/medication-event.test.tsx +212 -0
  154. package/src/components/prescription-actions/close-action-button.component.tsx +50 -0
  155. package/src/components/prescription-actions/dispense-action-button.component.tsx +57 -0
  156. package/src/components/prescription-actions/pause-action-button.component.tsx +49 -0
  157. package/src/conditions/conditions.component.tsx +118 -0
  158. package/src/conditions/conditions.resource.ts +100 -0
  159. package/src/conditions/conditions.scss +26 -0
  160. package/src/conditions/conditions.test.tsx +200 -0
  161. package/src/config-schema.ts +192 -0
  162. package/src/constants.ts +22 -0
  163. package/src/dashboard/dispensing-dashboard-link.component.tsx +36 -0
  164. package/src/dashboard/dispensing-dashboard.component.tsx +36 -0
  165. package/src/declarations.d.ts +2 -0
  166. package/src/diagnoses/diagnoses.component.tsx +111 -0
  167. package/src/diagnoses/diagnoses.resource.ts +30 -0
  168. package/src/diagnoses/diagnoses.scss +31 -0
  169. package/src/dispensing-link.component.tsx +9 -0
  170. package/src/dispensing-tiles/dispensing-tile.component.tsx +42 -0
  171. package/src/dispensing-tiles/dispensing-tile.scss +43 -0
  172. package/src/dispensing-tiles/dispensing-tiles.component.tsx +39 -0
  173. package/src/dispensing-tiles/dispensing-tiles.resource.tsx +30 -0
  174. package/src/dispensing-tiles/dispensing-tiles.scss +11 -0
  175. package/src/dispensing.component.tsx +31 -0
  176. package/src/dispensing.scss +5 -0
  177. package/src/dispensing.test.tsx +9 -0
  178. package/src/fill-prescription/fill-prescription-button.component.tsx +103 -0
  179. package/src/fill-prescription/fill-prescription-button.scss +8 -0
  180. package/src/fill-prescription/on-prescription-filled.modal.tsx +140 -0
  181. package/src/fill-prescription/on-prescription-filled.scss +7 -0
  182. package/src/forms/close-dispense-form.workspace.tsx +194 -0
  183. package/src/forms/dispense-form.workspace.test.tsx +334 -0
  184. package/src/forms/dispense-form.workspace.tsx +324 -0
  185. package/src/forms/forms.scss +152 -0
  186. package/src/forms/medication-dispense-review.component.tsx +649 -0
  187. package/src/forms/medication-dispense-review.test.tsx +158 -0
  188. package/src/forms/pause-dispense-form.workspace.tsx +196 -0
  189. package/src/forms/stock-dispense/stock-dispense.component.tsx +126 -0
  190. package/src/forms/stock-dispense/stock.resource.tsx +67 -0
  191. package/src/history/delete-confirm.modal.tsx +35 -0
  192. package/src/history/history-and-comments.component.tsx +338 -0
  193. package/src/history/history-and-comments.scss +54 -0
  194. package/src/index.ts +57 -0
  195. package/src/location/location.resource.test.tsx +108 -0
  196. package/src/location/location.resource.tsx +32 -0
  197. package/src/medication/medication.resource.test.tsx +156 -0
  198. package/src/medication/medication.resource.tsx +45 -0
  199. package/src/medication-dispense/medication-dispense.resource.test.tsx +243 -0
  200. package/src/medication-dispense/medication-dispense.resource.tsx +178 -0
  201. package/src/medication-request/medication-request.resource.test.tsx +1333 -0
  202. package/src/medication-request/medication-request.resource.tsx +257 -0
  203. package/src/patient/patient-info-cell.component.tsx +26 -0
  204. package/src/patient/patient.resources.ts +14 -0
  205. package/src/pharmacy-header/pharmacy-header.component.tsx +35 -0
  206. package/src/pharmacy-header/pharmacy-header.scss +55 -0
  207. package/src/pharmacy-header/pharmacy-illustration.component.tsx +30 -0
  208. package/src/prescriptions/patient-search-tab-panel.component.tsx +58 -0
  209. package/src/prescriptions/patient-search-tab-panel.scss +26 -0
  210. package/src/prescriptions/prescription-actions.component.tsx +24 -0
  211. package/src/prescriptions/prescription-actions.scss +14 -0
  212. package/src/prescriptions/prescription-details.component.tsx +152 -0
  213. package/src/prescriptions/prescription-details.scss +87 -0
  214. package/src/prescriptions/prescription-details.test.tsx +267 -0
  215. package/src/prescriptions/prescription-expanded.component.tsx +58 -0
  216. package/src/prescriptions/prescription-expanded.scss +56 -0
  217. package/src/prescriptions/prescription-tab-lists.component.tsx +70 -0
  218. package/src/prescriptions/prescription-tab-panel.component.tsx +83 -0
  219. package/src/prescriptions/prescriptions-table.component.tsx +189 -0
  220. package/src/prescriptions/prescriptions.scss +152 -0
  221. package/src/print-prescription/prescription-print-action.component.tsx +30 -0
  222. package/src/print-prescription/prescription-print-preview.modal.tsx +92 -0
  223. package/src/print-prescription/prescription-printout.component.tsx +154 -0
  224. package/src/print-prescription/print-prescription.scss +75 -0
  225. package/src/print-prescription/printable-prescriptions.component.tsx +57 -0
  226. package/src/routes.json +137 -0
  227. package/src/types.ts +530 -0
  228. package/src/utils.test.ts +2947 -0
  229. package/src/utils.ts +637 -0
  230. package/tools/i18next-parser.config.js +89 -0
  231. package/tools/setup-tests.ts +8 -0
  232. package/tools/update-openmrs-deps.mjs +42 -0
  233. package/translations/am.json +133 -0
  234. package/translations/ar.json +133 -0
  235. package/translations/ar_SY.json +133 -0
  236. package/translations/bn.json +133 -0
  237. package/translations/cs.json +133 -0
  238. package/translations/de.json +133 -0
  239. package/translations/en.json +133 -0
  240. package/translations/en_US.json +133 -0
  241. package/translations/es.json +133 -0
  242. package/translations/es_MX.json +133 -0
  243. package/translations/fr.json +133 -0
  244. package/translations/he.json +133 -0
  245. package/translations/hi.json +133 -0
  246. package/translations/hi_IN.json +133 -0
  247. package/translations/id.json +133 -0
  248. package/translations/it.json +133 -0
  249. package/translations/ka.json +133 -0
  250. package/translations/km.json +133 -0
  251. package/translations/ku.json +133 -0
  252. package/translations/ky.json +133 -0
  253. package/translations/lg.json +133 -0
  254. package/translations/ne.json +133 -0
  255. package/translations/pl.json +133 -0
  256. package/translations/pt.json +133 -0
  257. package/translations/pt_BR.json +133 -0
  258. package/translations/qu.json +133 -0
  259. package/translations/ro_RO.json +133 -0
  260. package/translations/ru_RU.json +133 -0
  261. package/translations/si.json +133 -0
  262. package/translations/sq.json +133 -0
  263. package/translations/sw.json +133 -0
  264. package/translations/sw_KE.json +133 -0
  265. package/translations/tr.json +133 -0
  266. package/translations/tr_TR.json +133 -0
  267. package/translations/uk.json +133 -0
  268. package/translations/uz.json +133 -0
  269. package/translations/uz@Latn.json +133 -0
  270. package/translations/uz_UZ.json +133 -0
  271. package/translations/vi.json +133 -0
  272. package/translations/zh.json +133 -0
  273. package/translations/zh_CN.json +133 -0
  274. package/translations/zh_TW.json +133 -0
  275. package/tsconfig.json +23 -0
  276. package/turbo.json +41 -0
  277. package/webpack.config.js +1 -0
@@ -0,0 +1,2947 @@
1
+ import dayjs from 'dayjs';
2
+ import {
3
+ type Coding,
4
+ type DosageInstruction,
5
+ type Medication,
6
+ type MedicationDispense,
7
+ MedicationDispenseStatus,
8
+ type MedicationReferenceOrCodeableConcept,
9
+ type MedicationRequest,
10
+ type MedicationRequestBundle,
11
+ MedicationRequestCombinedStatus,
12
+ MedicationRequestFulfillerStatus,
13
+ MedicationRequestStatus,
14
+ } from './types';
15
+ import {
16
+ calculateIsFreeTextDosage,
17
+ computeMedicationRequestCombinedStatus,
18
+ computeMedicationRequestStatus,
19
+ computeNewFulfillerStatusAfterDelete,
20
+ computeNewFulfillerStatusAfterDispenseEvent,
21
+ computePrescriptionStatus,
22
+ computeQuantityRemaining,
23
+ computeTotalQuantityDispensed,
24
+ computeTotalQuantityOrdered,
25
+ getAssociatedMedicationDispenses,
26
+ getAssociatedMedicationRequest,
27
+ getConceptCoding,
28
+ getConceptCodingDisplay,
29
+ getConceptCodingUuid,
30
+ getDosageInstruction,
31
+ getMedicationDisplay,
32
+ getMedicationReferenceOrCodeableConcept,
33
+ getMedicationsByConceptEndpoint,
34
+ getMostRecentMedicationDispenseStatus,
35
+ getNextMostRecentMedicationDispenseStatus,
36
+ getOpenMRSMedicineDrugName,
37
+ getPrescriptionDetailsEndpoint,
38
+ getPrescriptionTableEndpoint,
39
+ getQuantity,
40
+ getQuantityUnitsMatch,
41
+ getRefillsAllowed,
42
+ isMostRecentMedicationDispense,
43
+ } from './utils';
44
+
45
+ describe('Util Tests', () => {
46
+ describe('test computeMedicationRequestCombinedStatus', () => {
47
+ test('should return on-hold if status active and fulfiller status on-hold', () => {
48
+ const medicationRequest: MedicationRequest = {
49
+ dispenseRequest: {
50
+ numberOfRepeatsAllowed: 0,
51
+ quantity: undefined,
52
+ validityPeriod: { start: '' },
53
+ },
54
+ dosageInstruction: undefined,
55
+ encounter: { reference: '', type: '' },
56
+ id: '',
57
+ intent: '',
58
+ medicationReference: { display: '', reference: '', type: '' },
59
+ meta: { lastUpdated: '' },
60
+ priority: '',
61
+ requester: {
62
+ display: '',
63
+ identifier: { value: '' },
64
+ reference: '',
65
+ type: '',
66
+ },
67
+ resourceType: '',
68
+ status: MedicationRequestStatus.active,
69
+ subject: { display: '', reference: '', type: '' },
70
+ extension: [
71
+ {
72
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
73
+ valueCode: MedicationRequestFulfillerStatus.on_hold,
74
+ },
75
+ ],
76
+ };
77
+ expect(computeMedicationRequestCombinedStatus(medicationRequest, 90)).toBe(
78
+ MedicationRequestCombinedStatus.on_hold,
79
+ );
80
+ });
81
+ test('should return declined if status active and fulfiller status declined', () => {
82
+ const medicationRequest: MedicationRequest = {
83
+ dispenseRequest: {
84
+ numberOfRepeatsAllowed: 0,
85
+ quantity: undefined,
86
+ validityPeriod: { start: '' },
87
+ },
88
+ dosageInstruction: undefined,
89
+ encounter: { reference: '', type: '' },
90
+ id: '',
91
+ intent: '',
92
+ medicationReference: { display: '', reference: '', type: '' },
93
+ meta: { lastUpdated: '' },
94
+ priority: '',
95
+ requester: {
96
+ display: '',
97
+ identifier: { value: '' },
98
+ reference: '',
99
+ type: '',
100
+ },
101
+ resourceType: '',
102
+ status: MedicationRequestStatus.active,
103
+ subject: { display: '', reference: '', type: '' },
104
+ extension: [
105
+ {
106
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
107
+ valueCode: MedicationRequestFulfillerStatus.declined,
108
+ },
109
+ ],
110
+ };
111
+ expect(computeMedicationRequestCombinedStatus(medicationRequest, 90)).toBe(
112
+ MedicationRequestCombinedStatus.declined,
113
+ );
114
+ });
115
+ test('should return completed if status completed and fulfiller status completed', () => {
116
+ const medicationRequest: MedicationRequest = {
117
+ dispenseRequest: {
118
+ numberOfRepeatsAllowed: 0,
119
+ quantity: undefined,
120
+ validityPeriod: { start: '' },
121
+ },
122
+ dosageInstruction: undefined,
123
+ encounter: { reference: '', type: '' },
124
+ id: '',
125
+ intent: '',
126
+ medicationReference: { display: '', reference: '', type: '' },
127
+ meta: { lastUpdated: '' },
128
+ priority: '',
129
+ requester: {
130
+ display: '',
131
+ identifier: { value: '' },
132
+ reference: '',
133
+ type: '',
134
+ },
135
+ resourceType: '',
136
+ status: MedicationRequestStatus.completed,
137
+ subject: { display: '', reference: '', type: '' },
138
+ extension: [
139
+ {
140
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
141
+ valueCode: MedicationRequestFulfillerStatus.completed,
142
+ },
143
+ ],
144
+ };
145
+ expect(computeMedicationRequestCombinedStatus(medicationRequest, 90)).toBe(
146
+ MedicationRequestCombinedStatus.completed,
147
+ );
148
+ });
149
+ test('should return cancelled if status cancelled and no fulfiller status', () => {
150
+ const medicationRequest: MedicationRequest = {
151
+ dispenseRequest: {
152
+ numberOfRepeatsAllowed: 0,
153
+ quantity: undefined,
154
+ validityPeriod: { start: '' },
155
+ },
156
+ dosageInstruction: undefined,
157
+ encounter: { reference: '', type: '' },
158
+ id: '',
159
+ intent: '',
160
+ medicationReference: { display: '', reference: '', type: '' },
161
+ meta: { lastUpdated: '' },
162
+ priority: '',
163
+ requester: {
164
+ display: '',
165
+ identifier: { value: '' },
166
+ reference: '',
167
+ type: '',
168
+ },
169
+ resourceType: '',
170
+ status: MedicationRequestStatus.cancelled,
171
+ subject: { display: '', reference: '', type: '' },
172
+ };
173
+ expect(computeMedicationRequestCombinedStatus(medicationRequest, 90)).toBe(
174
+ MedicationRequestCombinedStatus.cancelled,
175
+ );
176
+ });
177
+ test('should return cancelled if status cancelled and fulfiller on-hold', () => {
178
+ const medicationRequest: MedicationRequest = {
179
+ dispenseRequest: {
180
+ numberOfRepeatsAllowed: 0,
181
+ quantity: undefined,
182
+ validityPeriod: { start: '' },
183
+ },
184
+ dosageInstruction: undefined,
185
+ encounter: { reference: '', type: '' },
186
+ id: '',
187
+ intent: '',
188
+ medicationReference: { display: '', reference: '', type: '' },
189
+ meta: { lastUpdated: '' },
190
+ priority: '',
191
+ requester: {
192
+ display: '',
193
+ identifier: { value: '' },
194
+ reference: '',
195
+ type: '',
196
+ },
197
+ resourceType: '',
198
+ status: MedicationRequestStatus.cancelled,
199
+ subject: { display: '', reference: '', type: '' },
200
+ extension: [
201
+ {
202
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
203
+ valueCode: MedicationRequestFulfillerStatus.on_hold,
204
+ },
205
+ ],
206
+ };
207
+ expect(computeMedicationRequestCombinedStatus(medicationRequest, 90)).toBe(
208
+ MedicationRequestCombinedStatus.cancelled,
209
+ );
210
+ });
211
+ test('should return cancelled if status cancelled and fulfiller declined', () => {
212
+ const medicationRequest: MedicationRequest = {
213
+ dispenseRequest: {
214
+ numberOfRepeatsAllowed: 0,
215
+ quantity: undefined,
216
+ validityPeriod: { start: '' },
217
+ },
218
+ dosageInstruction: undefined,
219
+ encounter: { reference: '', type: '' },
220
+ id: '',
221
+ intent: '',
222
+ medicationReference: { display: '', reference: '', type: '' },
223
+ meta: { lastUpdated: '' },
224
+ priority: '',
225
+ requester: {
226
+ display: '',
227
+ identifier: { value: '' },
228
+ reference: '',
229
+ type: '',
230
+ },
231
+ resourceType: '',
232
+ status: MedicationRequestStatus.cancelled,
233
+ subject: { display: '', reference: '', type: '' },
234
+ extension: [
235
+ {
236
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
237
+ valueCode: MedicationRequestFulfillerStatus.declined,
238
+ },
239
+ ],
240
+ };
241
+ expect(computeMedicationRequestCombinedStatus(medicationRequest, 90)).toBe(
242
+ MedicationRequestCombinedStatus.cancelled,
243
+ );
244
+ });
245
+ test('should return expired if validity period over 90 days ago and no fulfiller status', () => {
246
+ const medicationRequest: MedicationRequest = {
247
+ dispenseRequest: {
248
+ numberOfRepeatsAllowed: 0,
249
+ quantity: undefined,
250
+ validityPeriod: { start: '2020-04-04' },
251
+ },
252
+ dosageInstruction: undefined,
253
+ encounter: { reference: '', type: '' },
254
+ id: '',
255
+ intent: '',
256
+ medicationReference: { display: '', reference: '', type: '' },
257
+ meta: { lastUpdated: '' },
258
+ priority: '',
259
+ requester: {
260
+ display: '',
261
+ identifier: { value: '' },
262
+ reference: '',
263
+ type: '',
264
+ },
265
+ resourceType: '',
266
+ status: MedicationRequestStatus.active,
267
+ subject: { display: '', reference: '', type: '' },
268
+ };
269
+ expect(computeMedicationRequestCombinedStatus(medicationRequest, 90)).toBe(
270
+ MedicationRequestCombinedStatus.expired,
271
+ );
272
+ });
273
+ test('should return expired if validity period over 90 days and fulfiller status on-hold', () => {
274
+ const medicationRequest: MedicationRequest = {
275
+ dispenseRequest: {
276
+ numberOfRepeatsAllowed: 0,
277
+ quantity: undefined,
278
+ validityPeriod: { start: '2020-04-04' },
279
+ },
280
+ dosageInstruction: undefined,
281
+ encounter: { reference: '', type: '' },
282
+ id: '',
283
+ intent: '',
284
+ medicationReference: { display: '', reference: '', type: '' },
285
+ meta: { lastUpdated: '' },
286
+ priority: '',
287
+ requester: {
288
+ display: '',
289
+ identifier: { value: '' },
290
+ reference: '',
291
+ type: '',
292
+ },
293
+ resourceType: '',
294
+ status: MedicationRequestStatus.active,
295
+ subject: { display: '', reference: '', type: '' },
296
+ extension: [
297
+ {
298
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
299
+ valueCode: MedicationRequestFulfillerStatus.on_hold,
300
+ },
301
+ ],
302
+ };
303
+ expect(computeMedicationRequestCombinedStatus(medicationRequest, 90)).toBe(
304
+ MedicationRequestCombinedStatus.expired,
305
+ );
306
+ });
307
+ test('should return expired if validity period over 90 days and fulfiller status declined', () => {
308
+ const medicationRequest: MedicationRequest = {
309
+ dispenseRequest: {
310
+ numberOfRepeatsAllowed: 0,
311
+ quantity: undefined,
312
+ validityPeriod: { start: '2020-04-04' },
313
+ },
314
+ dosageInstruction: undefined,
315
+ encounter: { reference: '', type: '' },
316
+ id: '',
317
+ intent: '',
318
+ medicationReference: { display: '', reference: '', type: '' },
319
+ meta: { lastUpdated: '' },
320
+ priority: '',
321
+ requester: {
322
+ display: '',
323
+ identifier: { value: '' },
324
+ reference: '',
325
+ type: '',
326
+ },
327
+ resourceType: '',
328
+ status: MedicationRequestStatus.active,
329
+ subject: { display: '', reference: '', type: '' },
330
+ extension: [
331
+ {
332
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
333
+ valueCode: MedicationRequestFulfillerStatus.declined,
334
+ },
335
+ ],
336
+ };
337
+ expect(computeMedicationRequestCombinedStatus(medicationRequest, 90)).toBe(
338
+ MedicationRequestCombinedStatus.expired,
339
+ );
340
+ });
341
+ });
342
+
343
+ describe('test computeMedicationRequestStatus', () => {
344
+ test('should return Cancelled if Medication Request has status cancelled', () => {
345
+ const medicationRequest: MedicationRequest = {
346
+ dispenseRequest: {
347
+ numberOfRepeatsAllowed: 0,
348
+ quantity: undefined,
349
+ validityPeriod: { start: '' },
350
+ },
351
+ dosageInstruction: undefined,
352
+ encounter: { reference: '', type: '' },
353
+ id: '',
354
+ intent: '',
355
+ medicationReference: { display: '', reference: '', type: '' },
356
+ meta: { lastUpdated: '' },
357
+ priority: '',
358
+ requester: {
359
+ display: '',
360
+ identifier: { value: '' },
361
+ reference: '',
362
+ type: '',
363
+ },
364
+ resourceType: '',
365
+ status: MedicationRequestStatus.cancelled,
366
+ subject: { display: '', reference: '', type: '' },
367
+ };
368
+ expect(computeMedicationRequestStatus(medicationRequest, 0)).toBe(MedicationRequestStatus.cancelled);
369
+ });
370
+ test('should return Completed if Medication Request has status completed', () => {
371
+ const medicationRequest: MedicationRequest = {
372
+ dispenseRequest: {
373
+ numberOfRepeatsAllowed: 0,
374
+ quantity: undefined,
375
+ validityPeriod: { start: '' },
376
+ },
377
+ dosageInstruction: undefined,
378
+ encounter: { reference: '', type: '' },
379
+ id: '',
380
+ intent: '',
381
+ medicationReference: { display: '', reference: '', type: '' },
382
+ meta: { lastUpdated: '' },
383
+ priority: '',
384
+ requester: {
385
+ display: '',
386
+ identifier: { value: '' },
387
+ reference: '',
388
+ type: '',
389
+ },
390
+ resourceType: '',
391
+ status: MedicationRequestStatus.completed,
392
+ subject: { display: '', reference: '', type: '' },
393
+ };
394
+ expect(computeMedicationRequestStatus(medicationRequest, 0)).toBe(MedicationRequestStatus.completed);
395
+ });
396
+ test('should return Expired if Medication Request older than expired timeframe', () => {
397
+ const medicationRequest: MedicationRequest = {
398
+ dispenseRequest: {
399
+ numberOfRepeatsAllowed: 0,
400
+ quantity: undefined,
401
+ validityPeriod: { start: dayjs().subtract(91, 'days').toString() },
402
+ },
403
+ dosageInstruction: undefined,
404
+ encounter: { reference: '', type: '' },
405
+ id: '',
406
+ intent: '',
407
+ medicationReference: { display: '', reference: '', type: '' },
408
+ meta: { lastUpdated: '' },
409
+ priority: '',
410
+ requester: {
411
+ display: '',
412
+ identifier: { value: '' },
413
+ reference: '',
414
+ type: '',
415
+ },
416
+ resourceType: '',
417
+ status: null,
418
+ subject: { display: '', reference: '', type: '' },
419
+ };
420
+ expect(computeMedicationRequestStatus(medicationRequest, 90)).toBe(MedicationRequestStatus.expired);
421
+ });
422
+ test('should return Expired if Medication Request age is passed expired timeframe', () => {
423
+ const medicationRequest: MedicationRequest = {
424
+ dispenseRequest: {
425
+ numberOfRepeatsAllowed: 0,
426
+ quantity: undefined,
427
+ validityPeriod: { start: dayjs().subtract(91, 'days').toString() },
428
+ },
429
+ dosageInstruction: undefined,
430
+ encounter: { reference: '', type: '' },
431
+ id: '',
432
+ intent: '',
433
+ medicationReference: { display: '', reference: '', type: '' },
434
+ meta: { lastUpdated: '' },
435
+ priority: '',
436
+ requester: {
437
+ display: '',
438
+ identifier: { value: '' },
439
+ reference: '',
440
+ type: '',
441
+ },
442
+ resourceType: '',
443
+ status: null,
444
+ subject: { display: '', reference: '', type: '' },
445
+ };
446
+ expect(computeMedicationRequestStatus(medicationRequest, 90)).toBe(MedicationRequestStatus.expired);
447
+ });
448
+ test('should return Active if Medication Request age is equal to expired timeframe (even if status is expired)', () => {
449
+ const medicationRequest: MedicationRequest = {
450
+ dispenseRequest: {
451
+ numberOfRepeatsAllowed: 0,
452
+ quantity: undefined,
453
+ validityPeriod: {
454
+ start: dayjs().startOf('day').subtract(90, 'days').toString(),
455
+ },
456
+ },
457
+ dosageInstruction: undefined,
458
+ encounter: { reference: '', type: '' },
459
+ id: '',
460
+ intent: '',
461
+ medicationReference: { display: '', reference: '', type: '' },
462
+ meta: { lastUpdated: '' },
463
+ priority: '',
464
+ requester: {
465
+ display: '',
466
+ identifier: { value: '' },
467
+ reference: '',
468
+ type: '',
469
+ },
470
+ resourceType: '',
471
+ status: MedicationRequestStatus.expired,
472
+ subject: { display: '', reference: '', type: '' },
473
+ };
474
+ expect(computeMedicationRequestStatus(medicationRequest, 90)).toBe(MedicationRequestStatus.active);
475
+ });
476
+ test('should return Active if Medication Request is age is less than expired timeframe (even if status is expired)', () => {
477
+ const medicationRequest: MedicationRequest = {
478
+ dispenseRequest: {
479
+ numberOfRepeatsAllowed: 0,
480
+ quantity: undefined,
481
+ validityPeriod: {
482
+ start: dayjs().startOf('day').subtract(90, 'days').toString(),
483
+ },
484
+ },
485
+ dosageInstruction: undefined,
486
+ encounter: { reference: '', type: '' },
487
+ id: '',
488
+ intent: '',
489
+ medicationReference: { display: '', reference: '', type: '' },
490
+ meta: { lastUpdated: '' },
491
+ priority: '',
492
+ requester: {
493
+ display: '',
494
+ identifier: { value: '' },
495
+ reference: '',
496
+ type: '',
497
+ },
498
+ resourceType: '',
499
+ status: MedicationRequestStatus.expired,
500
+ subject: { display: '', reference: '', type: '' },
501
+ };
502
+ expect(computeMedicationRequestStatus(medicationRequest, 90)).toBe(MedicationRequestStatus.active);
503
+ });
504
+ test('should return Active as default', () => {
505
+ const medicationRequest: MedicationRequest = {
506
+ dispenseRequest: {
507
+ numberOfRepeatsAllowed: 0,
508
+ quantity: undefined,
509
+ validityPeriod: { start: '' },
510
+ },
511
+ dosageInstruction: undefined,
512
+ encounter: { reference: '', type: '' },
513
+ id: '',
514
+ intent: '',
515
+ medicationReference: { display: '', reference: '', type: '' },
516
+ meta: { lastUpdated: '' },
517
+ priority: '',
518
+ requester: {
519
+ display: '',
520
+ identifier: { value: '' },
521
+ reference: '',
522
+ type: '',
523
+ },
524
+ resourceType: '',
525
+ status: null,
526
+ subject: { display: '', reference: '', type: '' },
527
+ };
528
+ expect(computeMedicationRequestStatus(medicationRequest, 90)).toBe(MedicationRequestStatus.active);
529
+ });
530
+ });
531
+
532
+ describe('test computeNewFulfillerStatusAfterDelete', () => {
533
+ const medicationRequest: MedicationRequest = {
534
+ id: '1c1ad91e-8653-453a-9f59-8d5c36249aff',
535
+ dispenseRequest: {
536
+ numberOfRepeatsAllowed: undefined,
537
+ quantity: {
538
+ value: 30,
539
+ unit: 'mg',
540
+ code: '123abc',
541
+ },
542
+ validityPeriod: { start: '' },
543
+ },
544
+ dosageInstruction: undefined,
545
+ encounter: { reference: '', type: '' },
546
+ intent: '',
547
+ medicationReference: { display: '', reference: '', type: '' },
548
+ meta: { lastUpdated: '' },
549
+ priority: '',
550
+ requester: {
551
+ display: '',
552
+ identifier: { value: '' },
553
+ reference: '',
554
+ type: '',
555
+ },
556
+ resourceType: 'MedicationRequest',
557
+ status: MedicationRequestStatus.completed,
558
+ subject: { display: '', reference: '', type: '' },
559
+ extension: [
560
+ {
561
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
562
+ valueCode: MedicationRequestFulfillerStatus.declined,
563
+ },
564
+ ],
565
+ };
566
+
567
+ const medicationDispenseCompleteMostRecent: MedicationDispense = {
568
+ dosageInstruction: undefined,
569
+ id: 'ab663520-8b5f-4afe-a333-5196f69ccea7',
570
+ extension: [
571
+ {
572
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
573
+ valueDateTime: '2023-01-05T14:00:00-05:00',
574
+ },
575
+ ],
576
+ authorizingPrescription: [
577
+ {
578
+ reference: 'MedicationRequest/',
579
+ type: 'MedicationRequest',
580
+ },
581
+ ],
582
+ location: { display: '', reference: '', type: '' },
583
+ medicationReference: { display: '', reference: '', type: '' },
584
+ meta: { lastUpdated: '' },
585
+ quantity: {
586
+ value: 5,
587
+ unit: 'mg',
588
+ code: '123abc',
589
+ },
590
+ performer: undefined,
591
+ resourceType: 'MedicationDispense',
592
+ status: MedicationDispenseStatus.completed,
593
+ subject: { display: '', reference: '', type: '' },
594
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
595
+ type: undefined,
596
+ whenHandedOver: '2023-01-05T14:00:00-05:00',
597
+ whenPrepared: '2023-01-05T14:00:00-05:00',
598
+ };
599
+
600
+ const medicationDispenseDeclined: MedicationDispense = {
601
+ dosageInstruction: undefined,
602
+ id: '9f7987e8-95c6-42f3-96e6-fd2eaa3134a5',
603
+ extension: [
604
+ {
605
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
606
+ valueDateTime: '2023-01-04T14:00:00-05:00',
607
+ },
608
+ ],
609
+ authorizingPrescription: [
610
+ {
611
+ reference: 'MedicationRequest/1c1ad91e-8653-453a-9f59-8d5c36249aff',
612
+ type: 'MedicationRequest',
613
+ },
614
+ ],
615
+ location: { display: '', reference: '', type: '' },
616
+ medicationReference: { display: '', reference: '', type: '' },
617
+ meta: { lastUpdated: '' },
618
+ quantity: {
619
+ value: 5,
620
+ unit: 'mg',
621
+ code: '123abc',
622
+ },
623
+ performer: undefined,
624
+ resourceType: 'MedicationDispense',
625
+ status: MedicationDispenseStatus.declined,
626
+ subject: { display: '', reference: '', type: '' },
627
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
628
+ type: undefined,
629
+ whenHandedOver: '2023-01-04T14:00:00-05:00',
630
+ whenPrepared: '2023-01-04T14:00:00-05:00',
631
+ };
632
+
633
+ const medicationDispenseOnHold: MedicationDispense = {
634
+ dosageInstruction: undefined,
635
+ id: 'e2bf7117-aa87-4a92-9e61-f985f29a82aa',
636
+ extension: [
637
+ {
638
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
639
+ valueDateTime: '2023-01-03T14:00:00-05:00',
640
+ },
641
+ ],
642
+ authorizingPrescription: [
643
+ {
644
+ reference: 'MedicationRequest/1c1ad91e-8653-453a-9f59-8d5c36249aff',
645
+ type: 'MedicationRequest',
646
+ },
647
+ ],
648
+ location: { display: '', reference: '', type: '' },
649
+ medicationReference: { display: '', reference: '', type: '' },
650
+ meta: { lastUpdated: '' },
651
+ quantity: {
652
+ value: 5,
653
+ unit: 'mg',
654
+ code: '123abc',
655
+ },
656
+ performer: undefined,
657
+ resourceType: 'MedicationDispense',
658
+ status: MedicationDispenseStatus.on_hold,
659
+ subject: { display: '', reference: '', type: '' },
660
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
661
+ type: undefined,
662
+ whenHandedOver: '2023-01-03T14:00:00-05:00',
663
+ whenPrepared: '2023-01-03T14:00:00-05:00',
664
+ };
665
+
666
+ const medicationDispenseCompleteOldest: MedicationDispense = {
667
+ dosageInstruction: undefined,
668
+ id: '7fd2dcd2-6621-444d-9054-fe1d36acf498',
669
+ extension: [
670
+ {
671
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
672
+ valueDateTime: '2023-01-01T14:00:00-05:00',
673
+ },
674
+ ],
675
+ authorizingPrescription: [
676
+ {
677
+ reference: 'MedicationRequest/',
678
+ type: 'MedicationRequest',
679
+ },
680
+ ],
681
+ location: { display: '', reference: '', type: '' },
682
+ medicationReference: { display: '', reference: '', type: '' },
683
+ meta: { lastUpdated: '' },
684
+ quantity: {
685
+ value: 5,
686
+ unit: 'mg',
687
+ code: '123abc',
688
+ },
689
+ performer: undefined,
690
+ resourceType: 'MedicationDispense',
691
+ status: MedicationDispenseStatus.completed,
692
+ subject: { display: '', reference: '', type: '' },
693
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
694
+ type: undefined,
695
+ whenHandedOver: '2023-01-01T14:00:00-05:00',
696
+ whenPrepared: '2023-01-01T14:00:00-05:00',
697
+ };
698
+
699
+ test('should return declined if deleting most recent medication dispense and next most recent status declined', () => {
700
+ const medicationRequestBundle: MedicationRequestBundle = {
701
+ request: medicationRequest,
702
+ dispenses: [
703
+ medicationDispenseCompleteMostRecent,
704
+ medicationDispenseDeclined,
705
+ medicationDispenseOnHold,
706
+ medicationDispenseCompleteOldest,
707
+ ],
708
+ };
709
+
710
+ expect(
711
+ computeNewFulfillerStatusAfterDelete(medicationDispenseCompleteMostRecent, medicationRequestBundle, false),
712
+ ).toBe(MedicationRequestFulfillerStatus.declined);
713
+ }),
714
+ test('should return on-hold if deleting most recent medication dispense next most recent status on-hold', () => {
715
+ const medicationRequestBundle: MedicationRequestBundle = {
716
+ request: medicationRequest,
717
+ dispenses: [medicationDispenseCompleteMostRecent, medicationDispenseOnHold, medicationDispenseCompleteOldest],
718
+ };
719
+
720
+ expect(
721
+ computeNewFulfillerStatusAfterDelete(medicationDispenseCompleteMostRecent, medicationRequestBundle, false),
722
+ ).toBe(MedicationRequestFulfillerStatus.on_hold);
723
+ }),
724
+ test('should return null if deleting only medication dispense', () => {
725
+ const medicationRequestBundle: MedicationRequestBundle = {
726
+ request: medicationRequest,
727
+ dispenses: [medicationDispenseCompleteMostRecent],
728
+ };
729
+
730
+ expect(
731
+ computeNewFulfillerStatusAfterDelete(medicationDispenseCompleteMostRecent, medicationRequestBundle, false),
732
+ ).toBeNull();
733
+ }),
734
+ test('should return current fulfiller status if not most recent medication dispense and deleted dispense does not have status of completed', () => {
735
+ const medicationRequestBundle: MedicationRequestBundle = {
736
+ request: medicationRequest,
737
+ dispenses: [medicationDispenseDeclined, medicationDispenseOnHold, medicationDispenseCompleteMostRecent],
738
+ };
739
+
740
+ expect(computeNewFulfillerStatusAfterDelete(medicationDispenseOnHold, medicationRequestBundle, false)).toBe(
741
+ MedicationRequestFulfillerStatus.completed,
742
+ );
743
+ });
744
+ test('should return null if deleting a dispense with status completed', () => {
745
+ const medicationRequestBundle: MedicationRequestBundle = {
746
+ request: medicationRequest,
747
+ dispenses: [medicationDispenseCompleteMostRecent],
748
+ };
749
+
750
+ expect(
751
+ computeNewFulfillerStatusAfterDelete(medicationDispenseCompleteOldest, medicationRequestBundle, false),
752
+ ).toBe(null);
753
+ });
754
+ });
755
+
756
+ describe('test computeNewFulfillerStatusAfterDispenseEvent', () => {
757
+ const medicationRequest: MedicationRequest = {
758
+ id: '1c1ad91e-8653-453a-9f59-8d5c36249aff',
759
+ dispenseRequest: {
760
+ numberOfRepeatsAllowed: undefined,
761
+ quantity: {
762
+ value: 30,
763
+ unit: 'mg',
764
+ code: '123abc',
765
+ },
766
+ validityPeriod: { start: '' },
767
+ },
768
+ dosageInstruction: undefined,
769
+ encounter: { reference: '', type: '' },
770
+ intent: '',
771
+ medicationReference: { display: '', reference: '', type: '' },
772
+ meta: { lastUpdated: '' },
773
+ priority: '',
774
+ requester: {
775
+ display: '',
776
+ identifier: { value: '' },
777
+ reference: '',
778
+ type: '',
779
+ },
780
+ resourceType: 'MedicationRequest',
781
+ status: null,
782
+ subject: { display: '', reference: '', type: '' },
783
+ extension: [
784
+ {
785
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
786
+ valueCode: MedicationRequestFulfillerStatus.completed,
787
+ },
788
+ ],
789
+ };
790
+
791
+ const newMedicationDispense: MedicationDispense = {
792
+ // ie quantity dispense = quantity ordered
793
+ dosageInstruction: undefined,
794
+ id: '',
795
+ extension: [
796
+ {
797
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
798
+ valueDateTime: '',
799
+ },
800
+ ],
801
+ authorizingPrescription: [
802
+ {
803
+ reference: 'MedicationRequest/',
804
+ type: 'MedicationRequest',
805
+ },
806
+ ],
807
+ location: { display: '', reference: '', type: '' },
808
+ medicationReference: { display: '', reference: '', type: '' },
809
+ meta: { lastUpdated: '' },
810
+ quantity: {
811
+ value: null,
812
+ unit: 'mg',
813
+ code: '123abc',
814
+ },
815
+ performer: undefined,
816
+ resourceType: 'MedicationDispense',
817
+ status: null,
818
+ subject: { display: '', reference: '', type: '' },
819
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
820
+ type: undefined,
821
+ whenHandedOver: '',
822
+ whenPrepared: '',
823
+ };
824
+
825
+ const existingMedicationDispense: MedicationDispense = {
826
+ // ie quantity dispense = quantity ordered
827
+ dosageInstruction: undefined,
828
+ id: 'ab663520-8b5f-4afe-a333-5196f69ccea7',
829
+ extension: [
830
+ {
831
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
832
+ valueDateTime: '',
833
+ },
834
+ ],
835
+ authorizingPrescription: [
836
+ {
837
+ reference: 'MedicationRequest/',
838
+ type: 'MedicationRequest',
839
+ },
840
+ ],
841
+ location: { display: '', reference: '', type: '' },
842
+ medicationReference: { display: '', reference: '', type: '' },
843
+ meta: { lastUpdated: '' },
844
+ quantity: {
845
+ value: null,
846
+ unit: 'mg',
847
+ code: '123abc',
848
+ },
849
+ performer: undefined,
850
+ resourceType: 'MedicationDispense',
851
+ status: null,
852
+ subject: { display: '', reference: '', type: '' },
853
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
854
+ type: undefined,
855
+ whenHandedOver: '',
856
+ whenPrepared: '',
857
+ };
858
+
859
+ test('when adding new dispense should return null even if dispense meets or exceeds quantity if restrict total quantity dispensed config is false', () => {
860
+ newMedicationDispense.extension[0].valueDateTime = '2023-01-03T14:00:00-05:00';
861
+ newMedicationDispense.whenHandedOver = '2023-01-03T14:00:00-05:00';
862
+ newMedicationDispense.whenPrepared = '2023-01-03T14:00:00-05:00';
863
+ newMedicationDispense.status = MedicationDispenseStatus.completed;
864
+ newMedicationDispense.quantity.value = 30;
865
+ expect(
866
+ computeNewFulfillerStatusAfterDispenseEvent(
867
+ newMedicationDispense,
868
+ { request: medicationRequest, dispenses: [] },
869
+ false,
870
+ ),
871
+ ).toBeNull();
872
+ });
873
+
874
+ test('when adding new dispense should return on-hold if status of new dispense is on-hold and if restrict total quantity dispensed config is false', () => {
875
+ newMedicationDispense.extension[0].valueDateTime = '2023-01-03T14:00:00-05:00';
876
+ newMedicationDispense.status = MedicationDispenseStatus.on_hold;
877
+ newMedicationDispense.quantity.value = 0;
878
+ expect(
879
+ computeNewFulfillerStatusAfterDispenseEvent(
880
+ newMedicationDispense,
881
+ { request: medicationRequest, dispenses: [] },
882
+ false,
883
+ ),
884
+ ).toBe(MedicationRequestFulfillerStatus.on_hold);
885
+ });
886
+
887
+ test('when adding new dispense should return complete if total dispensed equals total ordered and restrict total quantity dispensed config is true', () => {
888
+ newMedicationDispense.extension[0].valueDateTime = '2023-01-03T14:00:00-05:00';
889
+ newMedicationDispense.status = MedicationDispenseStatus.completed;
890
+ newMedicationDispense.quantity.value = 30;
891
+ expect(
892
+ computeNewFulfillerStatusAfterDispenseEvent(
893
+ newMedicationDispense,
894
+ { request: medicationRequest, dispenses: [] },
895
+ true,
896
+ ),
897
+ ).toBe(MedicationRequestFulfillerStatus.completed);
898
+ });
899
+
900
+ test('when adding new dispense should return null if total dispensed less than total ordered and restrict total quantity dispensed config is true', () => {
901
+ newMedicationDispense.extension[0].valueDateTime = '2023-01-03T14:00:00-05:00';
902
+ newMedicationDispense.status = MedicationDispenseStatus.completed;
903
+ newMedicationDispense.quantity.value = 20;
904
+ expect(
905
+ computeNewFulfillerStatusAfterDispenseEvent(
906
+ newMedicationDispense,
907
+ { request: medicationRequest, dispenses: [] },
908
+ true,
909
+ ),
910
+ ).toBeNull();
911
+ });
912
+
913
+ test('when adding new on-hold dispense should return on-hold if restrict total quantity dispensed config is true', () => {
914
+ newMedicationDispense.extension[0].valueDateTime = '2023-01-03T14:00:00-05:00';
915
+ newMedicationDispense.status = MedicationDispenseStatus.on_hold;
916
+ newMedicationDispense.quantity.value = 0;
917
+ expect(
918
+ computeNewFulfillerStatusAfterDispenseEvent(
919
+ newMedicationDispense,
920
+ { request: medicationRequest, dispenses: [] },
921
+ true,
922
+ ),
923
+ ).toBe(MedicationRequestFulfillerStatus.on_hold);
924
+ });
925
+
926
+ test('when adding new dispense to request with existing dispense should return complete if meets total quantity ordered and restrict total quantity dispensed config is true', () => {
927
+ newMedicationDispense.extension[0].valueDateTime = '2023-01-03T14:00:00-05:00';
928
+ newMedicationDispense.status = MedicationDispenseStatus.on_hold;
929
+ newMedicationDispense.quantity.value = 20;
930
+ existingMedicationDispense.extension[0].valueDateTime = '2023-01-03T14:00:00-05:00';
931
+ existingMedicationDispense.status = MedicationDispenseStatus.on_hold;
932
+ existingMedicationDispense.quantity.value = 10;
933
+ expect(
934
+ computeNewFulfillerStatusAfterDispenseEvent(
935
+ newMedicationDispense,
936
+ {
937
+ request: medicationRequest,
938
+ dispenses: [existingMedicationDispense],
939
+ },
940
+ true,
941
+ ),
942
+ ).toBe(MedicationRequestFulfillerStatus.completed);
943
+ });
944
+
945
+ test('when adding new dispense to request with existing dispense should return null if does not meet total quantiy order and restrict total quantity dispensed config is true', () => {
946
+ newMedicationDispense.extension[0].valueDateTime = '2023-01-03T14:00:00-05:00';
947
+ newMedicationDispense.status = MedicationDispenseStatus.completed;
948
+ newMedicationDispense.quantity.value = 10;
949
+ existingMedicationDispense.extension[0].valueDateTime = '2023-01-03T14:00:00-05:00';
950
+ existingMedicationDispense.status = MedicationDispenseStatus.completed;
951
+ existingMedicationDispense.quantity.value = 10;
952
+ expect(
953
+ computeNewFulfillerStatusAfterDispenseEvent(
954
+ newMedicationDispense,
955
+ {
956
+ request: medicationRequest,
957
+ dispenses: [existingMedicationDispense],
958
+ },
959
+ true,
960
+ ),
961
+ ).toBeNull();
962
+ });
963
+
964
+ test('when editing existing dispense should return null if does not meet total quantity order and restrict total quantity dispensed config is true', () => {
965
+ existingMedicationDispense.extension[0].valueDateTime = '2023-01-03T14:00:00-05:00';
966
+ existingMedicationDispense.status = MedicationDispenseStatus.completed;
967
+ existingMedicationDispense.quantity.value = 30;
968
+ const editedExistingMedicationDispense = {
969
+ ...existingMedicationDispense,
970
+ };
971
+ editedExistingMedicationDispense.quantity.value = 20;
972
+ expect(
973
+ computeNewFulfillerStatusAfterDispenseEvent(
974
+ editedExistingMedicationDispense,
975
+ {
976
+ request: medicationRequest,
977
+ dispenses: [existingMedicationDispense],
978
+ },
979
+ true,
980
+ ),
981
+ ).toBeNull();
982
+ });
983
+
984
+ test('when editing existing dispense should return complete if meets total quantity order and restrict total quantity dispensed config is true', () => {
985
+ existingMedicationDispense.extension[0].valueDateTime = '2023-01-03T14:00:00-05:00';
986
+ existingMedicationDispense.status = MedicationDispenseStatus.completed;
987
+ existingMedicationDispense.quantity.value = 20;
988
+ const editedExistingMedicationDispense = {
989
+ ...existingMedicationDispense,
990
+ };
991
+ editedExistingMedicationDispense.quantity.value = 30;
992
+ expect(
993
+ computeNewFulfillerStatusAfterDispenseEvent(
994
+ editedExistingMedicationDispense,
995
+ {
996
+ request: medicationRequest,
997
+ dispenses: [existingMedicationDispense],
998
+ },
999
+ true,
1000
+ ),
1001
+ ).toBe(MedicationRequestFulfillerStatus.completed);
1002
+ });
1003
+
1004
+ test('when editing existing dispense should return fulfiller status completed if medication request status is completed and restrict total quantity dispensed is set false', () => {
1005
+ medicationRequest.status = MedicationRequestStatus.completed;
1006
+ existingMedicationDispense.extension[0].valueDateTime = '2023-01-03T14:00:00-05:00';
1007
+ existingMedicationDispense.status = MedicationDispenseStatus.completed;
1008
+ existingMedicationDispense.quantity.value = 20;
1009
+ const editedExistingMedicationDispense = {
1010
+ ...existingMedicationDispense,
1011
+ };
1012
+ editedExistingMedicationDispense.quantity.value = 30;
1013
+ expect(
1014
+ computeNewFulfillerStatusAfterDispenseEvent(
1015
+ editedExistingMedicationDispense,
1016
+ {
1017
+ request: medicationRequest,
1018
+ dispenses: [existingMedicationDispense],
1019
+ },
1020
+ false,
1021
+ ),
1022
+ ).toBe(MedicationRequestFulfillerStatus.completed);
1023
+ });
1024
+
1025
+ test('when editing existing dispense should return fulfiller status null if medication request status is *NOT* completed and restrict total quantity dispensed is set false', () => {
1026
+ medicationRequest.status = MedicationRequestStatus.active;
1027
+ existingMedicationDispense.extension[0].valueDateTime = '2023-01-03T14:00:00-05:00';
1028
+ existingMedicationDispense.status = MedicationDispenseStatus.completed;
1029
+ existingMedicationDispense.quantity.value = 20;
1030
+ const editedExistingMedicationDispense = {
1031
+ ...existingMedicationDispense,
1032
+ };
1033
+ editedExistingMedicationDispense.quantity.value = 30;
1034
+ expect(
1035
+ computeNewFulfillerStatusAfterDispenseEvent(
1036
+ editedExistingMedicationDispense,
1037
+ {
1038
+ request: medicationRequest,
1039
+ dispenses: [existingMedicationDispense],
1040
+ },
1041
+ false,
1042
+ ),
1043
+ ).toBe(null);
1044
+ });
1045
+ });
1046
+
1047
+ describe('test computePrescriptionStatus', () => {
1048
+ const activeMedicationRequest = {
1049
+ dispenseRequest: {
1050
+ numberOfRepeatsAllowed: 0,
1051
+ quantity: undefined,
1052
+ validityPeriod: { start: '' },
1053
+ },
1054
+ dosageInstruction: undefined,
1055
+ encounter: { reference: '', type: '' },
1056
+ id: '',
1057
+ intent: '',
1058
+ medicationReference: { display: '', reference: '', type: '' },
1059
+ meta: { lastUpdated: '' },
1060
+ priority: '',
1061
+ requester: {
1062
+ display: '',
1063
+ identifier: { value: '' },
1064
+ reference: '',
1065
+ type: '',
1066
+ },
1067
+ resourceType: '',
1068
+ status: MedicationRequestStatus.active,
1069
+ subject: { display: '', reference: '', type: '' },
1070
+ };
1071
+ // sanity check
1072
+ expect(computeMedicationRequestCombinedStatus(activeMedicationRequest, 90)).toBe(
1073
+ MedicationRequestCombinedStatus.active,
1074
+ );
1075
+ const cancelledMedicationRequest = {
1076
+ dispenseRequest: {
1077
+ numberOfRepeatsAllowed: 0,
1078
+ quantity: undefined,
1079
+ validityPeriod: { start: '' },
1080
+ },
1081
+ dosageInstruction: undefined,
1082
+ encounter: { reference: '', type: '' },
1083
+ id: '',
1084
+ intent: '',
1085
+ medicationReference: { display: '', reference: '', type: '' },
1086
+ meta: { lastUpdated: '' },
1087
+ priority: '',
1088
+ requester: {
1089
+ display: '',
1090
+ identifier: { value: '' },
1091
+ reference: '',
1092
+ type: '',
1093
+ },
1094
+ resourceType: '',
1095
+ status: MedicationRequestStatus.cancelled,
1096
+ subject: { display: '', reference: '', type: '' },
1097
+ };
1098
+ // sanity check
1099
+ expect(computeMedicationRequestCombinedStatus(cancelledMedicationRequest, 90)).toBe(
1100
+ MedicationRequestCombinedStatus.cancelled,
1101
+ );
1102
+ const expiredMedicationRequest = {
1103
+ dispenseRequest: {
1104
+ numberOfRepeatsAllowed: 0,
1105
+ quantity: undefined,
1106
+ validityPeriod: { start: '2020-04-04' },
1107
+ },
1108
+ dosageInstruction: undefined,
1109
+ encounter: { reference: '', type: '' },
1110
+ id: '',
1111
+ intent: '',
1112
+ medicationReference: { display: '', reference: '', type: '' },
1113
+ meta: { lastUpdated: '' },
1114
+ priority: '',
1115
+ requester: {
1116
+ display: '',
1117
+ identifier: { value: '' },
1118
+ reference: '',
1119
+ type: '',
1120
+ },
1121
+ resourceType: '',
1122
+ status: MedicationRequestStatus.active,
1123
+ subject: { display: '', reference: '', type: '' },
1124
+ };
1125
+ // sanity check
1126
+ expect(computeMedicationRequestCombinedStatus(expiredMedicationRequest, 90)).toBe(
1127
+ MedicationRequestCombinedStatus.expired,
1128
+ );
1129
+ const onHoldMedicationRequest = {
1130
+ dispenseRequest: {
1131
+ numberOfRepeatsAllowed: 0,
1132
+ quantity: undefined,
1133
+ validityPeriod: { start: '' },
1134
+ },
1135
+ dosageInstruction: undefined,
1136
+ encounter: { reference: '', type: '' },
1137
+ id: '',
1138
+ intent: '',
1139
+ medicationReference: { display: '', reference: '', type: '' },
1140
+ meta: { lastUpdated: '' },
1141
+ priority: '',
1142
+ requester: {
1143
+ display: '',
1144
+ identifier: { value: '' },
1145
+ reference: '',
1146
+ type: '',
1147
+ },
1148
+ resourceType: '',
1149
+ status: MedicationRequestStatus.active,
1150
+ subject: { display: '', reference: '', type: '' },
1151
+ extension: [
1152
+ {
1153
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
1154
+ valueCode: MedicationRequestFulfillerStatus.on_hold,
1155
+ },
1156
+ ],
1157
+ };
1158
+ // sanity check
1159
+ expect(computeMedicationRequestCombinedStatus(onHoldMedicationRequest, 90)).toBe(
1160
+ MedicationRequestCombinedStatus.on_hold,
1161
+ );
1162
+ const declinedMedicationRequest = {
1163
+ dispenseRequest: {
1164
+ numberOfRepeatsAllowed: 0,
1165
+ quantity: undefined,
1166
+ validityPeriod: { start: '' },
1167
+ },
1168
+ dosageInstruction: undefined,
1169
+ encounter: { reference: '', type: '' },
1170
+ id: '',
1171
+ intent: '',
1172
+ medicationReference: { display: '', reference: '', type: '' },
1173
+ meta: { lastUpdated: '' },
1174
+ priority: '',
1175
+ requester: {
1176
+ display: '',
1177
+ identifier: { value: '' },
1178
+ reference: '',
1179
+ type: '',
1180
+ },
1181
+ resourceType: '',
1182
+ status: MedicationRequestStatus.active,
1183
+ subject: { display: '', reference: '', type: '' },
1184
+ extension: [
1185
+ {
1186
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
1187
+ valueCode: MedicationRequestFulfillerStatus.declined,
1188
+ },
1189
+ ],
1190
+ };
1191
+ // santity check
1192
+ expect(computeMedicationRequestCombinedStatus(declinedMedicationRequest, 90)).toBe(
1193
+ MedicationRequestCombinedStatus.declined,
1194
+ );
1195
+ const completedMedicationRequest = {
1196
+ dispenseRequest: {
1197
+ numberOfRepeatsAllowed: 0,
1198
+ quantity: undefined,
1199
+ validityPeriod: { start: '' },
1200
+ },
1201
+ dosageInstruction: undefined,
1202
+ encounter: { reference: '', type: '' },
1203
+ id: '',
1204
+ intent: '',
1205
+ medicationReference: { display: '', reference: '', type: '' },
1206
+ meta: { lastUpdated: '' },
1207
+ priority: '',
1208
+ requester: {
1209
+ display: '',
1210
+ identifier: { value: '' },
1211
+ reference: '',
1212
+ type: '',
1213
+ },
1214
+ resourceType: '',
1215
+ status: MedicationRequestStatus.completed,
1216
+ subject: { display: '', reference: '', type: '' },
1217
+ extension: [
1218
+ {
1219
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
1220
+ valueCode: MedicationRequestFulfillerStatus.completed,
1221
+ },
1222
+ ],
1223
+ };
1224
+ // santiy-check
1225
+ expect(computeMedicationRequestCombinedStatus(completedMedicationRequest, 90)).toBe(
1226
+ MedicationRequestCombinedStatus.completed,
1227
+ );
1228
+ test('should return active if any medication request combined status active', () => {
1229
+ expect(
1230
+ computePrescriptionStatus(
1231
+ [
1232
+ activeMedicationRequest,
1233
+ cancelledMedicationRequest,
1234
+ expiredMedicationRequest,
1235
+ onHoldMedicationRequest,
1236
+ declinedMedicationRequest,
1237
+ completedMedicationRequest,
1238
+ ],
1239
+ 90,
1240
+ ),
1241
+ ).toBe(MedicationRequestCombinedStatus.active);
1242
+ });
1243
+ test('should return on-hold if any medication request combined status on-hold, and none active', () => {
1244
+ expect(
1245
+ computePrescriptionStatus(
1246
+ [
1247
+ cancelledMedicationRequest,
1248
+ expiredMedicationRequest,
1249
+ onHoldMedicationRequest,
1250
+ declinedMedicationRequest,
1251
+ completedMedicationRequest,
1252
+ ],
1253
+ 90,
1254
+ ),
1255
+ ).toBe(MedicationRequestCombinedStatus.on_hold);
1256
+ });
1257
+ test('should return completed if any medication request combined status completed, and none active or on hold', () => {
1258
+ expect(
1259
+ computePrescriptionStatus(
1260
+ [cancelledMedicationRequest, expiredMedicationRequest, declinedMedicationRequest, completedMedicationRequest],
1261
+ 90,
1262
+ ),
1263
+ ).toBe(MedicationRequestCombinedStatus.completed);
1264
+ });
1265
+ test('should return declined if any medication request combined status declined, and none active or on hold or completed', () => {
1266
+ expect(
1267
+ computePrescriptionStatus(
1268
+ [cancelledMedicationRequest, expiredMedicationRequest, declinedMedicationRequest],
1269
+ 90,
1270
+ ),
1271
+ ).toBe(MedicationRequestCombinedStatus.declined);
1272
+ });
1273
+ test('should return cancelled if any medication request combined status cancelled, and none active or on hold or completed or declined', () => {
1274
+ expect(computePrescriptionStatus([cancelledMedicationRequest, expiredMedicationRequest], 90)).toBe(
1275
+ MedicationRequestCombinedStatus.cancelled,
1276
+ );
1277
+ });
1278
+ test('should return expired if any medication request combined status expired, and none active or on hold or completed or declined or cancelled', () => {
1279
+ expect(computePrescriptionStatus([expiredMedicationRequest], 90)).toBe(MedicationRequestCombinedStatus.expired);
1280
+ });
1281
+ test('should return null for empty array', () => {
1282
+ expect(computePrescriptionStatus([], 90)).toBe(null);
1283
+ });
1284
+ test('should return null for null input', () => {
1285
+ expect(computePrescriptionStatus(null, 90)).toBe(null);
1286
+ });
1287
+ });
1288
+
1289
+ describe('test computeRemainingQuantity', () => {
1290
+ const medicationRequest: MedicationRequest = {
1291
+ id: '1c1ad91e-8653-453a-9f59-8d5c36249aff',
1292
+ dispenseRequest: {
1293
+ numberOfRepeatsAllowed: undefined,
1294
+ quantity: {
1295
+ value: 30,
1296
+ unit: 'mg',
1297
+ code: '123abc',
1298
+ },
1299
+ validityPeriod: { start: '' },
1300
+ },
1301
+ dosageInstruction: undefined,
1302
+ encounter: { reference: '', type: '' },
1303
+ intent: '',
1304
+ medicationReference: { display: '', reference: '', type: '' },
1305
+ meta: { lastUpdated: '' },
1306
+ priority: '',
1307
+ requester: {
1308
+ display: '',
1309
+ identifier: { value: '' },
1310
+ reference: '',
1311
+ type: '',
1312
+ },
1313
+ resourceType: 'MedicationRequest',
1314
+ status: MedicationRequestStatus.completed,
1315
+ subject: { display: '', reference: '', type: '' },
1316
+ extension: [
1317
+ {
1318
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
1319
+ valueCode: MedicationRequestFulfillerStatus.completed,
1320
+ },
1321
+ ],
1322
+ };
1323
+ const medicationDispense1: MedicationDispense = {
1324
+ dosageInstruction: undefined,
1325
+ id: '',
1326
+ authorizingPrescription: [
1327
+ {
1328
+ reference: 'MedicationRequest/1c1ad91e-8653-453a-9f59-8d5c36249aff',
1329
+ type: 'MedicationRequest',
1330
+ },
1331
+ ],
1332
+ location: { display: '', reference: '', type: '' },
1333
+ medicationReference: { display: '', reference: '', type: '' },
1334
+ meta: { lastUpdated: '' },
1335
+ quantity: {
1336
+ value: 5,
1337
+ unit: 'mg',
1338
+ code: '123abc',
1339
+ },
1340
+ performer: undefined,
1341
+ resourceType: 'MedicationDispense',
1342
+ status: MedicationDispenseStatus.completed,
1343
+ subject: { display: '', reference: '', type: '' },
1344
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
1345
+ type: undefined,
1346
+ whenHandedOver: '',
1347
+ whenPrepared: '',
1348
+ };
1349
+ const medicationDispense2: MedicationDispense = {
1350
+ dosageInstruction: undefined,
1351
+ id: '',
1352
+ authorizingPrescription: [
1353
+ {
1354
+ reference: 'MedicationRequest/1c1ad91e-8653-453a-9f59-8d5c36249aff',
1355
+ type: 'MedicationRequest',
1356
+ },
1357
+ ],
1358
+ location: { display: '', reference: '', type: '' },
1359
+ medicationReference: { display: '', reference: '', type: '' },
1360
+ meta: { lastUpdated: '' },
1361
+ quantity: {
1362
+ value: 10,
1363
+ unit: 'mg',
1364
+ code: '123abc',
1365
+ },
1366
+ performer: undefined,
1367
+ resourceType: 'MedicationDispense',
1368
+ status: MedicationDispenseStatus.completed,
1369
+ subject: { display: '', reference: '', type: '' },
1370
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
1371
+ type: undefined,
1372
+ whenHandedOver: '',
1373
+ whenPrepared: '',
1374
+ };
1375
+ const medicationDispenseNoQuantity: MedicationDispense = {
1376
+ dosageInstruction: undefined,
1377
+ id: '',
1378
+ authorizingPrescription: [
1379
+ {
1380
+ reference: 'MedicationRequest/1c1ad91e-8653-453a-9f59-8d5c36249aff',
1381
+ type: 'MedicationRequest',
1382
+ },
1383
+ ],
1384
+ location: { display: '', reference: '', type: '' },
1385
+ medicationReference: { display: '', reference: '', type: '' },
1386
+ meta: { lastUpdated: '' },
1387
+ quantity: undefined,
1388
+ performer: undefined,
1389
+ resourceType: 'MedicationDispense',
1390
+ status: MedicationDispenseStatus.completed,
1391
+ subject: { display: '', reference: '', type: '' },
1392
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
1393
+ type: undefined,
1394
+ whenHandedOver: '',
1395
+ whenPrepared: '',
1396
+ };
1397
+ const medicationRequestDifferentUnits: MedicationRequest = {
1398
+ id: '1c1ad91e-8653-453a-9f59-8d5c36249aff',
1399
+ dispenseRequest: {
1400
+ numberOfRepeatsAllowed: undefined,
1401
+ quantity: {
1402
+ value: 30,
1403
+ unit: 'kg',
1404
+ code: '456def',
1405
+ },
1406
+ validityPeriod: { start: '' },
1407
+ },
1408
+ dosageInstruction: undefined,
1409
+ encounter: { reference: '', type: '' },
1410
+ intent: '',
1411
+ medicationReference: { display: '', reference: '', type: '' },
1412
+ meta: { lastUpdated: '' },
1413
+ priority: '',
1414
+ requester: {
1415
+ display: '',
1416
+ identifier: { value: '' },
1417
+ reference: '',
1418
+ type: '',
1419
+ },
1420
+ resourceType: 'MedicationRequest',
1421
+ status: MedicationRequestStatus.completed,
1422
+ subject: { display: '', reference: '', type: '' },
1423
+ extension: [
1424
+ {
1425
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
1426
+ valueCode: MedicationRequestFulfillerStatus.completed,
1427
+ },
1428
+ ],
1429
+ };
1430
+
1431
+ test('should return quantity remaining', () => {
1432
+ expect(
1433
+ computeQuantityRemaining({
1434
+ request: medicationRequest,
1435
+ dispenses: [medicationDispense1, medicationDispense2, medicationDispenseNoQuantity],
1436
+ }),
1437
+ ).toBe(15);
1438
+ });
1439
+ test('should return quantity ordered if no dispense has happened', () => {
1440
+ expect(
1441
+ computeQuantityRemaining({
1442
+ request: medicationRequest,
1443
+ dispenses: [medicationDispenseNoQuantity],
1444
+ }),
1445
+ ).toBe(30);
1446
+ });
1447
+ test('should return amount orders if no dispenses', () => {
1448
+ expect(computeQuantityRemaining({ request: medicationRequest, dispenses: [] })).toBe(30);
1449
+ });
1450
+ test('should return zero for null input', () => {
1451
+ expect(computeQuantityRemaining(null)).toBe(0);
1452
+ });
1453
+ /* // TODO: figure out how to get this to work
1454
+ test("should throw Error if unit mismatch", () => {
1455
+ expect(
1456
+ computeQuantityRemaining(medicationRequestDifferentUnits, [
1457
+ medicationDispense1,
1458
+ medicationDispenseNoQuantity,
1459
+ medicationDispense2,
1460
+ ])
1461
+ ).toThrow(Error);
1462
+ });*/
1463
+ });
1464
+
1465
+ describe('test computeTotalQuantityDispensed', () => {
1466
+ const medicationDispense1: MedicationDispense = {
1467
+ dosageInstruction: undefined,
1468
+ id: '',
1469
+ location: { display: '', reference: '', type: '' },
1470
+ medicationReference: { display: '', reference: '', type: '' },
1471
+ meta: { lastUpdated: '' },
1472
+ quantity: {
1473
+ value: 5,
1474
+ unit: 'mg',
1475
+ code: '123abc',
1476
+ },
1477
+ performer: undefined,
1478
+ resourceType: 'MedicationDispense',
1479
+ status: MedicationDispenseStatus.completed,
1480
+ subject: { display: '', reference: '', type: '' },
1481
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
1482
+ type: undefined,
1483
+ whenHandedOver: '',
1484
+ whenPrepared: '',
1485
+ };
1486
+
1487
+ const medicationDispense2: MedicationDispense = {
1488
+ dosageInstruction: undefined,
1489
+ id: '',
1490
+ location: { display: '', reference: '', type: '' },
1491
+ medicationReference: { display: '', reference: '', type: '' },
1492
+ meta: { lastUpdated: '' },
1493
+ quantity: {
1494
+ value: 15,
1495
+ unit: 'mg',
1496
+ code: '123abc',
1497
+ },
1498
+ performer: undefined,
1499
+ resourceType: 'MedicationDispense',
1500
+ status: MedicationDispenseStatus.completed,
1501
+ subject: { display: '', reference: '', type: '' },
1502
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
1503
+ type: undefined,
1504
+ whenHandedOver: '',
1505
+ whenPrepared: '',
1506
+ };
1507
+
1508
+ const medicationDispenseNoQuantity: MedicationDispense = {
1509
+ dosageInstruction: undefined,
1510
+ id: '',
1511
+ location: { display: '', reference: '', type: '' },
1512
+ medicationReference: { display: '', reference: '', type: '' },
1513
+ meta: { lastUpdated: '' },
1514
+ quantity: undefined,
1515
+ performer: undefined,
1516
+ resourceType: 'MedicationDispense',
1517
+ status: MedicationDispenseStatus.completed,
1518
+ subject: { display: '', reference: '', type: '' },
1519
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
1520
+ type: undefined,
1521
+ whenHandedOver: '',
1522
+ whenPrepared: '',
1523
+ };
1524
+
1525
+ const medicationDispenseDifferentUnits: MedicationDispense = {
1526
+ dosageInstruction: undefined,
1527
+ id: '',
1528
+ location: { display: '', reference: '', type: '' },
1529
+ medicationReference: { display: '', reference: '', type: '' },
1530
+ meta: { lastUpdated: '' },
1531
+ quantity: {
1532
+ value: 1,
1533
+ unit: 'kg',
1534
+ code: '456ddef',
1535
+ },
1536
+ performer: undefined,
1537
+ resourceType: 'MedicationDispense',
1538
+ status: MedicationDispenseStatus.completed,
1539
+ subject: { display: '', reference: '', type: '' },
1540
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
1541
+ type: undefined,
1542
+ whenHandedOver: '',
1543
+ whenPrepared: '',
1544
+ };
1545
+
1546
+ test('should return 0 for null input', () => {
1547
+ expect(computeTotalQuantityDispensed(null)).toBe(0);
1548
+ });
1549
+ test('should return 0 if no dispense events have quantity', () =>
1550
+ expect(computeTotalQuantityDispensed([medicationDispenseNoQuantity])).toBe(0));
1551
+ test('should return total quantity dispensed', () => {
1552
+ expect(
1553
+ computeTotalQuantityDispensed([medicationDispense1, medicationDispenseNoQuantity, medicationDispense2]),
1554
+ ).toBe(20);
1555
+ });
1556
+ // TODO: figure out how to get this to work
1557
+ /*test("should throw Error if unit mismatch", () => {
1558
+ expect(
1559
+ computeTotalQuantityDispensed([
1560
+ medicationDispense1,
1561
+ medicationDispenseNoQuantity,
1562
+ medicationDispense2,
1563
+ medicationDispenseDifferentUnits,
1564
+ ])
1565
+ ).toThrow("Can't calculate quantity dispensed if units don't match");
1566
+ });*/
1567
+ });
1568
+
1569
+ describe('test computeTotalQuantityOrdered', () => {
1570
+ test('should calculate total quantity ordered when refills set', () => {
1571
+ const medicationRequest: MedicationRequest = {
1572
+ dispenseRequest: {
1573
+ numberOfRepeatsAllowed: 3,
1574
+ quantity: {
1575
+ value: 30,
1576
+ unit: 'mg',
1577
+ code: '123abc',
1578
+ },
1579
+ validityPeriod: { start: '' },
1580
+ },
1581
+ dosageInstruction: undefined,
1582
+ encounter: { reference: '', type: '' },
1583
+ id: '',
1584
+ intent: '',
1585
+ medicationReference: { display: '', reference: '', type: '' },
1586
+ meta: { lastUpdated: '' },
1587
+ priority: '',
1588
+ requester: {
1589
+ display: '',
1590
+ identifier: { value: '' },
1591
+ reference: '',
1592
+ type: '',
1593
+ },
1594
+ resourceType: 'MedicationRequest',
1595
+ status: MedicationRequestStatus.completed,
1596
+ subject: { display: '', reference: '', type: '' },
1597
+ extension: [
1598
+ {
1599
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
1600
+ valueCode: MedicationRequestFulfillerStatus.completed,
1601
+ },
1602
+ ],
1603
+ };
1604
+ expect(computeTotalQuantityOrdered(medicationRequest)).toBe(120);
1605
+ });
1606
+ test('should calculate total quantity ordered when refills not set', () => {
1607
+ const medicationRequest: MedicationRequest = {
1608
+ dispenseRequest: {
1609
+ numberOfRepeatsAllowed: undefined,
1610
+ quantity: {
1611
+ value: 30,
1612
+ unit: 'mg',
1613
+ code: '123abc',
1614
+ },
1615
+ validityPeriod: { start: '' },
1616
+ },
1617
+ dosageInstruction: undefined,
1618
+ encounter: { reference: '', type: '' },
1619
+ id: '',
1620
+ intent: '',
1621
+ medicationReference: { display: '', reference: '', type: '' },
1622
+ meta: { lastUpdated: '' },
1623
+ priority: '',
1624
+ requester: {
1625
+ display: '',
1626
+ identifier: { value: '' },
1627
+ reference: '',
1628
+ type: '',
1629
+ },
1630
+ resourceType: 'MedicationRequest',
1631
+ status: MedicationRequestStatus.completed,
1632
+ subject: { display: '', reference: '', type: '' },
1633
+ extension: [
1634
+ {
1635
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
1636
+ valueCode: MedicationRequestFulfillerStatus.completed,
1637
+ },
1638
+ ],
1639
+ };
1640
+ expect(computeTotalQuantityOrdered(medicationRequest)).toBe(30);
1641
+ });
1642
+ test('should return null when no quantity', () => {
1643
+ const medicationRequest: MedicationRequest = {
1644
+ dispenseRequest: {
1645
+ numberOfRepeatsAllowed: undefined,
1646
+ quantity: undefined,
1647
+ validityPeriod: { start: '' },
1648
+ },
1649
+ dosageInstruction: undefined,
1650
+ encounter: { reference: '', type: '' },
1651
+ id: '',
1652
+ intent: '',
1653
+ medicationReference: { display: '', reference: '', type: '' },
1654
+ meta: { lastUpdated: '' },
1655
+ priority: '',
1656
+ requester: {
1657
+ display: '',
1658
+ identifier: { value: '' },
1659
+ reference: '',
1660
+ type: '',
1661
+ },
1662
+ resourceType: 'MedicationRequest',
1663
+ status: MedicationRequestStatus.completed,
1664
+ subject: { display: '', reference: '', type: '' },
1665
+ extension: [
1666
+ {
1667
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
1668
+ valueCode: MedicationRequestFulfillerStatus.completed,
1669
+ },
1670
+ ],
1671
+ };
1672
+ expect(computeTotalQuantityOrdered(medicationRequest)).toBe(null);
1673
+ });
1674
+ });
1675
+
1676
+ describe('test getAssociatedMedicationDispense', () => {
1677
+ test('should return medication dispenses associated with request', () => {
1678
+ const medicationRequest: MedicationRequest = {
1679
+ id: '1c1ad91e-8653-453a-9f59-8d5c36249aff',
1680
+ dispenseRequest: {
1681
+ numberOfRepeatsAllowed: 0,
1682
+ quantity: undefined,
1683
+ validityPeriod: { start: '' },
1684
+ },
1685
+ dosageInstruction: undefined,
1686
+ encounter: { reference: '', type: '' },
1687
+ intent: '',
1688
+ medicationReference: { display: '', reference: '', type: '' },
1689
+ meta: { lastUpdated: '' },
1690
+ priority: '',
1691
+ requester: {
1692
+ display: '',
1693
+ identifier: { value: '' },
1694
+ reference: '',
1695
+ type: '',
1696
+ },
1697
+ resourceType: '',
1698
+ status: null,
1699
+ subject: { display: '', reference: '', type: '' },
1700
+ };
1701
+
1702
+ const medicationDispenses: Array<MedicationDispense> = [
1703
+ {
1704
+ dosageInstruction: undefined,
1705
+ id: 'e74e74a1-6b70-40fd-8c44-485178c71721',
1706
+ authorizingPrescription: [
1707
+ {
1708
+ reference: 'MedicationRequest/075318da-ce26-4de5-9700-e49820f9d974',
1709
+ type: 'MedicationRequest',
1710
+ },
1711
+ ],
1712
+ location: { display: '', reference: '', type: '' },
1713
+ medicationReference: { display: '', reference: '', type: '' },
1714
+ meta: { lastUpdated: '' },
1715
+ quantity: {
1716
+ value: 1,
1717
+ unit: '',
1718
+ code: '',
1719
+ },
1720
+ performer: undefined,
1721
+ resourceType: 'MedicationDispense',
1722
+ status: MedicationDispenseStatus.completed,
1723
+ subject: { display: '', reference: '', type: '' },
1724
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
1725
+ type: undefined,
1726
+ whenHandedOver: '',
1727
+ whenPrepared: '',
1728
+ },
1729
+ {
1730
+ dosageInstruction: undefined,
1731
+ id: 'f7b5585d-6867-4f3a-8151-da9ee1f70fab',
1732
+ authorizingPrescription: [
1733
+ {
1734
+ reference: 'MedicationRequest/1c1ad91e-8653-453a-9f59-8d5c36249aff',
1735
+ type: 'MedicationRequest',
1736
+ },
1737
+ ],
1738
+ location: { display: '', reference: '', type: '' },
1739
+ medicationReference: { display: '', reference: '', type: '' },
1740
+ meta: { lastUpdated: '' },
1741
+ quantity: {
1742
+ value: 1,
1743
+ unit: '',
1744
+ code: '',
1745
+ },
1746
+ performer: undefined,
1747
+ resourceType: 'MedicationDispense',
1748
+ status: MedicationDispenseStatus.completed,
1749
+ subject: { display: '', reference: '', type: '' },
1750
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
1751
+ type: undefined,
1752
+ whenHandedOver: '',
1753
+ whenPrepared: '',
1754
+ },
1755
+ {
1756
+ dosageInstruction: undefined,
1757
+ id: 'a2121f8e-1bcc-4cf9-b1e8-1edace155e7f',
1758
+ authorizingPrescription: [
1759
+ {
1760
+ reference: 'MedicationRequest/075318da-ce26-4de5-9700-e49820f9d974',
1761
+ type: 'MedicationRequest',
1762
+ },
1763
+ ],
1764
+ location: { display: '', reference: '', type: '' },
1765
+ medicationReference: { display: '', reference: '', type: '' },
1766
+ meta: { lastUpdated: '' },
1767
+ quantity: {
1768
+ value: 1,
1769
+ unit: '',
1770
+ code: '',
1771
+ },
1772
+ performer: undefined,
1773
+ resourceType: 'MedicationDispense',
1774
+ status: MedicationDispenseStatus.completed,
1775
+ subject: { display: '', reference: '', type: '' },
1776
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
1777
+ type: undefined,
1778
+ whenHandedOver: '',
1779
+ whenPrepared: '',
1780
+ },
1781
+ {
1782
+ dosageInstruction: undefined,
1783
+ id: 'b59a6c54-c178-4972-a33b-dfe9f968e71a',
1784
+ authorizingPrescription: [
1785
+ {
1786
+ reference: 'MedicationRequest/1c1ad91e-8653-453a-9f59-8d5c36249aff',
1787
+ type: 'MedicationRequest',
1788
+ },
1789
+ ],
1790
+ location: { display: '', reference: '', type: '' },
1791
+ medicationReference: { display: '', reference: '', type: '' },
1792
+ meta: { lastUpdated: '' },
1793
+ quantity: {
1794
+ value: 1,
1795
+ unit: '',
1796
+ code: '',
1797
+ },
1798
+ performer: undefined,
1799
+ resourceType: 'MedicationDispense',
1800
+ status: MedicationDispenseStatus.completed,
1801
+ subject: { display: '', reference: '', type: '' },
1802
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
1803
+ type: undefined,
1804
+ whenHandedOver: '',
1805
+ whenPrepared: '',
1806
+ },
1807
+ ];
1808
+ const results: Array<MedicationDispense> = getAssociatedMedicationDispenses(
1809
+ medicationRequest,
1810
+ medicationDispenses,
1811
+ );
1812
+ expect(results.length).toBe(2);
1813
+ expect(results).toContain(medicationDispenses[1]);
1814
+ expect(results).toContain(medicationDispenses[3]);
1815
+ });
1816
+ test('should return empty list if no associated requests', () => {
1817
+ const medicationRequest: MedicationRequest = {
1818
+ id: '1c1ad91e-8653-453a-9f59-8d5c36249aff',
1819
+ dispenseRequest: {
1820
+ numberOfRepeatsAllowed: 0,
1821
+ quantity: undefined,
1822
+ validityPeriod: { start: '' },
1823
+ },
1824
+ dosageInstruction: undefined,
1825
+ encounter: { reference: '', type: '' },
1826
+ intent: '',
1827
+ medicationReference: { display: '', reference: '', type: '' },
1828
+ meta: { lastUpdated: '' },
1829
+ priority: '',
1830
+ requester: {
1831
+ display: '',
1832
+ identifier: { value: '' },
1833
+ reference: '',
1834
+ type: '',
1835
+ },
1836
+ resourceType: '',
1837
+ status: null,
1838
+ subject: { display: '', reference: '', type: '' },
1839
+ };
1840
+
1841
+ const medicationDispenses: Array<MedicationDispense> = [
1842
+ {
1843
+ dosageInstruction: undefined,
1844
+ id: 'e74e74a1-6b70-40fd-8c44-485178c71721',
1845
+ authorizingPrescription: [
1846
+ {
1847
+ reference: 'MedicationRequest/075318da-ce26-4de5-9700-e49820f9d974',
1848
+ type: 'MedicationRequest',
1849
+ },
1850
+ ],
1851
+ location: { display: '', reference: '', type: '' },
1852
+ medicationReference: { display: '', reference: '', type: '' },
1853
+ meta: { lastUpdated: '' },
1854
+ quantity: {
1855
+ value: 1,
1856
+ unit: '',
1857
+ code: '',
1858
+ },
1859
+ performer: undefined,
1860
+ resourceType: 'MedicationDispense',
1861
+ status: MedicationDispenseStatus.completed,
1862
+ subject: { display: '', reference: '', type: '' },
1863
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
1864
+ type: undefined,
1865
+ whenHandedOver: '',
1866
+ whenPrepared: '',
1867
+ },
1868
+ ];
1869
+ const results: Array<MedicationDispense> = getAssociatedMedicationDispenses(
1870
+ medicationRequest,
1871
+ medicationDispenses,
1872
+ );
1873
+ expect(results.length).toBe(0);
1874
+ });
1875
+ });
1876
+
1877
+ describe('test getAssociatedRequest', () => {
1878
+ test('should return medication request associated with dispense', () => {
1879
+ const medicationRequest1: MedicationRequest = {
1880
+ id: '0c26097a-e856-4c01-a6b4-7c8e6c636618',
1881
+ dispenseRequest: {
1882
+ numberOfRepeatsAllowed: undefined,
1883
+ quantity: {
1884
+ value: 30,
1885
+ unit: 'mg',
1886
+ code: '123abc',
1887
+ },
1888
+ validityPeriod: { start: '' },
1889
+ },
1890
+ dosageInstruction: undefined,
1891
+ encounter: { reference: '', type: '' },
1892
+ intent: '',
1893
+ medicationReference: { display: '', reference: '', type: '' },
1894
+ meta: { lastUpdated: '' },
1895
+ priority: '',
1896
+ requester: {
1897
+ display: '',
1898
+ identifier: { value: '' },
1899
+ reference: '',
1900
+ type: '',
1901
+ },
1902
+ resourceType: 'MedicationRequest',
1903
+ status: MedicationRequestStatus.completed,
1904
+ subject: { display: '', reference: '', type: '' },
1905
+ extension: [
1906
+ {
1907
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
1908
+ valueCode: MedicationRequestFulfillerStatus.completed,
1909
+ },
1910
+ ],
1911
+ };
1912
+
1913
+ const medicationRequest2: MedicationRequest = {
1914
+ id: '1c1ad91e-8653-453a-9f59-8d5c36249aff',
1915
+ dispenseRequest: {
1916
+ numberOfRepeatsAllowed: undefined,
1917
+ quantity: {
1918
+ value: 30,
1919
+ unit: 'mg',
1920
+ code: '123abc',
1921
+ },
1922
+ validityPeriod: { start: '' },
1923
+ },
1924
+ dosageInstruction: undefined,
1925
+ encounter: { reference: '', type: '' },
1926
+ intent: '',
1927
+ medicationReference: { display: '', reference: '', type: '' },
1928
+ meta: { lastUpdated: '' },
1929
+ priority: '',
1930
+ requester: {
1931
+ display: '',
1932
+ identifier: { value: '' },
1933
+ reference: '',
1934
+ type: '',
1935
+ },
1936
+ resourceType: 'MedicationRequest',
1937
+ status: MedicationRequestStatus.completed,
1938
+ subject: { display: '', reference: '', type: '' },
1939
+ extension: [
1940
+ {
1941
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
1942
+ valueCode: MedicationRequestFulfillerStatus.completed,
1943
+ },
1944
+ ],
1945
+ };
1946
+
1947
+ const medicationDispense: MedicationDispense = {
1948
+ dosageInstruction: undefined,
1949
+ id: '998f4111-96e8-4cd6-aebd-7f55716621a0',
1950
+ authorizingPrescription: [
1951
+ {
1952
+ reference: 'MedicationRequest/1c1ad91e-8653-453a-9f59-8d5c36249aff',
1953
+ type: 'MedicationRequest',
1954
+ },
1955
+ ],
1956
+ location: { display: '', reference: '', type: '' },
1957
+ medicationReference: { display: '', reference: '', type: '' },
1958
+ meta: { lastUpdated: '' },
1959
+ quantity: {
1960
+ value: 5,
1961
+ unit: 'mg',
1962
+ code: '123abc',
1963
+ },
1964
+ performer: undefined,
1965
+ resourceType: 'MedicationDispense',
1966
+ status: MedicationDispenseStatus.completed,
1967
+ subject: { display: '', reference: '', type: '' },
1968
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
1969
+ type: undefined,
1970
+ whenHandedOver: '',
1971
+ whenPrepared: '',
1972
+ };
1973
+
1974
+ expect(getAssociatedMedicationRequest(medicationDispense, [medicationRequest1, medicationRequest2])).toBe(
1975
+ medicationRequest2,
1976
+ );
1977
+ });
1978
+ });
1979
+
1980
+ describe('test getConceptCoding', () => {
1981
+ test('should find the concept coding without a system', () => {
1982
+ const codings: Array<Coding> = [
1983
+ {
1984
+ system: 'SNOMED',
1985
+ code: '123456',
1986
+ display: 'Weight',
1987
+ },
1988
+ {
1989
+ code: '123abc',
1990
+ display: 'Weight',
1991
+ },
1992
+ {
1993
+ system: 'CIEL',
1994
+ code: 'abcdef',
1995
+ display: 'Weight',
1996
+ },
1997
+ ];
1998
+
1999
+ expect(getConceptCoding(codings).code).toBe('123abc');
2000
+ });
2001
+ test('should find the concept coding undefined system', () => {
2002
+ const codings: Array<Coding> = [
2003
+ {
2004
+ system: 'SNOMED',
2005
+ code: '123456',
2006
+ display: 'Weight',
2007
+ },
2008
+ {
2009
+ system: undefined,
2010
+ code: '123abc',
2011
+ display: 'Weight',
2012
+ },
2013
+ {
2014
+ system: 'CIEL',
2015
+ code: 'abcdef',
2016
+ display: 'Weight',
2017
+ },
2018
+ ];
2019
+
2020
+ expect(getConceptCoding(codings).code).toBe('123abc');
2021
+ });
2022
+ });
2023
+
2024
+ describe('test getConceptCodingUuid', () => {
2025
+ test('should find the concept coding uuid without a system', () => {
2026
+ const codings: Array<Coding> = [
2027
+ {
2028
+ system: 'SNOMED',
2029
+ code: '123456',
2030
+ display: 'Weight',
2031
+ },
2032
+ {
2033
+ code: '123abc',
2034
+ display: 'Weight',
2035
+ },
2036
+ {
2037
+ system: 'CIEL',
2038
+ code: 'abcdef',
2039
+ display: 'Weight',
2040
+ },
2041
+ ];
2042
+
2043
+ expect(getConceptCodingUuid(codings)).toBe('123abc');
2044
+ });
2045
+ test('should find the concept coding uuid without a system', () => {
2046
+ const codings: Array<Coding> = [
2047
+ {
2048
+ system: 'SNOMED',
2049
+ code: '123456',
2050
+ display: 'Weight',
2051
+ },
2052
+ {
2053
+ code: '123abc',
2054
+ display: 'Weight',
2055
+ },
2056
+ {
2057
+ system: 'CIEL',
2058
+ code: 'abcdef',
2059
+ display: 'Weight',
2060
+ },
2061
+ ];
2062
+ expect(getConceptCodingDisplay(codings)).toBe('Weight');
2063
+ });
2064
+ });
2065
+
2066
+ describe('test getDosageInstructions', () => {
2067
+ test('should return first element of dosage instructions array', () => {
2068
+ const dosageInstructions: Array<DosageInstruction> = [
2069
+ {
2070
+ asNeededBoolean: false,
2071
+ doseAndRate: undefined,
2072
+ route: { coding: undefined },
2073
+ text: 'first',
2074
+ timing: {
2075
+ code: { coding: undefined },
2076
+ repeat: { duration: 0, durationUnit: '' },
2077
+ },
2078
+ },
2079
+ {
2080
+ asNeededBoolean: false,
2081
+ doseAndRate: undefined,
2082
+ route: { coding: undefined },
2083
+ text: 'second',
2084
+ timing: {
2085
+ code: { coding: undefined },
2086
+ repeat: { duration: 0, durationUnit: '' },
2087
+ },
2088
+ },
2089
+ ];
2090
+
2091
+ expect(getDosageInstruction(dosageInstructions).text).toBe('first');
2092
+ });
2093
+ });
2094
+
2095
+ describe('test getMedicationsByConceptEndpoint', () => {
2096
+ test('should return medications by concept endpoint', () => {
2097
+ expect(getMedicationsByConceptEndpoint('123abc')).toBe('/ws/fhir2/R4/Medication?code=123abc');
2098
+ });
2099
+ });
2100
+
2101
+ describe('test getMedicationDisplay', () => {
2102
+ test('should return medication reference display when present', () => {
2103
+ const medication: MedicationReferenceOrCodeableConcept = {
2104
+ medicationReference: {
2105
+ reference: 'Medication/123abc',
2106
+ display: 'Aspirin',
2107
+ },
2108
+ medicationCodeableConcept: {
2109
+ coding: [
2110
+ {
2111
+ code: 'def687',
2112
+ display: 'Aspirin',
2113
+ },
2114
+ ],
2115
+ text: 'Aspirin',
2116
+ },
2117
+ };
2118
+ expect(getMedicationDisplay(medication)).toBe('Aspirin');
2119
+ });
2120
+ test('should return medication codeable concept when reference not present', () => {
2121
+ const medication: MedicationReferenceOrCodeableConcept = {
2122
+ medicationCodeableConcept: {
2123
+ coding: [
2124
+ {
2125
+ code: 'def687',
2126
+ display: 'Aspirin',
2127
+ },
2128
+ ],
2129
+ text: 'Aspirin',
2130
+ },
2131
+ };
2132
+ expect(getMedicationDisplay(medication)).toBe('Aspirin: Aspirin');
2133
+ });
2134
+ });
2135
+
2136
+ describe('test getMedicationReferenceOrCodeableConcept', () => {
2137
+ test('should return medication reference or codeable concept from Medication Request', () => {
2138
+ const medicationRequest: MedicationRequest = {
2139
+ dispenseRequest: {
2140
+ numberOfRepeatsAllowed: 3,
2141
+ quantity: {
2142
+ value: 5,
2143
+ unit: 'mg',
2144
+ code: '123abc',
2145
+ },
2146
+ validityPeriod: { start: '' },
2147
+ },
2148
+ dosageInstruction: undefined,
2149
+ encounter: { reference: '', type: '' },
2150
+ id: '',
2151
+ intent: '',
2152
+ medicationReference: {
2153
+ display: '',
2154
+ reference: 'Medication/123abc',
2155
+ type: '',
2156
+ },
2157
+ medicationCodeableConcept: {
2158
+ coding: undefined,
2159
+ text: 'Some concept',
2160
+ },
2161
+ meta: { lastUpdated: '' },
2162
+ priority: '',
2163
+ requester: {
2164
+ display: '',
2165
+ identifier: { value: '' },
2166
+ reference: '',
2167
+ type: '',
2168
+ },
2169
+ resourceType: 'MedicationRequest',
2170
+ status: null,
2171
+ subject: { display: '', reference: '', type: '' },
2172
+ };
2173
+ expect(getMedicationReferenceOrCodeableConcept(medicationRequest).medicationReference.reference).toBe(
2174
+ 'Medication/123abc',
2175
+ );
2176
+ expect(getMedicationReferenceOrCodeableConcept(medicationRequest).medicationCodeableConcept.text).toBe(
2177
+ 'Some concept',
2178
+ );
2179
+ });
2180
+ test('should return medication reference or codeable concept from Medication Dispense', () => {
2181
+ const medicationDispense: MedicationDispense = {
2182
+ dosageInstruction: undefined,
2183
+ id: '',
2184
+ location: { display: '', reference: '', type: '' },
2185
+ medicationReference: {
2186
+ display: '',
2187
+ reference: 'Medication/123abc',
2188
+ type: '',
2189
+ },
2190
+ medicationCodeableConcept: {
2191
+ coding: undefined,
2192
+ text: 'Some concept',
2193
+ },
2194
+ meta: { lastUpdated: '' },
2195
+ quantity: {
2196
+ value: 5,
2197
+ unit: 'mg',
2198
+ code: '123abc',
2199
+ },
2200
+ performer: undefined,
2201
+ resourceType: 'MedicationDispense',
2202
+ status: MedicationDispenseStatus.completed,
2203
+ subject: { display: '', reference: '', type: '' },
2204
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2205
+ type: undefined,
2206
+ whenHandedOver: '',
2207
+ whenPrepared: '',
2208
+ };
2209
+ expect(getMedicationReferenceOrCodeableConcept(medicationDispense).medicationReference.reference).toBe(
2210
+ 'Medication/123abc',
2211
+ );
2212
+ expect(getMedicationReferenceOrCodeableConcept(medicationDispense).medicationCodeableConcept.text).toBe(
2213
+ 'Some concept',
2214
+ );
2215
+ });
2216
+ });
2217
+
2218
+ describe('test getMostRecentMedicationDispenseStatus', () => {
2219
+ test('should return most recent status', () => {
2220
+ const medicationDispenses: Array<MedicationDispense> = [
2221
+ {
2222
+ dosageInstruction: undefined,
2223
+ id: 'e74e74a1-6b70-40fd-8c44-485178c71721',
2224
+ extension: [
2225
+ {
2226
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
2227
+ valueDateTime: '2023-01-05T14:00:00-05:00',
2228
+ },
2229
+ ],
2230
+ authorizingPrescription: [
2231
+ {
2232
+ reference: 'MedicationRequest/075318da-ce26-4de5-9700-e49820f9d974',
2233
+ type: 'MedicationRequest',
2234
+ },
2235
+ ],
2236
+ location: { display: '', reference: '', type: '' },
2237
+ medicationReference: { display: '', reference: '', type: '' },
2238
+ meta: { lastUpdated: '' },
2239
+ quantity: {
2240
+ value: 1,
2241
+ unit: '',
2242
+ code: '',
2243
+ },
2244
+ performer: undefined,
2245
+ resourceType: 'MedicationDispense',
2246
+ status: MedicationDispenseStatus.on_hold,
2247
+ subject: { display: '', reference: '', type: '' },
2248
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2249
+ type: undefined,
2250
+ whenHandedOver: '2023-01-05T14:00:00-05:00',
2251
+ whenPrepared: '2023-01-05T14:00:00-05:00',
2252
+ },
2253
+ {
2254
+ dosageInstruction: undefined,
2255
+ id: 'f7b5585d-6867-4f3a-8151-da9ee1f70fab',
2256
+ extension: [
2257
+ {
2258
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
2259
+ valueDateTime: '2023-01-05T20:00:00-05:00',
2260
+ },
2261
+ ],
2262
+ authorizingPrescription: [
2263
+ {
2264
+ reference: 'MedicationRequest/1c1ad91e-8653-453a-9f59-8d5c36249aff',
2265
+ type: 'MedicationRequest',
2266
+ },
2267
+ ],
2268
+ location: { display: '', reference: '', type: '' },
2269
+ medicationReference: { display: '', reference: '', type: '' },
2270
+ meta: { lastUpdated: '' },
2271
+ quantity: {
2272
+ value: 1,
2273
+ unit: '',
2274
+ code: '',
2275
+ },
2276
+ performer: undefined,
2277
+ resourceType: 'MedicationDispense',
2278
+ status: MedicationDispenseStatus.completed,
2279
+ subject: { display: '', reference: '', type: '' },
2280
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2281
+ type: undefined,
2282
+ whenHandedOver: '2023-01-05T20:00:00-05:00',
2283
+ whenPrepared: '2023-01-05T20:00:00-05:00',
2284
+ },
2285
+ {
2286
+ dosageInstruction: undefined,
2287
+ id: 'a2121f8e-1bcc-4cf9-b1e8-1edace155e7f',
2288
+ extension: [
2289
+ {
2290
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
2291
+ valueDateTime: '2023-01-05T17:00:00-05:00',
2292
+ },
2293
+ ],
2294
+ authorizingPrescription: [
2295
+ {
2296
+ reference: 'MedicationRequest/075318da-ce26-4de5-9700-e49820f9d974',
2297
+ type: 'MedicationRequest',
2298
+ },
2299
+ ],
2300
+ location: { display: '', reference: '', type: '' },
2301
+ medicationReference: { display: '', reference: '', type: '' },
2302
+ meta: { lastUpdated: '' },
2303
+ quantity: {
2304
+ value: 1,
2305
+ unit: '',
2306
+ code: '',
2307
+ },
2308
+ performer: undefined,
2309
+ resourceType: 'MedicationDispense',
2310
+ status: MedicationDispenseStatus.declined,
2311
+ subject: { display: '', reference: '', type: '' },
2312
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2313
+ type: undefined,
2314
+ whenHandedOver: '2023-01-05T17:00:00-05:00',
2315
+ whenPrepared: '2023-01-05T17:00:00-05:00',
2316
+ },
2317
+ ];
2318
+
2319
+ expect(getMostRecentMedicationDispenseStatus(medicationDispenses)).toBe(MedicationDispenseStatus.completed);
2320
+ });
2321
+ test('should return null for null input', () => {
2322
+ expect(getMostRecentMedicationDispenseStatus(null)).toBeNull();
2323
+ });
2324
+ test('should return null for empty list', () => {
2325
+ expect(getMostRecentMedicationDispenseStatus([])).toBeNull();
2326
+ });
2327
+ });
2328
+
2329
+ describe('test getNextMostRecentMedicationDispenseStatus', () => {
2330
+ test('should return next most recent status', () => {
2331
+ const medicationDispenses: Array<MedicationDispense> = [
2332
+ {
2333
+ dosageInstruction: undefined,
2334
+ id: 'e74e74a1-6b70-40fd-8c44-485178c71721',
2335
+ extension: [
2336
+ {
2337
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
2338
+ valueDateTime: '2023-01-05T14:00:00-05:00',
2339
+ },
2340
+ ],
2341
+ authorizingPrescription: [
2342
+ {
2343
+ reference: 'MedicationRequest/075318da-ce26-4de5-9700-e49820f9d974',
2344
+ type: 'MedicationRequest',
2345
+ },
2346
+ ],
2347
+ location: { display: '', reference: '', type: '' },
2348
+ medicationReference: { display: '', reference: '', type: '' },
2349
+ meta: { lastUpdated: '' },
2350
+ quantity: {
2351
+ value: 1,
2352
+ unit: '',
2353
+ code: '',
2354
+ },
2355
+ performer: undefined,
2356
+ resourceType: 'MedicationDispense',
2357
+ status: MedicationDispenseStatus.on_hold,
2358
+ subject: { display: '', reference: '', type: '' },
2359
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2360
+ type: undefined,
2361
+ whenHandedOver: '2023-01-05T14:00:00-05:00',
2362
+ whenPrepared: '2023-01-05T14:00:00-05:00',
2363
+ },
2364
+ {
2365
+ dosageInstruction: undefined,
2366
+ id: 'f7b5585d-6867-4f3a-8151-da9ee1f70fab',
2367
+ extension: [
2368
+ {
2369
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
2370
+ valueDateTime: '2023-01-05T20:00:00-05:00',
2371
+ },
2372
+ ],
2373
+ authorizingPrescription: [
2374
+ {
2375
+ reference: 'MedicationRequest/1c1ad91e-8653-453a-9f59-8d5c36249aff',
2376
+ type: 'MedicationRequest',
2377
+ },
2378
+ ],
2379
+ location: { display: '', reference: '', type: '' },
2380
+ medicationReference: { display: '', reference: '', type: '' },
2381
+ meta: { lastUpdated: '' },
2382
+ quantity: {
2383
+ value: 1,
2384
+ unit: '',
2385
+ code: '',
2386
+ },
2387
+ performer: undefined,
2388
+ resourceType: 'MedicationDispense',
2389
+ status: MedicationDispenseStatus.completed,
2390
+ subject: { display: '', reference: '', type: '' },
2391
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2392
+ type: undefined,
2393
+ whenHandedOver: '2023-01-05T20:00:00-05:00',
2394
+ whenPrepared: '2023-01-05T20:00:00-05:00',
2395
+ },
2396
+ {
2397
+ dosageInstruction: undefined,
2398
+ id: 'a2121f8e-1bcc-4cf9-b1e8-1edace155e7f',
2399
+ extension: [
2400
+ {
2401
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
2402
+ valueDateTime: '2023-01-05T17:00:00-05:00',
2403
+ },
2404
+ ],
2405
+ authorizingPrescription: [
2406
+ {
2407
+ reference: 'MedicationRequest/075318da-ce26-4de5-9700-e49820f9d974',
2408
+ type: 'MedicationRequest',
2409
+ },
2410
+ ],
2411
+ location: { display: '', reference: '', type: '' },
2412
+ medicationReference: { display: '', reference: '', type: '' },
2413
+ meta: { lastUpdated: '' },
2414
+ quantity: {
2415
+ value: 1,
2416
+ unit: '',
2417
+ code: '',
2418
+ },
2419
+ performer: undefined,
2420
+ resourceType: 'MedicationDispense',
2421
+ status: MedicationDispenseStatus.declined,
2422
+ subject: { display: '', reference: '', type: '' },
2423
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2424
+ type: undefined,
2425
+ whenHandedOver: '2023-01-05T17:00:00-05:00',
2426
+ whenPrepared: '2023-01-05T17:00:00-05:00',
2427
+ },
2428
+ ];
2429
+
2430
+ expect(getNextMostRecentMedicationDispenseStatus(medicationDispenses)).toBe(MedicationDispenseStatus.declined);
2431
+ });
2432
+ test('should return null if only one dispense', () => {
2433
+ const medicationDispenses: Array<MedicationDispense> = [
2434
+ {
2435
+ dosageInstruction: undefined,
2436
+ id: 'e74e74a1-6b70-40fd-8c44-485178c71721',
2437
+ extension: [
2438
+ {
2439
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
2440
+ valueDateTime: '2023-01-05T14:00:00-05:00',
2441
+ },
2442
+ ],
2443
+ authorizingPrescription: [
2444
+ {
2445
+ reference: 'MedicationRequest/075318da-ce26-4de5-9700-e49820f9d974',
2446
+ type: 'MedicationRequest',
2447
+ },
2448
+ ],
2449
+ location: { display: '', reference: '', type: '' },
2450
+ medicationReference: { display: '', reference: '', type: '' },
2451
+ meta: { lastUpdated: '' },
2452
+ quantity: {
2453
+ value: 1,
2454
+ unit: '',
2455
+ code: '',
2456
+ },
2457
+ performer: undefined,
2458
+ resourceType: 'MedicationDispense',
2459
+ status: MedicationDispenseStatus.on_hold,
2460
+ subject: { display: '', reference: '', type: '' },
2461
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2462
+ type: undefined,
2463
+ whenHandedOver: '2023-01-05T14:00:00-05:00',
2464
+ whenPrepared: '2023-01-05T14:00:00-05:00',
2465
+ },
2466
+ ];
2467
+ expect(getNextMostRecentMedicationDispenseStatus(medicationDispenses)).toBeNull();
2468
+ });
2469
+ test('should return null for null input', () => {
2470
+ expect(getNextMostRecentMedicationDispenseStatus(null)).toBeNull();
2471
+ });
2472
+ test('should return null for empty list', () => {
2473
+ expect(getMostRecentMedicationDispenseStatus([])).toBeNull();
2474
+ });
2475
+ });
2476
+
2477
+ describe('test getOpenMRSMedicineDrugName', () => {
2478
+ test('getOpenMRSMedicineDrugName should get drug name stored in FHIR extension', () => {
2479
+ const medication: Medication = {
2480
+ code: { coding: [], text: '' },
2481
+ extension: [
2482
+ {
2483
+ extension: [
2484
+ {
2485
+ url: 'http://fhir.openmrs.org/ext/medicine#drugName',
2486
+ valueString: 'Aspirin',
2487
+ },
2488
+ ],
2489
+ url: 'http://fhir.openmrs.org/ext/medicine',
2490
+ },
2491
+ ],
2492
+ id: '',
2493
+ meta: { lastUpdated: '' },
2494
+ resourceType: 'Medication',
2495
+ status: '',
2496
+ };
2497
+
2498
+ expect(getOpenMRSMedicineDrugName(medication)).toBe('Aspirin');
2499
+ });
2500
+ });
2501
+
2502
+ describe('test getPrescriptionTableActiveMedicationRequestsEndpoint', () => {
2503
+ test('should return endpoint with date parameter', () => {
2504
+ expect(getPrescriptionTableEndpoint('', 'ACTIVE', 1, 10, '2020-01-01', null, null)).toBe(
2505
+ '/ws/fhir2/R4/Encounter?_query=encountersWithMedicationRequests&_getpagesoffset=1&_count=10&date=ge2020-01-01&status=ACTIVE',
2506
+ );
2507
+ });
2508
+ test('should return endpoint with date and search term parameters', () => {
2509
+ expect(getPrescriptionTableEndpoint('', 'ACTIVE', 1, 10, '2020-01-01', 'bob', null)).toBe(
2510
+ '/ws/fhir2/R4/Encounter?_query=encountersWithMedicationRequests&_getpagesoffset=1&_count=10&date=ge2020-01-01&status=ACTIVE&patientSearchTerm=bob',
2511
+ );
2512
+ });
2513
+ test('should return endpoint with date and location parameters', () => {
2514
+ expect(getPrescriptionTableEndpoint('', 'ACTIVE', 1, 10, '2020-01-01', null, '123abc')).toBe(
2515
+ '/ws/fhir2/R4/Encounter?_query=encountersWithMedicationRequests&_getpagesoffset=1&_count=10&date=ge2020-01-01&status=ACTIVE&location=123abc',
2516
+ );
2517
+ });
2518
+ test('should return endpoint with date, location, and search term parameters', () => {
2519
+ expect(getPrescriptionTableEndpoint('', 'ACTIVE', 1, 10, '2020-01-01', 'bob', '123abc')).toBe(
2520
+ '/ws/fhir2/R4/Encounter?_query=encountersWithMedicationRequests&_getpagesoffset=1&_count=10&date=ge2020-01-01&status=ACTIVE&patientSearchTerm=bob&location=123abc',
2521
+ );
2522
+ });
2523
+
2524
+ test('should return endpoint with multiple comma-separated location parameters', () => {
2525
+ expect(getPrescriptionTableEndpoint('', 'ACTIVE', 1, 10, '2020-01-01', 'bob', '123abc,456def')).toBe(
2526
+ '/ws/fhir2/R4/Encounter?_query=encountersWithMedicationRequests&_getpagesoffset=1&_count=10&date=ge2020-01-01&status=ACTIVE&patientSearchTerm=bob&location=123abc,456def',
2527
+ );
2528
+ });
2529
+ test('should return custom endpoint properly populated', () => {
2530
+ expect(
2531
+ getPrescriptionTableEndpoint(
2532
+ '${fhirBaseUrl}/Encounter?_query=someCustomEndpoint&_getpagesoffset=${pageOffset}&_count=${pageSize}&date=ge${date}&status=ACTIVE&patientSearchTerm=${patientSearchTerm}&location=${location}',
2533
+ 'ACTIVE',
2534
+ 1,
2535
+ 10,
2536
+ '2020-01-01',
2537
+ 'bob',
2538
+ '123abc,456def',
2539
+ ),
2540
+ ).toBe(
2541
+ '/ws/fhir2/R4/Encounter?_query=someCustomEndpoint&_getpagesoffset=1&_count=10&date=ge2020-01-01&status=ACTIVE&patientSearchTerm=bob&location=123abc,456def',
2542
+ );
2543
+ });
2544
+ });
2545
+
2546
+ describe('test getPrescriptionDetailsEndpoint', () => {
2547
+ test('should return endpoint with encounter uuid', () => {
2548
+ expect(getPrescriptionDetailsEndpoint('123abc')).toBe(
2549
+ '/ws/fhir2/R4/MedicationRequest?encounter=123abc&_revinclude=MedicationDispense:prescription&_include=MedicationRequest:encounter',
2550
+ );
2551
+ });
2552
+ });
2553
+
2554
+ describe('test getQuantity', () => {
2555
+ test('should return quantity from Medication Request', () => {
2556
+ const medicationRequest: MedicationRequest = {
2557
+ dispenseRequest: {
2558
+ numberOfRepeatsAllowed: 3,
2559
+ quantity: {
2560
+ value: 5,
2561
+ unit: 'mg',
2562
+ code: '123abc',
2563
+ },
2564
+ validityPeriod: { start: '' },
2565
+ },
2566
+ dosageInstruction: undefined,
2567
+ encounter: { reference: '', type: '' },
2568
+ id: '',
2569
+ intent: '',
2570
+ medicationReference: { display: '', reference: '', type: '' },
2571
+ meta: { lastUpdated: '' },
2572
+ priority: '',
2573
+ requester: {
2574
+ display: '',
2575
+ identifier: { value: '' },
2576
+ reference: '',
2577
+ type: '',
2578
+ },
2579
+ resourceType: 'MedicationRequest',
2580
+ status: null,
2581
+ subject: { display: '', reference: '', type: '' },
2582
+ };
2583
+ expect(getQuantity(medicationRequest).value).toBe(5);
2584
+ });
2585
+ test('should return quantity from Medication Dispense', () => {
2586
+ const medicationDispense: MedicationDispense = {
2587
+ dosageInstruction: undefined,
2588
+ id: '',
2589
+ location: { display: '', reference: '', type: '' },
2590
+ medicationReference: { display: '', reference: '', type: '' },
2591
+ meta: { lastUpdated: '' },
2592
+ quantity: {
2593
+ value: 5,
2594
+ unit: 'mg',
2595
+ code: '123abc',
2596
+ },
2597
+ performer: undefined,
2598
+ resourceType: 'MedicationDispense',
2599
+ status: MedicationDispenseStatus.completed,
2600
+ subject: { display: '', reference: '', type: '' },
2601
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2602
+ type: undefined,
2603
+ whenHandedOver: '',
2604
+ whenPrepared: '',
2605
+ };
2606
+ expect(getQuantity(medicationDispense).value).toBe(5);
2607
+ });
2608
+ });
2609
+
2610
+ describe('test getQuantityUnitsMatch', () => {
2611
+ const medicationRequest: MedicationRequest = {
2612
+ dispenseRequest: {
2613
+ numberOfRepeatsAllowed: undefined,
2614
+ quantity: {
2615
+ value: 30,
2616
+ unit: 'mg',
2617
+ code: '123abc',
2618
+ },
2619
+ validityPeriod: { start: '' },
2620
+ },
2621
+ dosageInstruction: undefined,
2622
+ encounter: { reference: '', type: '' },
2623
+ id: '',
2624
+ intent: '',
2625
+ medicationReference: { display: '', reference: '', type: '' },
2626
+ meta: { lastUpdated: '' },
2627
+ priority: '',
2628
+ requester: {
2629
+ display: '',
2630
+ identifier: { value: '' },
2631
+ reference: '',
2632
+ type: '',
2633
+ },
2634
+ resourceType: 'MedicationRequest',
2635
+ status: MedicationRequestStatus.completed,
2636
+ subject: { display: '', reference: '', type: '' },
2637
+ extension: [
2638
+ {
2639
+ url: 'http://fhir.openmrs.org/ext/medicationrequest/fulfillerstatus',
2640
+ valueCode: MedicationRequestFulfillerStatus.completed,
2641
+ },
2642
+ ],
2643
+ };
2644
+ const medicationDispense: MedicationDispense = {
2645
+ dosageInstruction: undefined,
2646
+ id: '',
2647
+ location: { display: '', reference: '', type: '' },
2648
+ medicationReference: { display: '', reference: '', type: '' },
2649
+ meta: { lastUpdated: '' },
2650
+ quantity: {
2651
+ value: 5,
2652
+ unit: 'mg',
2653
+ code: '123abc',
2654
+ },
2655
+ performer: undefined,
2656
+ resourceType: 'MedicationDispense',
2657
+ status: MedicationDispenseStatus.completed,
2658
+ subject: { display: '', reference: '', type: '' },
2659
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2660
+ type: undefined,
2661
+ whenHandedOver: '',
2662
+ whenPrepared: '',
2663
+ };
2664
+ const medicationDispenseNoQuantity: MedicationDispense = {
2665
+ dosageInstruction: undefined,
2666
+ id: '',
2667
+ location: { display: '', reference: '', type: '' },
2668
+ medicationReference: { display: '', reference: '', type: '' },
2669
+ meta: { lastUpdated: '' },
2670
+ quantity: undefined,
2671
+ performer: undefined,
2672
+ resourceType: 'MedicationDispense',
2673
+ status: MedicationDispenseStatus.completed,
2674
+ subject: { display: '', reference: '', type: '' },
2675
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2676
+ type: undefined,
2677
+ whenHandedOver: '',
2678
+ whenPrepared: '',
2679
+ };
2680
+ const medicationDispenseDifferentUnits: MedicationDispense = {
2681
+ dosageInstruction: undefined,
2682
+ id: '',
2683
+ location: { display: '', reference: '', type: '' },
2684
+ medicationReference: { display: '', reference: '', type: '' },
2685
+ meta: { lastUpdated: '' },
2686
+ quantity: {
2687
+ value: 1,
2688
+ unit: 'kg',
2689
+ code: '456ddef',
2690
+ },
2691
+ performer: undefined,
2692
+ resourceType: 'MedicationDispense',
2693
+ status: MedicationDispenseStatus.completed,
2694
+ subject: { display: '', reference: '', type: '' },
2695
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2696
+ type: undefined,
2697
+ whenHandedOver: '',
2698
+ whenPrepared: '',
2699
+ };
2700
+ test('should return true if all quantity units match or are undefined', () => {
2701
+ expect(getQuantityUnitsMatch([medicationDispense, medicationRequest, medicationDispenseNoQuantity])).toBe(true);
2702
+ });
2703
+ test("should return false if all quantity units don't match", () => {
2704
+ expect(
2705
+ getQuantityUnitsMatch([
2706
+ medicationDispense,
2707
+ medicationRequest,
2708
+ medicationDispenseNoQuantity,
2709
+ medicationDispenseDifferentUnits,
2710
+ ]),
2711
+ ).toBe(false);
2712
+ });
2713
+ test('should return true for null input', () => {
2714
+ expect(getQuantityUnitsMatch(null)).toBe(true);
2715
+ });
2716
+ test('should return true for empty input', () => {
2717
+ expect(getQuantityUnitsMatch([])).toBe(true);
2718
+ });
2719
+ test('should return true if all quantity units undefined', () => {
2720
+ expect(getQuantityUnitsMatch([medicationDispenseNoQuantity])).toBe(true);
2721
+ });
2722
+ });
2723
+
2724
+ describe('test getRefillsAllowed', () => {
2725
+ test('should return refills allowed from Medication Request', () => {
2726
+ const medicationRequest: MedicationRequest = {
2727
+ dispenseRequest: {
2728
+ numberOfRepeatsAllowed: 3,
2729
+ quantity: {
2730
+ value: 5,
2731
+ unit: 'mg',
2732
+ code: '123abc',
2733
+ },
2734
+ validityPeriod: { start: '' },
2735
+ },
2736
+ dosageInstruction: undefined,
2737
+ encounter: { reference: '', type: '' },
2738
+ id: '',
2739
+ intent: '',
2740
+ medicationReference: { display: '', reference: '', type: '' },
2741
+ meta: { lastUpdated: '' },
2742
+ priority: '',
2743
+ requester: {
2744
+ display: '',
2745
+ identifier: { value: '' },
2746
+ reference: '',
2747
+ type: '',
2748
+ },
2749
+ resourceType: 'MedicationRequest',
2750
+ status: null,
2751
+ subject: { display: '', reference: '', type: '' },
2752
+ };
2753
+ expect(getRefillsAllowed(medicationRequest)).toBe(3);
2754
+ });
2755
+ test('should return null from Medication Dispense', () => {
2756
+ const medicationDispense: MedicationDispense = {
2757
+ dosageInstruction: undefined,
2758
+ id: '',
2759
+ location: { display: '', reference: '', type: '' },
2760
+ medicationReference: { display: '', reference: '', type: '' },
2761
+ meta: { lastUpdated: '' },
2762
+ quantity: {
2763
+ value: 5,
2764
+ unit: 'mg',
2765
+ code: '123abc',
2766
+ },
2767
+ performer: undefined,
2768
+ resourceType: 'MedicationDispense',
2769
+ status: MedicationDispenseStatus.completed,
2770
+ subject: { display: '', reference: '', type: '' },
2771
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2772
+ type: undefined,
2773
+ whenHandedOver: '',
2774
+ whenPrepared: '',
2775
+ };
2776
+ expect(getRefillsAllowed(medicationDispense)).toBeNull();
2777
+ });
2778
+ });
2779
+
2780
+ describe('test isMostRecentMedicationDispenseStatus', () => {
2781
+ const medicationDispense1: MedicationDispense = {
2782
+ dosageInstruction: undefined,
2783
+ id: 'e74e74a1-6b70-40fd-8c44-485178c71721',
2784
+ extension: [
2785
+ {
2786
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
2787
+ valueDateTime: '2023-01-05T14:00:00-05:00',
2788
+ },
2789
+ ],
2790
+ authorizingPrescription: [
2791
+ {
2792
+ reference: 'MedicationRequest/075318da-ce26-4de5-9700-e49820f9d974',
2793
+ type: 'MedicationRequest',
2794
+ },
2795
+ ],
2796
+ location: { display: '', reference: '', type: '' },
2797
+ medicationReference: { display: '', reference: '', type: '' },
2798
+ meta: { lastUpdated: '' },
2799
+ quantity: {
2800
+ value: 1,
2801
+ unit: '',
2802
+ code: '',
2803
+ },
2804
+ performer: undefined,
2805
+ resourceType: 'MedicationDispense',
2806
+ status: MedicationDispenseStatus.on_hold,
2807
+ subject: { display: '', reference: '', type: '' },
2808
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2809
+ type: undefined,
2810
+ whenHandedOver: '2023-01-05T14:00:00-05:00',
2811
+ whenPrepared: '2023-01-05T14:00:00-05:00',
2812
+ };
2813
+
2814
+ const medicationDispense2: MedicationDispense = {
2815
+ dosageInstruction: undefined,
2816
+ id: 'f7b5585d-6867-4f3a-8151-da9ee1f70fab',
2817
+ extension: [
2818
+ {
2819
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
2820
+ valueDateTime: '2023-01-05T20:00:00-05:00',
2821
+ },
2822
+ ],
2823
+ authorizingPrescription: [
2824
+ {
2825
+ reference: 'MedicationRequest/1c1ad91e-8653-453a-9f59-8d5c36249aff',
2826
+ type: 'MedicationRequest',
2827
+ },
2828
+ ],
2829
+ location: { display: '', reference: '', type: '' },
2830
+ medicationReference: { display: '', reference: '', type: '' },
2831
+ meta: { lastUpdated: '' },
2832
+ quantity: {
2833
+ value: 1,
2834
+ unit: '',
2835
+ code: '',
2836
+ },
2837
+ performer: undefined,
2838
+ resourceType: 'MedicationDispense',
2839
+ status: MedicationDispenseStatus.completed,
2840
+ subject: { display: '', reference: '', type: '' },
2841
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2842
+ type: undefined,
2843
+ whenHandedOver: '2023-01-05T20:00:00-05:00',
2844
+ whenPrepared: '2023-01-05T20:00:00-05:00',
2845
+ };
2846
+
2847
+ const medicationDispense3: MedicationDispense = {
2848
+ dosageInstruction: undefined,
2849
+ id: 'a2121f8e-1bcc-4cf9-b1e8-1edace155e7f',
2850
+ extension: [
2851
+ {
2852
+ url: 'http://fhir.openmrs.org/ext/medicationdispense/recorded',
2853
+ valueDateTime: '2023-01-05T17:00:00-05:00',
2854
+ },
2855
+ ],
2856
+ authorizingPrescription: [
2857
+ {
2858
+ reference: 'MedicationRequest/075318da-ce26-4de5-9700-e49820f9d974',
2859
+ type: 'MedicationRequest',
2860
+ },
2861
+ ],
2862
+ location: { display: '', reference: '', type: '' },
2863
+ medicationReference: { display: '', reference: '', type: '' },
2864
+ meta: { lastUpdated: '' },
2865
+ quantity: {
2866
+ value: 1,
2867
+ unit: '',
2868
+ code: '',
2869
+ },
2870
+ performer: undefined,
2871
+ resourceType: 'MedicationDispense',
2872
+ status: MedicationDispenseStatus.declined,
2873
+ subject: { display: '', reference: '', type: '' },
2874
+ substitution: { reason: [], type: undefined, wasSubstituted: false },
2875
+ type: undefined,
2876
+ whenHandedOver: '2023-01-05T17:00:00-05:0',
2877
+ whenPrepared: '2023-01-05T17:00:00-05:0',
2878
+ };
2879
+
2880
+ const medicationDispenses: Array<MedicationDispense> = [
2881
+ medicationDispense1,
2882
+ medicationDispense2,
2883
+ medicationDispense3,
2884
+ ];
2885
+
2886
+ test('should return true if most recent medication request', () => {
2887
+ expect(isMostRecentMedicationDispense(medicationDispense2, medicationDispenses)).toBe(true);
2888
+ });
2889
+ test('should return false if not most recent medication requst', () => {
2890
+ expect(isMostRecentMedicationDispense(medicationDispense1, medicationDispenses)).toBe(false);
2891
+ });
2892
+ test('should return false if null', () => {
2893
+ expect(isMostRecentMedicationDispense(null, medicationDispenses)).toBe(false);
2894
+ });
2895
+ });
2896
+
2897
+ describe('test calculateIsFreeTextDosage', () => {
2898
+ test('should return true when dosageInstruction is null', () => {
2899
+ expect(calculateIsFreeTextDosage(null)).toBe(true);
2900
+ });
2901
+
2902
+ test('should return true when dosageInstruction has no structured data', () => {
2903
+ const dosageInstruction = {
2904
+ text: 'Take as directed',
2905
+ } as DosageInstruction;
2906
+ expect(calculateIsFreeTextDosage(dosageInstruction)).toBe(true);
2907
+ });
2908
+
2909
+ test('should return false when dosageInstruction has doseAndRate with value', () => {
2910
+ const dosageInstruction = {
2911
+ doseAndRate: [
2912
+ {
2913
+ doseQuantity: {
2914
+ value: 5.0,
2915
+ unit: 'mg',
2916
+ code: 'mg',
2917
+ },
2918
+ },
2919
+ ],
2920
+ timing: {
2921
+ code: {
2922
+ coding: [{ code: '123', display: 'Once daily' }],
2923
+ },
2924
+ },
2925
+ route: {
2926
+ coding: [{ code: '456', display: 'Oral' }],
2927
+ text: 'Oral',
2928
+ },
2929
+ asNeededBoolean: false,
2930
+ } as DosageInstruction;
2931
+ expect(calculateIsFreeTextDosage(dosageInstruction)).toBe(false);
2932
+ });
2933
+
2934
+ test('should return true when doseAndRate exists but has no value', () => {
2935
+ const dosageInstruction = {
2936
+ doseAndRate: [
2937
+ {
2938
+ doseQuantity: {
2939
+ unit: 'mg',
2940
+ },
2941
+ },
2942
+ ],
2943
+ } as DosageInstruction;
2944
+ expect(calculateIsFreeTextDosage(dosageInstruction)).toBe(true);
2945
+ });
2946
+ });
2947
+ });