@openmrs/esm-billing-app 1.0.2-pre.82 → 1.0.2-pre.820

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 (207) hide show
  1. package/.eslintrc +16 -2
  2. package/README.md +54 -9
  3. package/__mocks__/bills.mock.ts +12 -0
  4. package/__mocks__/react-i18next.js +6 -5
  5. package/dist/1119.js +1 -1
  6. package/dist/1146.js +1 -2
  7. package/dist/1146.js.map +1 -1
  8. package/dist/1197.js +1 -1
  9. package/dist/1856.js +1 -0
  10. package/dist/1856.js.map +1 -0
  11. package/dist/2146.js +1 -1
  12. package/dist/2177.js +2 -0
  13. package/dist/2177.js.LICENSE.txt +9 -0
  14. package/dist/2177.js.map +1 -0
  15. package/dist/2524.js +1 -0
  16. package/dist/2524.js.map +1 -0
  17. package/dist/2690.js +1 -1
  18. package/dist/3041.js +1 -0
  19. package/dist/3041.js.map +1 -0
  20. package/dist/3099.js +1 -1
  21. package/dist/3584.js +1 -1
  22. package/dist/4055.js +1 -1
  23. package/dist/4132.js +1 -1
  24. package/dist/4225.js +1 -0
  25. package/dist/4225.js.map +1 -0
  26. package/dist/4300.js +1 -1
  27. package/dist/4335.js +1 -1
  28. package/dist/4344.js +1 -0
  29. package/dist/4344.js.map +1 -0
  30. package/dist/4618.js +1 -1
  31. package/dist/4652.js +1 -1
  32. package/dist/4724.js +1 -0
  33. package/dist/4724.js.map +1 -0
  34. package/dist/4739.js +1 -1
  35. package/dist/4739.js.map +1 -1
  36. package/dist/4944.js +1 -1
  37. package/dist/5173.js +1 -1
  38. package/dist/5241.js +1 -1
  39. package/dist/5422.js +1 -0
  40. package/dist/5422.js.map +1 -0
  41. package/dist/5442.js +1 -1
  42. package/dist/5661.js +1 -1
  43. package/dist/6022.js +1 -1
  44. package/dist/6468.js +1 -1
  45. package/dist/6540.js +1 -1
  46. package/dist/6540.js.map +1 -1
  47. package/dist/6606.js +1 -0
  48. package/dist/6606.js.map +1 -0
  49. package/dist/6679.js +1 -1
  50. package/dist/6840.js +1 -1
  51. package/dist/6859.js +1 -1
  52. package/dist/7097.js +1 -1
  53. package/dist/7159.js +1 -1
  54. package/dist/723.js +1 -1
  55. package/dist/7452.js +2 -0
  56. package/dist/7452.js.map +1 -0
  57. package/dist/7617.js +1 -1
  58. package/dist/795.js +1 -1
  59. package/dist/8163.js +1 -1
  60. package/dist/8349.js +1 -1
  61. package/dist/8618.js +1 -1
  62. package/dist/890.js +1 -1
  63. package/dist/8930.js +2 -0
  64. package/dist/{6525.js.LICENSE.txt → 8930.js.LICENSE.txt} +16 -4
  65. package/dist/8930.js.map +1 -0
  66. package/dist/9214.js +1 -1
  67. package/dist/9538.js +1 -1
  68. package/dist/9569.js +1 -1
  69. package/dist/961.js +1 -1
  70. package/dist/961.js.map +1 -1
  71. package/dist/986.js +1 -1
  72. package/dist/9879.js +1 -1
  73. package/dist/9895.js +1 -1
  74. package/dist/9900.js +1 -1
  75. package/dist/9913.js +1 -1
  76. package/dist/main.js +1 -1
  77. package/dist/main.js.map +1 -1
  78. package/dist/openmrs-esm-billing-app.js +1 -1
  79. package/dist/openmrs-esm-billing-app.js.buildmanifest.json +371 -265
  80. package/dist/openmrs-esm-billing-app.js.map +1 -1
  81. package/dist/routes.json +1 -1
  82. package/e2e/README.md +19 -18
  83. package/e2e/core/test.ts +1 -1
  84. package/e2e/fixtures/api.ts +1 -1
  85. package/e2e/specs/sample-test.spec.ts +0 -1
  86. package/e2e/support/github/Dockerfile +1 -1
  87. package/package.json +13 -10
  88. package/src/bill-history/bill-history.component.tsx +17 -25
  89. package/src/bill-history/bill-history.scss +4 -94
  90. package/src/bill-history/bill-history.test.tsx +37 -78
  91. package/src/bill-item-actions/bill-item-actions.scss +0 -4
  92. package/src/bill-item-actions/{edit-bill-item.component.tsx → edit-bill-item.modal.tsx} +100 -78
  93. package/src/bill-item-actions/edit-bill-item.test.tsx +116 -31
  94. package/src/billable-services/bill-waiver/bill-selection.component.tsx +2 -2
  95. package/src/billable-services/bill-waiver/bill-waiver-form.component.tsx +2 -3
  96. package/src/billable-services/bill-waiver/patient-bills.component.tsx +3 -3
  97. package/src/billable-services/bill-waiver/utils.ts +13 -3
  98. package/src/billable-services/billable-service.resource.ts +28 -12
  99. package/src/billable-services/billable-services-home.component.tsx +1 -1
  100. package/src/billable-services/billable-services.component.tsx +142 -145
  101. package/src/billable-services/billable-services.scss +3 -0
  102. package/src/billable-services/billable-services.test.tsx +2 -45
  103. package/src/billable-services/cash-point/add-cash-point.modal.tsx +168 -0
  104. package/src/billable-services/cash-point/cash-point-configuration.component.tsx +18 -192
  105. package/src/billable-services/cash-point/cash-point-configuration.scss +1 -5
  106. package/src/billable-services/create-edit/add-billable-service.component.tsx +358 -300
  107. package/src/billable-services/create-edit/add-billable-service.scss +6 -65
  108. package/src/billable-services/create-edit/add-billable-service.test.tsx +166 -80
  109. package/src/billable-services/create-edit/edit-billable-service.modal.tsx +51 -0
  110. package/src/billable-services/payment-modes/add-payment-mode.modal.tsx +121 -0
  111. package/src/billable-services/payment-modes/delete-payment-mode.modal.tsx +72 -0
  112. package/src/billable-services/payment-modes/payment-modes-config.component.tsx +125 -0
  113. package/src/billable-services/{payyment-modes → payment-modes}/payment-modes-config.scss +5 -4
  114. package/src/billing-form/billing-checkin-form.component.tsx +2 -3
  115. package/src/billing-form/billing-checkin-form.test.tsx +97 -24
  116. package/src/billing-form/billing-form.component.tsx +216 -269
  117. package/src/billing-form/billing-form.scss +143 -0
  118. package/src/billing.resource.ts +52 -68
  119. package/src/bills-table/bills-table.test.tsx +98 -54
  120. package/src/config-schema.ts +52 -24
  121. package/src/dashboard.meta.ts +4 -2
  122. package/src/helpers/functions.ts +5 -4
  123. package/src/index.ts +17 -6
  124. package/src/invoice/invoice-table.component.tsx +34 -68
  125. package/src/invoice/invoice-table.scss +8 -5
  126. package/src/invoice/invoice-table.test.tsx +273 -62
  127. package/src/invoice/invoice.component.tsx +38 -29
  128. package/src/invoice/invoice.scss +11 -4
  129. package/src/invoice/invoice.test.tsx +324 -120
  130. package/src/invoice/payments/invoice-breakdown/invoice-breakdown.scss +9 -9
  131. package/src/invoice/payments/payment-form/payment-form.component.tsx +43 -34
  132. package/src/invoice/payments/payment-form/payment-form.scss +5 -6
  133. package/src/invoice/payments/payment-form/payment-form.test.tsx +216 -66
  134. package/src/invoice/payments/payment-history/payment-history.component.tsx +6 -4
  135. package/src/invoice/payments/payment-history/payment-history.test.tsx +9 -14
  136. package/src/invoice/payments/payments.component.tsx +53 -65
  137. package/src/invoice/payments/payments.scss +4 -3
  138. package/src/invoice/payments/payments.test.tsx +282 -0
  139. package/src/invoice/payments/utils.ts +15 -27
  140. package/src/invoice/printable-invoice/print-receipt.component.tsx +3 -2
  141. package/src/invoice/printable-invoice/print-receipt.test.tsx +14 -25
  142. package/src/invoice/printable-invoice/printable-footer.component.tsx +2 -2
  143. package/src/invoice/printable-invoice/printable-footer.test.tsx +4 -13
  144. package/src/invoice/printable-invoice/printable-invoice-header.component.tsx +12 -11
  145. package/src/invoice/printable-invoice/printable-invoice-header.test.tsx +16 -14
  146. package/src/invoice/printable-invoice/printable-invoice.component.tsx +19 -33
  147. package/src/left-panel-link.test.tsx +1 -4
  148. package/src/metrics-cards/metrics-cards.test.tsx +18 -5
  149. package/src/modal/require-payment-modal.test.tsx +27 -22
  150. package/src/modal/{require-payment-modal.component.tsx → require-payment.modal.tsx} +17 -18
  151. package/src/routes.json +22 -2
  152. package/src/types/index.ts +80 -18
  153. package/translations/am.json +69 -21
  154. package/translations/ar.json +69 -21
  155. package/translations/ar_SY.json +69 -21
  156. package/translations/bn.json +74 -26
  157. package/translations/de.json +69 -21
  158. package/translations/en.json +69 -21
  159. package/translations/en_US.json +69 -21
  160. package/translations/es.json +69 -21
  161. package/translations/es_MX.json +69 -21
  162. package/translations/fr.json +82 -34
  163. package/translations/he.json +69 -21
  164. package/translations/hi.json +69 -21
  165. package/translations/hi_IN.json +69 -21
  166. package/translations/id.json +69 -21
  167. package/translations/it.json +104 -56
  168. package/translations/ka.json +69 -21
  169. package/translations/km.json +69 -21
  170. package/translations/ku.json +69 -21
  171. package/translations/ky.json +69 -21
  172. package/translations/lg.json +69 -21
  173. package/translations/ne.json +69 -21
  174. package/translations/pl.json +69 -21
  175. package/translations/pt.json +69 -21
  176. package/translations/pt_BR.json +69 -21
  177. package/translations/qu.json +69 -21
  178. package/translations/ro_RO.json +213 -165
  179. package/translations/ru_RU.json +69 -21
  180. package/translations/si.json +69 -21
  181. package/translations/sw.json +69 -21
  182. package/translations/sw_KE.json +69 -21
  183. package/translations/tr.json +69 -21
  184. package/translations/tr_TR.json +69 -21
  185. package/translations/uk.json +69 -21
  186. package/translations/uz.json +69 -21
  187. package/translations/uz@Latn.json +69 -21
  188. package/translations/uz_UZ.json +69 -21
  189. package/translations/vi.json +69 -21
  190. package/translations/zh.json +69 -21
  191. package/translations/zh_CN.json +124 -76
  192. package/dist/1146.js.LICENSE.txt +0 -21
  193. package/dist/2352.js +0 -1
  194. package/dist/2352.js.map +0 -1
  195. package/dist/246.js +0 -1
  196. package/dist/246.js.map +0 -1
  197. package/dist/6525.js +0 -2
  198. package/dist/6525.js.map +0 -1
  199. package/dist/8556.js +0 -2
  200. package/dist/8556.js.map +0 -1
  201. package/dist/8638.js +0 -1
  202. package/dist/8638.js.map +0 -1
  203. package/dist/9968.js +0 -1
  204. package/dist/9968.js.map +0 -1
  205. package/src/billable-services/payyment-modes/payment-modes-config.component.tsx +0 -280
  206. package/src/invoice/payments/payments.component.test.tsx +0 -121
  207. /package/dist/{8556.js.LICENSE.txt → 7452.js.LICENSE.txt} +0 -0
