@kenyaemr/esm-billing-app 5.4.2-pre.2198 → 5.4.2-pre.2203
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 +90 -90
- package/dist/574.js +1 -1
- package/dist/919.js +1 -1
- package/dist/919.js.map +1 -1
- package/dist/kenyaemr-esm-billing-app.js.buildmanifest.json +9 -9
- package/dist/main.js +3 -3
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/benefits-package/table/benefits-table.component.tsx +12 -5
- package/src/benefits-package/table/generic_data_table.component.tsx +1 -1
- package/src/billing.resource.ts +8 -0
- package/src/claims/claims-management/table/use-facility-claims.ts +5 -3
- package/src/invoice/invoice.component.tsx +46 -24
- package/src/invoice/invoice.scss +42 -12
- package/src/invoice/payments/invoice-breakdown/invoice-breakdown.scss +4 -4
- package/src/invoice/payments/payments.component.tsx +6 -2
- package/src/invoice/payments/payments.test.tsx +64 -10
- package/src/prompt-payment/prompt-payment.modal.test.tsx +4 -0
- package/src/prompt-payment/prompt-payment.resource.tsx +1 -6
- package/src/types/index.ts +11 -1
- package/translations/en.json +9 -0
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"}],"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":"paid-bill-receipt-print-preview-modal","component":"paidBillReceiptPrintPreviewModal"},{"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"}],"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"}],"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":"paid-bill-receipt-print-preview-modal","component":"paidBillReceiptPrintPreviewModal"},{"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"}],"version":"5.4.2-pre.2203"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Button, DataTableSkeleton } from '@carbon/react';
|
|
2
2
|
import { ArrowRight } from '@carbon/react/icons';
|
|
3
3
|
import { getPatientUuidFromStore, launchPatientWorkspace } from '@openmrs/esm-patient-common-lib';
|
|
4
|
-
import React from 'react';
|
|
4
|
+
import React, { useMemo } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import { usePreAuthRequests } from '../../hooks/use-pre-auth-requests';
|
|
7
7
|
import GenericDataTable from './generic_data_table.component';
|
|
8
8
|
import { formatDate, parseDate } from '@openmrs/esm-framework';
|
|
9
|
+
import { useFacilityClaims } from '../../claims/claims-management/table/use-facility-claims';
|
|
9
10
|
|
|
10
11
|
const headers = [
|
|
11
12
|
{
|
|
@@ -39,6 +40,12 @@ const BenefitsTable = () => {
|
|
|
39
40
|
const patientUuid = getPatientUuidFromStore();
|
|
40
41
|
const { isLoading, preAuthRequests } = usePreAuthRequests();
|
|
41
42
|
|
|
43
|
+
const { claims, mutate } = useFacilityClaims();
|
|
44
|
+
|
|
45
|
+
const claimsByUse = useMemo(() => {
|
|
46
|
+
return claims.filter((claim) => claim.use === 'preauthorization' && claim.patientId === patientUuid);
|
|
47
|
+
}, [claims]);
|
|
48
|
+
|
|
42
49
|
if (isLoading) {
|
|
43
50
|
return (
|
|
44
51
|
<DataTableSkeleton
|
|
@@ -52,7 +59,7 @@ const BenefitsTable = () => {
|
|
|
52
59
|
/>
|
|
53
60
|
);
|
|
54
61
|
}
|
|
55
|
-
|
|
62
|
+
//
|
|
56
63
|
const handleLaunchPreAuthForm = () => {
|
|
57
64
|
launchPatientWorkspace('benefits-pre-auth-form', {
|
|
58
65
|
workspaceTitle: 'Pre Auth Form',
|
|
@@ -63,10 +70,10 @@ const BenefitsTable = () => {
|
|
|
63
70
|
return (
|
|
64
71
|
<>
|
|
65
72
|
<GenericDataTable
|
|
66
|
-
rows={
|
|
73
|
+
rows={claimsByUse.map((r) => ({
|
|
67
74
|
...r,
|
|
68
|
-
lastUpdatedAt: formatDate(parseDate(r.
|
|
69
|
-
provider: r.provider.
|
|
75
|
+
lastUpdatedAt: formatDate(parseDate(r.dateFrom)),
|
|
76
|
+
provider: r.provider.person.display,
|
|
70
77
|
}))}
|
|
71
78
|
headers={headers}
|
|
72
79
|
title={t('preAuthRequests', 'Pre Auth Requests')}
|
package/src/billing.resource.ts
CHANGED
|
@@ -59,6 +59,10 @@ export const mapBillProperties = (bill: PatientInvoice): MappedBill => {
|
|
|
59
59
|
.map((ref) => `${ref.paymentMode}: ${ref.value}`)
|
|
60
60
|
.join(', '),
|
|
61
61
|
adjustmentReason: bill?.adjustmentReason,
|
|
62
|
+
balance: bill?.balance,
|
|
63
|
+
totalPayments: bill?.totalPayments,
|
|
64
|
+
totalDeposits: bill?.totalDeposits,
|
|
65
|
+
totalExempted: bill?.totalExempted,
|
|
62
66
|
};
|
|
63
67
|
|
|
64
68
|
return mappedBill;
|
|
@@ -134,6 +138,10 @@ export const useBill = (billUuid: string) => {
|
|
|
134
138
|
payments: bill?.payments,
|
|
135
139
|
totalAmount: bill?.lineItems?.map((item) => item.price * item.quantity).reduce((prev, curr) => prev + curr, 0),
|
|
136
140
|
tenderedAmount: bill?.payments?.map((item) => item.amountTendered).reduce((prev, curr) => prev + curr, 0),
|
|
141
|
+
totalPayments: bill?.totalPayments,
|
|
142
|
+
totalDeposits: bill?.totalDeposits,
|
|
143
|
+
totalExempted: bill?.totalExempted,
|
|
144
|
+
balance: bill?.balance,
|
|
137
145
|
};
|
|
138
146
|
|
|
139
147
|
return mappedBill;
|
|
@@ -4,7 +4,7 @@ import { FacilityClaim } from '../../../types';
|
|
|
4
4
|
|
|
5
5
|
export const useFacilityClaims = () => {
|
|
6
6
|
const customPresentation =
|
|
7
|
-
'custom:(uuid,claimCode,use,dateFrom,dateTo,claimedTotal,approvedTotal,status,externalId,responseUUID,provider:(display),patient:(display))';
|
|
7
|
+
'custom:(uuid,claimCode,use,dateFrom,dateTo,claimedTotal,approvedTotal,status,externalId,responseUUID,provider:(person:(display),display),patient:(uuid,display))';
|
|
8
8
|
const url = `${restBaseUrl}/claim?v=${customPresentation}`;
|
|
9
9
|
|
|
10
10
|
const { data, error, isLoading, mutate, isValidating } = useSWR<FetchResponse<{ results: Array<FacilityClaim> }>>(
|
|
@@ -14,13 +14,15 @@ export const useFacilityClaims = () => {
|
|
|
14
14
|
|
|
15
15
|
const formatClaim = (
|
|
16
16
|
claim: FacilityClaim,
|
|
17
|
-
): FacilityClaim & { id: string; providerName: string; patientName: string } => ({
|
|
17
|
+
): FacilityClaim & { id: string; providerName: string; patientName: string; patientId?: string } => ({
|
|
18
18
|
...claim,
|
|
19
19
|
id: claim.uuid,
|
|
20
|
-
providerName: claim.provider?.display,
|
|
20
|
+
providerName: claim.provider?.person?.display,
|
|
21
21
|
approvedTotal: claim.approvedTotal ?? 0,
|
|
22
22
|
status: claim.status,
|
|
23
23
|
patientName: claim.patient?.display,
|
|
24
|
+
insurer: claim.insurer ?? '',
|
|
25
|
+
patientId: claim.patient?.uuid,
|
|
24
26
|
});
|
|
25
27
|
|
|
26
28
|
const formattedClaims = data?.data.results.map(formatClaim) ?? [];
|
|
@@ -23,18 +23,14 @@ import { useBill, useDefaultFacility } from '../billing.resource';
|
|
|
23
23
|
import { spaBasePath } from '../constants';
|
|
24
24
|
import { convertToCurrency } from '../helpers';
|
|
25
25
|
import { usePaymentsReconciler } from '../hooks/use-payments-reconciler';
|
|
26
|
-
import { LineItem } from '../types';
|
|
26
|
+
import { LineItem, MappedBill } from '../types';
|
|
27
27
|
import InvoiceTable from './invoice-table.component';
|
|
28
28
|
import { removeQueuedPatient, useShaFacilityStatus, useVisitQueueEntry } from './invoice.resource';
|
|
29
29
|
import styles from './invoice.scss';
|
|
30
30
|
import Payments from './payments/payments.component';
|
|
31
31
|
import ReceiptPrintButton from './print-bill-receipt/receipt-print-button.component';
|
|
32
32
|
import PrintableInvoice from './printable-invoice/printable-invoice.component';
|
|
33
|
-
|
|
34
|
-
interface InvoiceDetailsProps {
|
|
35
|
-
label: string;
|
|
36
|
-
value: string | number;
|
|
37
|
-
}
|
|
33
|
+
import capitalize from 'lodash-es/capitalize';
|
|
38
34
|
|
|
39
35
|
const Invoice: React.FC = () => {
|
|
40
36
|
const { t } = useTranslation();
|
|
@@ -100,14 +96,6 @@ const Invoice: React.FC = () => {
|
|
|
100
96
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
101
97
|
}, [bill?.lineItems?.length]);
|
|
102
98
|
|
|
103
|
-
const invoiceDetails = {
|
|
104
|
-
'Total Amount': convertToCurrency(bill?.totalAmount),
|
|
105
|
-
'Amount Tendered': convertToCurrency(bill?.tenderedAmount),
|
|
106
|
-
'Invoice Number': bill.receiptNumber,
|
|
107
|
-
'Date And Time': formatDatetime(parseDate(bill.dateCreated), { mode: 'standard', noToday: true }),
|
|
108
|
-
'Invoice Status': bill?.status,
|
|
109
|
-
};
|
|
110
|
-
|
|
111
99
|
if (isLoadingPatient || isLoadingBill || isVisitLoading) {
|
|
112
100
|
return (
|
|
113
101
|
<div className={styles.invoiceContainer}>
|
|
@@ -197,13 +185,7 @@ const Invoice: React.FC = () => {
|
|
|
197
185
|
return (
|
|
198
186
|
<div className={styles.invoiceContainer}>
|
|
199
187
|
{patient && patientUuid && <ExtensionSlot name="patient-header-slot" state={{ patient, patientUuid }} />}
|
|
200
|
-
<
|
|
201
|
-
<section className={styles.details}>
|
|
202
|
-
{Object.entries(invoiceDetails).map(([key, val]) => (
|
|
203
|
-
<InvoiceDetails key={key} label={key} value={val} />
|
|
204
|
-
))}
|
|
205
|
-
</section>
|
|
206
|
-
</div>
|
|
188
|
+
<InvoiceSummary bill={bill} />
|
|
207
189
|
<div className={styles.actionArea}>
|
|
208
190
|
<ReceiptPrintButton bill={bill} />
|
|
209
191
|
<Button
|
|
@@ -256,10 +238,50 @@ const Invoice: React.FC = () => {
|
|
|
256
238
|
);
|
|
257
239
|
};
|
|
258
240
|
|
|
259
|
-
function
|
|
241
|
+
function InvoiceSummary({ bill }: { readonly bill: MappedBill }) {
|
|
242
|
+
const { t } = useTranslation();
|
|
243
|
+
return (
|
|
244
|
+
<>
|
|
245
|
+
<div className={styles.invoiceSummary}>
|
|
246
|
+
<span className={styles.invoiceSummaryTitle}>{t('invoiceSummary', 'Invoice Summary')}</span>
|
|
247
|
+
</div>
|
|
248
|
+
<div className={styles.invoiceSummaryContainer}>
|
|
249
|
+
<div className={styles.invoiceCard}>
|
|
250
|
+
<InvoiceSummaryItem label={t('invoiceNumber', 'Invoice Number')} value={bill.receiptNumber} />
|
|
251
|
+
<InvoiceSummaryItem
|
|
252
|
+
label={t('dateAndTime', 'Date And Time')}
|
|
253
|
+
value={formatDatetime(parseDate(bill.dateCreated), { mode: 'standard', noToday: true })}
|
|
254
|
+
/>
|
|
255
|
+
<InvoiceSummaryItem label={t('invoiceStatus', 'Invoice Status')} value={bill?.status} />
|
|
256
|
+
<InvoiceSummaryItem label={t('cashPoint', 'Cash Point')} value={bill?.cashPointName} />
|
|
257
|
+
<InvoiceSummaryItem label={t('cashier', 'Cashier')} value={capitalize(bill?.cashier?.display)} />
|
|
258
|
+
</div>
|
|
259
|
+
<div className={styles.divider} />
|
|
260
|
+
<div className={styles.invoiceCard}>
|
|
261
|
+
<InvoiceSummaryItem label={t('totalAmount', 'Total Amount')} value={convertToCurrency(bill?.totalAmount)} />
|
|
262
|
+
<InvoiceSummaryItem
|
|
263
|
+
label={t('totalExempted', 'Total Exempted')}
|
|
264
|
+
value={convertToCurrency(bill?.totalExempted)}
|
|
265
|
+
/>
|
|
266
|
+
<InvoiceSummaryItem
|
|
267
|
+
label={t('totalPayments', 'Total Payments')}
|
|
268
|
+
value={convertToCurrency(bill?.totalPayments)}
|
|
269
|
+
/>
|
|
270
|
+
<InvoiceSummaryItem
|
|
271
|
+
label={t('totalDeposits', 'Total Deposits')}
|
|
272
|
+
value={convertToCurrency(bill?.totalDeposits)}
|
|
273
|
+
/>
|
|
274
|
+
<InvoiceSummaryItem label={t('balance', 'Balance')} value={convertToCurrency(bill?.balance)} />
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
</>
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function InvoiceSummaryItem({ label, value }: { readonly label: string; readonly value: string | number }) {
|
|
260
282
|
return (
|
|
261
|
-
<div>
|
|
262
|
-
<
|
|
283
|
+
<div className={styles.invoiceSummaryItem}>
|
|
284
|
+
<span className={styles.label}>{label}</span>
|
|
263
285
|
<span className={styles.value}>{value}</span>
|
|
264
286
|
</div>
|
|
265
287
|
);
|
package/src/invoice/invoice.scss
CHANGED
|
@@ -31,18 +31,6 @@
|
|
|
31
31
|
row-gap: 1.5rem;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
.label {
|
|
35
|
-
@include type.type-style('body-compact-02');
|
|
36
|
-
color: colors.$gray-70;
|
|
37
|
-
margin: layout.$spacing-01;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.value {
|
|
41
|
-
@include type.type-style('heading-03');
|
|
42
|
-
display: inline-block;
|
|
43
|
-
margin-top: layout.$spacing-04;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
34
|
.backButton {
|
|
47
35
|
margin: layout.$spacing-04;
|
|
48
36
|
|
|
@@ -109,3 +97,45 @@
|
|
|
109
97
|
max-height: 2rem;
|
|
110
98
|
}
|
|
111
99
|
}
|
|
100
|
+
|
|
101
|
+
.invoiceSummaryContainer {
|
|
102
|
+
display: grid;
|
|
103
|
+
grid-template-columns: 1fr auto 1fr;
|
|
104
|
+
gap: layout.$spacing-05;
|
|
105
|
+
margin: 0 layout.$spacing-05 layout.$spacing-05 layout.$spacing-05;
|
|
106
|
+
background-color: colors.$white;
|
|
107
|
+
padding: layout.$spacing-05;
|
|
108
|
+
|
|
109
|
+
.divider {
|
|
110
|
+
width: 1px;
|
|
111
|
+
background-color: colors.$gray-20;
|
|
112
|
+
margin: 0 layout.$spacing-05;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.invoiceSummaryItem {
|
|
117
|
+
display: grid;
|
|
118
|
+
grid-template-columns: 1fr 1fr;
|
|
119
|
+
gap: layout.$spacing-05;
|
|
120
|
+
justify-content: center;
|
|
121
|
+
|
|
122
|
+
.label {
|
|
123
|
+
@include type.type-style('legal-02');
|
|
124
|
+
color: colors.$gray-70;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.value {
|
|
128
|
+
@include type.type-style('heading-01');
|
|
129
|
+
color: colors.$gray-70;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.invoiceSummaryTitle {
|
|
134
|
+
@include type.type-style('heading-01');
|
|
135
|
+
color: colors.$gray-70;
|
|
136
|
+
margin: layout.$spacing-05 layout.$spacing-05 0 layout.$spacing-05;
|
|
137
|
+
background-color: colors.$white;
|
|
138
|
+
display: block;
|
|
139
|
+
border-bottom: 1px solid colors.$gray-20;
|
|
140
|
+
padding: layout.$spacing-04;
|
|
141
|
+
}
|
|
@@ -5,18 +5,18 @@
|
|
|
5
5
|
.invoiceBreakdown {
|
|
6
6
|
display: grid;
|
|
7
7
|
grid-template-columns: 1fr 1fr;
|
|
8
|
-
align-items: flex-
|
|
8
|
+
align-items: flex-start;
|
|
9
9
|
margin: layout.$spacing-02 0;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
.label {
|
|
13
|
-
@include type.type-style('
|
|
13
|
+
@include type.type-style('legal-02');
|
|
14
14
|
color: colors.$gray-100;
|
|
15
|
-
text-align:
|
|
15
|
+
text-align: start;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
.value {
|
|
19
|
-
@
|
|
19
|
+
@include type.type-style('heading-01');
|
|
20
20
|
font-weight: bold;
|
|
21
21
|
margin-left: layout.$spacing-03;
|
|
22
22
|
text-align: start;
|
|
@@ -42,8 +42,8 @@ const Payments: React.FC<PaymentProps> = ({ bill, selectedLineItems }) => {
|
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
const totalWaivedAmount = computeWaivedAmount(bill);
|
|
45
|
-
const totalAmountTendered = formValues?.reduce((curr: number, prev) =>
|
|
46
|
-
const amountDue =
|
|
45
|
+
const totalAmountTendered = formValues?.reduce((curr: number, prev) => Number(prev.amount) + curr, 0) ?? 0;
|
|
46
|
+
const amountDue = bill.balance - totalAmountTendered;
|
|
47
47
|
|
|
48
48
|
// selected line items amount due
|
|
49
49
|
const selectedLineItemsAmountDue =
|
|
@@ -148,6 +148,10 @@ const Payments: React.FC<PaymentProps> = ({ bill, selectedLineItems }) => {
|
|
|
148
148
|
<div className={styles.divider} />
|
|
149
149
|
<div className={styles.paymentTotals}>
|
|
150
150
|
<InvoiceBreakDown label={t('totalAmount', 'Total Amount')} value={convertToCurrency(bill.totalAmount)} />
|
|
151
|
+
<InvoiceBreakDown
|
|
152
|
+
label={t('totalDeposits', 'Total Deposits')}
|
|
153
|
+
value={convertToCurrency(bill.totalDeposits)}
|
|
154
|
+
/>
|
|
151
155
|
<InvoiceBreakDown
|
|
152
156
|
label={t('totalTendered', 'Total Tendered')}
|
|
153
157
|
value={convertToCurrency(bill.tenderedAmount + totalAmountTendered)}
|
|
@@ -6,6 +6,8 @@ import { mockBill, mockedActiveSheet, mockLineItems, mockPaymentModes } from '..
|
|
|
6
6
|
import { processBillPayment, usePaymentModes } from '../../billing.resource';
|
|
7
7
|
import { useClockInStatus } from '../../payment-points/use-clock-in-status';
|
|
8
8
|
import Payments from './payments.component';
|
|
9
|
+
import { LineItem, PaymentMethod } from '../../types';
|
|
10
|
+
|
|
9
11
|
const mockProcessBillPayment = processBillPayment as jest.MockedFunction<typeof processBillPayment>;
|
|
10
12
|
const mockUsePaymentModes = usePaymentModes as jest.MockedFunction<typeof usePaymentModes>;
|
|
11
13
|
const mockShowSnackbar = showSnackbar as jest.MockedFunction<typeof showSnackbar>;
|
|
@@ -18,6 +20,37 @@ jest.mock('../../billing.resource', () => ({
|
|
|
18
20
|
jest.mock('../../payment-points/use-clock-in-status');
|
|
19
21
|
const mockedUseClockInStatus = useClockInStatus as jest.Mock;
|
|
20
22
|
|
|
23
|
+
// Update mockPaymentModes to include all required properties
|
|
24
|
+
const updatedMockPaymentModes: PaymentMethod[] = mockPaymentModes.map((mode) => ({
|
|
25
|
+
...mode,
|
|
26
|
+
retireReason: null,
|
|
27
|
+
auditInfo: {
|
|
28
|
+
dateCreated: '2024-01-01',
|
|
29
|
+
creator: {
|
|
30
|
+
uuid: 'user-1',
|
|
31
|
+
display: 'Test User',
|
|
32
|
+
links: [{ rel: 'self', uri: '/ws/rest/v1/user/user-1', resourceAlias: 'user' }],
|
|
33
|
+
},
|
|
34
|
+
dateChanged: null,
|
|
35
|
+
changedBy: null,
|
|
36
|
+
},
|
|
37
|
+
sortOrder: null,
|
|
38
|
+
resourceVersion: '1.8',
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
// Update mockLineItems to include all required properties
|
|
42
|
+
const updatedMockLineItems: LineItem[] = mockLineItems.map((item) => ({
|
|
43
|
+
...item,
|
|
44
|
+
itemOrServiceConceptUuid: 'concept-uuid-1',
|
|
45
|
+
serviceTypeUuid: 'servicetype-uuid-1',
|
|
46
|
+
order: {
|
|
47
|
+
uuid: 'order-uuid-1',
|
|
48
|
+
display: item.billableService.split(':')[1],
|
|
49
|
+
links: [],
|
|
50
|
+
type: 'testorder',
|
|
51
|
+
},
|
|
52
|
+
}));
|
|
53
|
+
|
|
21
54
|
describe('Payment', () => {
|
|
22
55
|
test('should display error when posting payment fails', async () => {
|
|
23
56
|
const user = userEvent.setup();
|
|
@@ -33,7 +66,7 @@ describe('Payment', () => {
|
|
|
33
66
|
};
|
|
34
67
|
mockProcessBillPayment.mockRejectedValueOnce(mockFieldErrorResponse);
|
|
35
68
|
mockUsePaymentModes.mockReturnValue({
|
|
36
|
-
paymentModes:
|
|
69
|
+
paymentModes: updatedMockPaymentModes,
|
|
37
70
|
isLoading: false,
|
|
38
71
|
error: null,
|
|
39
72
|
mutate: jest.fn(),
|
|
@@ -48,7 +81,7 @@ describe('Payment', () => {
|
|
|
48
81
|
isClockedInCurrentPaymentPoint: false,
|
|
49
82
|
});
|
|
50
83
|
|
|
51
|
-
render(<Payments bill={mockBill as any} selectedLineItems={
|
|
84
|
+
render(<Payments bill={mockBill as any} selectedLineItems={updatedMockLineItems} />);
|
|
52
85
|
const addPaymentMethod = screen.getByRole('button', { name: /Add payment option/i });
|
|
53
86
|
await user.click(addPaymentMethod);
|
|
54
87
|
await user.click(screen.getByRole('combobox', { name: /Payment method/i }));
|
|
@@ -72,8 +105,13 @@ describe('Payment', () => {
|
|
|
72
105
|
display: 'BillLineItem',
|
|
73
106
|
item: 'c15d25b9-12bb-441d-9241-cae541dd4575',
|
|
74
107
|
lineItemOrder: 0,
|
|
75
|
-
order:
|
|
76
|
-
|
|
108
|
+
order: {
|
|
109
|
+
uuid: 'order-uuid-1',
|
|
110
|
+
display: 'Medical Certificate',
|
|
111
|
+
links: [],
|
|
112
|
+
type: 'testorder',
|
|
113
|
+
},
|
|
114
|
+
paymentStatus: 'PENDING',
|
|
77
115
|
price: 500,
|
|
78
116
|
priceName: 'Default',
|
|
79
117
|
priceUuid: '',
|
|
@@ -82,14 +120,21 @@ describe('Payment', () => {
|
|
|
82
120
|
uuid: '314c25fd-2c90-4a7f-9f98-c99cd3f153e8',
|
|
83
121
|
voidReason: null,
|
|
84
122
|
voided: false,
|
|
123
|
+
itemOrServiceConceptUuid: 'concept-uuid-1',
|
|
124
|
+
serviceTypeUuid: 'servicetype-uuid-1',
|
|
85
125
|
},
|
|
86
126
|
{
|
|
87
127
|
billableService: '04be5832-5440-44d0-83d2-5c0dfd0ac7de',
|
|
88
128
|
display: 'BillLineItem',
|
|
89
129
|
item: '04be5832-5440-44d0-83d2-5c0dfd0ac7de',
|
|
90
130
|
lineItemOrder: 1,
|
|
91
|
-
order:
|
|
92
|
-
|
|
131
|
+
order: {
|
|
132
|
+
uuid: 'order-uuid-1',
|
|
133
|
+
display: 'Registration New',
|
|
134
|
+
links: [],
|
|
135
|
+
type: 'testorder',
|
|
136
|
+
},
|
|
137
|
+
paymentStatus: 'PENDING',
|
|
93
138
|
price: 100,
|
|
94
139
|
priceName: 'Default',
|
|
95
140
|
priceUuid: '',
|
|
@@ -98,14 +143,21 @@ describe('Payment', () => {
|
|
|
98
143
|
uuid: '60365e7e-d29e-4f13-b64b-9aecb5d36031',
|
|
99
144
|
voidReason: null,
|
|
100
145
|
voided: false,
|
|
146
|
+
itemOrServiceConceptUuid: 'concept-uuid-1',
|
|
147
|
+
serviceTypeUuid: 'servicetype-uuid-1',
|
|
101
148
|
},
|
|
102
149
|
{
|
|
103
150
|
billableService: '3f5d0684-a280-477e-a67b-2a956a1f6dca',
|
|
104
151
|
display: 'BillLineItem',
|
|
105
152
|
item: '3f5d0684-a280-477e-a67b-2a956a1f6dca',
|
|
106
153
|
lineItemOrder: 2,
|
|
107
|
-
order:
|
|
108
|
-
|
|
154
|
+
order: {
|
|
155
|
+
uuid: 'order-uuid-1',
|
|
156
|
+
display: 'Registration Revist',
|
|
157
|
+
links: [],
|
|
158
|
+
type: 'testorder',
|
|
159
|
+
},
|
|
160
|
+
paymentStatus: 'PENDING',
|
|
109
161
|
price: 50,
|
|
110
162
|
priceName: 'Default',
|
|
111
163
|
priceUuid: '',
|
|
@@ -114,6 +166,8 @@ describe('Payment', () => {
|
|
|
114
166
|
uuid: '006ee634-f1cf-4552-b751-f721679527af',
|
|
115
167
|
voidReason: null,
|
|
116
168
|
voided: false,
|
|
169
|
+
itemOrServiceConceptUuid: 'concept-uuid-1',
|
|
170
|
+
serviceTypeUuid: 'servicetype-uuid-1',
|
|
117
171
|
},
|
|
118
172
|
{
|
|
119
173
|
billableService: 'Hemoglobin',
|
|
@@ -153,12 +207,12 @@ describe('Payment', () => {
|
|
|
153
207
|
test('should automatically focus on the payment method field when user clicks add payment options', async () => {
|
|
154
208
|
const user = userEvent.setup();
|
|
155
209
|
mockUsePaymentModes.mockReturnValue({
|
|
156
|
-
paymentModes:
|
|
210
|
+
paymentModes: updatedMockPaymentModes,
|
|
157
211
|
isLoading: false,
|
|
158
212
|
error: null,
|
|
159
213
|
mutate: jest.fn(),
|
|
160
214
|
});
|
|
161
|
-
render(<Payments bill={mockBill as any} selectedLineItems={
|
|
215
|
+
render(<Payments bill={mockBill as any} selectedLineItems={updatedMockLineItems} />);
|
|
162
216
|
const addPaymentMethod = screen.getByRole('button', { name: /Add payment option/i });
|
|
163
217
|
await user.click(addPaymentMethod);
|
|
164
218
|
|
|
@@ -49,12 +49,7 @@ export const checkPaymentMethodExclusion = (currentVisit: Visit | null, excluded
|
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
const calculateBillBalance = (bills: Array<MappedBill>): number => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const totalBill = flattenBills.reduce((acc, curr) => acc + curr.price * curr.quantity, 0);
|
|
55
|
-
const totalPayments = bills.flatMap((bill) => bill.payments).reduce((acc, curr) => acc + curr.amountTendered, 0);
|
|
56
|
-
|
|
57
|
-
return totalBill - totalPayments;
|
|
52
|
+
return bills.reduce((acc, curr) => acc + curr.balance, 0);
|
|
58
53
|
};
|
|
59
54
|
|
|
60
55
|
/**
|
package/src/types/index.ts
CHANGED
|
@@ -22,6 +22,10 @@ export interface MappedBill {
|
|
|
22
22
|
display?: string;
|
|
23
23
|
referenceCodes?: string;
|
|
24
24
|
adjustmentReason?: string;
|
|
25
|
+
totalPayments?: number;
|
|
26
|
+
totalDeposits?: number;
|
|
27
|
+
totalExempted?: number;
|
|
28
|
+
balance?: number;
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
interface LocationLink {
|
|
@@ -137,6 +141,10 @@ export interface PatientInvoice {
|
|
|
137
141
|
adjustmentReason: any;
|
|
138
142
|
id: number;
|
|
139
143
|
resourceVersion: string;
|
|
144
|
+
totalPayments?: number;
|
|
145
|
+
totalDeposits?: number;
|
|
146
|
+
totalExempted?: number;
|
|
147
|
+
balance?: number;
|
|
140
148
|
}
|
|
141
149
|
|
|
142
150
|
export interface PatientDetails {
|
|
@@ -547,10 +555,12 @@ export type FacilityClaim = {
|
|
|
547
555
|
status: 'REJECTED' | 'ENTERED' | 'CHECKED' | 'VALUATED' | 'ERRORED';
|
|
548
556
|
provider: {
|
|
549
557
|
display: string;
|
|
558
|
+
person?: { display?: string };
|
|
550
559
|
} | null;
|
|
551
|
-
patient?: { display: string };
|
|
560
|
+
patient?: { display: string; uuid?: string };
|
|
552
561
|
externalId: string;
|
|
553
562
|
responseUUID: string;
|
|
563
|
+
insurer?: string;
|
|
554
564
|
};
|
|
555
565
|
export type BillingPromptType = 'patient-chart' | 'billing-orders';
|
|
556
566
|
|
package/translations/en.json
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"attributeRequired": "Attribute required",
|
|
25
25
|
"attributeRetired": "Attribute retired",
|
|
26
26
|
"attributeRetiredReason": "Attribute retired reason",
|
|
27
|
+
"balance": "Balance",
|
|
27
28
|
"benefits": "Benefits",
|
|
28
29
|
"billableExemptionAdministration": "Exemption Administration",
|
|
29
30
|
"billableServicesError": "Billable services error",
|
|
@@ -53,6 +54,7 @@
|
|
|
53
54
|
"cancelItem": "Cancel item",
|
|
54
55
|
"cancelled": "Cancelled",
|
|
55
56
|
"cashier": "Cashier",
|
|
57
|
+
"cashPoint": "Cash Point",
|
|
56
58
|
"cashPointName": "Cash Point Name",
|
|
57
59
|
"chargeItem": "Charge items table",
|
|
58
60
|
"chargeItems": "Charge Items",
|
|
@@ -81,6 +83,7 @@
|
|
|
81
83
|
"createNewDeposit": "Create a new deposit for this patient",
|
|
82
84
|
"creating": "Creating",
|
|
83
85
|
"date": "Date of Claim",
|
|
86
|
+
"dateAndTime": "Date And Time",
|
|
84
87
|
"dateCreated": "Date Created",
|
|
85
88
|
"delete": "Delete",
|
|
86
89
|
"deleteBill": "Delete Bill",
|
|
@@ -146,6 +149,9 @@
|
|
|
146
149
|
"invalidJsonError": "Invalid JSON received for the schema.",
|
|
147
150
|
"invoice": "Invoice",
|
|
148
151
|
"invoiceError": "Invoice error",
|
|
152
|
+
"invoiceNumber": "Invoice Number",
|
|
153
|
+
"invoiceStatus": "Invoice Status",
|
|
154
|
+
"invoiceSummary": "Invoice Summary",
|
|
149
155
|
"isPatientExemptedLegend": "Is patient exempted from payment?",
|
|
150
156
|
"item": "Item",
|
|
151
157
|
"items": "Items",
|
|
@@ -289,6 +295,9 @@
|
|
|
289
295
|
"timesheet": "Timesheet",
|
|
290
296
|
"total": "Total",
|
|
291
297
|
"totalAmount": "Total Amount",
|
|
298
|
+
"totalDeposits": "Total Deposits",
|
|
299
|
+
"totalExempted": "Total Exempted",
|
|
300
|
+
"totalPayments": "Total Payments",
|
|
292
301
|
"totalTendered": "Total Tendered",
|
|
293
302
|
"transactionHistory": "Transaction History",
|
|
294
303
|
"transactionList": "Transaction List",
|