@openmrs/esm-billing-app 1.0.2-pre.659 → 1.0.2-pre.664

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 (96) hide show
  1. package/dist/1119.js +1 -1
  2. package/dist/1197.js +1 -1
  3. package/dist/2146.js +1 -1
  4. package/dist/2690.js +1 -1
  5. package/dist/2747.js +1 -1
  6. package/dist/2747.js.map +1 -1
  7. package/dist/3099.js +1 -1
  8. package/dist/3584.js +1 -1
  9. package/dist/4055.js +1 -1
  10. package/dist/4132.js +1 -1
  11. package/dist/4300.js +1 -1
  12. package/dist/4335.js +1 -1
  13. package/dist/4618.js +1 -1
  14. package/dist/4652.js +1 -1
  15. package/dist/4944.js +1 -1
  16. package/dist/5173.js +1 -1
  17. package/dist/5241.js +1 -1
  18. package/dist/5442.js +1 -1
  19. package/dist/5661.js +1 -1
  20. package/dist/6022.js +1 -1
  21. package/dist/6468.js +1 -1
  22. package/dist/6679.js +1 -1
  23. package/dist/6840.js +1 -1
  24. package/dist/6859.js +1 -1
  25. package/dist/7097.js +1 -1
  26. package/dist/7159.js +1 -1
  27. package/dist/723.js +1 -1
  28. package/dist/7617.js +1 -1
  29. package/dist/795.js +1 -1
  30. package/dist/8163.js +1 -1
  31. package/dist/8349.js +1 -1
  32. package/dist/8618.js +1 -1
  33. package/dist/8638.js +1 -1
  34. package/dist/8638.js.map +1 -1
  35. package/dist/890.js +1 -1
  36. package/dist/9214.js +1 -1
  37. package/dist/9538.js +1 -1
  38. package/dist/9569.js +1 -1
  39. package/dist/986.js +1 -1
  40. package/dist/9879.js +1 -1
  41. package/dist/9895.js +1 -1
  42. package/dist/9900.js +1 -1
  43. package/dist/9913.js +1 -1
  44. package/dist/main.js +1 -1
  45. package/dist/main.js.map +1 -1
  46. package/dist/openmrs-esm-billing-app.js.buildmanifest.json +128 -128
  47. package/dist/routes.json +1 -1
  48. package/package.json +1 -1
  49. package/src/bill-history/bill-history.component.tsx +1 -1
  50. package/src/invoice/invoice-table.component.tsx +6 -43
  51. package/src/invoice/invoice-table.test.tsx +0 -11
  52. package/src/invoice/invoice.component.tsx +2 -12
  53. package/src/invoice/payments/payment-form/payment-form.component.tsx +2 -9
  54. package/src/invoice/payments/payment-form/payment-form.test.tsx +6 -36
  55. package/src/invoice/payments/payments.component.tsx +16 -27
  56. package/src/invoice/payments/{payments.component.test.tsx → payments.test.tsx} +4 -4
  57. package/src/invoice/payments/utils.ts +4 -22
  58. package/translations/am.json +0 -1
  59. package/translations/ar.json +0 -1
  60. package/translations/ar_SY.json +0 -1
  61. package/translations/bn.json +0 -1
  62. package/translations/de.json +0 -1
  63. package/translations/en.json +0 -1
  64. package/translations/en_US.json +0 -1
  65. package/translations/es.json +0 -1
  66. package/translations/es_MX.json +0 -1
  67. package/translations/fr.json +0 -1
  68. package/translations/he.json +0 -1
  69. package/translations/hi.json +0 -1
  70. package/translations/hi_IN.json +0 -1
  71. package/translations/id.json +0 -1
  72. package/translations/it.json +0 -1
  73. package/translations/ka.json +0 -1
  74. package/translations/km.json +0 -1
  75. package/translations/ku.json +0 -1
  76. package/translations/ky.json +0 -1
  77. package/translations/lg.json +0 -1
  78. package/translations/ne.json +0 -1
  79. package/translations/pl.json +0 -1
  80. package/translations/pt.json +0 -1
  81. package/translations/pt_BR.json +0 -1
  82. package/translations/qu.json +0 -1
  83. package/translations/ro_RO.json +0 -1
  84. package/translations/ru_RU.json +0 -1
  85. package/translations/si.json +0 -1
  86. package/translations/sw.json +0 -1
  87. package/translations/sw_KE.json +0 -1
  88. package/translations/tr.json +0 -1
  89. package/translations/tr_TR.json +0 -1
  90. package/translations/uk.json +0 -1
  91. package/translations/uz.json +0 -1
  92. package/translations/uz@Latn.json +0 -1
  93. package/translations/uz_UZ.json +0 -1
  94. package/translations/vi.json +0 -1
  95. package/translations/zh.json +0 -1
  96. package/translations/zh_CN.json +0 -1