@@ -1,22 +1,27 @@
1
1
  import React from 'react';
2
- import { render, screen, fireEvent, waitFor } from '@testing-library/react';
3
- import { showSnackbar } from '@openmrs/esm-framework';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { render, screen, waitFor } from '@testing-library/react';
4
+ import { type FetchResponse, showSnackbar } from '@openmrs/esm-framework';
4
5
  import { type MappedBill } from '../types';
5
6
  import { updateBillItems } from '../billing.resource';
6
- import ChangeStatus from './edit-bill-item.component';
7
+ import EditBillLineItemModal from './edit-bill-item.modal';
8
+
9
+ const mockUpdateBillItems = jest.mocked(updateBillItems);
10
+ const mockShowSnackbar = jest.mocked(showSnackbar);
7
11
 
8
- // Mock external dependencies
9
12
  jest.mock('../billing.resource', () => ({
10
13
  updateBillItems: jest.fn(() => Promise.resolve({})),
11
14
  }));
12
15
 
13
- jest.mock('@openmrs/esm-framework', () => ({
14
- showSnackbar: jest.fn(),
15
- }));
16
+ const mockBillableServices = [
17
+ { name: 'X-Ray Service', uuid: 'xray-uuid-123' },
18
+ { name: 'Lab Test Service', uuid: 'lab-uuid-456' },
19
+ { name: 'Consultation Service', uuid: 'consult-uuid-789' },
20
+ ];
16
21
 
