@openmrs/esm-billing-app 1.1.2-pre.8 → 1.2.0
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.
- package/.turbo/cache/31f1dfc7f71601df-meta.json +1 -0
- package/.turbo/cache/31f1dfc7f71601df.tar.zst +0 -0
- package/.turbo/turbo-build.log +13 -42
- package/__mocks__/bills.mock.ts +3 -2
- package/dist/1480.js +1 -0
- package/dist/1480.js.map +1 -0
- package/dist/1564.js +1 -0
- package/dist/1564.js.map +1 -0
- package/dist/1578.js +1 -0
- package/dist/1578.js.map +1 -0
- package/dist/1646.js +1 -0
- package/dist/1646.js.map +1 -0
- package/dist/1869.js +1 -0
- package/dist/1869.js.map +1 -0
- package/dist/1877.js +1 -0
- package/dist/1877.js.map +1 -0
- package/dist/1899.js +1 -0
- package/dist/1899.js.map +1 -0
- package/dist/196.js +2 -0
- package/dist/196.js.map +1 -0
- package/dist/2250.js +43 -0
- package/dist/2250.js.map +1 -0
- package/dist/2269.js +1 -0
- package/dist/2269.js.map +1 -0
- package/dist/2317.js +1 -0
- package/dist/2317.js.map +1 -0
- package/dist/2416.js +1 -0
- package/dist/2416.js.map +1 -0
- package/dist/2489.js +1 -0
- package/dist/2489.js.map +1 -0
- package/dist/282.js +1 -0
- package/dist/282.js.map +1 -0
- package/dist/2881.js +1 -0
- package/dist/2881.js.map +1 -0
- package/dist/2997.js +1 -0
- package/dist/2997.js.map +1 -0
- package/dist/3378.js +1 -0
- package/dist/3378.js.map +1 -0
- package/dist/3379.js +1 -0
- package/dist/3379.js.map +1 -0
- package/dist/3784.js +1 -0
- package/dist/3784.js.map +1 -0
- package/dist/3963.js +1 -0
- package/dist/3963.js.map +1 -0
- package/dist/4106.js +1 -0
- package/dist/4106.js.map +1 -0
- package/dist/4111.js +1 -0
- package/dist/4111.js.map +1 -0
- package/dist/434.js +1 -0
- package/dist/434.js.map +1 -0
- package/dist/4348.js +1 -0
- package/dist/4348.js.map +1 -0
- package/dist/4383.js +1 -0
- package/dist/4383.js.map +1 -0
- package/dist/4658.js +1 -0
- package/dist/4658.js.map +1 -0
- package/dist/4870.js +1 -0
- package/dist/4870.js.map +1 -0
- package/dist/4928.js +1 -0
- package/dist/4928.js.map +1 -0
- package/dist/5098.js +1 -0
- package/dist/5098.js.map +1 -0
- package/dist/5117.js +1 -0
- package/dist/5117.js.map +1 -0
- package/dist/5132.js +1 -0
- package/dist/5132.js.map +1 -0
- package/dist/5145.js +1 -0
- package/dist/5145.js.map +1 -0
- package/dist/5390.js +1 -0
- package/dist/5390.js.map +1 -0
- package/dist/5503.js +1 -0
- package/dist/5503.js.map +1 -0
- package/dist/556.js +1 -0
- package/dist/556.js.map +1 -0
- package/dist/5644.js +1 -0
- package/dist/5644.js.map +1 -0
- package/dist/5898.js +1 -0
- package/dist/5898.js.map +1 -0
- package/dist/5940.js +1 -0
- package/dist/5940.js.map +1 -0
- package/dist/6047.js +1 -0
- package/dist/6047.js.map +1 -0
- package/dist/6237.js +1 -0
- package/dist/6237.js.map +1 -0
- package/dist/6362.js +1 -0
- package/dist/6362.js.map +1 -0
- package/dist/6371.js +1 -0
- package/dist/6371.js.map +1 -0
- package/dist/6377.js +1 -0
- package/dist/6377.js.map +1 -0
- package/dist/6444.js +1 -0
- package/dist/6444.js.map +1 -0
- package/dist/6508.js +1 -0
- package/dist/6508.js.map +1 -0
- package/dist/6594.js +1 -0
- package/dist/6594.js.map +1 -0
- package/dist/6724.js +1 -0
- package/dist/6724.js.map +1 -0
- package/dist/6904.js +1 -0
- package/dist/6904.js.map +1 -0
- package/dist/7045.js +1 -0
- package/dist/7045.js.map +1 -0
- package/dist/7175.js +1 -0
- package/dist/7175.js.map +1 -0
- package/dist/7182.js +1 -0
- package/dist/7182.js.map +1 -0
- package/dist/7247.js +1 -0
- package/dist/7247.js.map +1 -0
- package/dist/7742.js +1 -0
- package/dist/7742.js.map +1 -0
- package/dist/7912.js +1 -0
- package/dist/7912.js.map +1 -0
- package/dist/8358.js +1 -0
- package/dist/8358.js.map +1 -0
- package/dist/8359.js +1 -0
- package/dist/8359.js.map +1 -0
- package/dist/8695.js +1 -0
- package/dist/8695.js.map +1 -0
- package/dist/903.js +1 -0
- package/dist/903.js.map +1 -0
- package/dist/9072.js +1 -0
- package/dist/9072.js.map +1 -0
- package/dist/9414.js +1 -0
- package/dist/9414.js.map +1 -0
- package/dist/9655.js +11 -0
- package/dist/9655.js.map +1 -0
- package/dist/9806.js +1 -0
- package/dist/9806.js.map +1 -0
- package/dist/990.js +1 -0
- package/dist/990.js.map +1 -0
- package/dist/main.js +17 -2
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-billing-app.js +6 -1
- package/dist/openmrs-esm-billing-app.js.buildmanifest.json +643 -436
- package/dist/openmrs-esm-billing-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/e2e/commands/billing-operations.ts +21 -0
- package/e2e/commands/types.ts +9 -1
- package/e2e/pages/discounts-page.ts +75 -0
- package/e2e/pages/index.ts +1 -0
- package/e2e/pages/invoice-page.ts +7 -7
- package/e2e/specs/bill-discounts.spec.ts +255 -0
- package/e2e/specs/billing-dashboard.spec.ts +3 -3
- package/e2e/specs/billing-patient-chart.spec.ts +2 -2
- package/package.json +13 -22
- package/rspack.config.js +1 -0
- package/src/bill-history/bill-action-menu.component.tsx +20 -2
- package/src/bill-history/bill-history.test.tsx +23 -22
- package/src/bill-item-actions/edit-bill-item.modal.tsx +1 -1
- package/src/bill-item-actions/edit-bill-item.test.tsx +29 -27
- package/src/billable-services/billable-service-form/billable-service-form.test.tsx +74 -73
- package/src/billable-services/billable-services-home.component.tsx +4 -2
- package/src/billable-services/billable-services.test.tsx +8 -7
- package/src/billable-services/dashboard/dashboard.test.tsx +3 -2
- package/src/billable-services-admin-card-link.test.tsx +2 -1
- package/src/billing-dashboard/billing-dashboard.test.tsx +19 -3
- package/src/billing-form/billing-checkin-form.component.tsx +7 -3
- package/src/billing-form/billing-checkin-form.test.tsx +22 -21
- package/src/billing-form/billing-form.resource.test.ts +7 -6
- package/src/billing-form/billing-form.test.tsx +77 -40
- package/src/billing-form/billing-form.workspace.tsx +25 -6
- package/src/billing-form/visit-attributes/visit-attributes-form.component.tsx +6 -2
- package/src/billing.resource.test.ts +43 -41
- package/src/billing.resource.ts +65 -16
- package/src/bills-table/bills-table.component.tsx +15 -4
- package/src/bills-table/bills-table.test.tsx +72 -71
- package/src/config-schema.ts +0 -7
- package/src/discounts/admin/discount-requests-left-panel-link.component.tsx +43 -0
- package/src/discounts/admin/discount-requests.component.tsx +316 -0
- package/src/discounts/admin/discount-requests.scss +133 -0
- package/src/discounts/admin/discount-requests.test.tsx +104 -0
- package/src/discounts/admin/review-bill-discounts/bill-line-items-table/bill-line-items-table.component.tsx +42 -0
- package/src/discounts/admin/review-bill-discounts/bill-line-items-table/bill-line-items-table.scss +76 -0
- package/src/discounts/admin/review-bill-discounts/bill-payments-table/bill-payments-table.component.tsx +50 -0
- package/src/discounts/admin/review-bill-discounts/bill-payments-table/bill-payments-table.scss +63 -0
- package/src/discounts/admin/review-bill-discounts/bill-receipt-rail/bill-receipt-rail.component.tsx +73 -0
- package/src/discounts/admin/review-bill-discounts/bill-receipt-rail/bill-receipt-rail.scss +54 -0
- package/src/discounts/admin/review-bill-discounts/bill-totals-summary/bill-totals-summary.component.tsx +95 -0
- package/src/discounts/admin/review-bill-discounts/bill-totals-summary/bill-totals-summary.scss +128 -0
- package/src/discounts/admin/review-bill-discounts/discount-card/discount-card.component.tsx +158 -0
- package/src/discounts/admin/review-bill-discounts/discount-card/discount-card.scss +164 -0
- package/src/discounts/admin/review-bill-discounts/discount-review-stack/discount-review-stack.component.tsx +86 -0
- package/src/discounts/admin/review-bill-discounts/discount-review-stack/discount-review-stack.scss +40 -0
- package/src/discounts/admin/review-bill-discounts/review-bill-discounts.modal.scss +14 -0
- package/src/discounts/admin/review-bill-discounts/review-bill-discounts.modal.test.tsx +153 -0
- package/src/discounts/admin/review-bill-discounts/review-bill-discounts.modal.tsx +167 -0
- package/src/discounts/admin/review-bill-discounts/review-bill-discounts.utils.ts +42 -0
- package/src/discounts/discounts-table.component.tsx +109 -0
- package/src/discounts/discounts-table.scss +37 -0
- package/src/discounts/discounts-table.test.tsx +67 -0
- package/src/discounts/discounts.resource.ts +71 -0
- package/src/discounts/request-discount.modal.scss +88 -0
- package/src/discounts/request-discount.modal.test.tsx +161 -0
- package/src/discounts/request-discount.modal.tsx +253 -0
- package/src/index.ts +52 -21
- package/src/invoice/invoice-table.component.tsx +116 -18
- package/src/invoice/invoice-table.test.tsx +165 -13
- package/src/invoice/invoice.component.tsx +111 -7
- package/src/invoice/invoice.test.tsx +366 -66
- package/src/invoice/line-item-action-menu.component.tsx +31 -1
- package/src/invoice/payments/payment-form/payment-form.test.tsx +20 -19
- package/src/invoice/payments/payment-history/payment-history.test.tsx +13 -10
- package/src/invoice/payments/payments.component.tsx +20 -6
- package/src/invoice/payments/payments.test.tsx +88 -23
- package/src/invoice/printable-invoice/print-receipt.test.tsx +10 -28
- package/src/invoice/printable-invoice/printable-footer.test.tsx +5 -4
- package/src/invoice/printable-invoice/printable-invoice-header.component.tsx +3 -3
- package/src/invoice/printable-invoice/printable-invoice-header.test.tsx +26 -11
- package/src/invoice/printable-invoice/printable-invoice.component.tsx +38 -15
- package/src/left-panel-link.test.tsx +3 -3
- package/src/metrics-cards/metrics-cards.test.tsx +11 -10
- package/src/modal/delete-bill-confirmation.modal.test.tsx +134 -0
- package/src/modal/delete-bill-confirmation.modal.tsx +98 -0
- package/src/modal/delete-line-item-confirmation.modal.test.tsx +11 -9
- package/src/modal/finalize-bill-confirmation.modal.test.tsx +10 -8
- package/src/modal/require-payment-modal.test.tsx +12 -11
- package/src/payment-status-tag/payment-status-tag.component.tsx +50 -0
- package/src/payment-status-tag/payment-status-tag.scss +6 -0
- package/src/payment-status-tag/payment-status-tag.test.tsx +113 -0
- package/src/refunds/admin/refund-requests-left-panel-link.component.tsx +43 -0
- package/src/refunds/admin/refund-requests.component.tsx +324 -0
- package/src/refunds/admin/refund-requests.scss +133 -0
- package/src/refunds/admin/refund-requests.test.tsx +99 -0
- package/src/refunds/admin/review-bill-refunds/bill-line-items-table/bill-line-items-table.component.tsx +42 -0
- package/src/refunds/admin/review-bill-refunds/bill-line-items-table/bill-line-items-table.scss +76 -0
- package/src/refunds/admin/review-bill-refunds/bill-payments-table/bill-payments-table.component.tsx +50 -0
- package/src/refunds/admin/review-bill-refunds/bill-payments-table/bill-payments-table.scss +63 -0
- package/src/refunds/admin/review-bill-refunds/bill-receipt-rail/bill-receipt-rail.component.tsx +84 -0
- package/src/refunds/admin/review-bill-refunds/bill-receipt-rail/bill-receipt-rail.scss +54 -0
- package/src/refunds/admin/review-bill-refunds/bill-totals-summary/bill-totals-summary.component.tsx +83 -0
- package/src/refunds/admin/review-bill-refunds/bill-totals-summary/bill-totals-summary.scss +65 -0
- package/src/refunds/admin/review-bill-refunds/refund-card/refund-card.component.tsx +170 -0
- package/src/refunds/admin/review-bill-refunds/refund-card/refund-card.scss +155 -0
- package/src/refunds/admin/review-bill-refunds/refund-review-stack/refund-review-stack.component.tsx +86 -0
- package/src/refunds/admin/review-bill-refunds/refund-review-stack/refund-review-stack.scss +40 -0
- package/src/refunds/admin/review-bill-refunds/review-bill-refunds.modal.scss +14 -0
- package/src/refunds/admin/review-bill-refunds/review-bill-refunds.modal.test.tsx +313 -0
- package/src/refunds/admin/review-bill-refunds/review-bill-refunds.modal.tsx +188 -0
- package/src/refunds/admin/review-bill-refunds/review-bill-refunds.utils.ts +66 -0
- package/src/refunds/refunds-table.component.tsx +137 -0
- package/src/refunds/refunds-table.scss +37 -0
- package/src/refunds/refunds-table.test.tsx +105 -0
- package/src/refunds/refunds.resource.test.ts +44 -0
- package/src/refunds/refunds.resource.ts +42 -0
- package/src/refunds/refunds.types.test.ts +15 -0
- package/src/refunds/request-refund.modal.scss +84 -0
- package/src/refunds/request-refund.modal.test.tsx +204 -0
- package/src/refunds/request-refund.modal.tsx +218 -0
- package/src/routes.json +36 -2
- package/src/types/index.ts +116 -1
- package/src/visit-bills/visit-bills-panel.component.tsx +151 -0
- package/src/visit-bills/visit-bills-panel.scss +31 -0
- package/src/visit-bills/visit-bills-panel.test.tsx +113 -0
- package/tools/empty-module.ts +1 -0
- package/tools/setup-tests.ts +9 -9
- package/translations/am.json +154 -16
- package/translations/ar.json +154 -16
- package/translations/ar_SY.json +154 -16
- package/translations/bn.json +154 -16
- package/translations/cs.json +154 -16
- package/translations/de.json +154 -16
- package/translations/en.json +154 -16
- package/translations/en_US.json +154 -16
- package/translations/es.json +154 -16
- package/translations/es_MX.json +154 -16
- package/translations/fr.json +154 -16
- package/translations/he.json +154 -16
- package/translations/hi.json +154 -16
- package/translations/hi_IN.json +154 -16
- package/translations/id.json +154 -16
- package/translations/it.json +154 -16
- package/translations/ka.json +154 -16
- package/translations/km.json +154 -16
- package/translations/ku.json +154 -16
- package/translations/ky.json +154 -16
- package/translations/lg.json +154 -16
- package/translations/ne.json +154 -16
- package/translations/pl.json +154 -16
- package/translations/pt.json +154 -16
- package/translations/pt_BR.json +154 -16
- package/translations/qu.json +154 -16
- package/translations/ro_RO.json +154 -16
- package/translations/ru_RU.json +154 -16
- package/translations/si.json +154 -16
- package/translations/sq.json +154 -16
- package/translations/sw.json +154 -16
- package/translations/sw_KE.json +154 -16
- package/translations/tr.json +154 -16
- package/translations/tr_TR.json +154 -16
- package/translations/uk.json +154 -16
- package/translations/uz.json +154 -16
- package/translations/uz@Latn.json +154 -16
- package/translations/uz_UZ.json +154 -16
- package/translations/vi.json +154 -16
- package/translations/zh.json +154 -16
- package/translations/zh_CN.json +179 -41
- package/translations/zh_TW.json +154 -16
- package/tsconfig.json +3 -3
- package/vitest.config.js +28 -0
- package/.turbo/cache/6c998b0f30a031ab-meta.json +0 -1
- package/.turbo/cache/6c998b0f30a031ab.tar.zst +0 -0
- package/dist/1119.js +0 -1
- package/dist/1197.js +0 -1
- package/dist/1435.js +0 -1
- package/dist/1435.js.map +0 -1
- package/dist/1807.js +0 -1
- package/dist/1807.js.map +0 -1
- package/dist/2146.js +0 -1
- package/dist/2177.js +0 -2
- package/dist/2177.js.LICENSE.txt +0 -9
- package/dist/2177.js.map +0 -1
- package/dist/2690.js +0 -1
- package/dist/2704.js +0 -1
- package/dist/2704.js.map +0 -1
- package/dist/3002.js +0 -1
- package/dist/3002.js.map +0 -1
- package/dist/3041.js +0 -1
- package/dist/3041.js.map +0 -1
- package/dist/3099.js +0 -1
- package/dist/3184.js +0 -2
- package/dist/3184.js.LICENSE.txt +0 -14
- package/dist/3184.js.map +0 -1
- package/dist/3584.js +0 -1
- package/dist/4055.js +0 -1
- package/dist/4132.js +0 -1
- package/dist/4225.js +0 -1
- package/dist/4225.js.map +0 -1
- package/dist/4300.js +0 -1
- package/dist/4335.js +0 -1
- package/dist/439.js +0 -1
- package/dist/4618.js +0 -1
- package/dist/4652.js +0 -1
- package/dist/4944.js +0 -1
- package/dist/5173.js +0 -1
- package/dist/5241.js +0 -1
- package/dist/5422.js +0 -1
- package/dist/5422.js.map +0 -1
- package/dist/5442.js +0 -1
- package/dist/5661.js +0 -1
- package/dist/6022.js +0 -1
- package/dist/6404.js +0 -1
- package/dist/6404.js.map +0 -1
- package/dist/6468.js +0 -1
- package/dist/6540.js +0 -2
- package/dist/6540.js.LICENSE.txt +0 -9
- package/dist/6540.js.map +0 -1
- package/dist/6589.js +0 -1
- package/dist/6606.js +0 -1
- package/dist/6606.js.map +0 -1
- package/dist/6679.js +0 -1
- package/dist/6792.js +0 -1
- package/dist/6792.js.map +0 -1
- package/dist/6840.js +0 -1
- package/dist/6859.js +0 -1
- package/dist/7097.js +0 -1
- package/dist/7159.js +0 -1
- package/dist/723.js +0 -1
- package/dist/7255.js +0 -1
- package/dist/7255.js.map +0 -1
- package/dist/7617.js +0 -1
- package/dist/795.js +0 -1
- package/dist/8163.js +0 -1
- package/dist/8341.js +0 -2
- package/dist/8341.js.LICENSE.txt +0 -52
- package/dist/8341.js.map +0 -1
- package/dist/8349.js +0 -1
- package/dist/8371.js +0 -1
- package/dist/8421.js +0 -1
- package/dist/8421.js.map +0 -1
- package/dist/8618.js +0 -1
- package/dist/890.js +0 -1
- package/dist/9214.js +0 -1
- package/dist/9538.js +0 -1
- package/dist/9569.js +0 -1
- package/dist/961.js +0 -2
- package/dist/961.js.LICENSE.txt +0 -19
- package/dist/961.js.map +0 -1
- package/dist/986.js +0 -1
- package/dist/9879.js +0 -1
- package/dist/9895.js +0 -1
- package/dist/9900.js +0 -1
- package/dist/9913.js +0 -1
- package/dist/main.js.LICENSE.txt +0 -62
- package/src/billable-services/bill-waiver/bill-selection.component.tsx +0 -76
- package/src/billable-services/bill-waiver/bill-waiver-form.component.tsx +0 -107
- package/src/billable-services/bill-waiver/bill-waiver-form.scss +0 -34
- package/src/billable-services/bill-waiver/bill-waiver.component.tsx +0 -34
- package/src/billable-services/bill-waiver/bill-waiver.scss +0 -10
- package/src/billable-services/bill-waiver/patient-bills.component.tsx +0 -134
- package/webpack.config.js +0 -1
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
InlineLoading,
|
|
5
|
+
ModalBody,
|
|
6
|
+
ModalFooter,
|
|
7
|
+
ModalHeader,
|
|
8
|
+
NumberInput,
|
|
9
|
+
Stack,
|
|
10
|
+
TextArea,
|
|
11
|
+
} from '@carbon/react';
|
|
12
|
+
import { useTranslation } from 'react-i18next';
|
|
13
|
+
import { getCoreTranslation, showSnackbar, useConfig } from '@openmrs/esm-framework';
|
|
14
|
+
import type { BillingConfig } from '../config-schema';
|
|
15
|
+
import { convertToCurrency } from '../helpers';
|
|
16
|
+
import { requestRefund } from './refunds.resource';
|
|
17
|
+
import styles from './request-refund.modal.scss';
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
closeModal: () => void;
|
|
21
|
+
bill: {
|
|
22
|
+
uuid: string;
|
|
23
|
+
total: number;
|
|
24
|
+
amountAfterDiscount: number;
|
|
25
|
+
receiptNumber?: string;
|
|
26
|
+
lineItemCount?: number;
|
|
27
|
+
};
|
|
28
|
+
lineItem?: {
|
|
29
|
+
uuid: string;
|
|
30
|
+
display: string;
|
|
31
|
+
total: number;
|
|
32
|
+
quantity?: number;
|
|
33
|
+
price?: number;
|
|
34
|
+
};
|
|
35
|
+
remainingRefundable: number;
|
|
36
|
+
onMutate?: () => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const RequestRefundModal: React.FC<Props> = ({ closeModal, bill, lineItem, remainingRefundable, onMutate }) => {
|
|
40
|
+
const { t } = useTranslation();
|
|
41
|
+
const { defaultCurrency } = useConfig<BillingConfig>();
|
|
42
|
+
const [amount, setAmount] = useState<number | null>(null);
|
|
43
|
+
const [reason, setReason] = useState('');
|
|
44
|
+
const [submitting, setSubmitting] = useState(false);
|
|
45
|
+
|
|
46
|
+
const isLineItem = !!lineItem;
|
|
47
|
+
const scopeTotal = lineItem?.total ?? bill.total;
|
|
48
|
+
const alreadyRefunded = isLineItem
|
|
49
|
+
? scopeTotal - remainingRefundable
|
|
50
|
+
: bill.amountAfterDiscount - remainingRefundable;
|
|
51
|
+
const trimmedReason = reason.trim();
|
|
52
|
+
|
|
53
|
+
const reasonError = reason.length > 1000 ? t('reasonTooLong', 'Reason cannot exceed 1000 characters') : null;
|
|
54
|
+
|
|
55
|
+
const amountError = (() => {
|
|
56
|
+
if (amount == null || Number.isNaN(amount)) return null;
|
|
57
|
+
if (remainingRefundable <= 0) return t('noRefundableAmount', 'No refundable amount remaining on this bill');
|
|
58
|
+
if (amount <= 0) return t('amountMustBePositive', 'Amount must be greater than 0');
|
|
59
|
+
if (amount > remainingRefundable)
|
|
60
|
+
return t('amountExceedsRefundable', 'Amount cannot exceed {{max}}', {
|
|
61
|
+
max: convertToCurrency(remainingRefundable, defaultCurrency),
|
|
62
|
+
});
|
|
63
|
+
return null;
|
|
64
|
+
})();
|
|
65
|
+
|
|
66
|
+
const canSubmit =
|
|
67
|
+
!submitting && amount != null && amount > 0 && trimmedReason.length > 0 && !reasonError && !amountError;
|
|
68
|
+
|
|
69
|
+
const handleSubmit = async () => {
|
|
70
|
+
if (!canSubmit || amount == null) return;
|
|
71
|
+
setSubmitting(true);
|
|
72
|
+
try {
|
|
73
|
+
await requestRefund({
|
|
74
|
+
bill: bill.uuid,
|
|
75
|
+
lineItem: lineItem?.uuid,
|
|
76
|
+
refundAmount: amount,
|
|
77
|
+
reason: trimmedReason,
|
|
78
|
+
});
|
|
79
|
+
onMutate?.();
|
|
80
|
+
showSnackbar({
|
|
81
|
+
title: t('refundRequested', 'Refund request submitted'),
|
|
82
|
+
subtitle: t('refundPendingReview', 'An admin will review your request'),
|
|
83
|
+
kind: 'success',
|
|
84
|
+
});
|
|
85
|
+
closeModal();
|
|
86
|
+
} catch (err: unknown) {
|
|
87
|
+
const subtitle = (err as any)?.responseBody?.error?.message ?? (err instanceof Error ? err.message : undefined);
|
|
88
|
+
showSnackbar({
|
|
89
|
+
title: t('refundRequestFailed', 'Could not submit refund request'),
|
|
90
|
+
subtitle,
|
|
91
|
+
kind: 'error',
|
|
92
|
+
});
|
|
93
|
+
} finally {
|
|
94
|
+
setSubmitting(false);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<>
|
|
100
|
+
<ModalHeader closeModal={closeModal} title={t('requestRefund', 'Request refund')} />
|
|
101
|
+
<ModalBody className={styles.modalBody}>
|
|
102
|
+
<Stack gap={5}>
|
|
103
|
+
<section className={styles.scopePanel} aria-label={t('refundScope', 'Refund scope')}>
|
|
104
|
+
<div className={styles.scopePrimary}>
|
|
105
|
+
{isLineItem ? lineItem.display : t('wholeBillScope', 'Whole bill')}
|
|
106
|
+
</div>
|
|
107
|
+
<ul className={styles.scopeMeta}>
|
|
108
|
+
{bill.receiptNumber && <li>{t('invoiceLabel', 'Invoice {{number}}', { number: bill.receiptNumber })}</li>}
|
|
109
|
+
{isLineItem && lineItem.quantity != null && lineItem.price != null && (
|
|
110
|
+
<li>
|
|
111
|
+
{t('qtyTimesPrice', 'Qty {{quantity}} × {{price}}', {
|
|
112
|
+
quantity: lineItem.quantity,
|
|
113
|
+
price: convertToCurrency(lineItem.price, defaultCurrency),
|
|
114
|
+
})}
|
|
115
|
+
</li>
|
|
116
|
+
)}
|
|
117
|
+
{!isLineItem && bill.lineItemCount != null && (
|
|
118
|
+
<li>{t('lineItemCount', '{{count}} line items', { count: bill.lineItemCount })}</li>
|
|
119
|
+
)}
|
|
120
|
+
<li className={styles.scopeTotal}>
|
|
121
|
+
{isLineItem
|
|
122
|
+
? t('lineTotalLabel', 'Line total {{total}}', {
|
|
123
|
+
total: convertToCurrency(scopeTotal, defaultCurrency),
|
|
124
|
+
})
|
|
125
|
+
: t('billTotalLabel', 'Bill total {{total}}', {
|
|
126
|
+
total: convertToCurrency(scopeTotal, defaultCurrency),
|
|
127
|
+
})}
|
|
128
|
+
</li>
|
|
129
|
+
</ul>
|
|
130
|
+
</section>
|
|
131
|
+
|
|
132
|
+
<NumberInput
|
|
133
|
+
id="refund-amount"
|
|
134
|
+
label={t('refundAmountLabel', 'Refund amount ({{currency}})', { currency: defaultCurrency })}
|
|
135
|
+
allowEmpty
|
|
136
|
+
min={0}
|
|
137
|
+
max={remainingRefundable}
|
|
138
|
+
value={amount ?? ''}
|
|
139
|
+
invalid={!!amountError}
|
|
140
|
+
invalidText={amountError ?? ''}
|
|
141
|
+
onChange={(_e, { value: v }) => {
|
|
142
|
+
if (v === '' || v == null) {
|
|
143
|
+
setAmount(null);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const n = typeof v === 'string' ? Number.parseFloat(v) : v;
|
|
147
|
+
setAmount(Number.isNaN(n) ? null : n);
|
|
148
|
+
}}
|
|
149
|
+
/>
|
|
150
|
+
|
|
151
|
+
{amount != null && amount > 0 && !amountError && (
|
|
152
|
+
<section className={styles.summaryCard} aria-label={t('refundSummary', 'Refund summary')}>
|
|
153
|
+
<span className={styles.summaryLabel}>
|
|
154
|
+
{isLineItem ? t('lineTotal', 'Line total') : t('billTotal', 'Bill total')}
|
|
155
|
+
</span>
|
|
156
|
+
<span className={styles.summaryValue}>
|
|
157
|
+
{convertToCurrency(isLineItem ? scopeTotal : bill.amountAfterDiscount, defaultCurrency)}
|
|
158
|
+
</span>
|
|
159
|
+
|
|
160
|
+
{alreadyRefunded > 0 && (
|
|
161
|
+
<>
|
|
162
|
+
<span className={styles.summaryLabel}>{t('alreadyRefunded', 'Already refunded')}</span>
|
|
163
|
+
<span className={`${styles.summaryValue} ${styles.summaryRefund}`}>
|
|
164
|
+
−{convertToCurrency(alreadyRefunded, defaultCurrency)}
|
|
165
|
+
</span>
|
|
166
|
+
</>
|
|
167
|
+
)}
|
|
168
|
+
|
|
169
|
+
<span className={styles.summaryLabel}>{t('refundAmount', 'Refund amount')}</span>
|
|
170
|
+
<span className={`${styles.summaryValue} ${styles.summaryRefund}`}>
|
|
171
|
+
−{convertToCurrency(amount, defaultCurrency)}
|
|
172
|
+
</span>
|
|
173
|
+
|
|
174
|
+
<span className={styles.summaryDivider} aria-hidden="true" />
|
|
175
|
+
|
|
176
|
+
<span className={styles.summaryTotalLabel}>{t('amountAfterRefund', 'Amount after refund')}</span>
|
|
177
|
+
<span className={styles.summaryTotalValue}>
|
|
178
|
+
{convertToCurrency(remainingRefundable - amount, defaultCurrency)}
|
|
179
|
+
</span>
|
|
180
|
+
</section>
|
|
181
|
+
)}
|
|
182
|
+
|
|
183
|
+
<TextArea
|
|
184
|
+
id="refund-reason"
|
|
185
|
+
labelText={t('reason', 'Reason')}
|
|
186
|
+
placeholder={
|
|
187
|
+
isLineItem
|
|
188
|
+
? t('lineItemReasonPlaceholder', 'e.g., duplicate charge, wrong item billed')
|
|
189
|
+
: t('billReasonPlaceholder', 'e.g., payment made in error, duplicate payment')
|
|
190
|
+
}
|
|
191
|
+
maxCount={1000}
|
|
192
|
+
enableCounter
|
|
193
|
+
required
|
|
194
|
+
rows={3}
|
|
195
|
+
value={reason}
|
|
196
|
+
invalid={!!reasonError}
|
|
197
|
+
invalidText={reasonError ?? ''}
|
|
198
|
+
onChange={(e) => setReason(e.target.value)}
|
|
199
|
+
/>
|
|
200
|
+
</Stack>
|
|
201
|
+
</ModalBody>
|
|
202
|
+
<ModalFooter>
|
|
203
|
+
<Button kind="secondary" onClick={closeModal}>
|
|
204
|
+
{getCoreTranslation('cancel')}
|
|
205
|
+
</Button>
|
|
206
|
+
<Button kind="primary" onClick={handleSubmit} disabled={!canSubmit}>
|
|
207
|
+
{submitting ? (
|
|
208
|
+
<InlineLoading description={t('submitting', 'Submitting') + '...'} />
|
|
209
|
+
) : (
|
|
210
|
+
<span>{t('submitRequest', 'Submit request')}</span>
|
|
211
|
+
)}
|
|
212
|
+
</Button>
|
|
213
|
+
</ModalFooter>
|
|
214
|
+
</>
|
|
215
|
+
);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
export default RequestRefundModal;
|
package/src/routes.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.openmrs.org/routes.schema.json",
|
|
3
3
|
"backendDependencies": {
|
|
4
|
-
"billing": ">=2.
|
|
4
|
+
"billing": ">=2.3.0-0",
|
|
5
5
|
"webservices.rest": ">=2.24.0"
|
|
6
6
|
},
|
|
7
7
|
"pages": [
|
|
@@ -35,6 +35,14 @@
|
|
|
35
35
|
"columnSpan": 4
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
|
+
{
|
|
39
|
+
"name": "visit-bills-panel",
|
|
40
|
+
"component": "visitBillsPanel",
|
|
41
|
+
"slot": "visit-summary-panels",
|
|
42
|
+
"meta": {
|
|
43
|
+
"title": "Bills"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
38
46
|
{
|
|
39
47
|
"name": "billing-summary-dashboard-link",
|
|
40
48
|
"component": "billingSummaryDashboardLink",
|
|
@@ -71,6 +79,12 @@
|
|
|
71
79
|
"slot": "patient-banner-tags-slot",
|
|
72
80
|
"order": 2
|
|
73
81
|
},
|
|
82
|
+
{
|
|
83
|
+
"name": "patient-banner-payment-status-tag",
|
|
84
|
+
"component": "patientPaymentStatusTag",
|
|
85
|
+
"slot": "patient-banner-tags-slot",
|
|
86
|
+
"order": 3
|
|
87
|
+
},
|
|
74
88
|
{
|
|
75
89
|
"name": "billable-services-left-panel-link",
|
|
76
90
|
"component": "billableServicesLeftPanelLink",
|
|
@@ -82,6 +96,18 @@
|
|
|
82
96
|
"component": "billingSettingsLeftPanelMenu",
|
|
83
97
|
"slot": "billable-services-left-panel-slot",
|
|
84
98
|
"order": 1
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "discount-requests-left-panel-link",
|
|
102
|
+
"component": "discountRequestsLeftPanelLink",
|
|
103
|
+
"slot": "billable-services-left-panel-slot",
|
|
104
|
+
"order": 2
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"name": "refund-requests-left-panel-link",
|
|
108
|
+
"component": "refundRequestsLeftPanelLink",
|
|
109
|
+
"slot": "billable-services-left-panel-slot",
|
|
110
|
+
"order": 3
|
|
85
111
|
}
|
|
86
112
|
],
|
|
87
113
|
"modals": [
|
|
@@ -116,7 +142,15 @@
|
|
|
116
142
|
{
|
|
117
143
|
"name": "finalize-bill-confirmation-modal",
|
|
118
144
|
"component": "finalizeBillConfirmationModal"
|
|
119
|
-
}
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"name": "delete-bill-confirmation-modal",
|
|
148
|
+
"component": "deleteBillConfirmationModal"
|
|
149
|
+
},
|
|
150
|
+
{ "name": "request-discount-modal", "component": "requestDiscountModal" },
|
|
151
|
+
{ "name": "review-bill-discounts-modal", "component": "reviewBillDiscountsModal" },
|
|
152
|
+
{ "name": "request-refund-modal", "component": "requestRefundModal" },
|
|
153
|
+
{ "name": "review-bill-refunds-modal", "component": "reviewBillRefundsModal" }
|
|
120
154
|
],
|
|
121
155
|
"workspaces2": [
|
|
122
156
|
{
|
package/src/types/index.ts
CHANGED
|
@@ -5,10 +5,26 @@ export const BillStatus = {
|
|
|
5
5
|
POSTED: 'POSTED',
|
|
6
6
|
PAID: 'PAID',
|
|
7
7
|
ADJUSTED: 'ADJUSTED',
|
|
8
|
+
PARTIALLY_REFUNDED: 'PARTIALLY_REFUNDED',
|
|
9
|
+
REFUNDED: 'REFUNDED',
|
|
10
|
+
REFUND_REQUESTED: 'REFUND_REQUESTED',
|
|
8
11
|
} as const;
|
|
9
12
|
|
|
10
13
|
export type BillStatus = (typeof BillStatus)[keyof typeof BillStatus];
|
|
11
14
|
|
|
15
|
+
export const BillLineItemStatus = {
|
|
16
|
+
PENDING: 'PENDING',
|
|
17
|
+
PAID: 'PAID',
|
|
18
|
+
CANCELLED: 'CANCELLED',
|
|
19
|
+
ADJUSTED: 'ADJUSTED',
|
|
20
|
+
EXEMPTED: 'EXEMPTED',
|
|
21
|
+
REFUND_REQUESTED: 'REFUND_REQUESTED',
|
|
22
|
+
REFUNDED: 'REFUNDED',
|
|
23
|
+
PARTIALLY_REFUNDED: 'PARTIALLY_REFUNDED',
|
|
24
|
+
} as const;
|
|
25
|
+
|
|
26
|
+
export type BillLineItemStatus = (typeof BillLineItemStatus)[keyof typeof BillLineItemStatus];
|
|
27
|
+
|
|
12
28
|
export interface MappedBill {
|
|
13
29
|
uuid: string;
|
|
14
30
|
id: number;
|
|
@@ -25,9 +41,13 @@ export interface MappedBill {
|
|
|
25
41
|
lineItems: Array<LineItem>;
|
|
26
42
|
billingService: string;
|
|
27
43
|
payments: Array<Payment>;
|
|
44
|
+
discounts?: Array<BillDiscount>;
|
|
45
|
+
refunds?: Array<BillRefund>;
|
|
28
46
|
totalAmount?: number;
|
|
47
|
+
netAmount: number;
|
|
29
48
|
tenderedAmount?: number;
|
|
30
49
|
display?: string;
|
|
50
|
+
visitUuid?: string;
|
|
31
51
|
}
|
|
32
52
|
|
|
33
53
|
interface LocationLink {
|
|
@@ -65,7 +85,7 @@ interface Provider {
|
|
|
65
85
|
export interface LineItem {
|
|
66
86
|
uuid?: string;
|
|
67
87
|
item?: string;
|
|
68
|
-
|
|
88
|
+
status: BillLineItemStatus;
|
|
69
89
|
billableService?: string;
|
|
70
90
|
quantity: number;
|
|
71
91
|
price: number;
|
|
@@ -157,7 +177,12 @@ export interface PatientInvoice {
|
|
|
157
177
|
status: string;
|
|
158
178
|
adjustmentReason: string | null;
|
|
159
179
|
id: number;
|
|
180
|
+
visit?: { uuid: string; display: string };
|
|
160
181
|
resourceVersion: string;
|
|
182
|
+
total: number;
|
|
183
|
+
amountAfterDiscount: number;
|
|
184
|
+
discounts: BillDiscount[];
|
|
185
|
+
refunds: BillRefund[];
|
|
161
186
|
}
|
|
162
187
|
|
|
163
188
|
export interface PatientDetails {
|
|
@@ -230,6 +255,7 @@ export type CreateBillPayload = {
|
|
|
230
255
|
payments: Array<PaymentPayload>;
|
|
231
256
|
patient: string;
|
|
232
257
|
status: string;
|
|
258
|
+
visit?: string;
|
|
233
259
|
};
|
|
234
260
|
|
|
235
261
|
export type UpdateBillPayload = {
|
|
@@ -261,3 +287,92 @@ export type PaymentModePayload = {
|
|
|
261
287
|
name: string;
|
|
262
288
|
description: string;
|
|
263
289
|
};
|
|
290
|
+
|
|
291
|
+
export const BillDiscountStatus = {
|
|
292
|
+
PENDING: 'PENDING',
|
|
293
|
+
APPROVED: 'APPROVED',
|
|
294
|
+
REJECTED: 'REJECTED',
|
|
295
|
+
} as const;
|
|
296
|
+
|
|
297
|
+
export type BillDiscountStatus = (typeof BillDiscountStatus)[keyof typeof BillDiscountStatus];
|
|
298
|
+
|
|
299
|
+
export const BillDiscountType = {
|
|
300
|
+
PERCENTAGE: 'PERCENTAGE',
|
|
301
|
+
FIXED_AMOUNT: 'FIXED_AMOUNT',
|
|
302
|
+
} as const;
|
|
303
|
+
|
|
304
|
+
export type BillDiscountType = (typeof BillDiscountType)[keyof typeof BillDiscountType];
|
|
305
|
+
|
|
306
|
+
export interface UserRef {
|
|
307
|
+
uuid: string;
|
|
308
|
+
display: string;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export interface BillDiscount {
|
|
312
|
+
uuid: string;
|
|
313
|
+
billUuid: string;
|
|
314
|
+
lineItemUuid: string | null;
|
|
315
|
+
discountType: BillDiscountType;
|
|
316
|
+
discountValue: number;
|
|
317
|
+
discountAmount: number;
|
|
318
|
+
justification: string;
|
|
319
|
+
initiator: UserRef;
|
|
320
|
+
approver: UserRef | null;
|
|
321
|
+
dateCreated: string;
|
|
322
|
+
status: BillDiscountStatus;
|
|
323
|
+
voided: boolean;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export interface RequestDiscountPayload {
|
|
327
|
+
bill: string;
|
|
328
|
+
lineItem?: string;
|
|
329
|
+
discountType: BillDiscountType;
|
|
330
|
+
discountValue: number;
|
|
331
|
+
justification: string;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export interface DecideDiscountPayload {
|
|
335
|
+
status: Exclude<BillDiscountStatus, 'PENDING'>;
|
|
336
|
+
approver: string;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export interface PatientPaymentStatus {
|
|
340
|
+
status: 'PAID' | 'UNPAID' | 'UNKNOWN';
|
|
341
|
+
reason: string;
|
|
342
|
+
}
|
|
343
|
+
export const RefundStatus = {
|
|
344
|
+
REQUESTED: 'REQUESTED',
|
|
345
|
+
APPROVED: 'APPROVED',
|
|
346
|
+
REJECTED: 'REJECTED',
|
|
347
|
+
COMPLETED: 'COMPLETED',
|
|
348
|
+
} as const;
|
|
349
|
+
export type RefundStatus = (typeof RefundStatus)[keyof typeof RefundStatus];
|
|
350
|
+
|
|
351
|
+
export interface BillRefund {
|
|
352
|
+
uuid: string;
|
|
353
|
+
billUuid: string;
|
|
354
|
+
lineItemUuid: string | null;
|
|
355
|
+
refundAmount: number;
|
|
356
|
+
reason: string;
|
|
357
|
+
initiator: UserRef;
|
|
358
|
+
approver: UserRef | null;
|
|
359
|
+
completer: UserRef | null;
|
|
360
|
+
dateApproved: string | null;
|
|
361
|
+
dateCompleted: string | null;
|
|
362
|
+
dateCreated: string;
|
|
363
|
+
status: RefundStatus;
|
|
364
|
+
voided: boolean;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export interface RequestRefundPayload {
|
|
368
|
+
bill: string;
|
|
369
|
+
lineItem?: string;
|
|
370
|
+
refundAmount: number;
|
|
371
|
+
reason: string;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export interface DecideRefundPayload {
|
|
375
|
+
status: Exclude<RefundStatus, 'REQUESTED'>;
|
|
376
|
+
approver?: string;
|
|
377
|
+
completer?: string;
|
|
378
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import {
|
|
4
|
+
DataTable,
|
|
5
|
+
DataTableSkeleton,
|
|
6
|
+
InlineNotification,
|
|
7
|
+
Layer,
|
|
8
|
+
Table,
|
|
9
|
+
TableBody,
|
|
10
|
+
TableCell,
|
|
11
|
+
TableContainer,
|
|
12
|
+
TableExpandedRow,
|
|
13
|
+
TableExpandHeader,
|
|
14
|
+
TableExpandRow,
|
|
15
|
+
TableHead,
|
|
16
|
+
TableHeader,
|
|
17
|
+
TableRow,
|
|
18
|
+
Tile,
|
|
19
|
+
} from '@carbon/react';
|
|
20
|
+
import { EmptyCardIllustration, ErrorState, formatDate, parseDate, useConfig } from '@openmrs/esm-framework';
|
|
21
|
+
import { useBills } from '../billing.resource';
|
|
22
|
+
import { convertToCurrency } from '../helpers';
|
|
23
|
+
import InvoiceTable from '../invoice/invoice-table.component';
|
|
24
|
+
import type { BillingConfig } from '../config-schema';
|
|
25
|
+
import styles from './visit-bills-panel.scss';
|
|
26
|
+
|
|
27
|
+
interface VisitBillsPanelProps {
|
|
28
|
+
visit: { uuid: string };
|
|
29
|
+
patientUuid: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const VisitBillsPanel: React.FC<VisitBillsPanelProps> = ({ visit, patientUuid }) => {
|
|
33
|
+
const { t } = useTranslation();
|
|
34
|
+
const { defaultCurrency } = useConfig<BillingConfig>();
|
|
35
|
+
const { bills, error, isLoading, isValidating, mutate } = useBills(patientUuid, undefined, visit.uuid);
|
|
36
|
+
const billsByUuid = useMemo(() => new Map(bills?.map((bill) => [bill.uuid, bill])), [bills]);
|
|
37
|
+
|
|
38
|
+
const headerData = [
|
|
39
|
+
{ header: t('billDate', 'Bill date'), key: 'billDate' },
|
|
40
|
+
{ header: t('invoiceNumber', 'Invoice number'), key: 'invoiceNumber' },
|
|
41
|
+
{ header: t('billedItems', 'Billed items'), key: 'billedItems' },
|
|
42
|
+
{ header: t('billTotal', 'Bill total'), key: 'billTotal' },
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
const setBilledItems = (bill) =>
|
|
46
|
+
bill?.lineItems
|
|
47
|
+
?.map((item) => item?.billableService || item?.item)
|
|
48
|
+
.filter(Boolean)
|
|
49
|
+
.join(' & ') || '--';
|
|
50
|
+
|
|
51
|
+
const formatBillDate = (dateCreated: string) => {
|
|
52
|
+
try {
|
|
53
|
+
return formatDate(parseDate(dateCreated), { mode: 'wide' });
|
|
54
|
+
} catch {
|
|
55
|
+
return '--';
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const rowData = bills?.map((bill) => ({
|
|
60
|
+
id: bill.uuid,
|
|
61
|
+
billDate: bill.dateCreated ? formatBillDate(bill.dateCreated) : '--',
|
|
62
|
+
invoiceNumber: bill.receiptNumber,
|
|
63
|
+
billedItems: setBilledItems(bill),
|
|
64
|
+
billTotal: convertToCurrency(bill.totalAmount ?? 0, defaultCurrency),
|
|
65
|
+
}));
|
|
66
|
+
|
|
67
|
+
if (isLoading) {
|
|
68
|
+
return <DataTableSkeleton showHeader={false} showToolbar={false} zebra />;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (error) {
|
|
72
|
+
return (
|
|
73
|
+
<Layer>
|
|
74
|
+
<ErrorState error={error} headerTitle={t('billList', 'Bill list')} />
|
|
75
|
+
</Layer>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!bills?.length) {
|
|
80
|
+
return (
|
|
81
|
+
<Layer className={styles.emptyStateContainer}>
|
|
82
|
+
<Tile className={styles.tile}>
|
|
83
|
+
<div className={styles.illo}>
|
|
84
|
+
<EmptyCardIllustration />
|
|
85
|
+
</div>
|
|
86
|
+
<p className={styles.content}>{t('noBillsToDisplay', 'There are no bills to display.')}</p>
|
|
87
|
+
</Tile>
|
|
88
|
+
</Layer>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<DataTable isSortable rows={rowData} headers={headerData} size="md" useZebraStyles>
|
|
94
|
+
{({
|
|
95
|
+
getExpandHeaderProps,
|
|
96
|
+
getHeaderProps,
|
|
97
|
+
getRowProps,
|
|
98
|
+
getTableContainerProps,
|
|
99
|
+
getTableProps,
|
|
100
|
+
headers,
|
|
101
|
+
rows,
|
|
102
|
+
}) => (
|
|
103
|
+
<TableContainer {...getTableContainerProps()}>
|
|
104
|
+
<Table {...getTableProps()} aria-label={t('billList', 'Bill list')}>
|
|
105
|
+
<TableHead>
|
|
106
|
+
<TableRow>
|
|
107
|
+
<TableExpandHeader enableToggle {...getExpandHeaderProps()} />
|
|
108
|
+
{headers.map((header) => (
|
|
109
|
+
<TableHeader key={header.key} {...getHeaderProps({ header })}>
|
|
110
|
+
{header.header}
|
|
111
|
+
</TableHeader>
|
|
112
|
+
))}
|
|
113
|
+
</TableRow>
|
|
114
|
+
</TableHead>
|
|
115
|
+
<TableBody>
|
|
116
|
+
{rows.map((row) => {
|
|
117
|
+
const currentBill = billsByUuid.get(row.id);
|
|
118
|
+
return (
|
|
119
|
+
<React.Fragment key={row.id}>
|
|
120
|
+
<TableExpandRow {...getRowProps({ row })}>
|
|
121
|
+
{row.cells.map((cell) => (
|
|
122
|
+
<TableCell key={cell.id}>{cell.value}</TableCell>
|
|
123
|
+
))}
|
|
124
|
+
</TableExpandRow>
|
|
125
|
+
{row.isExpanded ? (
|
|
126
|
+
<TableExpandedRow colSpan={headers.length + 1}>
|
|
127
|
+
{currentBill ? (
|
|
128
|
+
<InvoiceTable bill={currentBill} onMutate={mutate} isLoadingBill={isValidating} viewOnly />
|
|
129
|
+
) : (
|
|
130
|
+
<InlineNotification
|
|
131
|
+
kind="error"
|
|
132
|
+
lowContrast
|
|
133
|
+
title={t('billNotFound', 'Bill details could not be loaded')}
|
|
134
|
+
/>
|
|
135
|
+
)}
|
|
136
|
+
</TableExpandedRow>
|
|
137
|
+
) : (
|
|
138
|
+
<TableExpandedRow className={styles.hiddenRow} colSpan={headers.length + 1} />
|
|
139
|
+
)}
|
|
140
|
+
</React.Fragment>
|
|
141
|
+
);
|
|
142
|
+
})}
|
|
143
|
+
</TableBody>
|
|
144
|
+
</Table>
|
|
145
|
+
</TableContainer>
|
|
146
|
+
)}
|
|
147
|
+
</DataTable>
|
|
148
|
+
);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export default VisitBillsPanel;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
@use '@carbon/layout';
|
|
2
|
+
@use '@carbon/type';
|
|
3
|
+
@use '@openmrs/esm-styleguide/src/vars' as *;
|
|
4
|
+
|
|
5
|
+
.emptyStateContainer {
|
|
6
|
+
margin: layout.$spacing-03 0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.hiddenRow {
|
|
10
|
+
display: none;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.illo {
|
|
14
|
+
margin-top: layout.$spacing-05;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.content {
|
|
18
|
+
@include type.type-style('heading-compact-01');
|
|
19
|
+
color: $text-02;
|
|
20
|
+
margin-top: layout.$spacing-05;
|
|
21
|
+
margin-bottom: layout.$spacing-03;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.tile {
|
|
25
|
+
text-align: center;
|
|
26
|
+
border: 1px solid $ui-03;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.menuItem {
|
|
30
|
+
max-width: none;
|
|
31
|
+
}
|