@openmrs/esm-billing-app 1.0.2-pre.74 → 1.0.2-pre.749

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 (196) hide show
  1. package/README.md +55 -9
  2. package/__mocks__/bills.mock.ts +12 -0
  3. package/__mocks__/react-i18next.js +6 -5
  4. package/dist/1119.js +1 -1
  5. package/dist/1146.js +1 -2
  6. package/dist/1146.js.map +1 -1
  7. package/dist/1197.js +1 -1
  8. package/dist/1856.js +1 -0
  9. package/dist/1856.js.map +1 -0
  10. package/dist/2146.js +1 -1
  11. package/dist/2177.js +2 -0
  12. package/dist/2177.js.LICENSE.txt +9 -0
  13. package/dist/2177.js.map +1 -0
  14. package/dist/2524.js +1 -0
  15. package/dist/2524.js.map +1 -0
  16. package/dist/2690.js +1 -1
  17. package/dist/3041.js +1 -0
  18. package/dist/3041.js.map +1 -0
  19. package/dist/3099.js +1 -1
  20. package/dist/3584.js +1 -1
  21. package/dist/4055.js +1 -1
  22. package/dist/4132.js +1 -1
  23. package/dist/4225.js +1 -0
  24. package/dist/4225.js.map +1 -0
  25. package/dist/4300.js +1 -1
  26. package/dist/4335.js +1 -1
  27. package/dist/4618.js +1 -1
  28. package/dist/4652.js +1 -1
  29. package/dist/4724.js +1 -0
  30. package/dist/4724.js.map +1 -0
  31. package/dist/4739.js +1 -1
  32. package/dist/4739.js.map +1 -1
  33. package/dist/4944.js +1 -1
  34. package/dist/5173.js +1 -1
  35. package/dist/5241.js +1 -1
  36. package/dist/5422.js +1 -0
  37. package/dist/5422.js.map +1 -0
  38. package/dist/5442.js +1 -1
  39. package/dist/5661.js +1 -1
  40. package/dist/6022.js +1 -1
  41. package/dist/6468.js +1 -1
  42. package/dist/6540.js +1 -1
  43. package/dist/6540.js.map +1 -1
  44. package/dist/6606.js +1 -0
  45. package/dist/6606.js.map +1 -0
  46. package/dist/6679.js +1 -1
  47. package/dist/6840.js +1 -1
  48. package/dist/6859.js +1 -1
  49. package/dist/7097.js +1 -1
  50. package/dist/7159.js +1 -1
  51. package/dist/723.js +1 -1
  52. package/dist/7452.js +2 -0
  53. package/dist/7452.js.map +1 -0
  54. package/dist/7617.js +1 -1
  55. package/dist/795.js +1 -0
  56. package/dist/8163.js +1 -1
  57. package/dist/8349.js +1 -1
  58. package/dist/8618.js +1 -1
  59. package/dist/890.js +1 -1
  60. package/dist/8930.js +2 -0
  61. package/dist/{6525.js.LICENSE.txt → 8930.js.LICENSE.txt} +16 -4
  62. package/dist/8930.js.map +1 -0
  63. package/dist/9214.js +1 -1
  64. package/dist/942.js +1 -0
  65. package/dist/942.js.map +1 -0
  66. package/dist/9538.js +1 -1
  67. package/dist/9569.js +1 -0
  68. package/dist/961.js +1 -1
  69. package/dist/961.js.map +1 -1
  70. package/dist/986.js +1 -1
  71. package/dist/9879.js +1 -1
  72. package/dist/9895.js +1 -1
  73. package/dist/9900.js +1 -1
  74. package/dist/9913.js +1 -1
  75. package/dist/main.js +1 -1
  76. package/dist/main.js.map +1 -1
  77. package/dist/openmrs-esm-billing-app.js +1 -1
  78. package/dist/openmrs-esm-billing-app.js.buildmanifest.json +381 -231
  79. package/dist/openmrs-esm-billing-app.js.map +1 -1
  80. package/dist/routes.json +1 -1
  81. package/e2e/README.md +19 -18
  82. package/e2e/specs/sample-test.spec.ts +0 -1
  83. package/package.json +10 -10
  84. package/src/bill-history/bill-history.component.tsx +17 -25
  85. package/src/bill-history/bill-history.scss +4 -94
  86. package/src/bill-history/bill-history.test.tsx +37 -78
  87. package/src/bill-item-actions/bill-item-actions.scss +0 -4
  88. package/src/bill-item-actions/{edit-bill-item.component.tsx → edit-bill-item.modal.tsx} +58 -56
  89. package/src/bill-item-actions/edit-bill-item.test.tsx +22 -24
  90. package/src/billable-services/bill-waiver/bill-selection.component.tsx +2 -2
  91. package/src/billable-services/bill-waiver/patient-bills.component.tsx +3 -3
  92. package/src/billable-services/billable-service.resource.ts +4 -3
  93. package/src/billable-services/billable-services-home.component.tsx +1 -1
  94. package/src/billable-services/billable-services.component.tsx +115 -132
  95. package/src/billable-services/billable-services.scss +3 -0
  96. package/src/billable-services/billable-services.test.tsx +2 -45
  97. package/src/billable-services/cash-point/add-cash-point.modal.tsx +168 -0
  98. package/src/billable-services/cash-point/cash-point-configuration.component.tsx +17 -192
  99. package/src/billable-services/cash-point/cash-point-configuration.scss +1 -5
  100. package/src/billable-services/create-edit/add-billable-service.component.tsx +28 -24
  101. package/src/billable-services/create-edit/add-billable-service.scss +2 -5
  102. package/src/billable-services/create-edit/add-billable-service.test.tsx +6 -6
  103. package/src/billable-services/create-edit/edit-billable-service.modal.tsx +50 -0
  104. package/src/billable-services/payment-modes/add-payment-mode.modal.tsx +121 -0
  105. package/src/billable-services/payment-modes/delete-payment-mode.modal.tsx +72 -0
  106. package/src/billable-services/payment-modes/payment-modes-config.component.tsx +125 -0
  107. package/src/billable-services/{payyment-modes → payment-modes}/payment-modes-config.scss +5 -1
  108. package/src/billing-form/billing-checkin-form.component.tsx +2 -3
  109. package/src/billing-form/billing-checkin-form.test.tsx +0 -2
  110. package/src/billing-form/billing-form.component.tsx +210 -268
  111. package/src/billing-form/billing-form.scss +143 -0
  112. package/src/billing.resource.ts +16 -19
  113. package/src/bills-table/bills-table.test.tsx +97 -53
  114. package/src/config-schema.ts +52 -18
  115. package/src/dashboard.meta.ts +4 -2
  116. package/src/helpers/functions.ts +5 -4
  117. package/src/index.ts +17 -6
  118. package/src/invoice/invoice-table.component.tsx +24 -54
  119. package/src/invoice/invoice-table.scss +1 -5
  120. package/src/invoice/invoice-table.test.tsx +21 -47
  121. package/src/invoice/invoice.component.tsx +36 -29
  122. package/src/invoice/invoice.scss +7 -4
  123. package/src/invoice/invoice.test.tsx +22 -48
  124. package/src/invoice/payments/payment-form/payment-form.component.tsx +2 -9
  125. package/src/invoice/payments/payment-form/payment-form.test.tsx +14 -46
  126. package/src/invoice/payments/payment-history/payment-history.component.tsx +6 -4
  127. package/src/invoice/payments/payment-history/payment-history.test.tsx +9 -14
  128. package/src/invoice/payments/payments.component.tsx +16 -27
  129. package/src/invoice/payments/{payments.component.test.tsx → payments.test.tsx} +24 -10
  130. package/src/invoice/payments/utils.ts +4 -22
  131. package/src/invoice/printable-invoice/print-receipt.component.tsx +3 -2
  132. package/src/invoice/printable-invoice/print-receipt.test.tsx +14 -25
  133. package/src/invoice/printable-invoice/printable-footer.component.tsx +2 -2
  134. package/src/invoice/printable-invoice/printable-footer.test.tsx +4 -13
  135. package/src/invoice/printable-invoice/printable-invoice-header.component.tsx +12 -11
  136. package/src/invoice/printable-invoice/printable-invoice-header.test.tsx +16 -14
  137. package/src/invoice/printable-invoice/printable-invoice.component.tsx +19 -33
  138. package/src/metrics-cards/metrics-cards.test.tsx +18 -5
  139. package/src/modal/require-payment-modal.test.tsx +25 -20
  140. package/src/modal/{require-payment-modal.component.tsx → require-payment.modal.tsx} +17 -18
  141. package/src/routes.json +22 -2
  142. package/src/types/index.ts +13 -12
  143. package/translations/am.json +33 -16
  144. package/translations/ar.json +33 -16
  145. package/translations/ar_SY.json +33 -16
  146. package/translations/bn.json +38 -21
  147. package/translations/de.json +33 -16
  148. package/translations/en.json +33 -16
  149. package/translations/en_US.json +187 -0
  150. package/translations/es.json +48 -31
  151. package/translations/es_MX.json +33 -16
  152. package/translations/fr.json +47 -30
  153. package/translations/he.json +33 -16
  154. package/translations/hi.json +33 -16
  155. package/translations/hi_IN.json +33 -16
  156. package/translations/id.json +180 -163
  157. package/translations/it.json +70 -53
  158. package/translations/ka.json +187 -0
  159. package/translations/km.json +33 -16
  160. package/translations/ku.json +33 -16
  161. package/translations/ky.json +33 -16
  162. package/translations/lg.json +33 -16
  163. package/translations/ne.json +33 -16
  164. package/translations/pl.json +33 -16
  165. package/translations/pt.json +33 -16
  166. package/translations/pt_BR.json +33 -16
  167. package/translations/qu.json +33 -16
  168. package/translations/ro_RO.json +182 -165
  169. package/translations/ru_RU.json +33 -16
  170. package/translations/si.json +33 -16
  171. package/translations/sw.json +33 -16
  172. package/translations/sw_KE.json +33 -16
  173. package/translations/tr.json +33 -16
  174. package/translations/tr_TR.json +33 -16
  175. package/translations/uk.json +33 -16
  176. package/translations/uz.json +33 -16
  177. package/translations/uz@Latn.json +33 -16
  178. package/translations/uz_UZ.json +33 -16
  179. package/translations/vi.json +33 -16
  180. package/translations/zh.json +33 -16
  181. package/translations/zh_CN.json +91 -74
  182. package/dist/1146.js.LICENSE.txt +0 -21
  183. package/dist/2352.js +0 -1
  184. package/dist/2352.js.map +0 -1
  185. package/dist/246.js +0 -1
  186. package/dist/246.js.map +0 -1
  187. package/dist/6525.js +0 -2
  188. package/dist/6525.js.map +0 -1
  189. package/dist/8556.js +0 -2
  190. package/dist/8556.js.map +0 -1
  191. package/dist/8638.js +0 -1
  192. package/dist/8638.js.map +0 -1
  193. package/dist/9968.js +0 -1
  194. package/dist/9968.js.map +0 -1
  195. package/src/billable-services/payyment-modes/payment-modes-config.component.tsx +0 -280
  196. /package/dist/{8556.js.LICENSE.txt → 7452.js.LICENSE.txt} +0 -0