package/dist/routes.json CHANGED
@@ -1 +1 @@
1
- {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":">=2.24.0","fhir2":">=1.2"},"pages":[{"component":"billableServicesHome","route":"billable-services"}],"extensions":[{"component":"billingDashboardLink","name":"billing-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"billing","title":"billing","slot":"billing-dashboard-slot"},"featureFlag":"billing"},{"component":"root","name":"billing-dashboard-root","slot":"billing-dashboard-slot"},{"name":"billing-patient-summary","component":"billingPatientSummary","slot":"patient-chart-billing-dashboard-slot","order":10,"meta":{"columnSpan":4}},{"name":"billing-summary-dashboard-link","component":"billingSummaryDashboardLink","slot":"patient-chart-dashboard-slot","order":11,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-billing-dashboard-slot","path":"Billing history"},"featureFlag":"billing"},{"name":"billable-services-app-menu-item","component":"billableServicesAppMenuItem","slot":"app-menu-item-slot","meta":{"name":"Billable Services"}},{"name":"billing-checkin-form","slot":"extra-visit-attribute-slot","component":"billingCheckInForm","featureFlag":"billing"},{"slot":"system-admin-page-card-link-slot","component":"billableServicesCardLink","name":"billable-services-admin-card-link"},{"name":"patient-banner-billing-tags","component":"visitAttributeTags","slot":"patient-banner-tags-slot","order":2},{"name":"billing-home-tiles-ext","slot":"billing-home-tiles-slot","component":"serviceMetrics"},{"name":"edit-bill-line-item-dialog","component":"editBillLineItemDialog","online":true,"offline":true}],"modals":[{"name":"require-billing-modal","component":"requirePaymentModal"}],"workspaces":[{"name":"billing-form-workspace","title":"billingForm","component":"billingFormWorkspace","type":"form"}],"featureFlags":[{"flagName":"billing","label":"Billing module","description":"This feature introduces navigation links on the patient chart and home page to allow accessing the billing module features"}],"version":"1.0.2-pre.659"}
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":">=2.24.0","fhir2":">=1.2"},"pages":[{"component":"billableServicesHome","route":"billable-services"}],"extensions":[{"component":"billingDashboardLink","name":"billing-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"billing","title":"billing","slot":"billing-dashboard-slot"},"featureFlag":"billing"},{"component":"root","name":"billing-dashboard-root","slot":"billing-dashboard-slot"},{"name":"billing-patient-summary","component":"billingPatientSummary","slot":"patient-chart-billing-dashboard-slot","order":10,"meta":{"columnSpan":4}},{"name":"billing-summary-dashboard-link","component":"billingSummaryDashboardLink","slot":"patient-chart-dashboard-slot","order":11,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-billing-dashboard-slot","path":"Billing history"},"featureFlag":"billing"},{"name":"billable-services-app-menu-item","component":"billableServicesAppMenuItem","slot":"app-menu-item-slot","meta":{"name":"Billable Services"}},{"name":"billing-checkin-form","slot":"extra-visit-attribute-slot","component":"billingCheckInForm","featureFlag":"billing"},{"slot":"system-admin-page-card-link-slot","component":"billableServicesCardLink","name":"billable-services-admin-card-link"},{"name":"patient-banner-billing-tags","component":"visitAttributeTags","slot":"patient-banner-tags-slot","order":2},{"name":"billing-home-tiles-ext","slot":"billing-home-tiles-slot","component":"serviceMetrics"},{"name":"edit-bill-line-item-dialog","component":"editBillLineItemDialog","online":true,"offline":true}],"modals":[{"name":"require-billing-modal","component":"requirePaymentModal"}],"workspaces":[{"name":"billing-form-workspace","title":"billingForm","component":"billingFormWorkspace","type":"form"}],"featureFlags":[{"flagName":"billing","label":"Billing module","description":"This feature introduces navigation links on the patient chart and home page to allow accessing the billing module features"}],"version":"1.0.2-pre.664"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-billing-app",
3
- "version": "1.0.2-pre.659",
3
+ "version": "1.0.2-pre.664",
4
4
  "description": "O3 frontend module for handling billing concerns in healthcare settings",
5
5
  "browser": "dist/openmrs-esm-billing-app.js",
6
6
  "main": "src/index.ts",
@@ -155,7 +155,7 @@ const BillHistory: React.FC<BillHistoryProps> = ({ patientUuid }) => {
155
155
  {row.isExpanded ? (
156
156
  <TableExpandedRow className={styles.expandedRow} colSpan={headers.length + 1}>
157
157
  <div className={styles.container} key={i}>
158
- <InvoiceTable bill={currentBill} isSelectable={false} />
158
+ <InvoiceTable bill={currentBill} />
159
159
  </div>
160
160
  </TableExpandedRow>
161
161
  ) : (
@@ -1,4 +1,4 @@
1
- import React, { useMemo, useState, useEffect, useCallback } from 'react';
1
+ import React, { useMemo, useState, useCallback } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import fuzzy from 'fuzzy';
4
4
  import {
@@ -13,7 +13,6 @@ import {
13
13
  TableHead,
14
14
  TableHeader,
15
15
  TableRow,
16
- TableSelectRow,
17
16
  TableToolbarSearch,
18
17
  Tile,
19
18
  type DataTableRow,
@@ -22,33 +21,23 @@ import { Edit } from '@carbon/react/icons';
22
21
  import { isDesktop, showModal, useConfig, useDebounce, useLayoutType } from '@openmrs/esm-framework';
23
22
  import { type LineItem, type MappedBill } from '../types';
24
23
  import { convertToCurrency } from '../helpers';
24
+ import type { BillingConfig } from '../config-schema';
25
25
  import styles from './invoice-table.scss';
26
26
 
27
27
  type InvoiceTableProps = {
28
28
  bill: MappedBill;
29
- isSelectable?: boolean;
30
29
  isLoadingBill?: boolean;
31
- onSelectItem?: (selectedLineItems: LineItem[]) => void;
32
30
  };
33
31
 
34
- const InvoiceTable: React.FC<InvoiceTableProps> = ({ bill, isSelectable = true, isLoadingBill, onSelectItem }) => {
32
+ const InvoiceTable: React.FC<InvoiceTableProps> = ({ bill, isLoadingBill }) => {
35
33
  const { t } = useTranslation();
36
- const { defaultCurrency, showEditBillButton } = useConfig();
34
+ const { defaultCurrency, showEditBillButton } = useConfig<BillingConfig>();
37
35
  const layout = useLayoutType();
38
36
  const lineItems = useMemo(() => bill?.lineItems ?? [], [bill?.lineItems]);
39
- const paidLineItems = useMemo(() => lineItems?.filter((item) => item.paymentStatus === 'PAID') ?? [], [lineItems]);
40
37
  const responsiveSize = isDesktop(layout) ? 'sm' : 'lg';
41
-
42
- const [selectedLineItems, setSelectedLineItems] = useState(paidLineItems ?? []);
43
38
  const [searchTerm, setSearchTerm] = useState('');
44
39
  const debouncedSearchTerm = useDebounce(searchTerm);
45
40
 
46
- useEffect(() => {
47
- if (onSelectItem) {
48
- onSelectItem(selectedLineItems);
49
- }
50
- }, [selectedLineItems, onSelectItem]);
51
-
52
41
  const filteredLineItems = useMemo(() => {
53
42
  if (!debouncedSearchTerm) {
54
43
  return lineItems;
@@ -135,23 +124,10 @@ const InvoiceTable: React.FC<InvoiceTableProps> = ({ bill, isSelectable = true,
135
124
  );
136
125
  }
137
126
 
138
- const handleRowSelection = (row: typeof DataTableRow, checked: boolean) => {
139
- const matchingRow = filteredLineItems.find((item) => item.uuid === row.id);
140
- let newSelectedLineItems;
141
-
142
- if (checked) {
143
- newSelectedLineItems = [...selectedLineItems, matchingRow];
144
- } else {
145
- newSelectedLineItems = selectedLineItems.filter((item) => item.uuid !== row.id);
146
- }
147
- setSelectedLineItems(newSelectedLineItems);
148
- onSelectItem(newSelectedLineItems);
149
- };
150
-
151
127
  return (
152
128
  <>
153
- <DataTable headers={tableHeaders} isSortable rows={tableRows} size={responsiveSize} useZebraStyles>
154
- {({ rows, headers, getRowProps, getSelectionProps, getTableProps, getToolbarProps }) => (
129
+ <DataTable headers={tableHeaders} rows={tableRows} size={responsiveSize} useZebraStyles>
130
+ {({ rows, headers, getRowProps, getTableProps }) => (
155
131
  <TableContainer
156
132
  description={
157
133
  <span className={styles.tableDescription}>
@@ -172,7 +148,6 @@ const InvoiceTable: React.FC<InvoiceTableProps> = ({ bill, isSelectable = true,
172
148
  className={`${styles.invoiceTable} billingTable`}>
173
149
  <TableHead>
174
150
  <TableRow>
175
- {rows.length > 1 && isSelectable ? <TableHeader /> : null}
176
151
  {headers.map((header) => (
177
152
  <TableHeader key={header.key}>{header.header}</TableHeader>
178
153
  ))}
@@ -186,18 +161,6 @@ const InvoiceTable: React.FC<InvoiceTableProps> = ({ bill, isSelectable = true,
186
161
  {...getRowProps({
187
162
  row,
188
163
  })}>
189
- {rows.length > 1 && isSelectable && (
190
- <TableSelectRow
191
- aria-label="Select row"
192
- {...getSelectionProps({ row })}
193
- disabled={tableRows[index].status === 'PAID'}
194
- onChange={(checked: boolean) => handleRowSelection(row, checked)}
195
- checked={
196
- tableRows[index].status === 'PAID' ||
197
- Boolean(selectedLineItems?.find((item) => item?.uuid === row?.id))
198
- }
199
- />
200
- )}
201
164
  {row.cells.map((cell) => (
202
165
  <TableCell key={cell.id}>{cell.value}</TableCell>
203
166
  ))}
@@ -110,17 +110,6 @@ describe('InvoiceTable', () => {
110
110
  expect(screen.getByText('Item 2')).toBeInTheDocument();
111
111
  });
112
112
 
113
- it('correctly handles row selection', async () => {
114
- const user = userEvent.setup();
115
- const onSelectItem = jest.fn();
116
- render(<InvoiceTable bill={bill} onSelectItem={onSelectItem} />);
117
-
118
- const checkboxes = screen.getAllByLabelText('Select row');
119
- await user.click(checkboxes[0]);
120
-
121
- expect(onSelectItem).toHaveBeenCalledWith([bill.lineItems[0]]);
122
- });
123
-
124
113
  it('resets isRedirecting to false after timeout', async () => {
125
114
  const user = userEvent.setup();
126
115
  render(<InvoiceTable bill={bill} />);
@@ -12,7 +12,6 @@ import PrintableInvoice from './printable-invoice/printable-invoice.component';
12
12
  import { ErrorState } from '@openmrs/esm-patient-common-lib';
13
13
  import { convertToCurrency } from '../helpers';
14
14
  import { useBill, useDefaultFacility } from '../billing.resource';
15
- import { type LineItem } from '../types';
16
15
  import type { BillingConfig } from '../config-schema';
17
16
  import styles from './invoice.scss';
18
17
 
@@ -28,13 +27,9 @@ const Invoice: React.FC = () => {
28
27
  const { patient, isLoading: isLoadingPatient } = usePatient(patientUuid);
29
28
  const { bill, isLoading: isLoadingBill, error, mutate } = useBill(billUuid);
30
29
  const [isPrinting, setIsPrinting] = useState(false);
31
- const [selectedLineItems, setSelectedLineItems] = useState<LineItem[]>([]);
32
30
  const componentRef = useRef<HTMLDivElement>(null);
33
31
  const onBeforeGetContentResolve = useRef<(() => void) | null>(null);
34
32
  const { defaultCurrency } = useConfig<BillingConfig>();
35
- const handleSelectItem = (lineItems: LineItem[]) => {
36
- setSelectedLineItems(lineItems);
37
- };
38
33
 
39
34
  const handleAfterPrint = useCallback(() => {
40
35
  onBeforeGetContentResolve.current = null;
@@ -66,11 +61,6 @@ const Invoice: React.FC = () => {
66
61
  }
67
62
  }, [isPrinting]);
68
63
 
69
- useEffect(() => {
70
- const unPaidLineItems = bill?.lineItems?.filter((item) => item.paymentStatus === 'PENDING') ?? [];
71
- setSelectedLineItems(unPaidLineItems);
72
- }, [bill?.lineItems]);
73
-
74
64
  // Do not remove this comment. Adds the translation keys for the invoice details
75
65
  /**
76
66
  * t('totalAmount', 'Total Amount')
@@ -130,8 +120,8 @@ const Invoice: React.FC = () => {
130
120
  </div>
131
121
  </div>
132
122
 
133
- <InvoiceTable bill={bill} isLoadingBill={isLoadingBill} onSelectItem={handleSelectItem} />
134
- <Payments bill={bill} mutate={mutate} selectedLineItems={selectedLineItems} />
123
+ <InvoiceTable bill={bill} isLoadingBill={isLoadingBill} />
124
+ <Payments bill={bill} mutate={mutate} />
135
125
 
136
126
  {bill && patient && (
137
127
  <div className={styles.printContainer}>
@@ -10,19 +10,12 @@ import styles from './payment-form.scss';
10
10
 
11
11
  type PaymentFormProps = {
12
12
  disablePayment: boolean;
13
- clientBalance: number;
14
- isSingleLineItemSelected: boolean;
15
13
  isSingleLineItem: boolean;
16
14
  };
17
15
 
18
16
  const DEFAULT_PAYMENT = { method: '', amount: 0, referenceCode: '' };
19
17
 
20
- const PaymentForm: React.FC<PaymentFormProps> = ({
21
- disablePayment,
22
- clientBalance,
23
- isSingleLineItemSelected,
24
- isSingleLineItem,
25
- }) => {
18
+ const PaymentForm: React.FC<PaymentFormProps> = ({ disablePayment, isSingleLineItem }) => {
26
19
  const { t } = useTranslation();
27
20
  const {
28
21
  control,
@@ -119,7 +112,7 @@ const PaymentForm: React.FC<PaymentFormProps> = ({
119
112
  </div>
120
113
  ))}
121
114
  <Button
122
- disabled={disablePayment || (!isSingleLineItem && !isSingleLineItemSelected)}
115
+ disabled={disablePayment}
123
116
  size="md"
124
117
  onClick={handleAppendPaymentMode}
125
118
  className={styles.paymentButtons}
@@ -31,12 +31,7 @@ describe('PaymentForm Component', () => {
31
31
 
32
32
  render(
33
33
  <Wrapper>
34
- <PaymentForm
35
- disablePayment={false}
36
- clientBalance={100}
37
- isSingleLineItemSelected={false}
38
- isSingleLineItem={false}
39
- />
34
+ <PaymentForm disablePayment={false} isSingleLineItem={false} />
40
35
  </Wrapper>,
41
36
  );
42
37
 
@@ -53,12 +48,7 @@ describe('PaymentForm Component', () => {
53
48
 
54
49
  render(
55
50
  <Wrapper>
56
- <PaymentForm
57
- disablePayment={false}
58
- clientBalance={100}
59
- isSingleLineItemSelected={false}
60
- isSingleLineItem={false}
61
- />
51
+ <PaymentForm disablePayment={false} isSingleLineItem={false} />
62
52
  </Wrapper>,
63
53
  );
64
54
 
@@ -75,12 +65,7 @@ describe('PaymentForm Component', () => {
75
65
 
76
66
  render(
77
67
  <Wrapper>
78
- <PaymentForm
79
- disablePayment={false}
80
- clientBalance={100}
81
- isSingleLineItemSelected={false}
82
- isSingleLineItem={true}
83
- />
68
+ <PaymentForm disablePayment={false} isSingleLineItem={true} />
84
69
  </Wrapper>,
85
70
  );
86
71
 
@@ -103,12 +88,7 @@ describe('PaymentForm Component', () => {
103
88
 
104
89
  render(
105
90
  <Wrapper>
106
- <PaymentForm
107
- disablePayment={false}
108
- clientBalance={100}
109
- isSingleLineItemSelected={true}
110
- isSingleLineItem={false}
111
- />
91
+ <PaymentForm disablePayment={false} isSingleLineItem={false} />
112
92
  </Wrapper>,
113
93
  );
114
94
 
@@ -128,12 +108,7 @@ describe('PaymentForm Component', () => {
128
108
 
129
109
  render(
130
110
  <Wrapper>
131
- <PaymentForm
132
- disablePayment={true}
133
- clientBalance={100}
134
- isSingleLineItemSelected={true}
135
- isSingleLineItem={false}
136
- />
111
+ <PaymentForm disablePayment={true} isSingleLineItem={false} />
137
112
  </Wrapper>,
138
113
  );
139
114
 
@@ -151,12 +126,7 @@ describe('PaymentForm Component', () => {
151
126
 
152
127
  render(
153
128
  <Wrapper>
154
- <PaymentForm
155
- disablePayment={false}
156
- clientBalance={100}
157
- isSingleLineItemSelected={true}
158
- isSingleLineItem={false}
159
- />
129
+ <PaymentForm disablePayment={false} isSingleLineItem={false} />
160
130
  </Wrapper>,
161
131
  );
162
132
 
@@ -6,20 +6,19 @@ import { zodResolver } from '@hookform/resolvers/zod';
6
6
  import { navigate, showSnackbar, useConfig, useVisit } from '@openmrs/esm-framework';
7
7
  import { Button } from '@carbon/react';
8
8
  import { CardHeader } from '@openmrs/esm-patient-common-lib';
9
- import { type LineItem, type MappedBill } from '../../types';
10
- import { convertToCurrency } from '../../helpers';
11
- import { createPaymentPayload } from './utils';
12
- import { processBillPayment } from '../../billing.resource';
13
9
  import { InvoiceBreakDown } from './invoice-breakdown/invoice-breakdown.component';
14
10
  import PaymentHistory from './payment-history/payment-history.component';
15
11
  import PaymentForm from './payment-form/payment-form.component';
12
+ import { convertToCurrency } from '../../helpers';
13
+ import { createPaymentPayload } from './utils';
14
+ import { processBillPayment } from '../../billing.resource';
15
+ import { useBillableServices } from '../../billable-services/billable-service.resource';
16
16
  import { updateBillVisitAttribute } from './payment.resource';
17
+ import { type MappedBill } from '../../types';
17
18
  import styles from './payments.scss';
18
- import { useBillableServices } from '../../billable-services/billable-service.resource';
19
19
 
20
20
  type PaymentProps = {
21
21
  bill: MappedBill;
22
- selectedLineItems: Array<LineItem>;
23
22
  mutate: () => void;
24
23
  };
25
24
 
@@ -29,7 +28,7 @@ export type PaymentFormValue = {
29
28
  payment: Array<Payment>;
30
29
  };
31
30
 
32
- const Payments: React.FC<PaymentProps> = ({ bill, mutate, selectedLineItems }) => {
31
+ const Payments: React.FC<PaymentProps> = ({ bill, mutate }) => {
33
32
  const { t } = useTranslation();
34
33
  const { billableServices, isLoading, isValidating, error } = useBillableServices();
35
34
  const paymentSchema = z.object({
@@ -54,25 +53,23 @@ const Payments: React.FC<PaymentProps> = ({ bill, mutate, selectedLineItems }) =
54
53
  control: methods.control,
55
54
  });
56
55
 
57
- const selectedLineItemsTotal = selectedLineItems.reduce((total, item) => total + item.price * item.quantity, 0);
58
- const totalAmountTendered = formValues?.reduce((curr: number, prev) => curr + Number(prev.amount) ?? 0, 0) ?? 0;
59
- const amountDue = bill ? bill.totalAmount - selectedLineItemsTotal : 0;
60
- const clientBalance = bill ? bill.totalAmount - (bill.tenderedAmount + totalAmountTendered) : 0;
61
-
62
56
  const handleNavigateToBillingDashboard = () =>
63
57
  navigate({
64
58
  to: window.getOpenmrsSpaBase() + 'home/billing',
65
59
  });
66
60
 
61
+ const amountDue = bill.totalAmount - bill.tenderedAmount;
62
+
67
63
  const handleProcessPayment = () => {
68
64
  if (bill) {
65
+ const amountBeingTendered = formValues?.reduce((acc, curr) => acc + Number(curr.amount), 0);
66
+ const amountRemaining = amountDue - amountBeingTendered;
69
67
  const paymentPayload = createPaymentPayload(
70
68
  bill,
71
69
  bill?.patientUuid,
72
70
  formValues,
73
- amountDue,
71
+ amountRemaining,
74
72
  billableServices,
75
- selectedLineItems,
76
73
  );
77
74
  paymentPayload.payments.forEach((payment) => {
78
75
  payment.dateCreated = new Date(payment.dateCreated);
@@ -103,9 +100,6 @@ const Payments: React.FC<PaymentProps> = ({ bill, mutate, selectedLineItems }) =
103
100
  return null;
104
101
  }
105
102
 
106
- const amountDueLabel = selectedLineItems.length ? t('amountDue', 'Amount Due') : t('clientBalance', 'Client Balance');
107
- const amountDueValue = selectedLineItems.length ? amountDue : clientBalance;
108
-
109
103
  return (
110
104
  <FormProvider {...methods}>
111
105
  <div className={styles.wrapper}>
@@ -115,12 +109,7 @@ const Payments: React.FC<PaymentProps> = ({ bill, mutate, selectedLineItems }) =
115
109
  </CardHeader>
116
110
  <div>
117
111
  {bill && <PaymentHistory bill={bill} />}
118
- <PaymentForm
119
- disablePayment={clientBalance <= 0}
120
- clientBalance={clientBalance}
121
- isSingleLineItemSelected={selectedLineItems.length > 0}
122
- isSingleLineItem={bill.lineItems.length === 1}
123
- />
112
+ <PaymentForm disablePayment={amountDue <= 0} isSingleLineItem={bill.lineItems.length === 1} />
124
113
  </div>
125
114
  </div>
126
115
  <div className={styles.divider} />
@@ -131,13 +120,13 @@ const Payments: React.FC<PaymentProps> = ({ bill, mutate, selectedLineItems }) =
131
120
  />
132
121
  <InvoiceBreakDown
133
122
  label={t('totalTendered', 'Total Tendered')}
134
- value={convertToCurrency(bill?.tenderedAmount + totalAmountTendered, defaultCurrency)}
123
+ value={convertToCurrency(bill.tenderedAmount, defaultCurrency)}
135
124
  />
136
125
  <InvoiceBreakDown label={t('discount', 'Discount')} value={'--'} />
137
126
  <InvoiceBreakDown
138
- hasBalance={amountDueValue < 0}
139
- label={amountDueLabel}
140
- value={convertToCurrency(amountDueValue < 0 ? -amountDueValue : amountDueValue, defaultCurrency)}
127
+ hasBalance={amountDue < 0}
128
+ label={t('amountDue', 'Amount Due')}
129
+ value={convertToCurrency(amountDue < 0 ? -amountDue : amountDue, defaultCurrency)}
141
130
  />
142
131
  <div className={styles.processPayments}>
143
132
  <Button onClick={handleNavigateToBillingDashboard} kind="secondary">
@@ -108,14 +108,14 @@ describe('Payments', () => {
108
108
  });
109
109
 
110
110
  it('renders payment form and history', () => {
111
- render(<Payments bill={mockBill} mutate={mockMutate} selectedLineItems={mockSelectedLineItems} />);
111
+ render(<Payments bill={mockBill} mutate={mockMutate} />);
112
112
  expect(screen.getByText('Payments')).toBeInTheDocument();
113
113
  expect(screen.getByText('Total Amount:')).toBeInTheDocument();
114
114
  expect(screen.getByText('Total Tendered:')).toBeInTheDocument();
115
115
  });
116
116
 
117
117
  it('calculates and displays correct amounts', () => {
118
- render(<Payments bill={mockBill} mutate={mockMutate} selectedLineItems={mockSelectedLineItems} />);
118
+ render(<Payments bill={mockBill} mutate={mockMutate} />);
119
119
  const amountElements = screen.getAllByText('$1000.00');
120
120
  expect(amountElements[amountElements.length - 3]).toBeInTheDocument();
121
121
  expect(amountElements[amountElements.length - 2]).toBeInTheDocument();
@@ -123,12 +123,12 @@ describe('Payments', () => {
123
123
  });
124
124
 
125
125
  it('disables Process Payment button when form is invalid', () => {
126
- render(<Payments bill={mockBill} mutate={mockMutate} selectedLineItems={mockSelectedLineItems} />);
126
+ render(<Payments bill={mockBill} mutate={mockMutate} />);
127
127
  expect(screen.getByText('Process Payment')).toBeDisabled();
128
128
  });
129
129
 
130
130
  it('navigates to billing dashboard when Discard is clicked', async () => {
131
- render(<Payments bill={mockBill} mutate={mockMutate} selectedLineItems={mockSelectedLineItems} />);
131
+ render(<Payments bill={mockBill} mutate={mockMutate} />);
132
132
  await userEvent.click(screen.getByText('Discard'));
133
133
  expect(navigate).toHaveBeenCalled();
134
134
  });
@@ -1,24 +1,15 @@
1
- import { type LineItem, type MappedBill } from '../../types';
1
+ import { type MappedBill } from '../../types';
2
2
  import { type Payment } from './payments.component';
3
3
 
4
- const hasLineItem = (lineItems: Array<LineItem>, item: LineItem) => {
5
- if (lineItems?.length === 0) {
6
- return false;
7
- }
8
- const foundItem = lineItems.find((lineItem) => lineItem.uuid === item.uuid);
9
- return Boolean(foundItem);
10
- };
11
-
12
4
  export const createPaymentPayload = (
13
5
  bill: MappedBill,
14
6
  patientUuid: string,
15
7
  formValues: Array<Payment>,
16
8
  amountDue: number,
17
9
  billableServices: Array<any>,
18
- selectedLineItems: Array<LineItem>,
19
10
  ) => {
20
11
  const { cashier } = bill;
21
- const totalAmount = bill?.totalAmount;
12
+ const totalAmount = bill.totalAmount ?? 0;
22
13
  const paymentStatus = amountDue <= 0 ? 'PAID' : 'PENDING';
23
14
  const previousPayments = bill?.payments.map((payment) => ({
24
15
  amount: payment.amount,
@@ -37,30 +28,21 @@ export const createPaymentPayload = (
37
28
  }));
38
29
 
39
30
  const updatedPayments = [...newPayments, ...previousPayments];
40
- const totalAmountRendered = updatedPayments.reduce((acc, payment) => acc + payment.amountTendered, 0);
41
31
 
42
32
  const updatedLineItems = bill?.lineItems.map((lineItem) => ({
43
33
  ...lineItem,
44
34
  billableService: getBillableServiceUuid(billableServices, lineItem.billableService),
45
35
  item: processBillItem?.(lineItem),
46
- paymentStatus:
47
- bill?.lineItems.length > 1
48
- ? hasLineItem(selectedLineItems ?? [], lineItem) && totalAmountRendered >= lineItem.price * lineItem.quantity
49
- ? 'PAID'
50
- : 'PENDING'
51
- : paymentStatus,
36
+ paymentStatus: lineItem.paymentStatus === 'PAID' ? 'PAID' : paymentStatus,
52
37
  }));
53
38
 
54
- const allItemsBillPaymentStatus =
55
- updatedLineItems.filter((item) => item.paymentStatus === 'PENDING').length === 0 ? 'PAID' : 'PENDING';
56
-
57
39
  const processedPayment = {
58
40
  cashPoint: bill?.cashPointUuid,
59
41
  cashier: cashier.uuid,
60
42
  lineItems: updatedLineItems,
61
43
  payments: [...updatedPayments],
62
44
  patient: patientUuid,
63
- status: selectedLineItems?.length > 0 ? allItemsBillPaymentStatus : paymentStatus,
45
+ status: paymentStatus,
64
46
  };
65
47
 
66
48
  return processedPayment;
@@ -54,7 +54,6 @@
54
54
  "cashPointUuidPlaceholder": "Enter UUID",
55
55
  "checkFilters": "Check the filters above",
56
56
  "clearSearchInput": "Clear search input",
57
- "clientBalance": "Client Balance",
58
57
  "confirmDeleteMessage": "Are you sure you want to delete this payment mode? Proceed cautiously.",
59
58
  "createdSuccessfully": "Billable service created successfully",
60
59
  "currentPrice": "Current price",
@@ -54,7 +54,6 @@
54
54
  "cashPointUuidPlaceholder": "Enter UUID",
55
55
  "checkFilters": "Check the filters above",
56
56
  "clearSearchInput": "Clear search input",
57
- "clientBalance": "Client Balance",
58
57
  "confirmDeleteMessage": "Are you sure you want to delete this payment mode? Proceed cautiously.",
59
58
  "createdSuccessfully": "Billable service created successfully",
60
59
  "currentPrice": "Current price",
@@ -54,7 +54,6 @@
54
54
  "cashPointUuidPlaceholder": "Enter UUID",
55
55
  "checkFilters": "Check the filters above",
56
56
  "clearSearchInput": "Clear search input",
57
- "clientBalance": "Client Balance",
58
57
  "confirmDeleteMessage": "Are you sure you want to delete this payment mode? Proceed cautiously.",
59
58
  "createdSuccessfully": "Billable service created successfully",
60
59
  "currentPrice": "Current price",
@@ -54,7 +54,6 @@
54
54
  "cashPointUuidPlaceholder": "Enter UUID",
55
55
  "checkFilters": "Check the filters above",
56
56
  "clearSearchInput": "Clear search input",
57
- "clientBalance": "Client Balance",
58
57
  "confirmDeleteMessage": "Are you sure you want to delete this payment mode? Proceed cautiously.",
59
58
  "createdSuccessfully": "Billable service created successfully",
60
59
  "currentPrice": "Current price",
@@ -54,7 +54,6 @@
54
54
  "cashPointUuidPlaceholder": "Enter UUID",
55
55
  "checkFilters": "Check the filters above",
56
56
  "clearSearchInput": "Clear search input",
57
- "clientBalance": "Client Balance",
58
57
  "confirmDeleteMessage": "Are you sure you want to delete this payment mode? Proceed cautiously.",
59
58
  "createdSuccessfully": "Billable service created successfully",
60
59
  "currentPrice": "Current price",
@@ -54,7 +54,6 @@
54
54
  "cashPointUuidPlaceholder": "Enter UUID",
55
55
  "checkFilters": "Check the filters above",
56
56
  "clearSearchInput": "Clear search input",
57
- "clientBalance": "Client Balance",
58
57
  "confirmDeleteMessage": "Are you sure you want to delete this payment mode? Proceed cautiously.",
59
58
  "createdSuccessfully": "Billable service created successfully",
60
59
  "currentPrice": "Current price",
@@ -54,7 +54,6 @@
54
54
  "cashPointUuidPlaceholder": "Enter UUID",
55
55
  "checkFilters": "Check the filters above",
56
56
  "clearSearchInput": "Clear search input",
57
- "clientBalance": "Client Balance",
58
57
  "confirmDeleteMessage": "Are you sure you want to delete this payment mode? Proceed cautiously.",
59
58
  "createdSuccessfully": "Billable service created successfully",
60
59
  "currentPrice": "Current price",
@@ -54,7 +54,6 @@
54
54
  "cashPointUuidPlaceholder": "Enter UUID",
55
55
  "checkFilters": "Check the filters above",
56
56
  "clearSearchInput": "Clear search input",
57
- "clientBalance": "Client Balance",
58
57
  "confirmDeleteMessage": "Are you sure you want to delete this payment mode? Proceed cautiously.",
59
58
  "createdSuccessfully": "Billable service created successfully",
60
59
  "currentPrice": "Current price",
@@ -54,7 +54,6 @@
54
54
  "cashPointUuidPlaceholder": "Enter UUID",
55
55
  "checkFilters": "Check the filters above",
56
56
  "clearSearchInput": "Clear search input",
57
- "clientBalance": "Client Balance",
58
57
  "confirmDeleteMessage": "Are you sure you want to delete this payment mode? Proceed cautiously.",
59
58
  "createdSuccessfully": "Billable service created successfully",
60
59
  "currentPrice": "Current price",
@@ -54,7 +54,6 @@
54
54
  "cashPointUuidPlaceholder": "Enter UUID",
55
55
  "checkFilters": "Check the filters above",
56
56
  "clearSearchInput": "Clear search input",
57
- "clientBalance": "Client Balance",
58
57
  "confirmDeleteMessage": "Êtes vous sûr de vouloir supprimer le mode de paiement ? Soyez Prudent",
59
58
  "createdSuccessfully": "Billable service created successfully",
60
59
  "currentPrice": "Current price",
@@ -54,7 +54,6 @@
54
54
  "cashPointUuidPlaceholder": "Enter UUID",
55
55
  "checkFilters": "Check the filters above",
56
56
  "clearSearchInput": "Clear search input",
57
- "clientBalance": "Client Balance",
58
57
  "confirmDeleteMessage": "Are you sure you want to delete this payment mode? Proceed cautiously.",
59
58
  "createdSuccessfully": "Billable service created successfully",
60
59
  "currentPrice": "Current price",
@@ -54,7 +54,6 @@
54
54
  "cashPointUuidPlaceholder": "Enter UUID",
55
55
  "checkFilters": "Check the filters above",
56
56
  "clearSearchInput": "Clear search input",
57
- "clientBalance": "Client Balance",
58
57
  "confirmDeleteMessage": "Are you sure you want to delete this payment mode? Proceed cautiously.",
59
58
  "createdSuccessfully": "Billable service created successfully",
60
59
  "currentPrice": "Current price",
@@ -54,7 +54,6 @@
54
54
  "cashPointUuidPlaceholder": "Enter UUID",
55
55
  "checkFilters": "Check the filters above",
56
56
  "clearSearchInput": "Clear search input",
57
- "clientBalance": "Client Balance",
58
57
  "confirmDeleteMessage": "Are you sure you want to delete this payment mode? Proceed cautiously.",
59
58
  "createdSuccessfully": "Billable service created successfully",
60
59
  "currentPrice": "Current price",
@@ -54,7 +54,6 @@
54
54
  "cashPointUuidPlaceholder": "Masukkan UUID",
55
55
  "checkFilters": "Periksa filter di atas",
56
56
  "clearSearchInput": "Hapus pencarian",
57
- "clientBalance": "Saldo Klien",
58
57
  "confirmDeleteMessage": "Apakah Anda yakin ingin menghapus metode pembayaran ini? Lanjutkan dengan hati-hati.",
59
58
  "createdSuccessfully": "Layanan berbayar berhasil dibuat",
60
59
  "currentPrice": "Harga saat ini",