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

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 (36) hide show
  1. package/dist/1856.js +1 -1
  2. package/dist/3717.js +2 -0
  3. package/dist/3717.js.map +1 -0
  4. package/dist/4300.js +1 -1
  5. package/dist/4344.js +1 -1
  6. package/dist/4344.js.map +1 -1
  7. package/dist/4724.js +1 -1
  8. package/dist/4724.js.map +1 -1
  9. package/dist/4739.js +1 -1
  10. package/dist/4739.js.map +1 -1
  11. package/dist/6295.js +2 -0
  12. package/dist/6295.js.map +1 -0
  13. package/dist/main.js +1 -1
  14. package/dist/main.js.map +1 -1
  15. package/dist/openmrs-esm-billing-app.js +1 -1
  16. package/dist/openmrs-esm-billing-app.js.buildmanifest.json +70 -70
  17. package/dist/routes.json +1 -1
  18. package/package.json +1 -1
  19. package/src/bill-item-actions/bill-item-actions.scss +21 -1
  20. package/src/bill-item-actions/edit-bill-item.modal.tsx +19 -37
  21. package/src/bill-item-actions/edit-bill-item.test.tsx +105 -16
  22. package/src/billable-services/bill-waiver/bill-selection.component.tsx +2 -2
  23. package/src/billable-services/bill-waiver/bill-waiver-form.component.tsx +26 -29
  24. package/src/billing-form/billing-checkin-form.component.tsx +18 -13
  25. package/src/billing-form/billing-form.component.tsx +20 -37
  26. package/src/billing.resource.ts +23 -12
  27. package/src/invoice/invoice-table.component.tsx +1 -1
  28. package/src/invoice/invoice-table.test.tsx +1 -1
  29. package/src/routes.json +4 -6
  30. package/translations/en.json +5 -3
  31. package/dist/7452.js +0 -2
  32. package/dist/7452.js.map +0 -1
  33. package/dist/8930.js +0 -2
  34. package/dist/8930.js.map +0 -1
  35. /package/dist/{7452.js.LICENSE.txt → 3717.js.LICENSE.txt} +0 -0
  36. /package/dist/{8930.js.LICENSE.txt → 6295.js.LICENSE.txt} +0 -0
@@ -1,17 +1,15 @@
1
1
  import React from 'react';
2
2
  import userEvent from '@testing-library/user-event';
3
3
  import { render, screen, waitFor } from '@testing-library/react';
4
- import { type FetchResponse, showSnackbar } from '@openmrs/esm-framework';
4
+ import { type FetchResponse, getDefaultsFromConfigSchema, showSnackbar, useConfig } from '@openmrs/esm-framework';
5
+ import { configSchema, type BillingConfig } from '../config-schema';
5
6
  import { type MappedBill } from '../types';
6
7
  import { updateBillItems } from '../billing.resource';
7
8
  import EditBillLineItemModal from './edit-bill-item.modal';
8
9
 
9
10
  const mockUpdateBillItems = jest.mocked(updateBillItems);
10
11
  const mockShowSnackbar = jest.mocked(showSnackbar);
11
-
12
- jest.mock('../billing.resource', () => ({
13
- updateBillItems: jest.fn(() => Promise.resolve({})),
14
- }));
12
+ const mockUseConfig = jest.mocked(useConfig<BillingConfig>);
15
13
 
