@kenyaemr/esm-billing-app 5.4.2-pre.2351 → 5.4.2-pre.2356
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/turbo-build.log +4 -4
- package/dist/200.js +1 -1
- package/dist/452.js +1 -0
- package/dist/452.js.map +1 -0
- package/dist/956.js +1 -1
- package/dist/kenyaemr-esm-billing-app.js +1 -1
- package/dist/kenyaemr-esm-billing-app.js.buildmanifest.json +50 -50
- package/dist/kenyaemr-esm-billing-app.js.map +1 -1
- package/dist/main.js +3 -3
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -1
- package/src/invoice/invoice-actions.component.tsx +257 -0
- package/src/invoice/invoice.component.tsx +14 -257
- package/dist/985.js +0 -1
- package/dist/985.js.map +0 -1
package/dist/routes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0"},"pages":[{"component":"billableServicesHome","route":"billable-services"},{"component":"requirePaymentModal","routeRegex":"^patient/.+/chart","online":true,"offline":false}],"extensions":[{"component":"benefitsPackageDashboardLink","name":"benefits-package-dashboard-link","slot":"patient-chart-dashboard-slot","meta":{"name":"benefits-package","slot":"patient-chart-benefits-dashboard-slot","path":"insurance-benefits","columns":1,"columnSpan":1},"featureFlag":"healthInformationExchange"},{"component":"benefitsPackage","name":"benefits-package","slot":"patient-chart-benefits-dashboard-slot"},{"component":"root","name":"billing-dashboard-root","slot":"billing-dashboard-slot"},{"component":"benefitsEligibilyRequestForm","name":"benefits-eligibility-request-form"},{"component":"benefitsPreAuthForm","name":"benefits-pre-auth-form"},{"name":"billing-patient-summary","component":"billingPatientSummary","slot":"patient-chart-billing-dashboard-slot","order":10,"meta":{"columnSpan":4}},{"name":"billing-summary-dashboard-link","component":"billingSummaryDashboardLink","slot":"patient-chart-dashboard-slot","order":11,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-billing-dashboard-slot","path":"Billing","layoutMode":"anchored"}},{"name":"billing-check-in-form","slot":"extra-visit-attribute-slot","component":"billingCheckInForm"},{"name":"require-billing-modal","component":"requirePaymentModal"},{"name":"patient-banner-billing-tags","component":"visitAttributeTags","slot":"patient-banner-tags-slot","order":2},{"name":"initiate-payment-modal","component":"initiatePaymentDialog"},{"name":"delete-billableservice-modal","component":"deleteBillableServiceModal"},{"name":"refund-bill-modal","component":"refundBillModal"},{"name":"delete-bill-modal","component":"deleteBillModal"},{"name":"lab-order-billable-item","component":"labOrder","slot":"top-of-lab-order-form-slot"},{"name":"procedure-order-billable-item","component":"procedureOrder","slot":"top-of-procedure-order-form-slot"},{"name":"imaging-order-billable-item","component":"imagingOrder","slot":"top-of-imaging-order-form-slot"},{"name":"price-info-order","component":"priceInfoOrder"},{"name":"drug-order-billable-item","component":"drugOrder","slot":"medication-info-slot"},{"name":"order-action-button","component":"orderActionButton","slots":["prescription-action-button-slot","imaging-orders-action","procedure-orders-action","tests-ordered-actions-slot"],"order":0},{"component":"billingOverviewLink","name":"billing-overview-link","order":0,"slot":"billing-dashboard-group-nav-slot"},{"component":"billDepositDashboardLink","name":"bill-deposit-dashboard-link","slot":"billing-dashboard-group-nav-slot"},{"component":"paymentHistoryLink","name":"payment-history-link","slot":"billing-dashboard-group-nav-slot"},{"component":"paymentPointsLink","name":"payment-points-link","slot":"billing-dashboard-group-nav-slot"},{"component":"paymentModesLink","name":"payment-modes-link","slot":"billing-dashboard-group-nav-slot"},{"component":"billManagerLink","name":"bill-manager-link","slot":"billing-dashboard-group-nav-slot"},{"component":"chargeableItemsLink","name":"chargeable-items-link","slot":"billing-dashboard-group-nav-slot"},{"component":"billableExemptionsLink","name":"billable-exemptions-link","slot":"billing-dashboard-group-nav-slot"},{"component":"claimsManagementOverviewDashboardLink","name":"claims-management-overview-link","order":0,"slot":"claims-management-dashboard-link-slot"},{"component":"preAuthRequestsDashboardLink","name":"preauthrequest-overview-link","slot":"claims-management-dashboard-link-slot"},{"component":"claimsOverview","name":"claims-overview-dashboard-link","slot":"claims-management-overview-slot"},{"component":"waiveBillActionButton","name":"waive-bill-action-button","slot":"bill-actions-slot"},{"component":"deleteBillActionButton","name":"delete-bill-action-button","slot":"bill-actions-slot"},{"component":"refundLineItem","name":"refund-line-item","slot":"bill-actions-overflow-menu-slot"},{"name":"edit-line-item","component":"editLineItem","slot":"bill-actions-overflow-menu-slot"},{"name":"cancel-line-item","component":"cancelLineItem","slot":"bill-actions-overflow-menu-slot"}],"workspaces":[{"name":"create-bill-workspace","component":"createBillWorkspace","title":"Create Bill Workspace","type":"other-form"},{"name":"waive-bill-form","component":"waiveBillForm","title":"Waive Bill Form","type":"other-form"},{"name":"edit-bill-form","component":"editBillForm","title":"Edit Bill Form","type":"other-form"},{"name":"billable-service-form","component":"addServiceForm","title":"Create Charge Item Form","type":"other-form"},{"name":"commodity-form","component":"addCommodityForm","title":"Create Charge Item Form","type":"other-form"},{"name":"billing-form","component":"billingForm","title":"Billing Form","type":"other-form","width":"extra-wide"},{"name":"payment-mode-workspace","component":"paymentModeWorkspace","title":"Payment Mode Workspace","type":"other-form"},{"name":"cancel-bill-workspace","component":"cancelBillWorkspace","title":"Cancel Bill Workspace","type":"other-form"},{"name":"add-deposit-workspace","component":"addDepositWorkspace","title":"Add Deposit","type":"other-form"},{"name":"deposit-transaction-workspace","component":"depositTransactionWorkspace","title":"Deposit Transaction","type":"other-form"},{"name":"payment-workspace","component":"paymentWorkspace","title":"Payment Workspace","type":"other-form"}],"modals":[{"name":"create-payment-point","component":"createPaymentPoint"},{"name":"clock-out-modal","component":"clockOut"},{"name":"bulk-import-billable-services-modal","component":"bulkImportBillableServicesModal"},{"name":"delete-payment-mode-modal","component":"deletePaymentModeModal"},{"name":"manage-claim-request-modal","component":"manageClaimRequestModal"},{"name":"clock-in-modal","component":"clockIn"},{"name":"create-bill-item-modal","component":"createBillItemModal"},{"name":"delete-deposit-modal","component":"deleteDepositModal"},{"name":"reverse-transaction-modal","component":"reverseTransactionModal"},{"name":"print-preview-modal","component":"printPreviewModal"},{"name":"bill-action-modal","component":"billActionModal"}],"version":"5.4.2-pre.
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0"},"pages":[{"component":"billableServicesHome","route":"billable-services"},{"component":"requirePaymentModal","routeRegex":"^patient/.+/chart","online":true,"offline":false}],"extensions":[{"component":"benefitsPackageDashboardLink","name":"benefits-package-dashboard-link","slot":"patient-chart-dashboard-slot","meta":{"name":"benefits-package","slot":"patient-chart-benefits-dashboard-slot","path":"insurance-benefits","columns":1,"columnSpan":1},"featureFlag":"healthInformationExchange"},{"component":"benefitsPackage","name":"benefits-package","slot":"patient-chart-benefits-dashboard-slot"},{"component":"root","name":"billing-dashboard-root","slot":"billing-dashboard-slot"},{"component":"benefitsEligibilyRequestForm","name":"benefits-eligibility-request-form"},{"component":"benefitsPreAuthForm","name":"benefits-pre-auth-form"},{"name":"billing-patient-summary","component":"billingPatientSummary","slot":"patient-chart-billing-dashboard-slot","order":10,"meta":{"columnSpan":4}},{"name":"billing-summary-dashboard-link","component":"billingSummaryDashboardLink","slot":"patient-chart-dashboard-slot","order":11,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-billing-dashboard-slot","path":"Billing","layoutMode":"anchored"}},{"name":"billing-check-in-form","slot":"extra-visit-attribute-slot","component":"billingCheckInForm"},{"name":"require-billing-modal","component":"requirePaymentModal"},{"name":"patient-banner-billing-tags","component":"visitAttributeTags","slot":"patient-banner-tags-slot","order":2},{"name":"initiate-payment-modal","component":"initiatePaymentDialog"},{"name":"delete-billableservice-modal","component":"deleteBillableServiceModal"},{"name":"refund-bill-modal","component":"refundBillModal"},{"name":"delete-bill-modal","component":"deleteBillModal"},{"name":"lab-order-billable-item","component":"labOrder","slot":"top-of-lab-order-form-slot"},{"name":"procedure-order-billable-item","component":"procedureOrder","slot":"top-of-procedure-order-form-slot"},{"name":"imaging-order-billable-item","component":"imagingOrder","slot":"top-of-imaging-order-form-slot"},{"name":"price-info-order","component":"priceInfoOrder"},{"name":"drug-order-billable-item","component":"drugOrder","slot":"medication-info-slot"},{"name":"order-action-button","component":"orderActionButton","slots":["prescription-action-button-slot","imaging-orders-action","procedure-orders-action","tests-ordered-actions-slot"],"order":0},{"component":"billingOverviewLink","name":"billing-overview-link","order":0,"slot":"billing-dashboard-group-nav-slot"},{"component":"billDepositDashboardLink","name":"bill-deposit-dashboard-link","slot":"billing-dashboard-group-nav-slot"},{"component":"paymentHistoryLink","name":"payment-history-link","slot":"billing-dashboard-group-nav-slot"},{"component":"paymentPointsLink","name":"payment-points-link","slot":"billing-dashboard-group-nav-slot"},{"component":"paymentModesLink","name":"payment-modes-link","slot":"billing-dashboard-group-nav-slot"},{"component":"billManagerLink","name":"bill-manager-link","slot":"billing-dashboard-group-nav-slot"},{"component":"chargeableItemsLink","name":"chargeable-items-link","slot":"billing-dashboard-group-nav-slot"},{"component":"billableExemptionsLink","name":"billable-exemptions-link","slot":"billing-dashboard-group-nav-slot"},{"component":"claimsManagementOverviewDashboardLink","name":"claims-management-overview-link","order":0,"slot":"claims-management-dashboard-link-slot"},{"component":"preAuthRequestsDashboardLink","name":"preauthrequest-overview-link","slot":"claims-management-dashboard-link-slot"},{"component":"claimsOverview","name":"claims-overview-dashboard-link","slot":"claims-management-overview-slot"},{"component":"waiveBillActionButton","name":"waive-bill-action-button","slot":"bill-actions-slot"},{"component":"deleteBillActionButton","name":"delete-bill-action-button","slot":"bill-actions-slot"},{"component":"refundLineItem","name":"refund-line-item","slot":"bill-actions-overflow-menu-slot"},{"name":"edit-line-item","component":"editLineItem","slot":"bill-actions-overflow-menu-slot"},{"name":"cancel-line-item","component":"cancelLineItem","slot":"bill-actions-overflow-menu-slot"}],"workspaces":[{"name":"create-bill-workspace","component":"createBillWorkspace","title":"Create Bill Workspace","type":"other-form"},{"name":"waive-bill-form","component":"waiveBillForm","title":"Waive Bill Form","type":"other-form"},{"name":"edit-bill-form","component":"editBillForm","title":"Edit Bill Form","type":"other-form"},{"name":"billable-service-form","component":"addServiceForm","title":"Create Charge Item Form","type":"other-form"},{"name":"commodity-form","component":"addCommodityForm","title":"Create Charge Item Form","type":"other-form"},{"name":"billing-form","component":"billingForm","title":"Billing Form","type":"other-form","width":"extra-wide"},{"name":"payment-mode-workspace","component":"paymentModeWorkspace","title":"Payment Mode Workspace","type":"other-form"},{"name":"cancel-bill-workspace","component":"cancelBillWorkspace","title":"Cancel Bill Workspace","type":"other-form"},{"name":"add-deposit-workspace","component":"addDepositWorkspace","title":"Add Deposit","type":"other-form"},{"name":"deposit-transaction-workspace","component":"depositTransactionWorkspace","title":"Deposit Transaction","type":"other-form"},{"name":"payment-workspace","component":"paymentWorkspace","title":"Payment Workspace","type":"other-form"}],"modals":[{"name":"create-payment-point","component":"createPaymentPoint"},{"name":"clock-out-modal","component":"clockOut"},{"name":"bulk-import-billable-services-modal","component":"bulkImportBillableServicesModal"},{"name":"delete-payment-mode-modal","component":"deletePaymentModeModal"},{"name":"manage-claim-request-modal","component":"manageClaimRequestModal"},{"name":"clock-in-modal","component":"clockIn"},{"name":"create-bill-item-modal","component":"createBillItemModal"},{"name":"delete-deposit-modal","component":"deleteDepositModal"},{"name":"reverse-transaction-modal","component":"reverseTransactionModal"},{"name":"print-preview-modal","component":"printPreviewModal"},{"name":"bill-action-modal","component":"billActionModal"}],"version":"5.4.2-pre.2356"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kenyaemr/esm-billing-app",
|
|
3
|
-
"version": "5.4.2-pre.
|
|
3
|
+
"version": "5.4.2-pre.2356",
|
|
4
4
|
"description": "Billing app for KenyaEMR",
|
|
5
5
|
"browser": "dist/kenyaemr-esm-billing-app.js",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"@carbon/react": "1.x",
|
|
45
|
-
"@openmrs/esm-framework": "
|
|
45
|
+
"@openmrs/esm-framework": "7.x",
|
|
46
46
|
"react": "^18.1.0",
|
|
47
47
|
"react-i18next": "11.x",
|
|
48
48
|
"react-router-dom": "6.x",
|
package/src/index.ts
CHANGED
|
@@ -83,7 +83,7 @@ export const importTranslation = require.context('../translations', false, /.jso
|
|
|
83
83
|
|
|
84
84
|
// Dashboard Links
|
|
85
85
|
export const billingSummaryDashboardLink = getSyncLifecycle(
|
|
86
|
-
createDashboardLink({ ...dashboardMeta, icon: '', moduleName }),
|
|
86
|
+
createDashboardLink({ ...dashboardMeta, icon: 'omrs-icon-money', moduleName }),
|
|
87
87
|
options,
|
|
88
88
|
);
|
|
89
89
|
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { Button, Popover, PopoverContent } from '@carbon/react';
|
|
2
|
+
import { Close, Printer, Wallet, FolderOpen, BaggageClaim } from '@carbon/react/icons';
|
|
3
|
+
import {
|
|
4
|
+
launchWorkspace,
|
|
5
|
+
restBaseUrl,
|
|
6
|
+
showModal,
|
|
7
|
+
UserHasAccess,
|
|
8
|
+
useFeatureFlag,
|
|
9
|
+
useVisit,
|
|
10
|
+
useVisitContextStore,
|
|
11
|
+
defaultVisitCustomRepresentation,
|
|
12
|
+
navigate,
|
|
13
|
+
showSnackbar,
|
|
14
|
+
showToast,
|
|
15
|
+
updateVisit,
|
|
16
|
+
} from '@openmrs/esm-framework';
|
|
17
|
+
import React, { useState } from 'react';
|
|
18
|
+
import { useTranslation } from 'react-i18next';
|
|
19
|
+
import { useParams } from 'react-router-dom';
|
|
20
|
+
import { mutate } from 'swr';
|
|
21
|
+
import { convertToCurrency } from '../helpers';
|
|
22
|
+
import { MappedBill, LineItem } from '../types';
|
|
23
|
+
import { spaBasePath } from '../constants';
|
|
24
|
+
import { useCheckShareGnum } from './invoice.resource';
|
|
25
|
+
import styles from './invoice.scss';
|
|
26
|
+
import startCase from 'lodash-es/startCase';
|
|
27
|
+
|
|
28
|
+
interface InvoiceActionsProps {
|
|
29
|
+
readonly bill: MappedBill;
|
|
30
|
+
readonly selectedLineItems?: LineItem[];
|
|
31
|
+
readonly activeVisit?: any;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function InvoiceActions({ bill, selectedLineItems = [], activeVisit }: InvoiceActionsProps) {
|
|
35
|
+
const { t } = useTranslation();
|
|
36
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
37
|
+
const { billUuid, patientUuid } = useParams();
|
|
38
|
+
const { checkSHARegNum } = useCheckShareGnum();
|
|
39
|
+
const { patientUuid: visitStorePatientUuid, manuallySetVisitUuid } = useVisitContextStore();
|
|
40
|
+
const isProcessClaimsFormEnabled = useFeatureFlag('healthInformationExchange');
|
|
41
|
+
|
|
42
|
+
const isInsurancePayment = (payments) => {
|
|
43
|
+
return payments?.some((payment) => payment.instanceType.name === 'Insurance');
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const isShaFacilityStatusValid =
|
|
47
|
+
checkSHARegNum?.registrationNumber && checkSHARegNum.registrationNumber.trim() !== '';
|
|
48
|
+
|
|
49
|
+
const launchBillCloseOrReopenModal = (action: 'close' | 'reopen') => {
|
|
50
|
+
const dispose = showModal('bill-action-modal', {
|
|
51
|
+
closeModal: () => dispose(),
|
|
52
|
+
bill: bill,
|
|
53
|
+
action,
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const shouldCloseBill = bill.balance === 0 && !bill.closed;
|
|
58
|
+
|
|
59
|
+
const handlePrint = (documentType: string, documentTitle: string) => {
|
|
60
|
+
const dispose = showModal('print-preview-modal', {
|
|
61
|
+
onClose: () => dispose(),
|
|
62
|
+
title: documentTitle,
|
|
63
|
+
documentUrl: `/openmrs${restBaseUrl}/cashier/print?documentType=${documentType}&billId=${bill?.id}`,
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const handleBillPayment = () => {
|
|
68
|
+
const dispose = showModal('initiate-payment-modal', {
|
|
69
|
+
closeModal: () => dispose(),
|
|
70
|
+
bill: bill,
|
|
71
|
+
selectedLineItems,
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const mutateClaimForm = async () => {
|
|
76
|
+
const activeVisitUrlSuffix = `?patient=${patientUuid}&v=${defaultVisitCustomRepresentation}&includeInactive=false`;
|
|
77
|
+
const retrospectiveVisitUuid = patientUuid && visitStorePatientUuid == patientUuid ? manuallySetVisitUuid : null;
|
|
78
|
+
const retrospectiveVisitUrlSuffix = `/${retrospectiveVisitUuid}?v=${defaultVisitCustomRepresentation}`;
|
|
79
|
+
const activeVisitUrl = `${restBaseUrl}/visit${activeVisitUrlSuffix}`;
|
|
80
|
+
const retroVisitUrl = `${restBaseUrl}/visit${retrospectiveVisitUrlSuffix}`;
|
|
81
|
+
await mutate((key) => typeof key === 'string' && (key.startsWith(activeVisitUrl) || key.startsWith(retroVisitUrl)));
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const handleEndVisit = async () => {
|
|
85
|
+
if (activeVisit) {
|
|
86
|
+
const endVisitPayload = {
|
|
87
|
+
stopDatetime: new Date(),
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const abortController = new AbortController();
|
|
91
|
+
try {
|
|
92
|
+
await updateVisit(activeVisit.uuid, endVisitPayload, abortController);
|
|
93
|
+
await mutateClaimForm();
|
|
94
|
+
showSnackbar({
|
|
95
|
+
isLowContrast: true,
|
|
96
|
+
kind: 'success',
|
|
97
|
+
subtitle: t('visitEndSuccessssfully', 'visit ended successfully'),
|
|
98
|
+
title: t('visitEnded', 'Visit ended'),
|
|
99
|
+
});
|
|
100
|
+
} catch (error) {
|
|
101
|
+
showSnackbar({
|
|
102
|
+
title: t('errorEndingVisit', 'Error ending visit'),
|
|
103
|
+
kind: 'error',
|
|
104
|
+
isLowContrast: false,
|
|
105
|
+
subtitle: error?.message,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const handleViewClaims = async () => {
|
|
112
|
+
if (!isShaFacilityStatusValid) {
|
|
113
|
+
showToast({
|
|
114
|
+
critical: true,
|
|
115
|
+
kind: 'warning',
|
|
116
|
+
title: t('shaFacilityLicenseNumberRequired', 'Facility license number Required'),
|
|
117
|
+
description: t(
|
|
118
|
+
'shaFacilityLicenseNumbernRequiredDescription',
|
|
119
|
+
'Facility license number is required to process claims. Please update facility license number details.',
|
|
120
|
+
),
|
|
121
|
+
});
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (activeVisit) {
|
|
126
|
+
await handleEndVisit();
|
|
127
|
+
navigate({ to: `${spaBasePath}/billing/patient/${patientUuid}/${billUuid}/claims` });
|
|
128
|
+
} else {
|
|
129
|
+
navigate({ to: `${spaBasePath}/billing/patient/${patientUuid}/${billUuid}/claims` });
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<div className="invoiceSummaryActions">
|
|
135
|
+
<Popover isTabTip align="bottom-right" onKeyDown={() => {}} onRequestClose={() => setIsOpen(false)} open={isOpen}>
|
|
136
|
+
<button
|
|
137
|
+
className={styles.printButton}
|
|
138
|
+
aria-expanded
|
|
139
|
+
aria-label="Settings"
|
|
140
|
+
onClick={() => setIsOpen(!isOpen)}
|
|
141
|
+
type="button">
|
|
142
|
+
<span className={styles.printButtonContent}>
|
|
143
|
+
<span className={styles.printButtonText}>{t('print', 'Print')}</span>
|
|
144
|
+
<Printer />
|
|
145
|
+
</span>
|
|
146
|
+
</button>
|
|
147
|
+
<PopoverContent>
|
|
148
|
+
<div className={styles.popoverContent}>
|
|
149
|
+
<Button
|
|
150
|
+
kind="ghost"
|
|
151
|
+
size="sm"
|
|
152
|
+
onClick={() =>
|
|
153
|
+
handlePrint(
|
|
154
|
+
'invoice',
|
|
155
|
+
`${t('invoice', 'Invoice')} ${bill?.receiptNumber} - ${startCase(bill?.patientName)}`,
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
renderIcon={Printer}>
|
|
159
|
+
{t('printInvoice', 'Print Invoice')}
|
|
160
|
+
</Button>
|
|
161
|
+
<Button
|
|
162
|
+
kind="ghost"
|
|
163
|
+
size="sm"
|
|
164
|
+
onClick={() => {
|
|
165
|
+
const dispose = showModal('print-preview-modal', {
|
|
166
|
+
onClose: () => dispose(),
|
|
167
|
+
title: `${t('receipt', 'Receipt')} ${bill?.receiptNumber} - ${startCase(bill?.patientName)}`,
|
|
168
|
+
documentUrl: `/openmrs${restBaseUrl}/cashier/receipt?billId=${bill.id}`,
|
|
169
|
+
});
|
|
170
|
+
}}
|
|
171
|
+
renderIcon={Printer}>
|
|
172
|
+
{t('printReceipt', 'Print Receipt')}
|
|
173
|
+
</Button>
|
|
174
|
+
<Button
|
|
175
|
+
kind="ghost"
|
|
176
|
+
size="sm"
|
|
177
|
+
onClick={() =>
|
|
178
|
+
handlePrint(
|
|
179
|
+
'billstatement',
|
|
180
|
+
`${t('billStatement', 'Bill Statement')} ${bill?.receiptNumber} - ${startCase(bill?.patientName)}`,
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
renderIcon={Printer}>
|
|
184
|
+
{t('printBillStatement', 'Print Bill Statement')}
|
|
185
|
+
</Button>
|
|
186
|
+
</div>
|
|
187
|
+
</PopoverContent>
|
|
188
|
+
</Popover>
|
|
189
|
+
{shouldCloseBill && (
|
|
190
|
+
<UserHasAccess privilege="Close Cashier Bills">
|
|
191
|
+
<Button
|
|
192
|
+
kind="danger--ghost"
|
|
193
|
+
size="sm"
|
|
194
|
+
renderIcon={Close}
|
|
195
|
+
iconDescription="Add"
|
|
196
|
+
tooltipPosition="right"
|
|
197
|
+
onClick={() => launchBillCloseOrReopenModal('close')}>
|
|
198
|
+
{t('closeBill', 'Close Bill')}
|
|
199
|
+
</Button>
|
|
200
|
+
</UserHasAccess>
|
|
201
|
+
)}
|
|
202
|
+
{bill?.closed && (
|
|
203
|
+
<UserHasAccess privilege="Reopen Cashier Bills">
|
|
204
|
+
<Button
|
|
205
|
+
kind="ghost"
|
|
206
|
+
size="sm"
|
|
207
|
+
renderIcon={FolderOpen}
|
|
208
|
+
iconDescription="Add"
|
|
209
|
+
tooltipPosition="right"
|
|
210
|
+
onClick={() => launchBillCloseOrReopenModal('reopen')}>
|
|
211
|
+
{t('reopen', 'Reopen')}
|
|
212
|
+
</Button>
|
|
213
|
+
</UserHasAccess>
|
|
214
|
+
)}
|
|
215
|
+
<Button
|
|
216
|
+
kind="ghost"
|
|
217
|
+
size="sm"
|
|
218
|
+
renderIcon={Wallet}
|
|
219
|
+
iconDescription="Add"
|
|
220
|
+
tooltipPosition="right"
|
|
221
|
+
onClick={() =>
|
|
222
|
+
launchWorkspace('payment-workspace', {
|
|
223
|
+
bill,
|
|
224
|
+
workspaceTitle: t('additionalPayment', 'Additional Payment (Balance {{billBalance}})', {
|
|
225
|
+
billBalance: convertToCurrency(bill.balance),
|
|
226
|
+
}),
|
|
227
|
+
})
|
|
228
|
+
}>
|
|
229
|
+
{t('additionalPayment', 'Additional Payment')}
|
|
230
|
+
</Button>
|
|
231
|
+
{bill?.balance !== 0 && (
|
|
232
|
+
<Button
|
|
233
|
+
onClick={handleBillPayment}
|
|
234
|
+
disabled={bill?.balance === 0}
|
|
235
|
+
size="sm"
|
|
236
|
+
renderIcon={Wallet}
|
|
237
|
+
iconDescription="Add"
|
|
238
|
+
tooltipPosition="left">
|
|
239
|
+
{t('mpesaPayment', 'MPESA Payment')}
|
|
240
|
+
</Button>
|
|
241
|
+
)}
|
|
242
|
+
|
|
243
|
+
{isProcessClaimsFormEnabled && isInsurancePayment(bill?.payments) && (
|
|
244
|
+
<Button
|
|
245
|
+
onClick={handleViewClaims}
|
|
246
|
+
disabled={bill?.status !== 'PAID'}
|
|
247
|
+
kind="danger"
|
|
248
|
+
size="sm"
|
|
249
|
+
renderIcon={BaggageClaim}
|
|
250
|
+
iconDescription="Add"
|
|
251
|
+
tooltipPosition="bottom">
|
|
252
|
+
{activeVisit ? t('endVisitAndClaim', 'End visit and Process claims') : t('claim', 'Process claims')}
|
|
253
|
+
</Button>
|
|
254
|
+
)}
|
|
255
|
+
</div>
|
|
256
|
+
);
|
|
257
|
+
}
|
|
@@ -1,29 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
defaultVisitCustomRepresentation,
|
|
5
|
-
ExtensionSlot,
|
|
6
|
-
formatDatetime,
|
|
7
|
-
launchWorkspace,
|
|
8
|
-
navigate,
|
|
9
|
-
parseDate,
|
|
10
|
-
restBaseUrl,
|
|
11
|
-
showModal,
|
|
12
|
-
showSnackbar,
|
|
13
|
-
showToast,
|
|
14
|
-
updateVisit,
|
|
15
|
-
useFeatureFlag,
|
|
16
|
-
usePatient,
|
|
17
|
-
UserHasAccess,
|
|
18
|
-
useVisit,
|
|
19
|
-
useVisitContextStore,
|
|
20
|
-
} from '@openmrs/esm-framework';
|
|
1
|
+
import { InlineLoading } from '@carbon/react';
|
|
2
|
+
import { ExtensionSlot, formatDatetime, parseDate, usePatient, useVisit } from '@openmrs/esm-framework';
|
|
21
3
|
import { ErrorState } from '@openmrs/esm-patient-common-lib';
|
|
22
4
|
import React, { useEffect, useState } from 'react';
|
|
23
5
|
import { useTranslation } from 'react-i18next';
|
|
24
6
|
import { useParams } from 'react-router-dom';
|
|
25
7
|
import { useBill } from '../billing.resource';
|
|
26
|
-
import { spaBasePath } from '../constants';
|
|
27
8
|
import { convertToCurrency } from '../helpers';
|
|
28
9
|
import { usePaymentsReconciler } from '../hooks/use-payments-reconciler';
|
|
29
10
|
import { LineItem, MappedBill } from '../types';
|
|
@@ -31,27 +12,16 @@ import InvoiceTable from './invoice-table.component';
|
|
|
31
12
|
import styles from './invoice.scss';
|
|
32
13
|
import Payments from './payments/payments.component';
|
|
33
14
|
import capitalize from 'lodash-es/capitalize';
|
|
34
|
-
import {
|
|
35
|
-
import startCase from 'lodash-es/startCase';
|
|
36
|
-
import { useCheckShareGnum } from './invoice.resource';
|
|
15
|
+
import { InvoiceActions } from './invoice-actions.component';
|
|
37
16
|
|
|
38
17
|
const Invoice: React.FC = () => {
|
|
39
18
|
const { t } = useTranslation();
|
|
40
|
-
const { checkSHARegNum } = useCheckShareGnum();
|
|
41
19
|
const { billUuid, patientUuid } = useParams();
|
|
42
20
|
const { patient, isLoading: isLoadingPatient, error: patientError } = usePatient(patientUuid);
|
|
43
21
|
const { bill, isLoading: isLoadingBill, error: billingError } = useBill(billUuid);
|
|
44
|
-
const isInsurancePayment = (payments) => {
|
|
45
|
-
return payments?.some((payment) => payment.instanceType.name === 'Insurance');
|
|
46
|
-
};
|
|
47
22
|
usePaymentsReconciler(billUuid);
|
|
48
23
|
const { activeVisit, isLoading: isVisitLoading, error: visitError } = useVisit(patientUuid);
|
|
49
|
-
const { patientUuid: visitStorePatientUuid, manuallySetVisitUuid } = useVisitContextStore();
|
|
50
24
|
const [selectedLineItems, setSelectedLineItems] = useState([]);
|
|
51
|
-
const isProcessClaimsFormEnabled = useFeatureFlag('healthInformationExchange');
|
|
52
|
-
|
|
53
|
-
const isShaFacilityStatusValid =
|
|
54
|
-
checkSHARegNum?.registrationNumber && checkSHARegNum.registrationNumber.trim() !== '';
|
|
55
25
|
|
|
56
26
|
const handleSelectItem = (lineItems: Array<LineItem>) => {
|
|
57
27
|
const paidLineItems = bill?.lineItems?.filter((item) => item.paymentStatus === 'PAID') ?? [];
|
|
@@ -59,31 +29,6 @@ const Invoice: React.FC = () => {
|
|
|
59
29
|
setSelectedLineItems(uniqueLineItems);
|
|
60
30
|
};
|
|
61
31
|
|
|
62
|
-
const handlePrint = () => {
|
|
63
|
-
const dispose = showModal('print-preview-modal', {
|
|
64
|
-
onClose: () => dispose(),
|
|
65
|
-
title: `${t('invoice', 'Invoice')} ${bill?.receiptNumber} - ${startCase(bill?.patientName)}`,
|
|
66
|
-
documentUrl: `/openmrs${restBaseUrl}/cashier/print?documentType=invoice&billId=${bill?.id}`,
|
|
67
|
-
});
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const handleBillPayment = () => {
|
|
71
|
-
const dispose = showModal('initiate-payment-modal', {
|
|
72
|
-
closeModal: () => dispose(),
|
|
73
|
-
bill: bill,
|
|
74
|
-
selectedLineItems,
|
|
75
|
-
});
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const mutateClaimForm = async () => {
|
|
79
|
-
const activeVisitUrlSuffix = `?patient=${patientUuid}&v=${defaultVisitCustomRepresentation}&includeInactive=false`;
|
|
80
|
-
const retrospectiveVisitUuid = patientUuid && visitStorePatientUuid == patientUuid ? manuallySetVisitUuid : null;
|
|
81
|
-
const retrospectiveVisitUrlSuffix = `/${retrospectiveVisitUuid}?v=${defaultVisitCustomRepresentation}`;
|
|
82
|
-
const activeVisitUrl = `${restBaseUrl}/visit${activeVisitUrlSuffix}`;
|
|
83
|
-
const retroVisitUrl = `${restBaseUrl}/visit${retrospectiveVisitUrlSuffix}`;
|
|
84
|
-
await mutate((key) => typeof key === 'string' && (key.startsWith(activeVisitUrl) || key.startsWith(retroVisitUrl)));
|
|
85
|
-
};
|
|
86
|
-
|
|
87
32
|
useEffect(() => {
|
|
88
33
|
const paidLineItems = bill?.lineItems?.filter((item) => item.paymentStatus === 'PAID') ?? [];
|
|
89
34
|
setSelectedLineItems(paidLineItems);
|
|
@@ -114,220 +59,32 @@ const Invoice: React.FC = () => {
|
|
|
114
59
|
);
|
|
115
60
|
}
|
|
116
61
|
|
|
117
|
-
const handleEndVisit = async () => {
|
|
118
|
-
if (activeVisit) {
|
|
119
|
-
const endVisitPayload = {
|
|
120
|
-
stopDatetime: new Date(),
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
const abortController = new AbortController();
|
|
124
|
-
try {
|
|
125
|
-
await updateVisit(activeVisit.uuid, endVisitPayload, abortController);
|
|
126
|
-
await mutateClaimForm();
|
|
127
|
-
showSnackbar({
|
|
128
|
-
isLowContrast: true,
|
|
129
|
-
kind: 'success',
|
|
130
|
-
subtitle: t('visitEndSuccessssfully', 'visit ended successfully'),
|
|
131
|
-
title: t('visitEnded', 'Visit ended'),
|
|
132
|
-
});
|
|
133
|
-
} catch (error) {
|
|
134
|
-
showSnackbar({
|
|
135
|
-
title: t('errorEndingVisit', 'Error ending visit'),
|
|
136
|
-
kind: 'error',
|
|
137
|
-
isLowContrast: false,
|
|
138
|
-
subtitle: error?.message,
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
const handleViewClaims = async () => {
|
|
145
|
-
if (!isShaFacilityStatusValid) {
|
|
146
|
-
showToast({
|
|
147
|
-
critical: true,
|
|
148
|
-
kind: 'warning',
|
|
149
|
-
title: t('shaFacilityLicenseNumberRequired', 'Facility license number Required'),
|
|
150
|
-
description: t(
|
|
151
|
-
'shaFacilityLicenseNumbernRequiredDescription',
|
|
152
|
-
'Facility license number is required to process claims. Please update facility license number details.',
|
|
153
|
-
),
|
|
154
|
-
});
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (activeVisit) {
|
|
159
|
-
await handleEndVisit();
|
|
160
|
-
navigate({ to: `${spaBasePath}/billing/patient/${patientUuid}/${billUuid}/claims` });
|
|
161
|
-
} else {
|
|
162
|
-
navigate({ to: `${spaBasePath}/billing/patient/${patientUuid}/${billUuid}/claims` });
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
|
|
166
62
|
return (
|
|
167
63
|
<div className={styles.invoiceContainer}>
|
|
168
64
|
{patient && patientUuid && <ExtensionSlot name="patient-header-slot" state={{ patient, patientUuid }} />}
|
|
169
|
-
<InvoiceSummary bill={bill} />
|
|
170
|
-
<div className={styles.actionArea}>
|
|
171
|
-
<Button
|
|
172
|
-
onClick={handleBillPayment}
|
|
173
|
-
disabled={bill?.balance === 0}
|
|
174
|
-
size="sm"
|
|
175
|
-
renderIcon={Wallet}
|
|
176
|
-
iconDescription="Add"
|
|
177
|
-
tooltipPosition="left">
|
|
178
|
-
{t('mpesaPayment', 'MPESA Payment')}
|
|
179
|
-
</Button>
|
|
180
|
-
|
|
181
|
-
{isProcessClaimsFormEnabled && isInsurancePayment(bill?.payments) && (
|
|
182
|
-
<Button
|
|
183
|
-
onClick={handleViewClaims}
|
|
184
|
-
disabled={bill?.status !== 'PAID'}
|
|
185
|
-
kind="danger"
|
|
186
|
-
size="sm"
|
|
187
|
-
renderIcon={BaggageClaim}
|
|
188
|
-
iconDescription="Add"
|
|
189
|
-
tooltipPosition="bottom">
|
|
190
|
-
{activeVisit ? t('endVisitAndClaim', 'End visit and Process claims') : t('claim', 'Process claims')}
|
|
191
|
-
</Button>
|
|
192
|
-
)}
|
|
193
|
-
</div>
|
|
194
|
-
|
|
65
|
+
<InvoiceSummary bill={bill} selectedLineItems={selectedLineItems} activeVisit={activeVisit} />
|
|
195
66
|
<InvoiceTable bill={bill} isLoadingBill={isLoadingBill} onSelectItem={handleSelectItem} />
|
|
196
67
|
<Payments bill={bill} selectedLineItems={selectedLineItems} />
|
|
197
68
|
</div>
|
|
198
69
|
);
|
|
199
70
|
};
|
|
200
71
|
|
|
201
|
-
export function InvoiceSummary({
|
|
72
|
+
export function InvoiceSummary({
|
|
73
|
+
bill,
|
|
74
|
+
selectedLineItems,
|
|
75
|
+
activeVisit,
|
|
76
|
+
}: {
|
|
77
|
+
readonly bill: MappedBill;
|
|
78
|
+
readonly selectedLineItems?: LineItem[];
|
|
79
|
+
readonly activeVisit?: any;
|
|
80
|
+
}) {
|
|
202
81
|
const { t } = useTranslation();
|
|
203
|
-
const launchBillCloseOrReopenModal = (action: 'close' | 'reopen') => {
|
|
204
|
-
const dispose = showModal('bill-action-modal', {
|
|
205
|
-
closeModal: () => dispose(),
|
|
206
|
-
bill: bill,
|
|
207
|
-
action,
|
|
208
|
-
});
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
const shouldCloseBill = bill.balance === 0 && !bill.closed;
|
|
212
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
213
|
-
|
|
214
|
-
const handlePrint = (documentType: string, documentTitle: string) => {
|
|
215
|
-
const dispose = showModal('print-preview-modal', {
|
|
216
|
-
onClose: () => dispose(),
|
|
217
|
-
title: documentTitle,
|
|
218
|
-
documentUrl: `/openmrs${restBaseUrl}/cashier/print?documentType=${documentType}&billId=${bill?.id}`,
|
|
219
|
-
});
|
|
220
|
-
};
|
|
221
82
|
|
|
222
83
|
return (
|
|
223
84
|
<>
|
|
224
85
|
<div className={styles.invoiceSummary}>
|
|
225
86
|
<span className={styles.invoiceSummaryTitle}>{t('invoiceSummary', 'Invoice Summary')}</span>
|
|
226
|
-
<
|
|
227
|
-
<Popover
|
|
228
|
-
isTabTip
|
|
229
|
-
align="bottom-right"
|
|
230
|
-
onKeyDown={() => {}}
|
|
231
|
-
onRequestClose={() => setIsOpen(false)}
|
|
232
|
-
open={isOpen}>
|
|
233
|
-
<button
|
|
234
|
-
className={styles.printButton}
|
|
235
|
-
aria-expanded
|
|
236
|
-
aria-label="Settings"
|
|
237
|
-
onClick={() => setIsOpen(!isOpen)}
|
|
238
|
-
type="button">
|
|
239
|
-
<span className={styles.printButtonContent}>
|
|
240
|
-
<span className={styles.printButtonText}>{t('print', 'Print')}</span>
|
|
241
|
-
<Printer />
|
|
242
|
-
</span>
|
|
243
|
-
</button>
|
|
244
|
-
<PopoverContent>
|
|
245
|
-
<div className={styles.popoverContent}>
|
|
246
|
-
<Button
|
|
247
|
-
kind="ghost"
|
|
248
|
-
size="sm"
|
|
249
|
-
onClick={() =>
|
|
250
|
-
handlePrint(
|
|
251
|
-
'invoice',
|
|
252
|
-
`${t('invoice', 'Invoice')} ${bill?.receiptNumber} - ${startCase(bill?.patientName)}`,
|
|
253
|
-
)
|
|
254
|
-
}
|
|
255
|
-
renderIcon={Printer}>
|
|
256
|
-
{t('printInvoice', 'Print Invoice')}
|
|
257
|
-
</Button>
|
|
258
|
-
<Button
|
|
259
|
-
kind="ghost"
|
|
260
|
-
size="sm"
|
|
261
|
-
onClick={() => {
|
|
262
|
-
const dispose = showModal('print-preview-modal', {
|
|
263
|
-
onClose: () => dispose(),
|
|
264
|
-
title: `${t('receipt', 'Receipt')} ${bill?.receiptNumber} - ${startCase(bill?.patientName)}`,
|
|
265
|
-
documentUrl: `/openmrs${restBaseUrl}/cashier/receipt?billId=${bill.id}`,
|
|
266
|
-
});
|
|
267
|
-
}}
|
|
268
|
-
renderIcon={Printer}>
|
|
269
|
-
{t('printReceipt', 'Print Receipt')}
|
|
270
|
-
</Button>
|
|
271
|
-
<Button
|
|
272
|
-
kind="ghost"
|
|
273
|
-
size="sm"
|
|
274
|
-
onClick={() =>
|
|
275
|
-
handlePrint(
|
|
276
|
-
'billstatement',
|
|
277
|
-
`${t('billStatement', 'Bill Statement')} ${bill?.receiptNumber} - ${startCase(
|
|
278
|
-
bill?.patientName,
|
|
279
|
-
)}`,
|
|
280
|
-
)
|
|
281
|
-
}
|
|
282
|
-
renderIcon={Printer}>
|
|
283
|
-
{t('printBillStatement', 'Print Bill Statement')}
|
|
284
|
-
</Button>
|
|
285
|
-
</div>
|
|
286
|
-
</PopoverContent>
|
|
287
|
-
</Popover>
|
|
288
|
-
{shouldCloseBill && (
|
|
289
|
-
<UserHasAccess privilege="Close Cashier Bills">
|
|
290
|
-
<Button
|
|
291
|
-
kind="danger--ghost"
|
|
292
|
-
size="sm"
|
|
293
|
-
renderIcon={Close}
|
|
294
|
-
iconDescription="Add"
|
|
295
|
-
tooltipPosition="right"
|
|
296
|
-
onClick={() => launchBillCloseOrReopenModal('close')}>
|
|
297
|
-
{t('closeBill', 'Close Bill')}
|
|
298
|
-
</Button>
|
|
299
|
-
</UserHasAccess>
|
|
300
|
-
)}
|
|
301
|
-
{bill?.closed && (
|
|
302
|
-
<UserHasAccess privilege="Reopen Cashier Bills">
|
|
303
|
-
<Button
|
|
304
|
-
kind="ghost"
|
|
305
|
-
size="sm"
|
|
306
|
-
renderIcon={FolderOpen}
|
|
307
|
-
iconDescription="Add"
|
|
308
|
-
tooltipPosition="right"
|
|
309
|
-
onClick={() => launchBillCloseOrReopenModal('reopen')}>
|
|
310
|
-
{t('reopen', 'Reopen')}
|
|
311
|
-
</Button>
|
|
312
|
-
</UserHasAccess>
|
|
313
|
-
)}
|
|
314
|
-
<Button
|
|
315
|
-
kind="ghost"
|
|
316
|
-
size="sm"
|
|
317
|
-
renderIcon={Wallet}
|
|
318
|
-
iconDescription="Add"
|
|
319
|
-
tooltipPosition="right"
|
|
320
|
-
onClick={() =>
|
|
321
|
-
launchWorkspace('payment-workspace', {
|
|
322
|
-
bill,
|
|
323
|
-
workspaceTitle: t('additionalPayment', 'Additional Payment (Balance {{billBalance}})', {
|
|
324
|
-
billBalance: convertToCurrency(bill.balance),
|
|
325
|
-
}),
|
|
326
|
-
})
|
|
327
|
-
}>
|
|
328
|
-
{t('additionalPayment', 'Additional Payment')}
|
|
329
|
-
</Button>
|
|
330
|
-
</div>
|
|
87
|
+
<InvoiceActions bill={bill} selectedLineItems={selectedLineItems} activeVisit={activeVisit} />
|
|
331
88
|
</div>
|
|
332
89
|
<div className={styles.invoiceSummaryContainer}>
|
|
333
90
|
<div className={styles.invoiceCard}>
|