17
22
  jest.mock('../billable-services/billable-service.resource', () => ({
18
23
  useBillableServices: jest.fn(() => ({
19
- billableServices: [],
24
+ billableServices: mockBillableServices,
20
25
  })),
21
26
  }));
22
27
 
@@ -41,7 +46,7 @@ const mockBill: MappedBill = {
41
46
  voided: false,
42
47
  voidReason: null,
43
48
  priceName: 'Service Price',
44
- billableService: 'service-uuid',
49
+ billableService: 'X-Ray Service',
45
50
  priceUuid: 'price-uuid',
46
51
  lineItemOrder: 1,
47
52
  resourceVersion: '1.0',
@@ -62,7 +67,7 @@ const mockItem = {
62
67
  uuid: 'item-uuid',
63
68
  quantity: 2,
64
69
  price: 100,
65
- billableService: 'service-uuid',
70
+ billableService: 'X-Ray Service',
66
71
  paymentStatus: 'UNPAID',
67
72
  item: 'Test Service',
68
73
  display: 'Test Service',
@@ -77,61 +82,141 @@ const mockItem = {
77
82
  describe('ChangeStatus component', () => {
78
83
  const closeModalMock = jest.fn();
79
84
 
80
- beforeEach(() => {
81
- jest.clearAllMocks();
82
- });
83
-
84
85
  test('renders the form with correct fields and default values', () => {
85
- render(<ChangeStatus bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
86
+ render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
86
87
 
87
- expect(screen.getByText('Edit bill line item?')).toBeInTheDocument();
88
+ expect(screen.getByText('Edit bill line item')).toBeInTheDocument();
88
89
  expect(screen.getByText('John Doe · Main Cashpoint · 123456')).toBeInTheDocument();
89
90
  expect(screen.getByRole('spinbutton', { name: /Quantity/ })).toHaveValue(2);
90
91
  expect(screen.getByLabelText(/Unit Price/)).toHaveValue('100');
91
92
  expect(screen.getByText(/Total/)).toHaveTextContent('200');
92
93
  });
93
94
 
94
- test('updates total when quantity is changed', () => {
95
- render(<ChangeStatus bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
95
+ test('updates total when quantity is changed', async () => {
96
+ const user = userEvent.setup();
97
+ render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
96
98
 
97
99
  const quantityInput = screen.getByRole('spinbutton', { name: /Quantity/ });
98
- fireEvent.change(quantityInput, { target: { value: 3 } });
100
+ await user.type(quantityInput, '3');
99
101
 
100
102
  expect(screen.getByText(/Total/)).toHaveTextContent('300');
101
103
  });
102
104
 
103
105
  test('submits the form and shows a success notification', async () => {
104
- (updateBillItems as jest.Mock).mockResolvedValueOnce({});
106
+ const user = userEvent.setup();
107
+ mockUpdateBillItems.mockResolvedValueOnce({} as FetchResponse<any>);
105
108
 
106
- render(<ChangeStatus bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
109
+ render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
107
110
 
108
- fireEvent.click(screen.getByText(/Save/));
111
+ await user.click(screen.getByText(/Save/));
109
112
 
110
113
  await waitFor(() => {
111
- expect(updateBillItems).toHaveBeenCalled();
114
+ expect(mockUpdateBillItems).toHaveBeenCalled();
112
115
  expect(showSnackbar).toHaveBeenCalledWith({
113
- title: 'Save Bill',
114
- subtitle: 'Bill processing has been successful',
116
+ title: 'Line item updated',
117
+ subtitle: 'The bill line item has been updated successfully',
115
118
  kind: 'success',
116
- timeoutInMs: 3000,
117
119
  });
118
120
  expect(closeModalMock).toHaveBeenCalled();
119
121
  });
120
122
  });
121
123
 
122
124
  test('shows error notification when submission fails', async () => {
123
- (updateBillItems as jest.Mock).mockRejectedValueOnce({ message: 'Error occurred' });
125
+ const user = userEvent.setup();
126
+ mockUpdateBillItems.mockRejectedValueOnce({ message: 'Error occurred' });
124
127
 
125
- render(<ChangeStatus bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
128
+ render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
126
129
 
127
- fireEvent.click(screen.getByText(/Save/));
130
+ await user.click(screen.getByText(/Save/));
128
131
 
129
132
  await waitFor(() => {
130
- expect(showSnackbar).toHaveBeenCalledWith({
131
- title: 'Bill processing error',
133
+ expect(mockShowSnackbar).toHaveBeenCalledWith({
134
+ title: 'Failed to update line item',
132
135
  kind: 'error',
133
136
  subtitle: 'Error occurred',
134
137
  });
135
138
  });
136
139
  });
140
+
141
+ test('preserves billable service UUIDs for other line items when editing', async () => {
142
+ const user = userEvent.setup();
143
+ mockUpdateBillItems.mockResolvedValueOnce({} as FetchResponse<any>);
144
+
145
+ // Bill with multiple line items with different billable services
146
+ const billWithMultipleItems: MappedBill = {
147
+ ...mockBill,
148
+ lineItems: [
149
+ {
150
+ uuid: 'item-1',
151
+ quantity: 1,
152
+ price: 100,
153
+ billableService: 'X-Ray Service',
154
+ paymentStatus: 'PENDING',
155
+ item: 'X-Ray',
156
+ display: 'X-Ray',
157
+ voided: false,
158
+ voidReason: null,
159
+ priceName: 'X-Ray Price',
160
+ priceUuid: 'xray-price-uuid',
161
+ lineItemOrder: 1,
162
+ resourceVersion: '1.0',
163
+ },
164
+ {
165
+ uuid: 'item-2',
166
+ quantity: 2,
167
+ price: 50,
168
+ billableService: 'Lab Test Service',
169
+ paymentStatus: 'PENDING',
170
+ item: 'Lab Test',
171
+ display: 'Lab Test',
172
+ voided: false,
173
+ voidReason: null,
174
+ priceName: 'Lab Price',
175
+ priceUuid: 'lab-price-uuid',
176
+ lineItemOrder: 2,
177
+ resourceVersion: '1.0',
178
+ },
179
+ {
180
+ uuid: 'item-3',
181
+ quantity: 1,
182
+ price: 200,
183
+ billableService: 'Consultation Service',
184
+ paymentStatus: 'PENDING',
185
+ item: 'Consultation',
186
+ display: 'Consultation',
187
+ voided: false,
188
+ voidReason: null,
189
+ priceName: 'Consult Price',
190
+ priceUuid: 'consult-price-uuid',
191
+ lineItemOrder: 3,
192
+ resourceVersion: '1.0',
193
+ },
194
+ ],
195
+ };
196
+
197
+ // Editing the Lab Test item (item-2)
198
+ const itemToEdit = billWithMultipleItems.lineItems[1];
199
+
200
+ render(<EditBillLineItemModal bill={billWithMultipleItems} item={itemToEdit} closeModal={closeModalMock} />);
201
+
202
+ await user.click(screen.getByText(/Save/));
203
+
204
+ await waitFor(() => {
205
+ expect(mockUpdateBillItems).toHaveBeenCalled();
206
+ const payload = mockUpdateBillItems.mock.calls[0][0];
207
+
208
+ // Verify that each line item has the correct billable service UUID
209
+ const xrayItem = payload.lineItems.find((li) => li.uuid === 'item-1');
210
+ const consultItem = payload.lineItems.find((li) => li.uuid === 'item-3');
211
+
212
+ // These should NOT have the Lab Test UUID (lab-uuid-456)
213
+ // They should keep their original UUIDs
214
+ expect(xrayItem?.billableService).toBe('xray-uuid-123');
215
+ expect(consultItem?.billableService).toBe('consult-uuid-789');
216
+
217
+ // The edited item should have the Lab Test UUID
218
+ const labItem = payload.lineItems.find((li) => li.uuid === 'item-2');
219
+ expect(labItem?.billableService).toBe('lab-uuid-456');
220
+ });
221
+ });
137
222
  });
@@ -9,7 +9,7 @@ import {
9
9
  StructuredListWrapper,
10
10
  } from '@carbon/react';
11
11
  import { useTranslation } from 'react-i18next';
12
- import { useConfig } from '@openmrs/esm-framework';
12
+ import { getCoreTranslation, useConfig } from '@openmrs/esm-framework';
13
13
  import { convertToCurrency } from '../../helpers';
14
14
  import { type MappedBill, type LineItem } from '../../types';
15
15
  import BillWaiverForm from './bill-waiver-form.component';
@@ -44,7 +44,7 @@ const PatientBillsSelections: React.FC<{ bills: MappedBill; setPatientUuid: (pat
44
44
  <StructuredListCell head>{t('quantity', 'Quantity')}</StructuredListCell>
45
45
  <StructuredListCell head>{t('unitPrice', 'Unit Price')}</StructuredListCell>
46
46
  <StructuredListCell head>{t('total', 'Total')}</StructuredListCell>
47
- <StructuredListCell head>{t('actions', 'Actions')}</StructuredListCell>
47
+ <StructuredListCell head>{getCoreTranslation('actions')}</StructuredListCell>
48
48
  </StructuredListRow>
49
49
  </StructuredListHead>
50
50
  <StructuredListBody>
@@ -29,7 +29,7 @@ const BillWaiverForm: React.FC<BillWaiverFormProps> = ({ bill, lineItems, setPat
29
29
  return null;
30
30
  }
31
31
 
32
- const handleProcessPayment = (event) => {
32
+ const handleProcessPayment = () => {
33
33
  const waiverEndPointPayload = createBillWaiverPayload(
34
34
  bill,
35
35
  waiverAmount,
@@ -39,7 +39,7 @@ const BillWaiverForm: React.FC<BillWaiverFormProps> = ({ bill, lineItems, setPat
39
39
  );
40
40
 
41
41
  processBillPayment(waiverEndPointPayload, bill.uuid).then(
42
- (resp) => {
42
+ () => {
43
43
  showSnackbar({
44
44
  title: t('billWaiver', 'Bill waiver'),
45
45
  subtitle: t('billWaiverSuccess', 'Bill waiver successful'),
@@ -57,7 +57,6 @@ const BillWaiverForm: React.FC<BillWaiverFormProps> = ({ bill, lineItems, setPat
57
57
  title: t('billWaiver', 'Bill waiver'),
58
58
  subtitle: t('billWaiverError', 'Bill waiver failed {{error}}', { error: err.message }),
59
59
  kind: 'error',
60
- timeoutInMs: 3500,
61
60
  isLowContrast: true,
62
61
  });
63
62
  },
@@ -37,9 +37,9 @@ const PatientBills: React.FC<PatientBillsProps> = ({ patientUuid, bills, setPati
37
37
  }
38
38
 
39
39
  const tableHeaders = [
40
- { header: 'Date', key: 'date' },
41
- { header: 'Billable Service', key: 'billableService' },
42
- { header: 'Total Amount', key: 'totalAmount' },
40
+ { header: t('date', 'Date'), key: 'date' },
41
+ { header: t('billableService', 'Billable Service'), key: 'billableService' },
42
+ { header: t('totalAmount', 'Total Amount'), key: 'totalAmount' },
43
43
  ];
44
44
 
45
45
  const tableRows = bills.map((bill) => ({
@@ -1,6 +1,7 @@
1
1
  import { type OpenmrsResource } from '@openmrs/esm-framework';
2
- import type { LineItem, MappedBill } from '../../types';
2
+ import type { LineItem, MappedBill, PaymentPayload } from '../../types';
3
3
 
4
+ // TODO: Move this UUID to the config schema
4
5
  const WAIVER_UUID = 'eb6173cb-9678-4614-bbe1-0ccf7ed9d1d4';
5
6
 
6
7
  export const createBillWaiverPayload = (
@@ -12,7 +13,7 @@ export const createBillWaiverPayload = (
12
13
  ) => {
13
14
  const { cashier } = bill;
14
15
 
15
- const billPayment = {
16
+ const billPayment: PaymentPayload = {
16
17
  amount: parseFloat(totalAmount.toFixed(2)),
17
18
  amountTendered: parseFloat(Number(amountWaived).toFixed(2)),
18
19
  attributes: [],
@@ -25,11 +26,20 @@ export const createBillWaiverPayload = (
25
26
  paymentStatus: 'PAID',
26
27
  }));
27
28
 
29
+ // Transform existing payments to PaymentPayload format
30
+ const existingPayments: PaymentPayload[] = bill.payments.map((payment) => ({
31
+ amount: payment.amount,
32
+ amountTendered: payment.amountTendered,
33
+ attributes: payment.attributes,
34
+ instanceType: payment.instanceType.uuid,
35
+ dateCreated: payment.dateCreated,
36
+ }));
37
+
28
38
  const processedPayment = {
29
39
  cashPoint: bill.cashPointUuid,
30
40
  cashier: cashier.uuid,
31
41
  lineItems: processedLineItems,
32
- payments: [...bill.payments, billPayment],
42
+ payments: [...existingPayments, billPayment],
33
43
  patient: bill.patientUuid,
34
44
  };
35
45
 
@@ -1,8 +1,13 @@
1
1
  import useSWR from 'swr';
2
2
  import { type OpenmrsResource, openmrsFetch, restBaseUrl, useOpenmrsFetchAll, useConfig } from '@openmrs/esm-framework';
3
- import { type ServiceConcept } from '../types';
4
3
  import { apiBasePath } from '../constants';
5
- import { type BillableService } from '../types/index';
4
+ import {
5
+ type BillableService,
6
+ type ServiceConcept,
7
+ type CreateBillableServicePayload,
8
+ type UpdateBillableServicePayload,
9
+ } from '../types';
10
+ import type { BillingConfig } from '../config-schema';
6
11
 
7
12
  type ResponseObject = {
8
13
  results: Array<OpenmrsResource>;
@@ -10,7 +15,7 @@ type ResponseObject = {
10
15
 
11
16
  export const useBillableServices = () => {
12
17
  const url = `${apiBasePath}billableService?v=custom:(uuid,name,shortName,serviceStatus,concept:(uuid,display,name:(name)),serviceType:(display),servicePrices:(uuid,name,price,paymentMode:(uuid,name)))`;
13
- const { data, isLoading, isValidating, error, mutate } = useOpenmrsFetchAll<BillableService[]>(url);
18
+ const { data, isLoading, isValidating, error, mutate } = useOpenmrsFetchAll<BillableService>(url);
14
19
 
15
20
  return {
16
21
  billableServices: data ?? [],
@@ -22,16 +27,23 @@ export const useBillableServices = () => {
22
27
  };
23
28
 
24
29
  export function useServiceTypes() {
25
- const config = useConfig();
26
- const serviceConceptUuid = config.serviceTypes.billableService;
30
+ const { serviceTypes } = useConfig<BillingConfig>();
31
+ const serviceConceptUuid = serviceTypes.billableService;
27
32
  const url = `${restBaseUrl}/concept/${serviceConceptUuid}?v=custom:(setMembers:(uuid,display))`;
28
33
 
29
- const { data, error, isLoading } = useSWR<{ data }>(url, openmrsFetch);
34
+ const { data, error, isLoading } = useSWR<{ data: { setMembers: Array<{ uuid: string; display: string }> } }>(
35
+ url,
36
+ openmrsFetch,
37
+ );
38
+
39
+ const sortedServiceTypes = data?.data.setMembers
40
+ ? [...data.data.setMembers].sort((a, b) => a.display.localeCompare(b.display))
41
+ : [];
30
42
 
31
43
  return {
32
- serviceTypes: data?.data.setMembers ?? [],
44
+ serviceTypes: sortedServiceTypes,
33
45
  error,
34
- isLoading,
46
+ isLoadingServiceTypes: isLoading,
35
47
  };
36
48
  }
37
49
 
@@ -40,14 +52,18 @@ export const usePaymentModes = () => {
40
52
 
41
53
  const { data, error, isLoading } = useSWR<{ data: ResponseObject }>(url, openmrsFetch);
42
54
 
55
+ const sortedPaymentModes = data?.data.results
56
+ ? [...data.data.results].sort((a, b) => a.name.localeCompare(b.name))
57
+ : [];
58
+
43
59
  return {
44
- paymentModes: data?.data.results ?? [],
60
+ paymentModes: sortedPaymentModes,
45
61
  error,
46
- isLoading,
62
+ isLoadingPaymentModes: isLoading,
47
63
  };
48
64
  };
49
65
 
50
- export const createBillableSerice = (payload: any) => {
66
+ export const createBillableService = (payload: CreateBillableServicePayload) => {
51
67
  const url = `${apiBasePath}api/billable-service`;
52
68
  return openmrsFetch(url, {
53
69
  method: 'POST',
@@ -73,7 +89,7 @@ export function useConceptsSearch(conceptToLookup: string) {
73
89
  };
74
90
  }
75
91
 
76
- export const updateBillableService = (uuid: string, payload: any) => {
92
+ export const updateBillableService = (uuid: string, payload: UpdateBillableServicePayload) => {
77
93
  const url = `${apiBasePath}/billableService/${uuid}`;
78
94
  return openmrsFetch(url, {
79
95
  method: 'POST',
@@ -9,7 +9,7 @@ import BillWaiver from './bill-waiver/bill-waiver.component';
9
9
  import BillableServicesDashboard from './dashboard/dashboard.component';
10
10
  import BillingHeader from '../billing-header/billing-header.component';
11
11
  import CashPointConfiguration from './cash-point/cash-point-configuration.component';
12
- import PaymentModesConfig from './payyment-modes/payment-modes-config.component';
12
+ import PaymentModesConfig from './payment-modes/payment-modes-config.component';
13
13
  import styles from './billable-services.scss';
14
14
 
15
15
  const BillableServiceHome: React.FC = () => {