@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 { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
3
|
import { screen, render } from '@testing-library/react';
|
|
3
4
|
import { useConfig } from '@openmrs/esm-framework';
|
|
4
5
|
import { type BillingConfig } from '../../config-schema';
|
|
@@ -6,11 +7,11 @@ import { useDefaultFacility } from '../../billing.resource';
|
|
|
6
7
|
import { type MappedBill } from '../../types';
|
|
7
8
|
import PrintableInvoiceHeader from './printable-invoice-header.component';
|
|
8
9
|
|
|
9
|
-
const mockUseDefaultFacility =
|
|
10
|
-
const mockUseConfig =
|
|
10
|
+
const mockUseDefaultFacility = vi.mocked(useDefaultFacility);
|
|
11
|
+
const mockUseConfig = vi.mocked(useConfig<BillingConfig>);
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
useDefaultFacility:
|
|
13
|
+
vi.mock('../../billing.resource', () => ({
|
|
14
|
+
useDefaultFacility: vi.fn(),
|
|
14
15
|
}));
|
|
15
16
|
|
|
16
17
|
const testProps = {
|
|
@@ -41,7 +42,7 @@ describe('PrintableInvoiceHeader', () => {
|
|
|
41
42
|
mockUseDefaultFacility.mockReturnValue({ data: { display: 'MTRH', uuid: 'mtrh-uuid', links: [] } });
|
|
42
43
|
});
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
it('should render PrintableInvoiceHeader component', () => {
|
|
45
46
|
render(<PrintableInvoiceHeader {...testProps} defaultFacility={defaultFacility} bill={bill} />);
|
|
46
47
|
const header = screen.getByText('Invoice');
|
|
47
48
|
expect(header).toBeInTheDocument();
|
|
@@ -54,13 +55,13 @@ describe('PrintableInvoiceHeader', () => {
|
|
|
54
55
|
expect(screen.getByText(/15-May-1980/i)).toBeInTheDocument();
|
|
55
56
|
});
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
it('should display the logo when logo is provided', () => {
|
|
58
59
|
render(<PrintableInvoiceHeader {...testProps} defaultFacility={defaultFacility} bill={bill} />);
|
|
59
60
|
const logo = screen.getByAltText('logo');
|
|
60
61
|
expect(logo).toBeInTheDocument();
|
|
61
62
|
});
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
it('should display the default OpenMRS SVG logo when logo src is not provided', () => {
|
|
64
65
|
mockUseConfig.mockReturnValue({
|
|
65
66
|
logo: { src: '', alt: '' },
|
|
66
67
|
country: 'Kenya',
|
|
@@ -73,7 +74,7 @@ describe('PrintableInvoiceHeader', () => {
|
|
|
73
74
|
expect(logo.tagName).toBe('svg');
|
|
74
75
|
});
|
|
75
76
|
|
|
76
|
-
|
|
77
|
+
it('should display logo alt text when src is empty but alt is provided', () => {
|
|
77
78
|
mockUseConfig.mockReturnValue({
|
|
78
79
|
logo: { src: '', alt: 'Test Facility Logo' },
|
|
79
80
|
country: 'Kenya',
|
|
@@ -84,7 +85,7 @@ describe('PrintableInvoiceHeader', () => {
|
|
|
84
85
|
expect(screen.getByText('Test Facility Logo')).toBeInTheDocument();
|
|
85
86
|
});
|
|
86
87
|
|
|
87
|
-
|
|
88
|
+
it('should format birthDate correctly', () => {
|
|
88
89
|
const propsWithDifferentDate = {
|
|
89
90
|
patientDetails: {
|
|
90
91
|
...testProps.patientDetails,
|
|
@@ -96,7 +97,7 @@ describe('PrintableInvoiceHeader', () => {
|
|
|
96
97
|
expect(screen.getByText(/25-Dec-1995/i)).toBeInTheDocument();
|
|
97
98
|
});
|
|
98
99
|
|
|
99
|
-
|
|
100
|
+
it('should not render birthDate and gender when not provided', () => {
|
|
100
101
|
const propsWithoutBirthDateAndGender = {
|
|
101
102
|
patientDetails: {
|
|
102
103
|
...testProps.patientDetails,
|
|
@@ -112,9 +113,23 @@ describe('PrintableInvoiceHeader', () => {
|
|
|
112
113
|
expect(screen.queryByText(/Gender:/i)).not.toBeInTheDocument();
|
|
113
114
|
});
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
it('should handle null defaultFacility gracefully', () => {
|
|
116
117
|
render(<PrintableInvoiceHeader {...testProps} defaultFacility={null} bill={bill} />);
|
|
117
118
|
expect(screen.getByRole('heading', { name: /Invoice/i, level: 1 })).toBeInTheDocument();
|
|
118
119
|
expect(screen.getByText(/john Doe/i)).toBeInTheDocument();
|
|
119
120
|
});
|
|
121
|
+
|
|
122
|
+
it('should use netAmount to calculate amount balance when a discount is applied', () => {
|
|
123
|
+
const discountedBill = {
|
|
124
|
+
...bill,
|
|
125
|
+
totalAmount: 100,
|
|
126
|
+
netAmount: 80,
|
|
127
|
+
tenderedAmount: 20,
|
|
128
|
+
} as MappedBill;
|
|
129
|
+
|
|
130
|
+
render(<PrintableInvoiceHeader {...testProps} defaultFacility={defaultFacility} bill={discountedBill} />);
|
|
131
|
+
|
|
132
|
+
expect(screen.getByText(': KES 60')).toBeInTheDocument();
|
|
133
|
+
expect(screen.queryByText(': KES 80')).not.toBeInTheDocument();
|
|
134
|
+
});
|
|
120
135
|
});
|
|
@@ -83,12 +83,6 @@ const PrintableInvoice: React.FC<PrintableInvoiceProps> = ({ bill, patient, comp
|
|
|
83
83
|
return [];
|
|
84
84
|
}, [bill, defaultCurrency]);
|
|
85
85
|
|
|
86
|
-
const summaryHeaders = [
|
|
87
|
-
{ key: 'total', header: t('totalAmount', 'Total Amount') },
|
|
88
|
-
{ key: 'paid', header: t('totalPaid', 'Total Paid') },
|
|
89
|
-
{ key: 'balance', header: t('amountBalance', 'Amount Balance') },
|
|
90
|
-
];
|
|
91
|
-
|
|
92
86
|
const patientDetails = useMemo(() => {
|
|
93
87
|
const address = patient?.address?.[0];
|
|
94
88
|
const addressParts = [address?.line?.join(' '), address?.city, address?.district, address?.state].filter(Boolean);
|
|
@@ -136,14 +130,43 @@ const PrintableInvoice: React.FC<PrintableInvoiceProps> = ({ bill, patient, comp
|
|
|
136
130
|
</TableContainer>
|
|
137
131
|
)}
|
|
138
132
|
</DataTable>
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
133
|
+
{bill?.netAmount != null && bill.totalAmount !== bill.netAmount ? (
|
|
134
|
+
<>
|
|
135
|
+
<div className={styles.balanceContainer}>
|
|
136
|
+
<span className={styles.itemHeading}>{t('subtotal', 'Subtotal')}:</span>{' '}
|
|
137
|
+
<span className={styles.itemLabel}>
|
|
138
|
+
<strong>
|
|
139
|
+
{defaultCurrency} {bill?.totalAmount}
|
|
140
|
+
</strong>
|
|
141
|
+
</span>
|
|
142
|
+
</div>
|
|
143
|
+
<div className={styles.balanceContainer}>
|
|
144
|
+
<span className={styles.itemHeading}>{t('discount', 'Discount')}:</span>{' '}
|
|
145
|
+
<span className={styles.itemLabel}>
|
|
146
|
+
<strong>
|
|
147
|
+
- {defaultCurrency} {(bill?.totalAmount ?? 0) - (bill?.netAmount ?? 0)}
|
|
148
|
+
</strong>
|
|
149
|
+
</span>
|
|
150
|
+
</div>
|
|
151
|
+
<div className={styles.balanceContainer}>
|
|
152
|
+
<span className={styles.itemHeading}>{t('totalAmount', 'Total amount')}:</span>{' '}
|
|
153
|
+
<span className={styles.itemLabel}>
|
|
154
|
+
<strong>
|
|
155
|
+
{defaultCurrency} {bill?.netAmount}
|
|
156
|
+
</strong>
|
|
157
|
+
</span>
|
|
158
|
+
</div>
|
|
159
|
+
</>
|
|
160
|
+
) : (
|
|
161
|
+
<div className={styles.balanceContainer}>
|
|
162
|
+
<span className={styles.itemHeading}>{t('totalAmount', 'Total amount')}:</span>{' '}
|
|
163
|
+
<span className={styles.itemLabel}>
|
|
164
|
+
<strong>
|
|
165
|
+
{defaultCurrency} {bill?.totalAmount}
|
|
166
|
+
</strong>
|
|
167
|
+
</span>
|
|
168
|
+
</div>
|
|
169
|
+
)}
|
|
147
170
|
{bill?.payments?.length > 0 && (
|
|
148
171
|
<div className={styles.paymentHistoryContainer}>
|
|
149
172
|
<DataTable rows={paymentHistoryRows} headers={paymentHistoryHeaders} size={responsiveSize}>
|
|
@@ -184,7 +207,7 @@ const PrintableInvoice: React.FC<PrintableInvoiceProps> = ({ bill, patient, comp
|
|
|
184
207
|
<span className={styles.itemHeading}>{t('balance', 'Balance')}:</span>
|
|
185
208
|
<span className={styles.itemLabel}>
|
|
186
209
|
<strong>
|
|
187
|
-
{defaultCurrency} {bill?.
|
|
210
|
+
{defaultCurrency} {bill?.netAmount - bill?.tenderedAmount}
|
|
188
211
|
</strong>
|
|
189
212
|
</span>
|
|
190
213
|
</div>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
2
3
|
import { render, screen } from '@testing-library/react';
|
|
3
4
|
import { MemoryRouter } from 'react-router-dom';
|
|
4
5
|
import { LinkExtension, createLeftPanelLink } from './left-panel-link.component';
|
|
5
|
-
import userEvent from '@testing-library/user-event';
|
|
6
6
|
|
|
7
7
|
window.getOpenmrsSpaBase = () => '/openmrs/spa/';
|
|
8
8
|
|
|
@@ -12,7 +12,7 @@ describe('LinkExtension Component', () => {
|
|
|
12
12
|
return render(component, { wrapper: MemoryRouter });
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
it('renders correctly', () => {
|
|
16
16
|
const config = { name: 'billing', title: 'Billing' };
|
|
17
17
|
renderWithRouter(<LinkExtension config={config} />, {
|
|
18
18
|
route: '/billing/6eb8d678-514d-46ad-9554-51e48d96d567',
|
|
@@ -23,7 +23,7 @@ describe('LinkExtension Component', () => {
|
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
describe('createLeftPanelLink Function', () => {
|
|
26
|
-
|
|
26
|
+
it('returns a component that renders LinkExtension', () => {
|
|
27
27
|
const config = { name: 'billing', title: 'Billing' };
|
|
28
28
|
const TestComponent = createLeftPanelLink(config);
|
|
29
29
|
|
|
@@ -1,4 +1,5 @@
|
|
|
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 { billsSummary } from '../../__mocks__/bills.mock';
|
|
@@ -7,11 +8,11 @@ import { type MappedBill } from '../types';
|
|
|
7
8
|
import { configSchema, type BillingConfig } from '../config-schema';
|
|
8
9
|
import MetricsCards from './metrics-cards.component';
|
|
9
10
|
|
|
10
|
-
const mockUseBills =
|
|
11
|
-
const mockUseConfig =
|
|
11
|
+
const mockUseBills = vi.mocked<typeof useBills>(useBills);
|
|
12
|
+
const mockUseConfig = vi.mocked(useConfig<BillingConfig>);
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
useBills:
|
|
14
|
+
vi.mock('../billing.resource', () => ({
|
|
15
|
+
useBills: vi.fn(),
|
|
15
16
|
}));
|
|
16
17
|
|
|
17
18
|
describe('MetricsCards', () => {
|
|
@@ -19,31 +20,31 @@ describe('MetricsCards', () => {
|
|
|
19
20
|
mockUseConfig.mockReturnValue({ ...getDefaultsFromConfigSchema(configSchema), defaultCurrency: 'USD' });
|
|
20
21
|
});
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
mockUseBills.mockReturnValue({ isLoading: true, bills: [], error: null, isValidating: false, mutate:
|
|
23
|
+
it('renders loading state', () => {
|
|
24
|
+
mockUseBills.mockReturnValue({ isLoading: true, bills: [], error: null, isValidating: false, mutate: vi.fn() });
|
|
24
25
|
renderMetricsCards();
|
|
25
26
|
expect(screen.getByText(/Loading bill metrics.../i)).toBeInTheDocument();
|
|
26
27
|
});
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
it('renders error state', () => {
|
|
29
30
|
mockUseBills.mockReturnValue({
|
|
30
31
|
isLoading: false,
|
|
31
32
|
bills: [],
|
|
32
33
|
error: new Error('Internal server error'),
|
|
33
34
|
isValidating: false,
|
|
34
|
-
mutate:
|
|
35
|
+
mutate: vi.fn(),
|
|
35
36
|
});
|
|
36
37
|
renderMetricsCards();
|
|
37
38
|
expect(screen.getByText(/error state/i)).toBeInTheDocument();
|
|
38
39
|
});
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
it('renders metrics cards', () => {
|
|
41
42
|
mockUseBills.mockReturnValue({
|
|
42
43
|
isLoading: false,
|
|
43
44
|
bills: billsSummary as unknown as MappedBill[],
|
|
44
45
|
error: null,
|
|
45
46
|
isValidating: false,
|
|
46
|
-
mutate:
|
|
47
|
+
mutate: vi.fn(),
|
|
47
48
|
});
|
|
48
49
|
renderMetricsCards();
|
|
49
50
|
expect(screen.getByRole('heading', { name: /cumulative bills/i })).toBeInTheDocument();
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
5
|
+
import { showSnackbar } from '@openmrs/esm-framework';
|
|
6
|
+
import { deleteBill } from '../billing.resource';
|
|
7
|
+
import { type MappedBill } from '../types';
|
|
8
|
+
import DeleteBillModal from './delete-bill-confirmation.modal';
|
|
9
|
+
|
|
10
|
+
const mockDeleteBill = vi.mocked(deleteBill);
|
|
11
|
+
const mockShowSnackbar = vi.mocked(showSnackbar);
|
|
12
|
+
|
|
13
|
+
vi.mock('../billing.resource', () => ({
|
|
14
|
+
deleteBill: vi.fn(),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
const mockBill = {
|
|
18
|
+
uuid: 'bill-uuid',
|
|
19
|
+
receiptNumber: 'RCPT-001',
|
|
20
|
+
} as MappedBill;
|
|
21
|
+
|
|
22
|
+
describe('DeleteBillModal', () => {
|
|
23
|
+
const mockCloseModal = vi.fn();
|
|
24
|
+
const mockOnSuccess = vi.fn();
|
|
25
|
+
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
vi.clearAllMocks();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('calls deleteBill with trimmed reason, fires onSuccess, shows success snackbar, and closes modal', async () => {
|
|
31
|
+
const user = userEvent.setup();
|
|
32
|
+
mockDeleteBill.mockResolvedValueOnce({} as any);
|
|
33
|
+
|
|
34
|
+
render(<DeleteBillModal closeModal={mockCloseModal} bill={mockBill} onSuccess={mockOnSuccess} />);
|
|
35
|
+
|
|
36
|
+
const deleteReasonInput = screen.getByLabelText(/Reason for deletion/i);
|
|
37
|
+
await user.type(deleteReasonInput, 'Test delete reason');
|
|
38
|
+
|
|
39
|
+
await user.click(screen.getByRole('button', { name: /delete/i }));
|
|
40
|
+
|
|
41
|
+
await waitFor(() => {
|
|
42
|
+
expect(mockDeleteBill).toHaveBeenCalledWith(mockBill.uuid, 'Test delete reason');
|
|
43
|
+
expect(mockOnSuccess).toHaveBeenCalled();
|
|
44
|
+
expect(mockShowSnackbar).toHaveBeenCalledWith({
|
|
45
|
+
kind: 'success',
|
|
46
|
+
subtitle: 'Bill deleted successfully',
|
|
47
|
+
title: 'Bill deleted',
|
|
48
|
+
});
|
|
49
|
+
expect(mockCloseModal).toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('shows error message from responseBody when delete fails', async () => {
|
|
54
|
+
const user = userEvent.setup();
|
|
55
|
+
|
|
56
|
+
mockDeleteBill.mockRejectedValueOnce({
|
|
57
|
+
responseBody: {
|
|
58
|
+
error: {
|
|
59
|
+
message: 'Cannot delete paid bill',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
render(<DeleteBillModal closeModal={mockCloseModal} bill={mockBill} onSuccess={mockOnSuccess} />);
|
|
65
|
+
|
|
66
|
+
const deleteReasonInput = screen.getByLabelText(/Reason for deletion/i);
|
|
67
|
+
await user.type(deleteReasonInput, 'Test delete reason');
|
|
68
|
+
|
|
69
|
+
await user.click(screen.getByRole('button', { name: /delete/i }));
|
|
70
|
+
|
|
71
|
+
await waitFor(() => {
|
|
72
|
+
expect(mockShowSnackbar).toHaveBeenCalledWith({
|
|
73
|
+
kind: 'error',
|
|
74
|
+
subtitle: 'Cannot delete paid bill',
|
|
75
|
+
title: 'Failed to delete bill',
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('shows fallback error message when error has no responseBody message', async () => {
|
|
81
|
+
const user = userEvent.setup();
|
|
82
|
+
|
|
83
|
+
mockDeleteBill.mockRejectedValueOnce({});
|
|
84
|
+
|
|
85
|
+
render(<DeleteBillModal closeModal={mockCloseModal} bill={mockBill} onSuccess={mockOnSuccess} />);
|
|
86
|
+
|
|
87
|
+
const deleteReasonInput = screen.getByLabelText(/Reason for deletion/i);
|
|
88
|
+
await user.type(deleteReasonInput, 'Test delete reason');
|
|
89
|
+
|
|
90
|
+
await user.click(screen.getByRole('button', { name: /delete/i }));
|
|
91
|
+
|
|
92
|
+
await waitFor(() => {
|
|
93
|
+
expect(mockShowSnackbar).toHaveBeenCalledWith({
|
|
94
|
+
kind: 'error',
|
|
95
|
+
subtitle: 'Unable to delete bill. Please try again.',
|
|
96
|
+
title: 'Failed to delete bill',
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('disables delete button when reason is empty', () => {
|
|
102
|
+
render(<DeleteBillModal closeModal={mockCloseModal} bill={mockBill} onSuccess={mockOnSuccess} />);
|
|
103
|
+
|
|
104
|
+
const deleteButton = screen.getByRole('button', { name: /delete/i });
|
|
105
|
+
expect(deleteButton).toBeDisabled();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('disables delete button when reason contains only whitespace', async () => {
|
|
109
|
+
const user = userEvent.setup();
|
|
110
|
+
render(<DeleteBillModal closeModal={mockCloseModal} bill={mockBill} onSuccess={mockOnSuccess} />);
|
|
111
|
+
|
|
112
|
+
const deleteReasonInput = screen.getByLabelText(/Reason for deletion/i);
|
|
113
|
+
await user.type(deleteReasonInput, ' ');
|
|
114
|
+
|
|
115
|
+
const deleteButton = screen.getByRole('button', { name: /delete/i });
|
|
116
|
+
expect(deleteButton).toBeDisabled();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('trims reason before sending to API', async () => {
|
|
120
|
+
const user = userEvent.setup();
|
|
121
|
+
mockDeleteBill.mockResolvedValueOnce({} as any);
|
|
122
|
+
|
|
123
|
+
render(<DeleteBillModal closeModal={mockCloseModal} bill={mockBill} onSuccess={mockOnSuccess} />);
|
|
124
|
+
|
|
125
|
+
const deleteReasonInput = screen.getByLabelText(/Reason for deletion/i);
|
|
126
|
+
await user.type(deleteReasonInput, ' Test delete reason with spaces ');
|
|
127
|
+
|
|
128
|
+
await user.click(screen.getByRole('button', { name: /delete/i }));
|
|
129
|
+
|
|
130
|
+
await waitFor(() => {
|
|
131
|
+
expect(mockDeleteBill).toHaveBeenCalledWith(mockBill.uuid, 'Test delete reason with spaces');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Button, InlineLoading, ModalBody, ModalFooter, ModalHeader, Stack, TextArea } from '@carbon/react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { getCoreTranslation, showSnackbar } from '@openmrs/esm-framework';
|
|
5
|
+
import { deleteBill } from '../billing.resource';
|
|
6
|
+
import { type MappedBill } from '../types';
|
|
7
|
+
import styles from './delete-line-item-confirmation.scss';
|
|
8
|
+
|
|
9
|
+
interface DeleteBillModalParams {
|
|
10
|
+
closeModal: () => void;
|
|
11
|
+
bill: MappedBill;
|
|
12
|
+
onSuccess?: () => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const DeleteBillModal: React.FC<DeleteBillModalParams> = ({ closeModal, bill, onSuccess }) => {
|
|
16
|
+
const { t } = useTranslation();
|
|
17
|
+
const [isDeleting, setIsDeleting] = useState(false);
|
|
18
|
+
const [deleteReason, setDeleteReason] = useState('');
|
|
19
|
+
|
|
20
|
+
const handleDelete = async () => {
|
|
21
|
+
if (!bill?.uuid) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
setIsDeleting(true);
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
await deleteBill(bill.uuid, deleteReason.trim());
|
|
29
|
+
|
|
30
|
+
showSnackbar({
|
|
31
|
+
title: t('billDeleted', 'Bill deleted'),
|
|
32
|
+
subtitle: t('billDeleteSuccess', 'Bill deleted successfully'),
|
|
33
|
+
kind: 'success',
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
onSuccess?.();
|
|
37
|
+
closeModal();
|
|
38
|
+
} catch (err: any) {
|
|
39
|
+
const message =
|
|
40
|
+
err?.responseBody?.error?.message ||
|
|
41
|
+
err?.message ||
|
|
42
|
+
t('deleteBillFailedTryAgain', 'Unable to delete bill. Please try again.');
|
|
43
|
+
|
|
44
|
+
showSnackbar({
|
|
45
|
+
title: t('billDeleteFailed', 'Failed to delete bill'),
|
|
46
|
+
subtitle: message,
|
|
47
|
+
kind: 'error',
|
|
48
|
+
});
|
|
49
|
+
} finally {
|
|
50
|
+
setIsDeleting(false);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<>
|
|
56
|
+
<ModalHeader closeModal={closeModal} title={t('deleteBill', 'Delete bill')} />
|
|
57
|
+
|
|
58
|
+
<ModalBody className={styles.modalBody}>
|
|
59
|
+
<Stack gap={5}>
|
|
60
|
+
<p>
|
|
61
|
+
{t(
|
|
62
|
+
'deleteBillConfirmation',
|
|
63
|
+
'Are you sure you want to delete bill {{receiptNumber}}? This action cannot be undone.',
|
|
64
|
+
{ receiptNumber: bill?.receiptNumber },
|
|
65
|
+
)}
|
|
66
|
+
</p>
|
|
67
|
+
<TextArea
|
|
68
|
+
enableCounter
|
|
69
|
+
id="deleteBillReason"
|
|
70
|
+
labelText={t('deleteReason', 'Reason for deletion')}
|
|
71
|
+
maxCount={255}
|
|
72
|
+
onChange={(e) => setDeleteReason(e.target.value)}
|
|
73
|
+
placeholder={t('deleteBillReasonPlaceholder', 'Enter the reason for deleting this bill')}
|
|
74
|
+
required
|
|
75
|
+
rows={3}
|
|
76
|
+
value={deleteReason}
|
|
77
|
+
/>
|
|
78
|
+
</Stack>
|
|
79
|
+
</ModalBody>
|
|
80
|
+
|
|
81
|
+
<ModalFooter>
|
|
82
|
+
<Button kind="secondary" onClick={closeModal} disabled={isDeleting}>
|
|
83
|
+
{getCoreTranslation('cancel')}
|
|
84
|
+
</Button>
|
|
85
|
+
|
|
86
|
+
<Button kind="danger" onClick={handleDelete} disabled={isDeleting || !deleteReason.trim()}>
|
|
87
|
+
{isDeleting ? (
|
|
88
|
+
<InlineLoading className={styles.spinner} description={t('deleting', 'Deleting') + '...'} />
|
|
89
|
+
) : (
|
|
90
|
+
<span>{getCoreTranslation('delete')}</span>
|
|
91
|
+
)}
|
|
92
|
+
</Button>
|
|
93
|
+
</ModalFooter>
|
|
94
|
+
</>
|
|
95
|
+
);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export default DeleteBillModal;
|
|
@@ -1,23 +1,25 @@
|
|
|
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, waitFor } from '@testing-library/react';
|
|
4
5
|
import { showSnackbar } from '@openmrs/esm-framework';
|
|
5
6
|
import { deleteBillItem } from '../billing.resource';
|
|
7
|
+
import { type LineItem } from '../types';
|
|
6
8
|
import DeleteLineItem from './delete-line-item-confirmation.modal';
|
|
7
9
|
|
|
8
|
-
const mockDeleteBillItem =
|
|
9
|
-
const mockShowSnackbar =
|
|
10
|
+
const mockDeleteBillItem = vi.mocked(deleteBillItem);
|
|
11
|
+
const mockShowSnackbar = vi.mocked(showSnackbar);
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
deleteBillItem:
|
|
13
|
+
vi.mock('../billing.resource', () => ({
|
|
14
|
+
deleteBillItem: vi.fn(),
|
|
13
15
|
}));
|
|
14
16
|
|
|
15
|
-
const mockItem = {
|
|
17
|
+
const mockItem: LineItem = {
|
|
16
18
|
uuid: 'item-uuid',
|
|
17
19
|
quantity: 2,
|
|
18
20
|
price: 100,
|
|
19
21
|
billableService: 'X-Ray Service',
|
|
20
|
-
|
|
22
|
+
status: 'PENDING',
|
|
21
23
|
item: 'Test Service',
|
|
22
24
|
display: 'Test Service',
|
|
23
25
|
voided: false,
|
|
@@ -29,11 +31,11 @@ const mockItem = {
|
|
|
29
31
|
};
|
|
30
32
|
|
|
31
33
|
describe('DeleteLineItem Modal', () => {
|
|
32
|
-
const mockCloseModal =
|
|
33
|
-
const mockMutate =
|
|
34
|
+
const mockCloseModal = vi.fn();
|
|
35
|
+
const mockMutate = vi.fn();
|
|
34
36
|
|
|
35
37
|
beforeEach(() => {
|
|
36
|
-
|
|
38
|
+
vi.clearAllMocks();
|
|
37
39
|
});
|
|
38
40
|
|
|
39
41
|
it('renders delete confirmation modal', () => {
|
|
@@ -1,17 +1,18 @@
|
|
|
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, waitFor } from '@testing-library/react';
|
|
4
5
|
import { showSnackbar } from '@openmrs/esm-framework';
|
|
5
6
|
import { finalizeBill } from '../billing.resource';
|
|
6
7
|
import FinalizeBillModal from './finalize-bill-confirmation.modal';
|
|
7
8
|
import type { MappedBill } from '../types';
|
|
8
|
-
import { BillStatus } from '../types';
|
|
9
|
+
import { BillStatus, BillLineItemStatus } from '../types';
|
|
9
10
|
|
|
10
|
-
const mockFinalizeBill =
|
|
11
|
-
const mockShowSnackbar =
|
|
11
|
+
const mockFinalizeBill = vi.mocked(finalizeBill);
|
|
12
|
+
const mockShowSnackbar = vi.mocked(showSnackbar);
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
finalizeBill:
|
|
14
|
+
vi.mock('../billing.resource', () => ({
|
|
15
|
+
finalizeBill: vi.fn(),
|
|
15
16
|
}));
|
|
16
17
|
|
|
17
18
|
const mockBill: MappedBill = {
|
|
@@ -33,19 +34,20 @@ const mockBill: MappedBill = {
|
|
|
33
34
|
item: 'X-Ray',
|
|
34
35
|
quantity: 1,
|
|
35
36
|
price: 500,
|
|
36
|
-
|
|
37
|
+
status: BillLineItemStatus.PENDING,
|
|
37
38
|
billableService: 'X-Ray Service',
|
|
38
39
|
},
|
|
39
40
|
],
|
|
40
41
|
billingService: 'X-Ray Service',
|
|
41
42
|
payments: [],
|
|
42
43
|
totalAmount: 500,
|
|
44
|
+
netAmount: 500,
|
|
43
45
|
tenderedAmount: 0,
|
|
44
46
|
};
|
|
45
47
|
|
|
46
48
|
describe('FinalizeBillModal', () => {
|
|
47
|
-
const mockCloseModal =
|
|
48
|
-
const mockMutate =
|
|
49
|
+
const mockCloseModal = vi.fn();
|
|
50
|
+
const mockMutate = vi.fn();
|
|
49
51
|
|
|
50
52
|
it('renders the confirmation modal with correct content', () => {
|
|
51
53
|
render(<FinalizeBillModal closeModal={mockCloseModal} bill={mockBill} onMutate={mockMutate} />);
|
|
@@ -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 { getDefaultsFromConfigSchema, useConfig } from '@openmrs/esm-framework';
|
|
@@ -7,19 +8,19 @@ import { type MappedBill } from '../types';
|
|
|
7
8
|
import { configSchema, type BillingConfig } from '../config-schema';
|
|
8
9
|
import RequirePaymentModal from './require-payment.modal';
|
|
9
10
|
|
|
10
|
-
const mockUseConfig =
|
|
11
|
-
const mockUseBills =
|
|
11
|
+
const mockUseConfig = vi.mocked(useConfig<BillingConfig>);
|
|
12
|
+
const mockUseBills = vi.mocked<typeof useBills>(useBills);
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
useBills:
|
|
14
|
+
vi.mock('../billing.resource', () => ({
|
|
15
|
+
useBills: vi.fn(),
|
|
15
16
|
}));
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
convertToCurrency: (value, currency) => `${currency} ${value.toFixed(2)}`,
|
|
18
|
+
vi.mock('../helpers', () => ({
|
|
19
|
+
convertToCurrency: (value: number, currency: string) => `${currency} ${value.toFixed(2)}`,
|
|
19
20
|
}));
|
|
20
21
|
|
|
21
22
|
describe('RequirePaymentModal', () => {
|
|
22
|
-
const closeModal =
|
|
23
|
+
const closeModal = vi.fn();
|
|
23
24
|
const patientUuid = '12345';
|
|
24
25
|
|
|
25
26
|
beforeEach(() => {
|
|
@@ -27,13 +28,13 @@ describe('RequirePaymentModal', () => {
|
|
|
27
28
|
});
|
|
28
29
|
|
|
29
30
|
it('renders correctly', () => {
|
|
30
|
-
mockUseBills.mockReturnValue({ bills: [], isLoading: false, error: null, isValidating: false, mutate:
|
|
31
|
+
mockUseBills.mockReturnValue({ bills: [], isLoading: false, error: null, isValidating: false, mutate: vi.fn() });
|
|
31
32
|
render(<RequirePaymentModal closeModal={closeModal} patientUuid={patientUuid} />);
|
|
32
33
|
expect(screen.getByText('Patient Billing Alert')).toBeInTheDocument();
|
|
33
34
|
});
|
|
34
35
|
|
|
35
36
|
it('displays loading state', () => {
|
|
36
|
-
mockUseBills.mockReturnValue({ bills: [], isLoading: true, error: null, isValidating: false, mutate:
|
|
37
|
+
mockUseBills.mockReturnValue({ bills: [], isLoading: true, error: null, isValidating: false, mutate: vi.fn() });
|
|
37
38
|
render(<RequirePaymentModal closeModal={closeModal} patientUuid={patientUuid} />);
|
|
38
39
|
expect(screen.getByText('Loading bill items...')).toBeInTheDocument();
|
|
39
40
|
});
|
|
@@ -53,7 +54,7 @@ describe('RequirePaymentModal', () => {
|
|
|
53
54
|
isLoading: false,
|
|
54
55
|
error: null,
|
|
55
56
|
isValidating: false,
|
|
56
|
-
mutate:
|
|
57
|
+
mutate: vi.fn(),
|
|
57
58
|
});
|
|
58
59
|
render(<RequirePaymentModal closeModal={closeModal} patientUuid={patientUuid} />);
|
|
59
60
|
expect(screen.getByText('Service 1')).toBeInTheDocument();
|
|
@@ -62,7 +63,7 @@ describe('RequirePaymentModal', () => {
|
|
|
62
63
|
|
|
63
64
|
it('handles closeModal', async () => {
|
|
64
65
|
const user = userEvent.setup();
|
|
65
|
-
mockUseBills.mockReturnValue({ bills: [], isLoading: false, error: null, isValidating: false, mutate:
|
|
66
|
+
mockUseBills.mockReturnValue({ bills: [], isLoading: false, error: null, isValidating: false, mutate: vi.fn() });
|
|
66
67
|
render(<RequirePaymentModal closeModal={closeModal} patientUuid={patientUuid} />);
|
|
67
68
|
await user.click(screen.getByText('Cancel'));
|
|
68
69
|
await user.click(screen.getByText('OK'));
|