@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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
3
|
import userEvent from '@testing-library/user-event';
|
|
3
4
|
import { render, screen } from '@testing-library/react';
|
|
4
5
|
import { FormProvider, useForm } from 'react-hook-form';
|
|
@@ -6,11 +7,11 @@ import type { PaymentFormValue } from '../payments.component';
|
|
|
6
7
|
import { usePaymentModes } from '../payment.resource';
|
|
7
8
|
import PaymentForm from './payment-form.component';
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
usePaymentModes:
|
|
10
|
+
vi.mock('../payment.resource', () => ({
|
|
11
|
+
usePaymentModes: vi.fn(),
|
|
11
12
|
}));
|
|
12
13
|
|
|
13
|
-
const mockUsePaymentModes =
|
|
14
|
+
const mockUsePaymentModes = vi.mocked(usePaymentModes);
|
|
14
15
|
|
|
15
16
|
type WrapperProps = {
|
|
16
17
|
children: React.ReactNode;
|
|
@@ -26,12 +27,12 @@ const Wrapper: React.FC<WrapperProps> = ({ children, defaultValues }) => {
|
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
describe('PaymentForm Component', () => {
|
|
29
|
-
|
|
30
|
+
it('should render skeleton while loading payment modes', () => {
|
|
30
31
|
mockUsePaymentModes.mockReturnValue({
|
|
31
32
|
paymentModes: [],
|
|
32
33
|
isLoading: true,
|
|
33
34
|
error: null,
|
|
34
|
-
mutate:
|
|
35
|
+
mutate: vi.fn(),
|
|
35
36
|
});
|
|
36
37
|
|
|
37
38
|
render(
|
|
@@ -45,12 +46,12 @@ describe('PaymentForm Component', () => {
|
|
|
45
46
|
expect(screen.queryByPlaceholderText(/enter amount/i)).not.toBeInTheDocument();
|
|
46
47
|
});
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
it('should render error message when payment modes fail to load', () => {
|
|
49
50
|
mockUsePaymentModes.mockReturnValue({
|
|
50
51
|
paymentModes: [],
|
|
51
52
|
isLoading: false,
|
|
52
53
|
error: new Error('Failed to load payment modes'),
|
|
53
|
-
mutate:
|
|
54
|
+
mutate: vi.fn(),
|
|
54
55
|
});
|
|
55
56
|
|
|
56
57
|
render(
|
|
@@ -62,12 +63,12 @@ describe('PaymentForm Component', () => {
|
|
|
62
63
|
expect(screen.getByText(/error state/i)).toBeInTheDocument();
|
|
63
64
|
});
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
it('should render payment form with method, amount and reference fields when not disabled', () => {
|
|
66
67
|
mockUsePaymentModes.mockReturnValue({
|
|
67
68
|
paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
|
|
68
69
|
isLoading: false,
|
|
69
70
|
error: null,
|
|
70
|
-
mutate:
|
|
71
|
+
mutate: vi.fn(),
|
|
71
72
|
});
|
|
72
73
|
|
|
73
74
|
render(
|
|
@@ -81,12 +82,12 @@ describe('PaymentForm Component', () => {
|
|
|
81
82
|
expect(screen.getByText(/select payment method/i)).toBeInTheDocument();
|
|
82
83
|
});
|
|
83
84
|
|
|
84
|
-
|
|
85
|
+
it('should not render form when disablePayment is true', () => {
|
|
85
86
|
mockUsePaymentModes.mockReturnValue({
|
|
86
87
|
paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
|
|
87
88
|
isLoading: false,
|
|
88
89
|
error: null,
|
|
89
|
-
mutate:
|
|
90
|
+
mutate: vi.fn(),
|
|
90
91
|
});
|
|
91
92
|
|
|
92
93
|
render(
|
|
@@ -99,12 +100,12 @@ describe('PaymentForm Component', () => {
|
|
|
99
100
|
expect(screen.queryByText(/add payment method/i)).not.toBeInTheDocument();
|
|
100
101
|
});
|
|
101
102
|
|
|
102
|
-
|
|
103
|
+
it('should render amount input without leading zero', () => {
|
|
103
104
|
mockUsePaymentModes.mockReturnValue({
|
|
104
105
|
paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
|
|
105
106
|
isLoading: false,
|
|
106
107
|
error: null,
|
|
107
|
-
mutate:
|
|
108
|
+
mutate: vi.fn(),
|
|
108
109
|
});
|
|
109
110
|
|
|
110
111
|
render(
|
|
@@ -117,13 +118,13 @@ describe('PaymentForm Component', () => {
|
|
|
117
118
|
expect(amountInput.value).toBe('');
|
|
118
119
|
});
|
|
119
120
|
|
|
120
|
-
|
|
121
|
+
it('should allow user to clear amount input without reverting to zero', async () => {
|
|
121
122
|
const user = userEvent.setup();
|
|
122
123
|
mockUsePaymentModes.mockReturnValue({
|
|
123
124
|
paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
|
|
124
125
|
isLoading: false,
|
|
125
126
|
error: null,
|
|
126
|
-
mutate:
|
|
127
|
+
mutate: vi.fn(),
|
|
127
128
|
});
|
|
128
129
|
|
|
129
130
|
render(
|
|
@@ -141,13 +142,13 @@ describe('PaymentForm Component', () => {
|
|
|
141
142
|
expect(amountInput.value).toBe('');
|
|
142
143
|
});
|
|
143
144
|
|
|
144
|
-
|
|
145
|
+
it('should handle amount input with decimal values', async () => {
|
|
145
146
|
const user = userEvent.setup();
|
|
146
147
|
mockUsePaymentModes.mockReturnValue({
|
|
147
148
|
paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
|
|
148
149
|
isLoading: false,
|
|
149
150
|
error: null,
|
|
150
|
-
mutate:
|
|
151
|
+
mutate: vi.fn(),
|
|
151
152
|
});
|
|
152
153
|
|
|
153
154
|
render(
|
|
@@ -162,12 +163,12 @@ describe('PaymentForm Component', () => {
|
|
|
162
163
|
expect(amountInput.value).toBe('10.5');
|
|
163
164
|
});
|
|
164
165
|
|
|
165
|
-
|
|
166
|
+
it('should not auto-focus reference number input on mount', () => {
|
|
166
167
|
mockUsePaymentModes.mockReturnValue({
|
|
167
168
|
paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
|
|
168
169
|
isLoading: false,
|
|
169
170
|
error: null,
|
|
170
|
-
mutate:
|
|
171
|
+
mutate: vi.fn(),
|
|
171
172
|
});
|
|
172
173
|
|
|
173
174
|
render(
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
3
|
import { render, screen } from '@testing-library/react';
|
|
3
4
|
import { getDefaultsFromConfigSchema, useConfig } from '@openmrs/esm-framework';
|
|
4
5
|
import { type BillingConfig, configSchema } from '../../../config-schema';
|
|
5
6
|
import { type MappedBill } from '../../../types';
|
|
6
7
|
import PaymentHistory from './payment-history.component';
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
convertToCurrency:
|
|
9
|
+
vi.mock('../../../helpers', () => ({
|
|
10
|
+
convertToCurrency: vi.fn((amount, currency) => `${currency} ${amount.toFixed(2)}`),
|
|
10
11
|
}));
|
|
11
12
|
|
|
12
|
-
const mockUseConfig =
|
|
13
|
+
const mockUseConfig = vi.mocked(useConfig<BillingConfig>);
|
|
13
14
|
|
|
14
15
|
describe('PaymentHistory Component', () => {
|
|
15
16
|
beforeEach(() => {
|
|
@@ -73,6 +74,7 @@ describe('PaymentHistory Component', () => {
|
|
|
73
74
|
dateCreated: '2023-09-01T12:00:00Z',
|
|
74
75
|
lineItems: [],
|
|
75
76
|
billingService: 'Billing Service',
|
|
77
|
+
netAmount: 0,
|
|
76
78
|
};
|
|
77
79
|
|
|
78
80
|
const emptyBill: MappedBill = {
|
|
@@ -101,13 +103,14 @@ describe('PaymentHistory Component', () => {
|
|
|
101
103
|
dateCreated: '2023-09-02T10:00:00Z',
|
|
102
104
|
lineItems: [],
|
|
103
105
|
billingService: 'Billing Service',
|
|
106
|
+
netAmount: 0,
|
|
104
107
|
};
|
|
105
108
|
|
|
106
|
-
|
|
109
|
+
it('renders without crashing', () => {
|
|
107
110
|
render(<PaymentHistory bill={mockBill} />);
|
|
108
111
|
});
|
|
109
112
|
|
|
110
|
-
|
|
113
|
+
it('renders correct table headers', () => {
|
|
111
114
|
render(<PaymentHistory bill={mockBill} />);
|
|
112
115
|
expect(screen.getByText('Date of payment')).toBeInTheDocument();
|
|
113
116
|
expect(screen.getByText('Bill amount')).toBeInTheDocument();
|
|
@@ -115,13 +118,13 @@ describe('PaymentHistory Component', () => {
|
|
|
115
118
|
expect(screen.getByText('Payment method')).toBeInTheDocument();
|
|
116
119
|
});
|
|
117
120
|
|
|
118
|
-
|
|
121
|
+
it('renders the correct number of rows', () => {
|
|
119
122
|
render(<PaymentHistory bill={mockBill} />);
|
|
120
123
|
const rows = screen.getAllByRole('row');
|
|
121
124
|
expect(rows).toHaveLength(3);
|
|
122
125
|
});
|
|
123
126
|
|
|
124
|
-
|
|
127
|
+
it('renders correct data in the rows', () => {
|
|
125
128
|
render(<PaymentHistory bill={mockBill} />);
|
|
126
129
|
|
|
127
130
|
expect(screen.getByText('01-Sept-2023')).toBeInTheDocument();
|
|
@@ -135,17 +138,17 @@ describe('PaymentHistory Component', () => {
|
|
|
135
138
|
expect(screen.getByText('Cash')).toBeInTheDocument();
|
|
136
139
|
});
|
|
137
140
|
|
|
138
|
-
|
|
141
|
+
it('handles empty payments gracefully', () => {
|
|
139
142
|
render(<PaymentHistory bill={emptyBill} />);
|
|
140
143
|
expect(screen.queryByRole('table')).not.toBeInTheDocument();
|
|
141
144
|
});
|
|
142
145
|
|
|
143
|
-
|
|
146
|
+
it('does not render when bill is undefined', () => {
|
|
144
147
|
render(<PaymentHistory bill={undefined} />);
|
|
145
148
|
expect(screen.queryByRole('table')).not.toBeInTheDocument();
|
|
146
149
|
});
|
|
147
150
|
|
|
148
|
-
|
|
151
|
+
it('formats dates and converts amounts correctly', () => {
|
|
149
152
|
render(<PaymentHistory bill={mockBill} />);
|
|
150
153
|
|
|
151
154
|
expect(screen.getByText('01-Sept-2023')).toBeInTheDocument();
|
|
@@ -8,10 +8,11 @@ import { CardHeader, navigate, showSnackbar, useConfig, useVisit } from '@openmr
|
|
|
8
8
|
import { InvoiceBreakDown } from './invoice-breakdown/invoice-breakdown.component';
|
|
9
9
|
import PaymentForm from './payment-form/payment-form.component';
|
|
10
10
|
import PaymentHistory from './payment-history/payment-history.component';
|
|
11
|
-
import {
|
|
11
|
+
import { useSWRConfig } from 'swr';
|
|
12
|
+
import { processBillPayment, patientPaymentStatusCacheKey } from '../../billing.resource';
|
|
12
13
|
import { updateBillVisitAttribute } from './payment.resource';
|
|
13
14
|
import { convertToCurrency } from '../../helpers';
|
|
14
|
-
import { BillStatus, type MappedBill } from '../../types';
|
|
15
|
+
import { BillStatus, RefundStatus, type MappedBill } from '../../types';
|
|
15
16
|
import styles from './payments.scss';
|
|
16
17
|
|
|
17
18
|
type PaymentProps = {
|
|
@@ -27,6 +28,7 @@ export type PaymentFormValue = {
|
|
|
27
28
|
|
|
28
29
|
const Payments: React.FC<PaymentProps> = ({ bill, mutate }) => {
|
|
29
30
|
const { t } = useTranslation();
|
|
31
|
+
const { mutate: swrMutate } = useSWRConfig();
|
|
30
32
|
const paymentSchema = z.object({
|
|
31
33
|
method: z.string().refine((value) => !!value, 'Payment method is required'),
|
|
32
34
|
amount: z
|
|
@@ -35,7 +37,7 @@ const Payments: React.FC<PaymentProps> = ({ bill, mutate }) => {
|
|
|
35
37
|
invalid_type_error: t('amountRequired', 'Amount is required'),
|
|
36
38
|
})
|
|
37
39
|
.positive({ message: t('amountMustBePositive', 'Amount must be greater than 0') })
|
|
38
|
-
.max(bill?.
|
|
40
|
+
.max((bill?.netAmount ?? 0) - (bill?.tenderedAmount ?? 0), {
|
|
39
41
|
message: t('paymentAmountCannotExceedAmountDue', 'Payment amount cannot exceed amount due'),
|
|
40
42
|
}),
|
|
41
43
|
referenceCode: z.union([z.number(), z.string()]).optional(),
|
|
@@ -69,7 +71,11 @@ const Payments: React.FC<PaymentProps> = ({ bill, mutate }) => {
|
|
|
69
71
|
return null;
|
|
70
72
|
}
|
|
71
73
|
|
|
72
|
-
const
|
|
74
|
+
const refundTotal = (bill.refunds ?? [])
|
|
75
|
+
.filter((r) => r.status === RefundStatus.COMPLETED)
|
|
76
|
+
.reduce((sum, r) => sum + r.refundAmount, 0);
|
|
77
|
+
|
|
78
|
+
const amountDue = (bill.netAmount ?? 0) - (bill.tenderedAmount ?? 0);
|
|
73
79
|
|
|
74
80
|
const handleProcessPayment = async () => {
|
|
75
81
|
if (!formValues?.method || formValues.amount == null) {
|
|
@@ -95,6 +101,7 @@ const Payments: React.FC<PaymentProps> = ({ bill, mutate }) => {
|
|
|
95
101
|
}
|
|
96
102
|
methods.reset(defaultPaymentValues);
|
|
97
103
|
mutate();
|
|
104
|
+
swrMutate(patientPaymentStatusCacheKey(bill.patientUuid));
|
|
98
105
|
} catch (error) {
|
|
99
106
|
showSnackbar({
|
|
100
107
|
title: t('errorProcessingPayment', 'Error processing payment'),
|
|
@@ -126,11 +133,18 @@ const Payments: React.FC<PaymentProps> = ({ bill, mutate }) => {
|
|
|
126
133
|
label={t('totalTendered', 'Total tendered')}
|
|
127
134
|
value={convertToCurrency(bill.tenderedAmount ?? 0, defaultCurrency)}
|
|
128
135
|
/>
|
|
129
|
-
<InvoiceBreakDown
|
|
136
|
+
<InvoiceBreakDown
|
|
137
|
+
label={t('discount', 'Discount')}
|
|
138
|
+
value={`- ${convertToCurrency((bill.totalAmount ?? 0) - (bill.netAmount ?? 0), defaultCurrency)}`}
|
|
139
|
+
/>
|
|
140
|
+
<InvoiceBreakDown
|
|
141
|
+
label={t('refunds', 'Refunds')}
|
|
142
|
+
value={`- ${convertToCurrency(refundTotal, defaultCurrency)}`}
|
|
143
|
+
/>
|
|
130
144
|
<InvoiceBreakDown
|
|
131
145
|
hasBalance={amountDue < 0}
|
|
132
146
|
label={t('amountDue', 'Amount due')}
|
|
133
|
-
value={convertToCurrency(amountDue
|
|
147
|
+
value={convertToCurrency(amountDue, defaultCurrency)}
|
|
134
148
|
/>
|
|
135
149
|
<div className={styles.processPayments}>
|
|
136
150
|
<Button onClick={handleNavigateToBillingDashboard} kind="secondary">
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
3
|
import userEvent from '@testing-library/user-event';
|
|
3
4
|
import { render, screen } from '@testing-library/react';
|
|
4
5
|
import {
|
|
@@ -9,18 +10,19 @@ import {
|
|
|
9
10
|
type VisitReturnType,
|
|
10
11
|
} from '@openmrs/esm-framework';
|
|
11
12
|
import { useBillableServices } from '../../billable-services/billable-service.resource';
|
|
13
|
+
import { processBillPayment } from '../../billing.resource';
|
|
12
14
|
import { BillStatus, type MappedBill } from '../../types';
|
|
13
15
|
import { configSchema, type BillingConfig } from '../../config-schema';
|
|
14
16
|
import { usePaymentModes } from './payment.resource';
|
|
15
17
|
import Payments from './payments.component';
|
|
16
18
|
|
|
17
|
-
const mockUseVisit =
|
|
18
|
-
const mockUseConfig =
|
|
19
|
-
const mockUseBillableServices =
|
|
20
|
-
const mockUsePaymentModes =
|
|
21
|
-
const mockFormatToParts =
|
|
22
|
-
const mockFormat =
|
|
23
|
-
const mockResolvedOptions =
|
|
19
|
+
const mockUseVisit = vi.mocked(useVisit);
|
|
20
|
+
const mockUseConfig = vi.mocked(useConfig<BillingConfig>);
|
|
21
|
+
const mockUseBillableServices = vi.mocked(useBillableServices);
|
|
22
|
+
const mockUsePaymentModes = vi.mocked(usePaymentModes);
|
|
23
|
+
const mockFormatToParts = vi.fn().mockReturnValue([{ type: 'integer', value: '1000' }]);
|
|
24
|
+
const mockFormat = vi.fn().mockReturnValue('$1000.00');
|
|
25
|
+
const mockResolvedOptions = vi.fn().mockReturnValue({
|
|
24
26
|
locale: 'en-US',
|
|
25
27
|
numberingSystem: 'latn',
|
|
26
28
|
style: 'currency',
|
|
@@ -29,24 +31,24 @@ const mockResolvedOptions = jest.fn().mockReturnValue({
|
|
|
29
31
|
maximumFractionDigits: 2,
|
|
30
32
|
});
|
|
31
33
|
|
|
32
|
-
global.Intl.NumberFormat
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
global.Intl.NumberFormat = vi.fn().mockImplementation(function () {
|
|
35
|
+
this.formatToParts = mockFormatToParts;
|
|
36
|
+
this.format = mockFormat;
|
|
37
|
+
this.resolvedOptions = mockResolvedOptions;
|
|
38
|
+
}) as any;
|
|
39
|
+
global.Intl.NumberFormat.supportedLocalesOf = vi.fn().mockReturnValue(['en-US']);
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
processBillPayment:
|
|
41
|
+
vi.mock('../../billing.resource', () => ({
|
|
42
|
+
processBillPayment: vi.fn(),
|
|
41
43
|
}));
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
updateBillVisitAttribute:
|
|
45
|
-
usePaymentModes:
|
|
45
|
+
vi.mock('./payment.resource', () => ({
|
|
46
|
+
updateBillVisitAttribute: vi.fn(),
|
|
47
|
+
usePaymentModes: vi.fn(),
|
|
46
48
|
}));
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
useBillableServices:
|
|
50
|
+
vi.mock('../../billable-services/billable-service.resource', () => ({
|
|
51
|
+
useBillableServices: vi.fn(),
|
|
50
52
|
}));
|
|
51
53
|
|
|
52
54
|
describe('Payments', () => {
|
|
@@ -107,9 +109,10 @@ describe('Payments', () => {
|
|
|
107
109
|
dateCreated: '2023-09-01T12:00:00Z',
|
|
108
110
|
lineItems: [],
|
|
109
111
|
billingService: 'Billing Service',
|
|
112
|
+
netAmount: 0,
|
|
110
113
|
};
|
|
111
114
|
|
|
112
|
-
const mockMutate =
|
|
115
|
+
const mockMutate = vi.fn();
|
|
113
116
|
|
|
114
117
|
beforeEach(() => {
|
|
115
118
|
mockUseVisit.mockReturnValue({ currentVisit: null } as unknown as VisitReturnType);
|
|
@@ -119,7 +122,7 @@ describe('Payments', () => {
|
|
|
119
122
|
isLoading: false,
|
|
120
123
|
isValidating: false,
|
|
121
124
|
error: null,
|
|
122
|
-
mutate:
|
|
125
|
+
mutate: vi.fn(),
|
|
123
126
|
});
|
|
124
127
|
mockUsePaymentModes.mockReturnValue({
|
|
125
128
|
paymentModes: [
|
|
@@ -128,7 +131,7 @@ describe('Payments', () => {
|
|
|
128
131
|
],
|
|
129
132
|
isLoading: false,
|
|
130
133
|
error: null,
|
|
131
|
-
mutate:
|
|
134
|
+
mutate: vi.fn(),
|
|
132
135
|
});
|
|
133
136
|
});
|
|
134
137
|
|
|
@@ -243,6 +246,7 @@ describe('Payments', () => {
|
|
|
243
246
|
...mockBill,
|
|
244
247
|
status: BillStatus.POSTED,
|
|
245
248
|
totalAmount: 100,
|
|
249
|
+
netAmount: 100,
|
|
246
250
|
tenderedAmount: 0,
|
|
247
251
|
};
|
|
248
252
|
|
|
@@ -262,6 +266,7 @@ describe('Payments', () => {
|
|
|
262
266
|
...mockBill,
|
|
263
267
|
status: BillStatus.POSTED,
|
|
264
268
|
totalAmount: 100,
|
|
269
|
+
netAmount: 100,
|
|
265
270
|
tenderedAmount: 0,
|
|
266
271
|
lineItems: [],
|
|
267
272
|
};
|
|
@@ -272,6 +277,66 @@ describe('Payments', () => {
|
|
|
272
277
|
expect(screen.getByText(/select payment method/i)).toBeInTheDocument();
|
|
273
278
|
});
|
|
274
279
|
|
|
280
|
+
it('blocks payment greater than (netAmount - tendered) on a discounted bill', async () => {
|
|
281
|
+
const user = userEvent.setup();
|
|
282
|
+
const mockProcessBillPayment = vi.mocked(processBillPayment);
|
|
283
|
+
mockProcessBillPayment.mockResolvedValue({} as any);
|
|
284
|
+
|
|
285
|
+
const billWithDiscount: MappedBill = {
|
|
286
|
+
...mockBill,
|
|
287
|
+
status: BillStatus.POSTED,
|
|
288
|
+
totalAmount: 500,
|
|
289
|
+
netAmount: 400,
|
|
290
|
+
tenderedAmount: 0,
|
|
291
|
+
payments: [],
|
|
292
|
+
lineItems: [],
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
render(<Payments bill={billWithDiscount} mutate={mockMutate} />);
|
|
296
|
+
|
|
297
|
+
const methodDropdown = await screen.findByRole('combobox', { name: /payment method/i });
|
|
298
|
+
await user.click(methodDropdown);
|
|
299
|
+
await user.click(screen.getByText('Cash'));
|
|
300
|
+
|
|
301
|
+
// 450 > netAmount (400). If the schema bound regressed to totalAmount (500) this would pass.
|
|
302
|
+
await user.type(screen.getByPlaceholderText(/enter amount/i), '450');
|
|
303
|
+
|
|
304
|
+
expect(screen.getByText('Process Payment')).toBeDisabled();
|
|
305
|
+
expect(mockProcessBillPayment).not.toHaveBeenCalled();
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('sends a non-null amount in the payment payload when processing a discounted bill', async () => {
|
|
309
|
+
const user = userEvent.setup();
|
|
310
|
+
const mockProcessBillPayment = vi.mocked(processBillPayment);
|
|
311
|
+
mockProcessBillPayment.mockResolvedValue({} as any);
|
|
312
|
+
|
|
313
|
+
const billWithDiscount: MappedBill = {
|
|
314
|
+
...mockBill,
|
|
315
|
+
status: BillStatus.POSTED,
|
|
316
|
+
totalAmount: 500,
|
|
317
|
+
netAmount: 400,
|
|
318
|
+
tenderedAmount: 0,
|
|
319
|
+
payments: [],
|
|
320
|
+
lineItems: [],
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
render(<Payments bill={billWithDiscount} mutate={mockMutate} />);
|
|
324
|
+
|
|
325
|
+
const methodDropdown = await screen.findByRole('combobox', { name: /payment method/i });
|
|
326
|
+
await user.click(methodDropdown);
|
|
327
|
+
await user.click(screen.getByText('Cash'));
|
|
328
|
+
|
|
329
|
+
await user.type(screen.getByPlaceholderText(/enter amount/i), '100');
|
|
330
|
+
|
|
331
|
+
await user.click(screen.getByText('Process Payment'));
|
|
332
|
+
|
|
333
|
+
expect(mockProcessBillPayment).toHaveBeenCalledTimes(1);
|
|
334
|
+
const [payload] = mockProcessBillPayment.mock.calls[0];
|
|
335
|
+
expect(payload.amount).toBeTypeOf('number');
|
|
336
|
+
expect(payload.amount).not.toBeNaN();
|
|
337
|
+
expect(payload.amountTendered).toBe(100);
|
|
338
|
+
});
|
|
339
|
+
|
|
275
340
|
it('should display process payment button', () => {
|
|
276
341
|
const billWithAmountDue: MappedBill = {
|
|
277
342
|
...mockBill,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
3
|
import userEvent from '@testing-library/user-event';
|
|
3
4
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
4
5
|
import PrintReceipt from './print-receipt.component';
|
|
@@ -20,10 +21,10 @@ describe('PrintReceipt', () => {
|
|
|
20
21
|
});
|
|
21
22
|
|
|
22
23
|
mockLink = document.createElement('a');
|
|
23
|
-
|
|
24
|
+
vi.spyOn(mockLink, 'click').mockImplementation(() => {});
|
|
24
25
|
|
|
25
26
|
const originalCreateElement = document.createElement.bind(document);
|
|
26
|
-
|
|
27
|
+
vi.spyOn(document, 'createElement').mockImplementation((tagName: string) => {
|
|
27
28
|
if (tagName === 'a') {
|
|
28
29
|
mockLink.href = '';
|
|
29
30
|
mockLink.download = '';
|
|
@@ -31,13 +32,10 @@ describe('PrintReceipt', () => {
|
|
|
31
32
|
}
|
|
32
33
|
return originalCreateElement(tagName);
|
|
33
34
|
});
|
|
34
|
-
|
|
35
|
-
jest.useFakeTimers();
|
|
36
35
|
});
|
|
37
36
|
|
|
38
37
|
afterEach(() => {
|
|
39
|
-
|
|
40
|
-
jest.useRealTimers();
|
|
38
|
+
vi.restoreAllMocks();
|
|
41
39
|
Object.defineProperty(window, 'location', {
|
|
42
40
|
value: originalLocation,
|
|
43
41
|
writable: true,
|
|
@@ -54,7 +52,7 @@ describe('PrintReceipt', () => {
|
|
|
54
52
|
});
|
|
55
53
|
|
|
56
54
|
it('shows loading state and disables button during download', async () => {
|
|
57
|
-
const user = userEvent.setup(
|
|
55
|
+
const user = userEvent.setup();
|
|
58
56
|
render(<PrintReceipt billUuid={TEST_BILL_UUID} />);
|
|
59
57
|
|
|
60
58
|
const button = screen.getByRole('button', { name: /print receipt/i });
|
|
@@ -66,16 +64,12 @@ describe('PrintReceipt', () => {
|
|
|
66
64
|
});
|
|
67
65
|
|
|
68
66
|
it('initiates download when button is clicked', async () => {
|
|
69
|
-
const user = userEvent.setup(
|
|
67
|
+
const user = userEvent.setup();
|
|
70
68
|
render(<PrintReceipt billUuid={TEST_BILL_UUID} />);
|
|
71
69
|
|
|
72
70
|
const button = screen.getByRole('button', { name: /print receipt/i });
|
|
73
71
|
await user.click(button);
|
|
74
72
|
|
|
75
|
-
act(() => {
|
|
76
|
-
jest.advanceTimersByTime(1000);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
73
|
await waitFor(() => {
|
|
80
74
|
expect(mockLink.click).toHaveBeenCalled();
|
|
81
75
|
});
|
|
@@ -85,7 +79,7 @@ describe('PrintReceipt', () => {
|
|
|
85
79
|
});
|
|
86
80
|
|
|
87
81
|
it('re-enables button after download completes', async () => {
|
|
88
|
-
const user = userEvent.setup(
|
|
82
|
+
const user = userEvent.setup();
|
|
89
83
|
render(<PrintReceipt billUuid={TEST_BILL_UUID} />);
|
|
90
84
|
|
|
91
85
|
const button = screen.getByRole('button', { name: /print receipt/i });
|
|
@@ -93,10 +87,6 @@ describe('PrintReceipt', () => {
|
|
|
93
87
|
|
|
94
88
|
expect(button).toBeDisabled();
|
|
95
89
|
|
|
96
|
-
act(() => {
|
|
97
|
-
jest.advanceTimersByTime(1000);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
90
|
await waitFor(() => {
|
|
101
91
|
expect(button).toBeEnabled();
|
|
102
92
|
});
|
|
@@ -106,7 +96,7 @@ describe('PrintReceipt', () => {
|
|
|
106
96
|
});
|
|
107
97
|
|
|
108
98
|
it('prevents multiple simultaneous downloads', async () => {
|
|
109
|
-
const user = userEvent.setup(
|
|
99
|
+
const user = userEvent.setup();
|
|
110
100
|
render(<PrintReceipt billUuid={TEST_BILL_UUID} />);
|
|
111
101
|
|
|
112
102
|
const button = screen.getByRole('button', { name: /print receipt/i });
|
|
@@ -117,10 +107,6 @@ describe('PrintReceipt', () => {
|
|
|
117
107
|
|
|
118
108
|
expect(button).toBeDisabled();
|
|
119
109
|
|
|
120
|
-
act(() => {
|
|
121
|
-
jest.advanceTimersByTime(1000);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
110
|
await waitFor(() => {
|
|
125
111
|
expect(button).toBeEnabled();
|
|
126
112
|
});
|
|
@@ -134,16 +120,12 @@ describe('PrintReceipt', () => {
|
|
|
134
120
|
});
|
|
135
121
|
|
|
136
122
|
it('handles empty bill UUID', async () => {
|
|
137
|
-
const user = userEvent.setup(
|
|
123
|
+
const user = userEvent.setup();
|
|
138
124
|
render(<PrintReceipt billUuid="" />);
|
|
139
125
|
|
|
140
126
|
const button = screen.getByRole('button', { name: /print receipt/i });
|
|
141
127
|
await user.click(button);
|
|
142
128
|
|
|
143
|
-
act(() => {
|
|
144
|
-
jest.advanceTimersByTime(1000);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
129
|
await waitFor(() => {
|
|
148
130
|
expect(mockLink.click).toHaveBeenCalled();
|
|
149
131
|
});
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
3
|
import { screen, render } from '@testing-library/react';
|
|
3
4
|
import { useDefaultFacility } from '../../billing.resource';
|
|
4
5
|
import PrintableFooter from './printable-footer.component';
|
|
5
6
|
|
|
6
|
-
const mockUseDefaultFacility =
|
|
7
|
+
const mockUseDefaultFacility = vi.mocked<typeof useDefaultFacility>(useDefaultFacility);
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
useDefaultFacility:
|
|
9
|
+
vi.mock('../../billing.resource', () => ({
|
|
10
|
+
useDefaultFacility: vi.fn(),
|
|
10
11
|
}));
|
|
11
12
|
|
|
12
13
|
describe('PrintableFooter', () => {
|
|
13
|
-
|
|
14
|
+
it('should render PrintableFooter component', () => {
|
|
14
15
|
mockUseDefaultFacility.mockReturnValue({
|
|
15
16
|
data: { display: 'MTRH', uuid: 'mtrh-uuid', links: [] },
|
|
16
17
|
});
|
|
@@ -17,13 +17,13 @@ const PrintableInvoiceHeader: React.FC<PrintableInvoiceHeaderProps> = ({ patient
|
|
|
17
17
|
const { logo, country, defaultCurrency } = useConfig<BillingConfig>();
|
|
18
18
|
|
|
19
19
|
const invoiceDetails = {
|
|
20
|
-
[t('
|
|
20
|
+
[t('invoiceNo', 'Invoice #')]: bill?.receiptNumber,
|
|
21
21
|
[t('invoiceDate', 'Invoice date')]: bill?.dateCreated
|
|
22
22
|
? formatDate(parseDate(bill.dateCreated), { mode: 'wide', noToday: true, time: false })
|
|
23
23
|
: '--',
|
|
24
|
-
[t('totalAmount', 'Total
|
|
24
|
+
[t('totalAmount', 'Total amount')]: `${defaultCurrency} ${bill?.totalAmount}`,
|
|
25
25
|
[t('totalPaid', 'Total paid')]: `${defaultCurrency} ${bill?.tenderedAmount}`,
|
|
26
|
-
[t('amountBalance', 'Amount balance')]: `${defaultCurrency} ${bill?.
|
|
26
|
+
[t('amountBalance', 'Amount balance')]: `${defaultCurrency} ${bill?.netAmount - bill?.tenderedAmount}`,
|
|
27
27
|
...(bill?.status && { [t('invoiceStatus', 'Invoice status')]: bill.status }),
|
|
28
28
|
};
|
|
29
29
|
|