@@ -1,19 +1,17 @@
1
1
  import React from 'react';
2
2
  import { screen, render } from '@testing-library/react';
3
3
  import { useConfig } from '@openmrs/esm-framework';
4
+ import { type BillingConfig } from '../../config-schema';
4
5
  import { useDefaultFacility } from '../../billing.resource';
5
6
  import PrintableInvoiceHeader from './printable-invoice-header.component';
6
7
 
7
- const mockUseDefaultFacility = useDefaultFacility as jest.MockedFunction<typeof useDefaultFacility>;
8
- const mockUseConfig = useConfig as jest.MockedFunction<typeof useConfig>;
8
+ const mockUseDefaultFacility = jest.mocked(useDefaultFacility);
9
+ const mockUseConfig = jest.mocked(useConfig<BillingConfig>);
9
10
 
10
11
  jest.mock('../../billing.resource', () => ({
11
12
  useDefaultFacility: jest.fn(),
12
13
  }));
13
14
 
14
- jest.mock('@openmrs/esm-framework', () => ({
15
- useConfig: jest.fn(),
16
- }));
17
15
  const testProps = {
18
16
  patientDetails: {
19
17
  name: 'John Doe',
@@ -25,11 +23,19 @@ const testProps = {
25
23
  },
26
24
  };
27
25
 
26
+ const defaultFacility = { display: 'MTRH', uuid: 'mtrh-uuid', links: [] };
27
+
28
28
  describe('PrintableInvoiceHeader', () => {
29
+ beforeEach(() => {
30
+ mockUseConfig.mockReturnValue({
31
+ logo: { src: 'logo.png', alt: 'logo' },
32
+ country: 'Kenya',
33
+ } as unknown as BillingConfig);
34
+ mockUseDefaultFacility.mockReturnValue({ data: { display: 'MTRH', uuid: 'mtrh-uuid', links: [] } });
35
+ });
36
+
29
37
  test('should render PrintableInvoiceHeader component', () => {
30
- mockUseConfig.mockReturnValue({ logo: { src: 'logo.png', alt: 'logo' } });
31
- mockUseDefaultFacility.mockReturnValue({ data: { display: 'MTRH', uuid: 'mtrh-uuid' }, isLoading: false });
32
- render(<PrintableInvoiceHeader {...testProps} />);
38
+ render(<PrintableInvoiceHeader {...testProps} defaultFacility={defaultFacility} />);
33
39
  const header = screen.getByText('Invoice');
34
40
  expect(header).toBeInTheDocument();
35
41
 
@@ -41,17 +47,13 @@ describe('PrintableInvoiceHeader', () => {
41
47
  });
42
48
 
43
49
  test('should display the logo when logo is provided', () => {
44
- mockUseConfig.mockReturnValue({ logo: { src: 'logo.png', alt: 'logo' } });
45
- mockUseDefaultFacility.mockReturnValue({ data: { display: 'MTRH', uuid: 'mtrh-uuid' }, isLoading: false });
46
- render(<PrintableInvoiceHeader {...testProps} />);
50
+ render(<PrintableInvoiceHeader {...testProps} defaultFacility={defaultFacility} />);
47
51
  const logo = screen.getByAltText('logo');
48
52
  expect(logo).toBeInTheDocument();
49
53
  });
50
54
 
51
55
  test('should display the default logo when logo is not provided', () => {
52
- mockUseConfig.mockReturnValue({ logo: {} });
53
- mockUseDefaultFacility.mockReturnValue({ data: { display: 'MTRH', uuid: 'mtrh-uuid' }, isLoading: false });
54
- render(<PrintableInvoiceHeader {...testProps} />);
56
+ render(<PrintableInvoiceHeader {...testProps} defaultFacility={defaultFacility} />);
55
57
  const logo = screen.getByRole('img');
56
58
  expect(logo).toBeInTheDocument();
57
59
  });
@@ -8,9 +8,8 @@ import {
8
8
  TableBody,
9
9
  TableHeader,
10
10
  TableCell,
11
- DataTableSkeleton,
12
11
  } from '@carbon/react';
13
- import { age, isDesktop, useLayoutType } from '@openmrs/esm-framework';
12
+ import { age, isDesktop, type SessionLocation, useLayoutType } from '@openmrs/esm-framework';
14
13
  import { getGender } from '../../helpers';
15
14
  import { type MappedBill } from '../../types';
16
15
  import { useTranslation } from 'react-i18next';
@@ -21,25 +20,26 @@ import styles from './printable-invoice.scss';
21
20
  type PrintableInvoiceProps = {
22
21
  bill: MappedBill;
23
22
  patient: fhir.Patient;
24
- isLoading: boolean;
23
+ componentRef: React.RefObject<HTMLDivElement>;
24
+ defaultFacility: SessionLocation;
25
25
  };
26
26
 
27
- const PrintableInvoice: React.FC<PrintableInvoiceProps> = ({ bill, patient, isLoading }) => {
27
+ const PrintableInvoice: React.FC<PrintableInvoiceProps> = ({ bill, patient, componentRef, defaultFacility }) => {
28
28
  const { t } = useTranslation();
29
29
  const layout = useLayoutType();
30
30
  const responsiveSize = isDesktop(layout) ? 'sm' : 'lg';
31
31
  const headerData = [
32
- { header: 'Inventory item', key: 'billItem' },
33
- { header: 'Quantity', key: 'quantity' },
34
- { header: 'Unit price', key: 'price' },
35
- { header: 'Total', key: 'total' },
32
+ { header: t('inventoryItem', 'Inventory item'), key: 'billItem' },
33
+ { header: t('quantity', 'Quantity'), key: 'quantity' },
34
+ { header: t('unitPrice', 'Unit price'), key: 'price' },
35
+ { header: t('total', 'Total'), key: 'total' },
36
36
  ];
37
37
 
38
38
  const rowData =
39
39
  bill?.lineItems?.map((item) => {
40
40
  return {
41
41
  id: `${item.uuid}`,
42
- billItem: item.item,
42
+ billItem: item.billableService ?? item.item,
43
43
  quantity: item.quantity,
44
44
  price: item.price,
45
45
  total: item.price * item.quantity,
@@ -47,10 +47,10 @@ const PrintableInvoice: React.FC<PrintableInvoiceProps> = ({ bill, patient, isLo
47
47
  }) ?? [];
48
48
 
49
49
  const invoiceTotal = {
50
- 'Total Amount': bill?.totalAmount,
51
- 'Amount Tendered': bill?.tenderedAmount,
52
- 'Discount Amount': 0,
53
- 'Amount due': bill?.totalAmount - bill?.tenderedAmount,
50
+ [t('totalAmount', 'Total Amount')]: bill?.totalAmount,
51
+ [t('amountTendered', 'Amount Tendered')]: bill?.tenderedAmount,
52
+ [t('discountAmount', 'Discount Amount')]: 0,
53
+ [t('amountDue', 'Amount due')]: bill?.totalAmount - bill?.tenderedAmount,
54
54
  };
55
55
 
56
56
  const patientDetails = useMemo(() => {
@@ -65,28 +65,14 @@ const PrintableInvoice: React.FC<PrintableInvoiceProps> = ({ bill, patient, isLo
65
65
  }, [patient, t]);
66
66
 
67
67
  const invoiceDetails = {
68
- 'Invoice #': bill?.receiptNumber,
69
- 'Invoice date': bill.dateCreated,
70
- Status: bill?.status,
68
+ [t('invoiceNumber', 'Invoice #')]: bill?.receiptNumber,
69
+ [t('invoiceDate', 'Invoice date')]: bill?.dateCreated,
70
+ [t('status', 'Status')]: bill?.status,
71
71
  };
72
72
 
73
- if (isLoading) {
74
- return (
75
- <div className={styles.loaderContainer}>
76
- <DataTableSkeleton
77
- columnCount={headerData?.length ?? 0}
78
- showHeader={false}
79
- showToolbar={false}
80
- size={responsiveSize}
81
- zebra
82
- />
83
- </div>
84
- );
85
- }
86
-
87
73
  return (
88
- <div className={styles.container}>
89
- <PrintableInvoiceHeader patientDetails={patientDetails} />
74
+ <div className={styles.container} ref={componentRef}>
75
+ <PrintableInvoiceHeader patientDetails={patientDetails} defaultFacility={defaultFacility} />
90
76
  <div className={styles.printableInvoiceContainer}>
91
77
  <div className={styles.detailsContainer}>
92
78
  {Object.entries(invoiceDetails).map(([key, val]) => (
@@ -99,7 +85,7 @@ const PrintableInvoice: React.FC<PrintableInvoiceProps> = ({ bill, patient, isLo
99
85
 
100
86
  <div className={styles.itemsContainer}>
101
87
  <div className={styles.tableContainer}>
102
- <DataTable isSortable rows={rowData} headers={headerData} size={responsiveSize} useZebraStyles={false}>
88
+ <DataTable rows={rowData} headers={headerData} size={responsiveSize} useZebraStyles={false}>
103
89
  {({ rows, headers, getRowProps, getTableProps }) => (
104
90
  <TableContainer>
105
91
  <Table {...getTableProps()} aria-label="Invoice line items">
@@ -3,10 +3,11 @@ import { render, screen } from '@testing-library/react';
3
3
  import { useConfig } from '@openmrs/esm-framework';
4
4
  import { billsSummary } from '../../__mocks__/bills.mock';
5
5
  import { useBills } from '../billing.resource';
6
+ import { type MappedBill } from '../types';
6
7
  import MetricsCards from './metrics-cards.component';
7
8
 
8
- const mockUseBills = useBills as jest.Mock;
9
- const mockUseConfig = useConfig as jest.Mock;
9
+ const mockUseBills = jest.mocked(useBills);
10
+ const mockUseConfig = jest.mocked(useConfig);
10
11
 
11
12
  jest.mock('../billing.resource', () => ({
12
13
  useBills: jest.fn(),
@@ -14,13 +15,19 @@ jest.mock('../billing.resource', () => ({
14
15
 
15
16
  describe('MetricsCards', () => {
16
17
  test('renders loading state', () => {
17
- mockUseBills.mockReturnValue({ isLoading: true, bills: [], error: null });
18
+ mockUseBills.mockReturnValue({ isLoading: true, bills: [], error: null, isValidating: false, mutate: jest.fn() });
18
19
  renderMetricsCards();
19
20
  expect(screen.getByText(/Loading bill metrics.../i)).toBeInTheDocument();
20
21
  });
21
22
 
22
23
  test('renders error state', () => {
23
- mockUseBills.mockReturnValue({ isLoading: false, bills: [], error: new Error('Internal server error') });
24
+ mockUseBills.mockReturnValue({
25
+ isLoading: false,
26
+ bills: [],
27
+ error: new Error('Internal server error'),
28
+ isValidating: false,
29
+ mutate: jest.fn(),
30
+ });
24
31
  renderMetricsCards();
25
32
  expect(
26
33
  screen.getByText(
@@ -30,7 +37,13 @@ describe('MetricsCards', () => {
30
37
  });
31
38
 
32
39
  test('renders metrics cards', () => {
33
- mockUseBills.mockReturnValue({ isLoading: false, bills: billsSummary, error: null });
40
+ mockUseBills.mockReturnValue({
41
+ isLoading: false,
42
+ bills: billsSummary as unknown as MappedBill[],
43
+ error: null,
44
+ isValidating: false,
45
+ mutate: jest.fn(),
46
+ });
34
47
  mockUseConfig.mockImplementation(() => ({ defaultCurrency: 'USD' }));
35
48
  renderMetricsCards();
36
49
  expect(screen.getByRole('heading', { name: /cumulative bills/i })).toBeInTheDocument();
@@ -1,16 +1,14 @@
1
1
  import React from 'react';
2
- import { render, screen, fireEvent } from '@testing-library/react';
3
- import '@testing-library/jest-dom';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { render, screen } from '@testing-library/react';
4
+ import { getDefaultsFromConfigSchema, useConfig } from '@openmrs/esm-framework';
4
5
  import { useBills } from '../billing.resource';
5
- import RequirePaymentModal from './require-payment-modal.component';
6
+ import { type MappedBill } from '../types';
7
+ import { configSchema, type BillingConfig } from '../config-schema';
8
+ import RequirePaymentModal from './require-payment.modal';
6
9
 
7
- jest.mock('react-i18next', () => ({
8
- useTranslation: () => ({ t: (key: string) => key }),
9
- }));
10
-
11
- jest.mock('@openmrs/esm-framework', () => ({
12
- useConfig: () => ({ defaultCurrency: 'USD' }),
13
- }));
10
+ const mockUseConfig = jest.mocked(useConfig<BillingConfig>);
11
+ const mockUseBills = jest.mocked<typeof useBills>(useBills);
14
12
 
15
13
  jest.mock('../billing.resource', () => ({
16
14
  useBills: jest.fn(),
@@ -25,19 +23,19 @@ describe('RequirePaymentModal', () => {
25
23
  const patientUuid = '12345';
26
24
 
27
25
  beforeEach(() => {
28
- jest.clearAllMocks();
26
+ mockUseConfig.mockReturnValue({ ...getDefaultsFromConfigSchema(configSchema), defaultCurrency: 'USD' });
29
27
  });
30
28
 
31
29
  it('renders correctly', () => {
32
- (useBills as jest.Mock).mockReturnValue({ bills: [], isLoading: false, error: null });
30
+ mockUseBills.mockReturnValue({ bills: [], isLoading: false, error: null, isValidating: false, mutate: jest.fn() });
33
31
  render(<RequirePaymentModal closeModal={closeModal} patientUuid={patientUuid} />);
34
- expect(screen.getByText('patientBillingAlert')).toBeInTheDocument();
32
+ expect(screen.getByText('Patient Billing Alert')).toBeInTheDocument();
35
33
  });
36
34
 
37
35
  it('displays loading state', () => {
38
- (useBills as jest.Mock).mockReturnValue({ bills: [], isLoading: true, error: null });
36
+ mockUseBills.mockReturnValue({ bills: [], isLoading: true, error: null, isValidating: false, mutate: jest.fn() });
39
37
  render(<RequirePaymentModal closeModal={closeModal} patientUuid={patientUuid} />);
40
- expect(screen.getByText('inlineLoading')).toBeInTheDocument();
38
+ expect(screen.getByText('Loading bill items...')).toBeInTheDocument();
41
39
  });
42
40
 
43
41
  it('displays line items', () => {
@@ -50,17 +48,24 @@ describe('RequirePaymentModal', () => {
50
48
  ],
51
49
  },
52
50
  ];
53
- (useBills as jest.Mock).mockReturnValue({ bills, isLoading: false, error: null });
51
+ mockUseBills.mockReturnValue({
52
+ bills: bills as unknown as MappedBill[],
53
+ isLoading: false,
54
+ error: null,
55
+ isValidating: false,
56
+ mutate: jest.fn(),
57
+ });
54
58
  render(<RequirePaymentModal closeModal={closeModal} patientUuid={patientUuid} />);
55
59
  expect(screen.getByText('Service 1')).toBeInTheDocument();
56
60
  expect(screen.getByText('Item 1')).toBeInTheDocument();
57
61
  });
58
62
 
59
- it('handles closeModal', () => {
60
- (useBills as jest.Mock).mockReturnValue({ bills: [], isLoading: false, error: null });
63
+ it('handles closeModal', async () => {
64
+ const user = userEvent.setup();
65
+ mockUseBills.mockReturnValue({ bills: [], isLoading: false, error: null, isValidating: false, mutate: jest.fn() });
61
66
  render(<RequirePaymentModal closeModal={closeModal} patientUuid={patientUuid} />);
62
- fireEvent.click(screen.getByText('cancel'));
63
- fireEvent.click(screen.getByText('ok'));
67
+ await user.click(screen.getByText('Cancel'));
68
+ await user.click(screen.getByText('OK'));
64
69
  expect(closeModal).toHaveBeenCalledTimes(2);
65
70
  });
66
71
  });
@@ -12,7 +12,7 @@ import {
12
12
  StructuredListRow,
13
13
  StructuredListWrapper,
14
14
  } from '@carbon/react';
15
- import { useConfig } from '@openmrs/esm-framework';
15
+ import { getCoreTranslation, useConfig } from '@openmrs/esm-framework';
16
16
  import { useBills } from '../billing.resource';
17
17
  import { convertToCurrency } from '../helpers';
18
18
  import styles from './require-payment.scss';
@@ -29,22 +29,23 @@ const RequirePaymentModal: React.FC<RequirePaymentModalProps> = ({ closeModal, p
29
29
  const lineItems = bills.filter((bill) => bill?.status !== 'PAID').flatMap((bill) => bill?.lineItems);
30
30
 
31
31
  return (
32
- <div>
32
+ <>
33
33
  <ModalHeader closeModal={closeModal} title={t('patientBillingAlert', 'Patient Billing Alert')} />
34
34
  <ModalBody>
35
35
  <p className={styles.bodyShort02}>
36
36
  {t(
37
37
  'billPaymentRequiredMessage',
38
- 'The current patient has pending bill. Advice patient to settle bill before receiving services',
38
+ 'The current patient has a pending bill. Advise the patient to settle the bill before receiving services',
39
39
  )}
40
40
  </p>
41
41
  {isLoading && (
42
42
  <InlineLoading
43
43
  status="active"
44
44
  iconDescription="Loading"
45
- description={t('inlineLoading', 'Loading bill items...')}
45
+ description={t('loadingBillItems', 'Loading bill items') + '...'}
46
46
  />
47
47
  )}
48
+
48
49
  <StructuredListWrapper isCondensed>
49
50
  <StructuredListHead>
50
51
  <StructuredListRow head>
@@ -55,30 +56,28 @@ const RequirePaymentModal: React.FC<RequirePaymentModalProps> = ({ closeModal, p
55
56
  </StructuredListRow>
56
57
  </StructuredListHead>
57
58
  <StructuredListBody>
58
- {lineItems.map((lineItem) => {
59
- return (
60
- <StructuredListRow>
61
- <StructuredListCell>{lineItem.billableService || lineItem.item}</StructuredListCell>
62
- <StructuredListCell>{lineItem.quantity}</StructuredListCell>
63
- <StructuredListCell>{convertToCurrency(lineItem.price, defaultCurrency)}</StructuredListCell>
64
- <StructuredListCell>
65
- {convertToCurrency(lineItem.quantity * lineItem.price, defaultCurrency)}
66
- </StructuredListCell>
67
- </StructuredListRow>
68
- );
69
- })}
59
+ {lineItems.map((lineItem) => (
60
+ <StructuredListRow key={lineItem.uuid}>
61
+ <StructuredListCell>{lineItem.billableService || lineItem.item}</StructuredListCell>
62
+ <StructuredListCell>{lineItem.quantity}</StructuredListCell>
63
+ <StructuredListCell>{convertToCurrency(lineItem.price, defaultCurrency)}</StructuredListCell>
64
+ <StructuredListCell>
65
+ {convertToCurrency(lineItem.quantity * lineItem.price, defaultCurrency)}
66
+ </StructuredListCell>
67
+ </StructuredListRow>
68
+ ))}
70
69
  </StructuredListBody>
71
70
  </StructuredListWrapper>
72
71
  </ModalBody>
73
72
  <ModalFooter>
74
73
  <Button kind="secondary" onClick={closeModal}>
75
- {t('cancel', 'Cancel')}
74
+ {getCoreTranslation('cancel')}
76
75
  </Button>
77
76
  <Button kind="primary" onClick={closeModal}>
78
77
  {t('ok', 'OK')}
79
78
  </Button>
80
79
  </ModalFooter>
81
- </div>
80
+ </>
82
81
  );
83
82
  };
84
83
 
package/src/routes.json CHANGED
@@ -81,12 +81,32 @@
81
81
  },
82
82
  {
83
83
  "name": "edit-bill-line-item-dialog",
84
- "component": "editBillLineItemDialog",
84
+ "component": "editBillLineItemModal",
85
85
  "online": true,
86
86
  "offline": true
87
87
  }
88
88
  ],
89
89
  "modals": [
90
+ {
91
+ "name": "add-cash-point-modal",
92
+ "component": "addCashPointModal"
93
+ },
94
+ {
95
+ "name": "add-payment-mode-modal",
96
+ "component": "addPaymentModeModal"
97
+ },
98
+ {
99
+ "name": "delete-payment-mode-modal",
100
+ "component": "deletePaymentModeModal"
101
+ },
102
+ {
103
+ "name": "edit-bill-item-modal",
104
+ "component": "editBillLineItemModal"
105
+ },
106
+ {
107
+ "name": "edit-billable-service-modal",
108
+ "component": "editBillableServiceModal"
109
+ },
90
110
  {
91
111
  "name": "require-billing-modal",
92
112
  "component": "requirePaymentModal"
@@ -107,4 +127,4 @@
107
127
  "description": "This feature introduces navigation links on the patient chart and home page to allow accessing the billing module features"
108
128
  }
109
129
  ]
110
- }
130
+ }
@@ -52,19 +52,19 @@ interface Provider {
52
52
  }
53
53
 
54
54
  export interface LineItem {
55
- uuid: string;
56
- display: string;
57
- voided: boolean;
58
- voidReason: string | null;
59
- item: string;
60
- billableService: string;
55
+ uuid?: string;
56
+ item?: string;
57
+ paymentStatus: string;
58
+ billableService?: string;
61
59
  quantity: number;
62
60
  price: number;
63
- priceName: string;
64
- priceUuid: string;
65
- lineItemOrder: number;
66
- resourceVersion: string;
67
- paymentStatus: string;
61
+ priceName?: string;
62
+ priceUuid?: string;
63
+ lineItemOrder?: number;
64
+ resourceVersion?: string;
65
+ display?: string;
66
+ voided?: boolean;
67
+ voidReason?: string | null;
68
68
  }
69
69
 
70
70
  interface PatientLink {
@@ -168,7 +168,7 @@ export type ServiceConcept = {
168
168
  display: string;
169
169
  };
170
170
 
171
- export type BillabeItem = {
171
+ export type BillableItem = {
172
172
  uuid: string;
173
173
  id?: number;
174
174
  name?: string;
@@ -177,6 +177,7 @@ export type BillabeItem = {
177
177
  };
178
178
 
179
179
  export type ServicePrice = {
180
+ name: string;
180
181
  price: string;
181
182
  uuid: string;
182
183
  };
@@ -1,19 +1,25 @@
1
1
  {
2
- "actions": "Actions",
2
+ "action": "Action",
3
3
  "addBill": "Add bill item(s)",
4
4
  "addBillableServices": "Add Billable Services",
5
5
  "addCashPoint": "Add Cash Point",
6
6
  "addNewBillableService": "Add new billable service",
7
+ "addNewCashPoint": "Add New Cash Point",
8
+ "addNewPaymentMode": "Add New Payment Mode",
7
9
  "addNewService": "Add new service",
8
10
  "addPaymentMode": "Add Payment Mode",
9
11
  "addPaymentOptions": "Add payment option",
10
12
  "amount": "Amount",
11
13
  "amountDue": "Amount Due",
14
+ "amountTendered": "Amount Tendered",
12
15
  "amountToWaiveAriaLabel": "Enter amount to waive",
13
16
  "amountToWaiveHelper": "Specify the amount to be deducted from the bill",
14
17
  "amountToWaiveLabel": "Amount to Waive",
15
18
  "billableService": "Billable service",
16
19
  "billableServices": "Billable Services",
20
+ "billableServices__lower": "billable services",
21
+ "billAmount": "Bill amount",
22
+ "billCode": "Bill code",
17
23
  "billedItems": "Billed Items",
18
24
  "billedTo": "Billed to",
19
25
  "billErrorService": "Bill service error",
@@ -29,36 +35,38 @@
29
35
  "billName": " {{billName}} ",
30
36
  "billPayment": "Bill payment",
31
37
  "billPaymentError": "Bill payment error",
32
- "billPaymentRequiredMessage": "The current patient has pending bill. Advice patient to settle bill before receiving services",
38
+ "billPaymentRequiredMessage": "The current patient has a pending bill. Advise the patient to settle the bill before receiving services",
39
+ "billProcessingError": "Bill processing error",
40
+ "billProcessingSuccess": "Bill processing has been successful",
33
41
  "billServicesManagement": "Bill services management",
34
42
  "billsList": "Bill list",
35
43
  "billTotal": "Bill total",
36
44
  "billWaiver": "Bill waiver",
37
45
  "billWaiverError": "Bill waiver failed {{error}}",
38
46
  "billWaiverSuccess": "Bill waiver successful",
39
- "cancel": "Cancel",
40
47
  "cashPointConfig": "Cash Point Config",
41
48
  "cashPointHistory": "Cash Point History",
42
49
  "cashPointLocation": "Cash Point Location",
43
50
  "cashPointName": "Cash Point Name",
44
51
  "cashPointNamePlaceholder": "e.g., Pharmacy Cash Point",
52
+ "cashPointNameRequired": "Cash Point Name is required",
45
53
  "cashPointSaved": "Cash point was successfully saved.",
46
54
  "cashPointUuid": "Cash Point UUID",
47
55
  "cashPointUuidPlaceholder": "Enter UUID",
48
56
  "checkFilters": "Check the filters above",
49
- "clearSearchInput": "Clear search input",
50
- "clientBalance": "Client Balance",
51
57
  "confirmDeleteMessage": "Are you sure you want to delete this payment mode? Proceed cautiously.",
52
58
  "createdSuccessfully": "Billable service created successfully",
53
59
  "currentPrice": "Current price",
54
- "delete": "Delete",
60
+ "date": "Date",
61
+ "dateAndTime": "Date And Time",
62
+ "dateOfPayment": "Date of payment",
55
63
  "deletePaymentMode": "Delete Payment Mode",
64
+ "deleting": "Deleting",
56
65
  "description": "Description",
57
66
  "descriptionPlaceholder": "e.g., Used for all cash transactions",
58
67
  "discard": "Discard",
59
68
  "discount": "Discount",
60
- "duplicateCashPointError": "A cash point with the same name or UUID already exists. Please use a unique name and UUID.",
61
- "duplicatePaymentModeError": "A payment mode with the same name already exists. Please create another payment mode",
69
+ "discountAmount": "Discount Amount",
62
70
  "editBillableService": "Edit billable service",
63
71
  "editBillableServices": "Edit Billable Services",
64
72
  "editBillLineItem": "Edit bill line item?",
@@ -73,6 +81,7 @@
73
81
  "errorFetchingPaymentModes": "An error occurred while fetching payment modes.",
74
82
  "errorLoadingBillServices": "Error loading bill services",
75
83
  "errorLoadingPaymentModes": "Payment modes error",
84
+ "errorPrintingInvoice": "Error printing invoice",
76
85
  "errorSavingCashPoint": "An error occurred while saving the cash point.",
77
86
  "errorSavingPaymentMode": "An error occurred while saving the payment mode.",
78
87
  "filterBy": "Filter by",
@@ -80,19 +89,27 @@
80
89
  "grandTotal": "Grand total",
81
90
  "home": "Home",
82
91
  "identifier": "Identifier",
83
- "inlineLoading": "Loading bill items...",
84
92
  "insuranceScheme": "Insurance scheme",
93
+ "invalidUuidFormat": "Invalid UUID format",
85
94
  "invalidWaiverAmount": "Invalid waiver amount",
95
+ "inventoryItem": "Inventory item",
86
96
  "invoice": "Invoice",
97
+ "invoiceDate": "Invoice date",
87
98
  "invoiceError": "Invoice error",
99
+ "invoiceNumber": "Invoice #",
100
+ "invoiceStatus": "Invoice Status",
88
101
  "item": "Item",
89
102
  "itemsToBeBilled": "Items to be billed",
90
103
  "launchBillForm": "Launch bill form",
91
104
  "lineItems": "Line items",
92
105
  "loading": "Loading data...",
106
+ "loadingBillInfo": "Loading bill information...",
93
107
  "loadingBillingServices": "Loading billing services...",
108
+ "loadingBillItems": "Loading bill items",
109
+ "loadingData": "Loading data",
94
110
  "loadingDescription": "Loading",
95
111
  "location": "Select Location",
112
+ "locationRequired": "Location is required",
96
113
  "manageBillableServices": "Manage billable services",
97
114
  "name": "Name",
98
115
  "nextPage": "Next page",
@@ -101,8 +118,7 @@
101
118
  "noMatchingItemsToDisplay": "No matching items to display",
102
119
  "noMatchingServicesToDisplay": "No matching services to display",
103
120
  "noResultsFor": "No results for",
104
- "noResultsFound": "No results found",
105
- "noServicesToDisplay": "There are no services to display",
121
+ "number": "No",
106
122
  "ok": "OK",
107
123
  "patientBillingAlert": "Patient Billing Alert",
108
124
  "patientBills": "Patient bill",
@@ -116,6 +132,7 @@
116
132
  "paymentModeHistory": "Payment Mode History",
117
133
  "paymentModeName": "Payment Mode Name",
118
134
  "paymentModeNamePlaceholder": "e.g., Cash, Credit Card",
135
+ "paymentModeNameRequired": "Payment Mode Name is required",
119
136
  "paymentModeSaved": "Payment mode was successfully saved.",
120
137
  "paymentModesConfig": "Payment Modes Config",
121
138
  "payments": "Payments",
@@ -130,41 +147,41 @@
130
147
  "printReceipt": "Print receipt",
131
148
  "processPayment": "Process Payment",
132
149
  "quantity": "Quantity",
133
- "quantityGreaterThanZero": "Quantity must be greater than zero",
134
150
  "quantityRequired": "Quantity is required",
135
151
  "referenceNumber": "Reference number",
136
- "save": "Save",
137
152
  "saveAndClose": "Save and close",
153
+ "saveBill": "Save Bill",
138
154
  "saving": "Saving",
139
155
  "searchConcepts": "Search associated concept",
140
156
  "searching": "Searching",
141
157
  "searchItems": "Search items and services",
142
158
  "searchThisTable": "Search this table",
143
159
  "selectBillableService": "Select a billable service...",
144
- "selectCategory": "Select category",
160
+ "selectLocation": "Select Location",
145
161
  "selectPatientCategory": "Select patient category",
146
162
  "selectPaymentMethod": "Select payment method",
147
163
  "sellingAmount": "Enter selling price",
148
164
  "sellingPrice": "Selling Price",
149
- "service": "Service",
150
165
  "serviceMetrics": "Service Metrics",
151
166
  "serviceName": "Service Name",
152
167
  "serviceNameExceedsLimit": "Service Name exceeds the character limit of {{MAX_NAME_LENGTH}}.",
153
168
  "serviceShortName": "Short Name",
154
169
  "servicesList": "Services list",
170
+ "serviceStatus": "Service Status",
155
171
  "serviceType": "Service Type",
156
172
  "shortName": "Short Name",
157
173
  "shortNameExceedsLimit": "Short Name exceeds the character limit of {{MAX_NAME_LENGTH}}.",
158
174
  "status": "Service Status",
159
- "stockItem": "Stock Item",
160
175
  "submitting": "Submitting...",
161
176
  "success": "Success",
162
177
  "total": "Total",
163
178
  "totalAmount": "Total Amount",
164
179
  "totalTendered": "Total Tendered",
165
180
  "unitPrice": "Unit price",
181
+ "unitPriceHelperText": "This is the unit price for this item.",
166
182
  "updatedSuccessfully": "Billable service updated successfully",
167
183
  "uuid": "UUID",
184
+ "uuidRequired": "UUID is required",
168
185
  "visitTime": "Visit time",
169
186
  "waiverForm": "Waiver form"
170
187
  }