16
14
  const mockBillableServices = [
17
15
  { name: 'X-Ray Service', uuid: 'xray-uuid-123' },
@@ -19,6 +17,10 @@ const mockBillableServices = [
19
17
  { name: 'Consultation Service', uuid: 'consult-uuid-789' },
20
18
  ];
21
19
 
20
+ jest.mock('../billing.resource', () => ({
21
+ updateBillItems: jest.fn().mockResolvedValue({}),
22
+ }));
23
+
22
24
  jest.mock('../billable-services/billable-service.resource', () => ({
23
25
  useBillableServices: jest.fn(() => ({
24
26
  billableServices: mockBillableServices,
@@ -79,34 +81,44 @@ const mockItem = {
79
81
  resourceVersion: '1.0',
80
82
  };
81
83
 
82
- describe('ChangeStatus component', () => {
83
- const closeModalMock = jest.fn();
84
+ describe('EditBillItem', () => {
85
+ beforeEach(() => {
86
+ mockUseConfig.mockReturnValue({
87
+ ...getDefaultsFromConfigSchema(configSchema),
88
+ defaultCurrency: 'USD',
89
+ });
90
+ });
91
+
92
+ const mockCloseModal = jest.fn();
84
93
 
85
94
  test('renders the form with correct fields and default values', () => {
86
- render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
95
+ render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={mockCloseModal} />);
87
96
 
88
97
  expect(screen.getByText('Edit bill line item')).toBeInTheDocument();
89
- expect(screen.getByText('John Doe · Main Cashpoint · 123456')).toBeInTheDocument();
98
+ expect(screen.getByText(/John Doe/)).toBeInTheDocument();
99
+ expect(screen.getByText(/Main Cashpoint/)).toBeInTheDocument();
100
+ expect(screen.getByText(/123456/)).toBeInTheDocument();
90
101
  expect(screen.getByRole('spinbutton', { name: /Quantity/ })).toHaveValue(2);
91
102
  expect(screen.getByLabelText(/Unit Price/)).toHaveValue('100');
92
- expect(screen.getByText(/Total/)).toHaveTextContent('200');
103
+ expect(screen.getByText(/Total/)).toHaveTextContent(/200/);
93
104
  });
94
105
 
95
106
  test('updates total when quantity is changed', async () => {
96
107
  const user = userEvent.setup();
97
- render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
108
+ render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={mockCloseModal} />);
98
109
 
99
110
  const quantityInput = screen.getByRole('spinbutton', { name: /Quantity/ });
111
+ await user.clear(quantityInput);
100
112
  await user.type(quantityInput, '3');
101
113
 
102
- expect(screen.getByText(/Total/)).toHaveTextContent('300');
114
+ expect(screen.getByText(/Total/)).toHaveTextContent(/300/);
103
115
  });
104
116
 
105
117
  test('submits the form and shows a success notification', async () => {
106
118
  const user = userEvent.setup();
107
119
  mockUpdateBillItems.mockResolvedValueOnce({} as FetchResponse<any>);
108
120
 
109
- render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
121
+ render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={mockCloseModal} />);
110
122
 
111
123
  await user.click(screen.getByText(/Save/));
112
124
 
@@ -117,7 +129,7 @@ describe('ChangeStatus component', () => {
117
129
  subtitle: 'The bill line item has been updated successfully',
118
130
  kind: 'success',
119
131
  });
120
- expect(closeModalMock).toHaveBeenCalled();
132
+ expect(mockCloseModal).toHaveBeenCalled();
121
133
  });
122
134
  });
123
135
 
@@ -125,7 +137,7 @@ describe('ChangeStatus component', () => {
125
137
  const user = userEvent.setup();
126
138
  mockUpdateBillItems.mockRejectedValueOnce({ message: 'Error occurred' });
127
139
 
128
- render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
140
+ render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={mockCloseModal} />);
129
141
 
130
142
  await user.click(screen.getByText(/Save/));
131
143
 
@@ -197,7 +209,7 @@ describe('ChangeStatus component', () => {
197
209
  // Editing the Lab Test item (item-2)
198
210
  const itemToEdit = billWithMultipleItems.lineItems[1];
199
211
 
200
- render(<EditBillLineItemModal bill={billWithMultipleItems} item={itemToEdit} closeModal={closeModalMock} />);
212
+ render(<EditBillLineItemModal bill={billWithMultipleItems} item={itemToEdit} closeModal={mockCloseModal} />);
201
213
 
202
214
  await user.click(screen.getByText(/Save/));
203
215
 
@@ -219,4 +231,81 @@ describe('ChangeStatus component', () => {
219
231
  expect(labItem?.billableService).toBe('lab-uuid-456');
220
232
  });
221
233
  });
234
+
235
+ test('shows validation error for quantity less than 1', async () => {
236
+ const user = userEvent.setup();
237
+ render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={mockCloseModal} />);
238
+
239
+ const quantityInput = screen.getByRole('spinbutton', { name: /Quantity/ });
240
+ await user.clear(quantityInput);
241
+ await user.type(quantityInput, '0');
242
+
243
+ // Try to submit
244
+ await user.click(screen.getByText(/Save/));
245
+
246
+ // Should show validation error
247
+ await waitFor(() => {
248
+ expect(screen.getByText(/Quantity must be at least 1/)).toBeInTheDocument();
249
+ });
250
+
251
+ // Should NOT call the update function
252
+ expect(mockUpdateBillItems).not.toHaveBeenCalled();
253
+ });
254
+
255
+ test('shows validation error for quantity greater than 100', async () => {
256
+ const user = userEvent.setup();
257
+ render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={mockCloseModal} />);
258
+
259
+ const quantityInput = screen.getByRole('spinbutton', { name: /Quantity/ });
260
+ await user.clear(quantityInput);
261
+ await user.type(quantityInput, '101');
262
+
263
+ await user.click(screen.getByText(/Save/));
264
+
265
+ await waitFor(() => {
266
+ expect(screen.getByText(/Quantity cannot exceed 100/)).toBeInTheDocument();
267
+ });
268
+ expect(mockUpdateBillItems).not.toHaveBeenCalled();
269
+ });
270
+
271
+ test('shows validation error for non-integer quantity', async () => {
272
+ const user = userEvent.setup();
273
+ render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={mockCloseModal} />);
274
+
275
+ const quantityInput = screen.getByRole('spinbutton', { name: /Quantity/ });
276
+ await user.clear(quantityInput);
277
+ await user.type(quantityInput, '2.5');
278
+
279
+ await user.click(screen.getByText(/Save/));
280
+
281
+ await waitFor(() => {
282
+ expect(screen.getByText(/Quantity must be a whole number/)).toBeInTheDocument();
283
+ });
284
+ expect(mockUpdateBillItems).not.toHaveBeenCalled();
285
+ });
286
+
287
+ test('clears validation error when valid quantity is entered', async () => {
288
+ const user = userEvent.setup();
289
+ render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={mockCloseModal} />);
290
+
291
+ const quantityInput = screen.getByRole('spinbutton', { name: /Quantity/ });
292
+
293
+ // Enter invalid value
294
+ await user.clear(quantityInput);
295
+ await user.type(quantityInput, '0');
296
+ await user.click(screen.getByText(/Save/));
297
+
298
+ await waitFor(() => {
299
+ expect(screen.getByText(/Quantity must be at least 1/)).toBeInTheDocument();
300
+ });
301
+
302
+ // Fix it
303
+ await user.clear(quantityInput);
304
+ await user.type(quantityInput, '5');
305
+
306
+ // Error should disappear
307
+ await waitFor(() => {
308
+ expect(screen.queryByText(/Quantity must be at least 1/)).not.toBeInTheDocument();
309
+ });
310
+ });
222
311
  });
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useState } from 'react';
2
2
  import {
3
3
  Checkbox,
4
4
  Layer,
@@ -20,7 +20,7 @@ const PatientBillsSelections: React.FC<{ bills: MappedBill; setPatientUuid: (pat
20
20
  setPatientUuid,
21
21
  }) => {
22
22
  const { t } = useTranslation();
23
- const [selectedBills, setSelectedBills] = React.useState<Array<LineItem>>([]);
23
+ const [selectedBills, setSelectedBills] = useState<Array<LineItem>>([]);
24
24
  const { defaultCurrency } = useConfig();
25
25
 
26
26
  const checkBoxLabel = (lineItem) => {
@@ -1,11 +1,11 @@
1
- import React from 'react';
1
+ import React, { useState } from 'react';
2
2
  import { Form, Stack, FormGroup, Layer, Button, NumberInput } from '@carbon/react';
3
3
  import { TaskAdd } from '@carbon/react/icons';
4
4
  import { mutate } from 'swr';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { showSnackbar, useConfig } from '@openmrs/esm-framework';
7
7
  import { createBillWaiverPayload } from './utils';
8
- import { convertToCurrency } from '../../helpers';
8
+ import { calculateTotalAmount, convertToCurrency } from '../../helpers';
9
9
  import { processBillPayment } from '../../billing.resource';
10
10
  import { useBillableItems } from '../../billing-form/billing-form.resource';
11
11
  import type { LineItem, MappedBill } from '../../types';
@@ -20,16 +20,16 @@ type BillWaiverFormProps = {
20
20
 
21
21
  const BillWaiverForm: React.FC<BillWaiverFormProps> = ({ bill, lineItems, setPatientUuid }) => {
22
22
  const { t } = useTranslation();
23
- const [waiverAmount, setWaiverAmount] = React.useState(0);
24
- const { lineItems: billableLineItems, isLoading: isLoadingLineItems, error: lineError } = useBillableItems();
25
- const totalAmount = lineItems.reduce((acc, curr) => acc + curr.price * curr.quantity, 0);
23
+ const [waiverAmount, setWaiverAmount] = useState(0);
24
+ const { lineItems: billableLineItems } = useBillableItems();
25
+ const totalAmount = calculateTotalAmount(lineItems);
26
26
  const { defaultCurrency } = useConfig();
27
27
 
28
28
  if (lineItems?.length === 0) {
29
29
  return null;
30
30
  }
31
31
 
32
- const handleProcessPayment = () => {
32
+ const handleProcessPayment = async () => {
33
33
  const waiverEndPointPayload = createBillWaiverPayload(
34
34
  bill,
35
35
  waiverAmount,
@@ -38,29 +38,26 @@ const BillWaiverForm: React.FC<BillWaiverFormProps> = ({ bill, lineItems, setPat
38
38
  billableLineItems,
39
39
  );
40
40
 
41
- processBillPayment(waiverEndPointPayload, bill.uuid).then(
42
- () => {
43
- showSnackbar({
44
- title: t('billWaiver', 'Bill waiver'),
45
- subtitle: t('billWaiverSuccess', 'Bill waiver successful'),
46
- kind: 'success',
47
- timeoutInMs: 3500,
48
- isLowContrast: true,
49
- });
50
- setPatientUuid('');
51
- mutate((key) => typeof key === 'string' && key.startsWith(`${apiBasePath}bill?v=full`), undefined, {
52
- revalidate: true,
53
- });
54
- },
55
- (err) => {
56
- showSnackbar({
57
- title: t('billWaiver', 'Bill waiver'),
58
- subtitle: t('billWaiverError', 'Bill waiver failed {{error}}', { error: err.message }),
59
- kind: 'error',
60
- isLowContrast: true,
61
- });
62
- },
63
- );
41
+ try {
42
+ await processBillPayment(waiverEndPointPayload, bill.uuid);
43
+ showSnackbar({
44
+ title: t('billWaiver', 'Bill waiver'),
45
+ subtitle: t('billWaiverSuccess', 'Bill waiver successful'),
46
+ kind: 'success',
47
+ isLowContrast: true,
48
+ });
49
+ setPatientUuid('');
50
+ mutate((key) => typeof key === 'string' && key.startsWith(`${apiBasePath}bill?v=full`), undefined, {
51
+ revalidate: true,
52
+ });
53
+ } catch (error) {
54
+ showSnackbar({
55
+ title: t('billWaiver', 'Bill waiver'),
56
+ subtitle: t('billWaiverError', 'Bill waiver failed {{error}}', { error: error?.message }),
57
+ kind: 'error',
58
+ isLowContrast: true,
59
+ });
60
+ }
64
61
  };
65
62
 
66
63
  return (
@@ -21,20 +21,25 @@ const BillingCheckInForm: React.FC<BillingCheckInFormProps> = ({ patientUuid, se
21
21
  const [paymentMethod, setPaymentMethod] = useState<any>();
22
22
  let lineList = [];
23
23
 
24
- const handleCreateExtraVisitInfo = useCallback((createBillPayload) => {
25
- createPatientBill(createBillPayload).then(
26
- (res) => {
27
- showSnackbar({ title: 'Patient Bill', subtitle: 'Patient has been billed successfully', kind: 'success' });
28
- },
29
- (error) => {
24
+ const handleCreateExtraVisitInfo = useCallback(
25
+ async (createBillPayload) => {
26
+ try {
27
+ await createPatientBill(createBillPayload);
30
28
  showSnackbar({
31
- title: 'Patient Bill Error',
32
- subtitle: 'An error has occurred while creating patient bill',
29
+ title: t('patientBill', 'Patient bill'),
30
+ subtitle: t('billCreatedSuccessfully', 'Bill created successfully'),
31
+ kind: 'success',
32
+ });
33
+ } catch (error) {
34
+ showSnackbar({
35
+ title: t('billCreationError', 'Bill creation error'),
36
+ subtitle: t('errorCreatingBill', 'An error occurred while creating the bill'),
33
37
  kind: 'error',
34
38
  });
35
- },
36
- );
37
- }, []);
39
+ }
40
+ },
41
+ [t],
42
+ );
38
43
 
39
44
  const handleBillingService = ({ selectedItem }) => {
40
45
  const cashPointUuid = cashPoints?.[0]?.uuid ?? '';
@@ -74,7 +79,7 @@ const BillingCheckInForm: React.FC<BillingCheckInFormProps> = ({ patientUuid, se
74
79
  <InlineLoading
75
80
  status="active"
76
81
  iconDescription={getCoreTranslation('loading')}
77
- description={t('loadingBillingServices', 'Loading billing services...')}
82
+ description={`${t('loadingBillingServices', 'Loading billing services')}...`}
78
83
  />
79
84
  );
80
85
  }
@@ -110,7 +115,7 @@ const BillingCheckInForm: React.FC<BillingCheckInFormProps> = ({ patientUuid, se
110
115
  <div className={styles.sectionTitle}>{t('billing', 'Billing')}</div>
111
116
  <div className={styles.sectionField}></div>
112
117
  <Dropdown
113
- label={t('selectBillableService', 'Select a billable service...')}
118
+ label={t('selectBillableService', 'Select a billable service')}
114
119
  onChange={handleBillingService}
115
120
  id="billable-items"
116
121
  items={lineList}
@@ -1,21 +1,7 @@
1
1
  import React, { useState } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { mutate } from 'swr';
4
- import {
5
- Button,
6
- ButtonSet,
7
- ComboBox,
8
- Form,
9
- NumberInput,
10
- InlineLoading,
11
- InlineNotification,
12
- Table,
13
- TableHead,
14
- TableBody,
15
- TableRow,
16
- TableHeader,
17
- TableCell,
18
- } from '@carbon/react';
4
+ import { Button, ButtonSet, ComboBox, Form, NumberInput, InlineLoading, InlineNotification } from '@carbon/react';
19
5
  import { TrashCan } from '@carbon/react/icons';
20
6
  import { useConfig, useLayoutType, showSnackbar, getCoreTranslation } from '@openmrs/esm-framework';
21
7
  import { processBillItems, useBillableServices } from '../billing.resource';
@@ -119,7 +105,7 @@ const BillingForm: React.FC<BillingFormProps> = ({ patientUuid, closeWorkspace }
119
105
  return true;
120
106
  };
121
107
 
122
- const postBillItems = () => {
108
+ const postBillItems = async () => {
123
109
  if (!validateSelectedItems()) {
124
110
  return;
125
111
  }
@@ -147,27 +133,24 @@ const BillingForm: React.FC<BillingFormProps> = ({ patientUuid, closeWorkspace }
147
133
  });
148
134
 
149
135
  const url = `${apiBasePath}bill`;
150
- processBillItems(bill).then(
151
- () => {
152
- setIsSubmitting(false);
153
-
154
- closeWorkspace();
155
- mutate((key) => typeof key === 'string' && key.startsWith(url), undefined, { revalidate: true });
156
- showSnackbar({
157
- title: t('saveBill', 'Save Bill'),
158
- subtitle: t('billProcessingSuccess', 'Bill processing has been successful'),
159
- kind: 'success',
160
- });
161
- },
162
- (error) => {
163
- setIsSubmitting(false);
164
- showSnackbar({
165
- title: t('billProcessingError', 'Bill processing error'),
166
- kind: 'error',
167
- subtitle: error?.message,
168
- });
169
- },
170
- );
136
+ try {
137
+ await processBillItems(bill);
138
+ closeWorkspace();
139
+ mutate((key) => typeof key === 'string' && key.startsWith(url), undefined, { revalidate: true });
140
+ showSnackbar({
141
+ title: t('saveBill', 'Save Bill'),
142
+ subtitle: t('billProcessingSuccess', 'Bill processing has been successful'),
143
+ kind: 'success',
144
+ });
145
+ } catch (error) {
146
+ showSnackbar({
147
+ title: t('billProcessingError', 'Bill processing error'),
148
+ kind: 'error',
149
+ subtitle: error?.message,
150
+ });
151
+ } finally {
152
+ setIsSubmitting(false);
153
+ }
171
154
  };
172
155
 
173
156
  return (
@@ -1,6 +1,5 @@
1
- import isEmpty from 'lodash-es/isEmpty';
2
- import sortBy from 'lodash-es/sortBy';
3
1
  import useSWR from 'swr';
2
+ import sortBy from 'lodash-es/sortBy';
4
3
  import {
5
4
  formatDate,
6
5
  parseDate,
@@ -21,9 +20,11 @@ import type {
21
20
  } from './types';
22
21
 
23
22
  const mapBillProperties = (bill: PatientInvoice): MappedBill => {
23
+ const activeLineItems = bill?.lineItems?.filter((item) => !item.voided) || [];
24
+
24
25
  const status =
25
- bill.lineItems.length > 1
26
- ? bill.lineItems.some((item) => item.paymentStatus === 'PENDING')
26
+ activeLineItems.length > 1
27
+ ? activeLineItems.some((item) => item.paymentStatus === 'PENDING')
27
28
  ? 'PENDING'
28
29
  : 'PAID'
29
30
  : bill.status;
@@ -41,28 +42,38 @@ const mapBillProperties = (bill: PatientInvoice): MappedBill => {
41
42
  cashPointName: bill?.cashPoint?.name,
42
43
  cashPointLocation: bill?.cashPoint?.location?.display,
43
44
  dateCreated: bill?.dateCreated ? formatDate(parseDate(bill.dateCreated), { mode: 'wide' }) : '--',
44
- lineItems: bill?.lineItems,
45
- billingService: bill?.lineItems.map((lineItem) => lineItem?.item || lineItem?.billableService || '--').join(' '),
45
+ lineItems: activeLineItems,
46
+ billingService: activeLineItems.map((lineItem) => lineItem?.item || lineItem?.billableService || '--').join(' '),
46
47
  payments: bill.payments,
47
48
  display: bill?.display,
48
- totalAmount: bill?.lineItems?.map((item) => item.price * item.quantity).reduce((prev, curr) => prev + curr, 0),
49
+ totalAmount: activeLineItems?.map((item) => item.price * item.quantity).reduce((prev, curr) => prev + curr, 0),
49
50
  tenderedAmount: bill?.payments?.map((item) => item.amountTendered).reduce((prev, curr) => prev + curr, 0),
50
51
  };
51
52
  };
52
53
 
53
54
  export const useBills = (patientUuid: string = '', billStatus: string = '') => {
54
- const url = `${apiBasePath}bill?q=&v=full`;
55
+ // Build URL with status parameter if provided
56
+ const buildUrl = () => {
57
+ let url = `${apiBasePath}bill?v=full`;
55
58
 
56
- const patientUrl = `${apiBasePath}bill?patientUuid=${patientUuid}&v=full`;
59
+ if (patientUuid) {
60
+ url += `&patientUuid=${patientUuid}`;
61
+ }
62
+
63
+ if (billStatus) {
64
+ url += `&status=${billStatus}`;
65
+ }
66
+
67
+ return url;
68
+ };
57
69
 
58
70
  const { data, error, isLoading, isValidating, mutate } = useSWR<{ data: { results: Array<PatientInvoice> } }>(
59
- isEmpty(patientUuid) ? url : patientUrl,
71
+ buildUrl(),
60
72
  openmrsFetch,
61
73
  );
62
74
 
63
75
  const sortedBills = sortBy(data?.data?.results ?? [], ['dateCreated']).reverse();
64
- const filteredBills = billStatus === '' ? sortedBills : sortedBills?.filter((bill) => bill?.status === billStatus);
65
- const mappedResults = filteredBills?.map((bill) => mapBillProperties(bill));
76
+ const mappedResults = sortedBills?.map((bill) => mapBillProperties(bill));
66
77
 
67
78
  return {
68
79
  bills: mappedResults,
@@ -73,7 +73,7 @@ const InvoiceTable: React.FC<InvoiceTableProps> = ({ bill, isLoadingBill }) => {
73
73
 
74
74
  const handleSelectBillItem = useCallback(
75
75
  (row: LineItem) => {
76
- const dispose = showModal('edit-bill-line-item-dialog', {
76
+ const dispose = showModal('edit-bill-line-item-modal', {
77
77
  bill,
78
78
  item: row,
79
79
  closeModal: () => dispose(),
@@ -168,7 +168,7 @@ describe('InvoiceTable', () => {
168
168
 
169
169
  expect(mockShowModal).toHaveBeenCalledTimes(1);
170
170
  expect(mockShowModal).toHaveBeenCalledWith(
171
- 'edit-bill-line-item-dialog',
171
+ 'edit-bill-line-item-modal',
172
172
  expect.objectContaining({
173
173
  bill: defaultBill,
174
174
  item: expect.objectContaining({ uuid: '1' }),
package/src/routes.json CHANGED
@@ -78,12 +78,6 @@
78
78
  "name": "billing-home-tiles-ext",
79
79
  "slot": "billing-home-tiles-slot",
80
80
  "component": "serviceMetrics"
81
- },
82
- {
83
- "name": "edit-bill-line-item-dialog",
84
- "component": "editBillLineItemModal",
85
- "online": true,
86
- "offline": true
87
81
  }
88
82
  ],
89
83
  "modals": [
@@ -103,6 +97,10 @@
103
97
  "name": "edit-bill-item-modal",
104
98
  "component": "editBillLineItemModal"
105
99
  },
100
+ {
101
+ "name": "edit-bill-line-item-modal",
102
+ "component": "editBillLineItemModal"
103
+ },
106
104
  {
107
105
  "name": "edit-billable-service-modal",
108
106
  "component": "editBillableServiceModal"
@@ -24,6 +24,8 @@
24
24
  "billableServices__lower": "billable services",
25
25
  "billAmount": "Bill amount",
26
26
  "billCode": "Bill code",
27
+ "billCreatedSuccessfully": "Bill created successfully",
28
+ "billCreationError": "Bill creation error",
27
29
  "billedItems": "Billed Items",
28
30
  "billedTo": "Billed to",
29
31
  "billErrorService": "Bill service error",
@@ -81,7 +83,7 @@
81
83
  "enterSellingPrice": "Enter selling price",
82
84
  "enterServiceName": "Enter service name",
83
85
  "enterServiceShortName": "Enter service short name",
84
- "error": "Error",
86
+ "errorCreatingBill": "An error occurred while creating the bill",
85
87
  "errorDeletingPaymentMode": "An error occurred while deleting the payment mode.",
86
88
  "errorFetchingCashPoints": "An error occurred while fetching cash points.",
87
89
  "errorFetchingLocations": "An error occurred while fetching locations.",
@@ -132,6 +134,7 @@
132
134
  "noResultsFor": "No results for",
133
135
  "number": "No",
134
136
  "ok": "OK",
137
+ "patientBill": "Patient bill",
135
138
  "patientBillingAlert": "Patient Billing Alert",
136
139
  "patientBills": "Patient bill",
137
140
  "patientBillsDescription": "List of patient bills",
@@ -152,7 +155,6 @@
152
155
  "paymentOptionRequired": "At least one payment option is required",
153
156
  "paymentProcessedSuccessfully": "Payment processed successfully",
154
157
  "payments": "Payments",
155
- "pleaseRequiredFields": "Please fill all required fields",
156
158
  "policyNumber": "Policy number",
157
159
  "postWaiver": "Post waiver",
158
160
  "previousPage": "Previous page",
@@ -181,7 +183,7 @@
181
183
  "searching": "Searching",
182
184
  "searchItems": "Search items and services",
183
185
  "searchThisTable": "Search this table",
184
- "selectBillableService": "Select a billable service...",
186
+ "selectBillableService": "Select a billable service",
185
187
  "selectedItems": "Selected Items",
186
188
  "selectLocation": "Select Location",
187
189
  "selectPatientCategory": "Select patient category",