@openmrs/esm-billing-app 1.0.2-pre.666 → 1.0.2-pre.673
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/dist/1119.js +1 -1
- package/dist/1197.js +1 -1
- package/dist/2146.js +1 -1
- package/dist/2690.js +1 -1
- package/dist/3099.js +1 -1
- package/dist/3584.js +1 -1
- package/dist/4055.js +1 -1
- package/dist/4132.js +1 -1
- package/dist/4300.js +1 -1
- package/dist/4335.js +1 -1
- package/dist/4618.js +1 -1
- package/dist/4652.js +1 -1
- package/dist/4739.js +1 -1
- package/dist/4739.js.map +1 -1
- package/dist/4944.js +1 -1
- package/dist/5173.js +1 -1
- package/dist/5241.js +1 -1
- package/dist/5442.js +1 -1
- package/dist/5661.js +1 -1
- package/dist/6022.js +1 -1
- package/dist/6468.js +1 -1
- package/dist/6679.js +1 -1
- package/dist/6840.js +1 -1
- package/dist/6859.js +1 -1
- package/dist/7097.js +1 -1
- package/dist/7159.js +1 -1
- package/dist/723.js +1 -1
- package/dist/7617.js +1 -1
- package/dist/795.js +1 -1
- package/dist/8163.js +1 -1
- package/dist/8349.js +1 -1
- package/dist/8618.js +1 -1
- package/dist/8638.js +1 -1
- package/dist/8638.js.map +1 -1
- package/dist/890.js +1 -1
- package/dist/9214.js +1 -1
- package/dist/9538.js +1 -1
- package/dist/9569.js +1 -1
- package/dist/986.js +1 -1
- package/dist/9879.js +1 -1
- package/dist/9895.js +1 -1
- package/dist/9900.js +1 -1
- package/dist/9913.js +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-billing-app.js.buildmanifest.json +127 -127
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/billing-form/billing-form.component.tsx +109 -261
- package/src/billing-form/billing-form.scss +3 -0
- package/src/billing.resource.ts +5 -12
- package/src/types/index.ts +13 -12
- package/translations/am.json +1 -0
- package/translations/ar.json +1 -0
- package/translations/ar_SY.json +1 -0
- package/translations/bn.json +1 -0
- package/translations/de.json +1 -0
- package/translations/en.json +0 -6
- package/translations/en_US.json +1 -0
- package/translations/es.json +1 -0
- package/translations/es_MX.json +1 -0
- package/translations/fr.json +1 -0
- package/translations/he.json +1 -0
- package/translations/hi.json +1 -0
- package/translations/hi_IN.json +1 -0
- package/translations/id.json +1 -0
- package/translations/it.json +1 -0
- package/translations/ka.json +1 -0
- package/translations/km.json +1 -0
- package/translations/ku.json +1 -0
- package/translations/ky.json +1 -0
- package/translations/lg.json +1 -0
- package/translations/ne.json +1 -0
- package/translations/pl.json +1 -0
- package/translations/pt.json +1 -0
- package/translations/pt_BR.json +1 -0
- package/translations/qu.json +1 -0
- package/translations/ro_RO.json +1 -0
- package/translations/ru_RU.json +1 -0
- package/translations/si.json +1 -0
- package/translations/sw.json +1 -0
- package/translations/sw_KE.json +1 -0
- package/translations/tr.json +1 -0
- package/translations/tr_TR.json +1 -0
- package/translations/uk.json +1 -0
- package/translations/uz.json +1 -0
- package/translations/uz@Latn.json +1 -0
- package/translations/uz_UZ.json +1 -0
- package/translations/vi.json +1 -0
- package/translations/zh.json +1 -0
- package/translations/zh_CN.json +1 -0
package/dist/routes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":">=2.24.0","fhir2":">=1.2"},"pages":[{"component":"billableServicesHome","route":"billable-services"}],"extensions":[{"component":"billingDashboardLink","name":"billing-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"billing","title":"billing","slot":"billing-dashboard-slot"},"featureFlag":"billing"},{"component":"root","name":"billing-dashboard-root","slot":"billing-dashboard-slot"},{"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 history"},"featureFlag":"billing"},{"name":"billable-services-app-menu-item","component":"billableServicesAppMenuItem","slot":"app-menu-item-slot","meta":{"name":"Billable Services"}},{"name":"billing-checkin-form","slot":"extra-visit-attribute-slot","component":"billingCheckInForm","featureFlag":"billing"},{"slot":"system-admin-page-card-link-slot","component":"billableServicesCardLink","name":"billable-services-admin-card-link"},{"name":"patient-banner-billing-tags","component":"visitAttributeTags","slot":"patient-banner-tags-slot","order":2},{"name":"billing-home-tiles-ext","slot":"billing-home-tiles-slot","component":"serviceMetrics"},{"name":"edit-bill-line-item-dialog","component":"editBillLineItemDialog","online":true,"offline":true}],"modals":[{"name":"require-billing-modal","component":"requirePaymentModal"}],"workspaces":[{"name":"billing-form-workspace","title":"billingForm","component":"billingFormWorkspace","type":"form"}],"featureFlags":[{"flagName":"billing","label":"Billing module","description":"This feature introduces navigation links on the patient chart and home page to allow accessing the billing module features"}],"version":"1.0.2-pre.
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":">=2.24.0","fhir2":">=1.2"},"pages":[{"component":"billableServicesHome","route":"billable-services"}],"extensions":[{"component":"billingDashboardLink","name":"billing-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"billing","title":"billing","slot":"billing-dashboard-slot"},"featureFlag":"billing"},{"component":"root","name":"billing-dashboard-root","slot":"billing-dashboard-slot"},{"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 history"},"featureFlag":"billing"},{"name":"billable-services-app-menu-item","component":"billableServicesAppMenuItem","slot":"app-menu-item-slot","meta":{"name":"Billable Services"}},{"name":"billing-checkin-form","slot":"extra-visit-attribute-slot","component":"billingCheckInForm","featureFlag":"billing"},{"slot":"system-admin-page-card-link-slot","component":"billableServicesCardLink","name":"billable-services-admin-card-link"},{"name":"patient-banner-billing-tags","component":"visitAttributeTags","slot":"patient-banner-tags-slot","order":2},{"name":"billing-home-tiles-ext","slot":"billing-home-tiles-slot","component":"serviceMetrics"},{"name":"edit-bill-line-item-dialog","component":"editBillLineItemDialog","online":true,"offline":true}],"modals":[{"name":"require-billing-modal","component":"requirePaymentModal"}],"workspaces":[{"name":"billing-form-workspace","title":"billingForm","component":"billingFormWorkspace","type":"form"}],"featureFlags":[{"flagName":"billing","label":"Billing module","description":"This feature introduces navigation links on the patient chart and home page to allow accessing the billing module features"}],"version":"1.0.2-pre.673"}
|
package/package.json
CHANGED
|
@@ -1,31 +1,28 @@
|
|
|
1
|
-
import React, { useState
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { mutate } from 'swr';
|
|
4
4
|
import {
|
|
5
5
|
Button,
|
|
6
6
|
ButtonSet,
|
|
7
|
+
ComboBox,
|
|
7
8
|
Form,
|
|
9
|
+
NumberInput,
|
|
8
10
|
InlineLoading,
|
|
9
|
-
|
|
10
|
-
RadioButtonGroup,
|
|
11
|
-
Search,
|
|
12
|
-
Stack,
|
|
11
|
+
InlineNotification,
|
|
13
12
|
Table,
|
|
14
|
-
TableBody,
|
|
15
|
-
TableCell,
|
|
16
13
|
TableHead,
|
|
17
|
-
|
|
14
|
+
TableBody,
|
|
18
15
|
TableRow,
|
|
16
|
+
TableHeader,
|
|
17
|
+
TableCell,
|
|
19
18
|
} from '@carbon/react';
|
|
20
19
|
import { TrashCan } from '@carbon/react/icons';
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
20
|
+
import { useConfig, useLayoutType, showSnackbar } from '@openmrs/esm-framework';
|
|
21
|
+
import { processBillItems, useBillableServices } from '../billing.resource';
|
|
22
|
+
import { calculateTotalAmount, convertToCurrency } from '../helpers/functions';
|
|
23
|
+
import type { BillingConfig } from '../config-schema';
|
|
24
|
+
import type { BillableItem, LineItem } from '../types';
|
|
25
25
|
import { apiBasePath } from '../constants';
|
|
26
|
-
import { convertToCurrency } from '../helpers';
|
|
27
|
-
import { type BillabeItem } from '../types';
|
|
28
|
-
import { useFetchSearchResults, processBillItems } from '../billing.resource';
|
|
29
26
|
import styles from './billing-form.scss';
|
|
30
27
|
|
|
31
28
|
type BillingFormProps = {
|
|
@@ -34,150 +31,47 @@ type BillingFormProps = {
|
|
|
34
31
|
};
|
|
35
32
|
|
|
36
33
|
const BillingForm: React.FC<BillingFormProps> = ({ patientUuid, closeWorkspace }) => {
|
|
37
|
-
const { t } = useTranslation();
|
|
38
|
-
const { defaultCurrency, postBilledItems } = useConfig();
|
|
39
34
|
const isTablet = useLayoutType() === 'tablet';
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
const [searchOptions, setSearchOptions] = useState([]);
|
|
43
|
-
const [billItems, setBillItems] = useState([]);
|
|
44
|
-
const [category, setCategory] = useState('');
|
|
45
|
-
const [saveDisabled, setSaveDisabled] = useState<boolean>(false);
|
|
35
|
+
const { t } = useTranslation();
|
|
36
|
+
const { defaultCurrency, postBilledItems } = useConfig<BillingConfig>();
|
|
46
37
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
47
|
-
const [
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Qnty: z.number().min(1, t('quantityGreaterThanZero', 'Quantity must be at least one for all items.')), // zod logic
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
const calculateTotal = (event, itemName) => {
|
|
64
|
-
const quantity = parseInt(event.target.value);
|
|
65
|
-
let isValid = true;
|
|
66
|
-
|
|
67
|
-
try {
|
|
68
|
-
billItemSchema.parse({ Qnty: quantity });
|
|
69
|
-
} catch (error) {
|
|
70
|
-
isValid = false;
|
|
71
|
-
const parsedErrorMessage = JSON.parse(error.message);
|
|
72
|
-
showToast({
|
|
73
|
-
title: t('saveBill', 'Save Bill'),
|
|
74
|
-
kind: 'error',
|
|
75
|
-
description: parsedErrorMessage[0].message,
|
|
76
|
-
});
|
|
38
|
+
const [selectedItems, setSelectedItems] = useState<LineItem[]>([]);
|
|
39
|
+
const { data, error, isLoading } = useBillableServices();
|
|
40
|
+
|
|
41
|
+
const selectBillableItem = (item: BillableItem) => {
|
|
42
|
+
if (!item) return;
|
|
43
|
+
const existingItem = selectedItems.find((selectedItem) => selectedItem.uuid === item.uuid);
|
|
44
|
+
|
|
45
|
+
if (existingItem) {
|
|
46
|
+
const updatedItem = { ...existingItem, quantity: existingItem.quantity + 1 };
|
|
47
|
+
setSelectedItems(
|
|
48
|
+
[...selectedItems].map((selectedItem) => (selectedItem.uuid === item.uuid ? updatedItem : selectedItem)),
|
|
49
|
+
);
|
|
50
|
+
return;
|
|
77
51
|
}
|
|
78
52
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
setBillItems(updatedItems);
|
|
91
|
-
|
|
92
|
-
const updatedGrandTotal = updatedItems.reduce((acc, item) => acc + item.Total, 0);
|
|
93
|
-
setGrandTotal(updatedGrandTotal);
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const calculateTotalAfterAddBillItem = (items) => {
|
|
97
|
-
const sum = items.reduce((acc, item) => acc + item.Price * item.Qnty, 0);
|
|
98
|
-
setGrandTotal(sum);
|
|
53
|
+
const mappedItem: LineItem = {
|
|
54
|
+
uuid: item.uuid,
|
|
55
|
+
display: item.name,
|
|
56
|
+
quantity: 1,
|
|
57
|
+
price: item.servicePrices?.length > 0 ? parseFloat(item.servicePrices?.[0]?.price) : 0,
|
|
58
|
+
billableService: item.uuid,
|
|
59
|
+
paymentStatus: 'PENDING',
|
|
60
|
+
lineItemOrder: 0,
|
|
61
|
+
};
|
|
62
|
+
setSelectedItems([...selectedItems, mappedItem]);
|
|
99
63
|
};
|
|
100
64
|
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
let updatedItems = [];
|
|
105
|
-
if (existingItemIndex >= 0) {
|
|
106
|
-
updatedItems = billItems.map((item, index) => {
|
|
107
|
-
if (index === existingItemIndex) {
|
|
108
|
-
const updatedQuantity = item.Qnty + 1;
|
|
109
|
-
return { ...item, Qnty: updatedQuantity, Total: updatedQuantity * item.Price };
|
|
110
|
-
}
|
|
111
|
-
return item;
|
|
112
|
-
});
|
|
113
|
-
} else {
|
|
114
|
-
const newItem = {
|
|
115
|
-
uuid: itemid,
|
|
116
|
-
Item: itemname,
|
|
117
|
-
Qnty: 1,
|
|
118
|
-
Price: itemPrice,
|
|
119
|
-
Total: itemPrice,
|
|
120
|
-
category: itemcategory,
|
|
121
|
-
};
|
|
122
|
-
updatedItems = [...billItems, newItem];
|
|
123
|
-
setAddedItems([...addedItems, newItem]);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
setBillItems(updatedItems);
|
|
127
|
-
calculateTotalAfterAddBillItem(updatedItems);
|
|
128
|
-
(document.getElementById('searchField') as HTMLInputElement).value = '';
|
|
65
|
+
const updateQuantity = (uuid: string, quantity: number) => {
|
|
66
|
+
const updatedItems = [...selectedItems].map((item) => (item.uuid === uuid ? { ...item, quantity } : item));
|
|
67
|
+
setSelectedItems(updatedItems);
|
|
129
68
|
};
|
|
130
69
|
|
|
131
|
-
const
|
|
132
|
-
const updatedItems =
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
// Update the list of added items
|
|
136
|
-
setAddedItems(addedItems.filter((item) => item.uuid !== uuid));
|
|
137
|
-
|
|
138
|
-
const updatedGrandTotal = updatedItems.reduce((acc, item) => acc + item.Total, 0);
|
|
139
|
-
setGrandTotal(updatedGrandTotal);
|
|
70
|
+
const removeSelectedBillableItem = (uuid: string) => {
|
|
71
|
+
const updatedItems = [...selectedItems].filter((item) => item.uuid !== uuid);
|
|
72
|
+
setSelectedItems(updatedItems);
|
|
140
73
|
};
|
|
141
74
|
|
|
142
|
-
const { data, error, isLoading, isValidating } = useFetchSearchResults(debouncedSearchTerm, category);
|
|
143
|
-
|
|
144
|
-
const handleSearchTermChange = (e: React.ChangeEvent<HTMLInputElement>) => setSearchTerm(e.target.value);
|
|
145
|
-
|
|
146
|
-
const filterItems = useMemo(() => {
|
|
147
|
-
if (!debouncedSearchTerm || isLoading || error) {
|
|
148
|
-
return [];
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const res = data as { results: BillabeItem[] };
|
|
152
|
-
const existingItemUuids = new Set(billItems.map((item) => item.uuid));
|
|
153
|
-
|
|
154
|
-
const preprocessedData = res?.results
|
|
155
|
-
?.map((item) => {
|
|
156
|
-
return {
|
|
157
|
-
uuid: item.uuid || '',
|
|
158
|
-
Item: item.commonName ? item.commonName : item.name,
|
|
159
|
-
Qnty: 1,
|
|
160
|
-
Price: item.commonName ? 10 : item.servicePrices[0]?.price,
|
|
161
|
-
Total: item.commonName ? 10 : item.servicePrices[0]?.price,
|
|
162
|
-
category: item.commonName ? 'StockItem' : 'Service',
|
|
163
|
-
};
|
|
164
|
-
})
|
|
165
|
-
.filter((item) => !existingItemUuids.has(item.uuid));
|
|
166
|
-
|
|
167
|
-
return debouncedSearchTerm
|
|
168
|
-
? fuzzy
|
|
169
|
-
.filter(debouncedSearchTerm, preprocessedData, {
|
|
170
|
-
extract: (o) => `${o.Item}`,
|
|
171
|
-
})
|
|
172
|
-
.sort((r1, r2) => r1.score - r2.score)
|
|
173
|
-
.map((result) => result.original)
|
|
174
|
-
: searchOptions;
|
|
175
|
-
}, [debouncedSearchTerm, isLoading, error, data, billItems, searchOptions]);
|
|
176
|
-
|
|
177
|
-
useEffect(() => {
|
|
178
|
-
setSearchOptions(filterItems);
|
|
179
|
-
}, [filterItems]);
|
|
180
|
-
|
|
181
75
|
const postBillItems = () => {
|
|
182
76
|
setIsSubmitting(true);
|
|
183
77
|
const bill = {
|
|
@@ -189,23 +83,16 @@ const BillingForm: React.FC<BillingFormProps> = ({ patientUuid, closeWorkspace }
|
|
|
189
83
|
status: 'PENDING',
|
|
190
84
|
};
|
|
191
85
|
|
|
192
|
-
|
|
193
|
-
const lineItem:
|
|
194
|
-
quantity:
|
|
195
|
-
price: item.
|
|
196
|
-
priceName: 'Default',
|
|
197
|
-
priceUuid: postBilledItems.priceUuid,
|
|
86
|
+
selectedItems.forEach((item) => {
|
|
87
|
+
const lineItem: LineItem = {
|
|
88
|
+
quantity: item.quantity,
|
|
89
|
+
price: item.price,
|
|
198
90
|
lineItemOrder: 0,
|
|
199
91
|
paymentStatus: 'PENDING',
|
|
92
|
+
billableService: item.uuid,
|
|
200
93
|
};
|
|
201
94
|
|
|
202
|
-
|
|
203
|
-
lineItem.item = item.uuid;
|
|
204
|
-
} else {
|
|
205
|
-
lineItem.billableService = item.uuid;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
bill?.lineItems.push(lineItem);
|
|
95
|
+
bill.lineItems.push(lineItem);
|
|
209
96
|
});
|
|
210
97
|
|
|
211
98
|
const url = `${apiBasePath}bill`;
|
|
@@ -233,57 +120,28 @@ const BillingForm: React.FC<BillingFormProps> = ({ patientUuid, closeWorkspace }
|
|
|
233
120
|
);
|
|
234
121
|
};
|
|
235
122
|
|
|
236
|
-
const handleClearSearchTerm = () => {
|
|
237
|
-
setSearchOptions([]);
|
|
238
|
-
};
|
|
239
|
-
|
|
240
123
|
return (
|
|
241
124
|
<Form className={styles.form}>
|
|
242
125
|
<div className={styles.grid}>
|
|
243
|
-
|
|
244
|
-
<
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
<RadioButton labelText={t('service', 'Service')} value="Service" id="service" />
|
|
252
|
-
</RadioButtonGroup>
|
|
253
|
-
</Stack>
|
|
254
|
-
<Stack>
|
|
255
|
-
<Search
|
|
256
|
-
size="lg"
|
|
257
|
-
id="searchField"
|
|
258
|
-
disabled={disableSearch}
|
|
259
|
-
closeButtonLabelText={t('clearSearchInput', 'Clear search input')}
|
|
260
|
-
className={styles.mt2}
|
|
261
|
-
placeholder={t('searchItems', 'Search items and services')}
|
|
262
|
-
labelText={t('searchItems', 'Search items and services')}
|
|
263
|
-
onKeyUp={handleSearchTermChange}
|
|
264
|
-
onClear={handleClearSearchTerm}
|
|
126
|
+
{isLoading ? (
|
|
127
|
+
<InlineLoading description={t('loading', 'Loading') + '...'} />
|
|
128
|
+
) : error ? (
|
|
129
|
+
<InlineNotification
|
|
130
|
+
kind="error"
|
|
131
|
+
lowContrast
|
|
132
|
+
title={t('billErrorService', 'Bill service error')}
|
|
133
|
+
subtitle={t('errorLoadingBillServices', 'Error loading bill services')}
|
|
265
134
|
/>
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
{
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
{row.Item} Qnty.{row.Qnty} {defaultCurrency}.{row.Price}
|
|
277
|
-
</Button>
|
|
278
|
-
</li>
|
|
279
|
-
))}
|
|
280
|
-
|
|
281
|
-
{searchOptions?.length === 0 && !isLoading && !!debouncedSearchTerm && (
|
|
282
|
-
<p>{t('noResultsFound', 'No results found')}</p>
|
|
283
|
-
)}
|
|
284
|
-
</ul>
|
|
285
|
-
</Stack>
|
|
286
|
-
<Stack>
|
|
135
|
+
) : (
|
|
136
|
+
<ComboBox
|
|
137
|
+
id="searchItems"
|
|
138
|
+
onChange={({ selectedItem: item }: { selectedItem: BillableItem }) => selectBillableItem(item)}
|
|
139
|
+
itemToString={(item: BillableItem) => item?.name || ''}
|
|
140
|
+
items={data ?? []}
|
|
141
|
+
titleText={t('searchItems', 'Search items and services')}
|
|
142
|
+
/>
|
|
143
|
+
)}
|
|
144
|
+
{selectedItems && selectedItems.length > 0 && (
|
|
287
145
|
<Table aria-label="sample table" className={styles.mt2}>
|
|
288
146
|
<TableHead>
|
|
289
147
|
<TableRow>
|
|
@@ -295,63 +153,53 @@ const BillingForm: React.FC<BillingFormProps> = ({ patientUuid, closeWorkspace }
|
|
|
295
153
|
</TableRow>
|
|
296
154
|
</TableHead>
|
|
297
155
|
<TableBody>
|
|
298
|
-
{
|
|
299
|
-
|
|
300
|
-
<
|
|
301
|
-
|
|
302
|
-
<
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
<
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
<TrashCan onClick={() => removeItemFromBill(row.uuid)} className={styles.removeButton} />
|
|
322
|
-
</TableCell>
|
|
323
|
-
</TableRow>
|
|
324
|
-
))
|
|
325
|
-
) : (
|
|
326
|
-
<p>{t('loading', 'Loading...')}</p>
|
|
327
|
-
)}
|
|
156
|
+
{selectedItems.map((row) => (
|
|
157
|
+
<TableRow>
|
|
158
|
+
<TableCell>{row.display}</TableCell>
|
|
159
|
+
<TableCell>
|
|
160
|
+
<NumberInput
|
|
161
|
+
id={row.uuid}
|
|
162
|
+
min={1}
|
|
163
|
+
value={row.quantity}
|
|
164
|
+
onChange={(_, { value }) => {
|
|
165
|
+
const number = parseFloat(String(value));
|
|
166
|
+
updateQuantity(row.uuid, isNaN(number) ? 1 : number);
|
|
167
|
+
}}
|
|
168
|
+
/>
|
|
169
|
+
</TableCell>
|
|
170
|
+
<TableCell id={row.uuid + 'Price'}>{row.price}</TableCell>
|
|
171
|
+
<TableCell id={row.uuid + 'Total'} className="totalValue">
|
|
172
|
+
{row.price * row.quantity}
|
|
173
|
+
</TableCell>
|
|
174
|
+
<TableCell>
|
|
175
|
+
<TrashCan className={styles.removeButton} onClick={() => removeSelectedBillableItem(row.uuid)} />
|
|
176
|
+
</TableCell>
|
|
177
|
+
</TableRow>
|
|
178
|
+
))}
|
|
328
179
|
<TableRow>
|
|
329
180
|
<TableCell colSpan={3}></TableCell>
|
|
330
181
|
<TableCell style={{ fontWeight: 'bold' }}>{t('grandTotal', 'Grand total')}:</TableCell>
|
|
331
|
-
<TableCell id="GrandTotalSum">
|
|
182
|
+
<TableCell id="GrandTotalSum">
|
|
183
|
+
{convertToCurrency(calculateTotalAmount(selectedItems), defaultCurrency)}
|
|
184
|
+
</TableCell>
|
|
332
185
|
</TableRow>
|
|
333
186
|
</TableBody>
|
|
334
187
|
</Table>
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
<ButtonSet className={isTablet ? styles.tablet : styles.desktop}>
|
|
338
|
-
<Button className={styles.button} kind="secondary" disabled={isSubmitting} onClick={closeWorkspace}>
|
|
339
|
-
{t('discard', 'Discard')}
|
|
340
|
-
</Button>
|
|
341
|
-
<Button
|
|
342
|
-
className={styles.button}
|
|
343
|
-
kind="primary"
|
|
344
|
-
onClick={postBillItems}
|
|
345
|
-
disabled={isSubmitting || saveDisabled}
|
|
346
|
-
type="submit">
|
|
347
|
-
{isSubmitting ? (
|
|
348
|
-
<InlineLoading description={t('saving', 'Saving') + '...'} />
|
|
349
|
-
) : (
|
|
350
|
-
t('saveAndClose', 'Save and close')
|
|
351
|
-
)}
|
|
352
|
-
</Button>
|
|
353
|
-
</ButtonSet>
|
|
188
|
+
)}
|
|
354
189
|
</div>
|
|
190
|
+
|
|
191
|
+
<ButtonSet className={isTablet ? styles.tablet : styles.desktop}>
|
|
192
|
+
<Button className={styles.button} kind="secondary" disabled={isSubmitting || selectedItems.length === 0} onClick={closeWorkspace}>
|
|
193
|
+
{t('discard', 'Discard')}
|
|
194
|
+
</Button>
|
|
195
|
+
<Button className={styles.button} kind="primary" onClick={postBillItems} disabled={isSubmitting} type="submit">
|
|
196
|
+
{isSubmitting ? (
|
|
197
|
+
<InlineLoading description={t('saving', 'Saving') + '...'} />
|
|
198
|
+
) : (
|
|
199
|
+
t('saveAndClose', 'Save and close')
|
|
200
|
+
)}
|
|
201
|
+
</Button>
|
|
202
|
+
</ButtonSet>
|
|
355
203
|
</Form>
|
|
356
204
|
);
|
|
357
205
|
};
|
package/src/billing.resource.ts
CHANGED
|
@@ -9,11 +9,11 @@ import {
|
|
|
9
9
|
openmrsFetch,
|
|
10
10
|
useSession,
|
|
11
11
|
useVisit,
|
|
12
|
-
restBaseUrl,
|
|
13
12
|
type SessionLocation,
|
|
13
|
+
useOpenmrsFetchAll,
|
|
14
14
|
} from '@openmrs/esm-framework';
|
|
15
15
|
import { apiBasePath, omrsDateFormat } from './constants';
|
|
16
|
-
import type { MappedBill, PatientInvoice } from './types';
|
|
16
|
+
import type { MappedBill, PatientInvoice, BillableItem } from './types';
|
|
17
17
|
import SelectedDateContext from './hooks/selectedDateContext';
|
|
18
18
|
|
|
19
19
|
export const useBills = (patientUuid: string = '', billStatus: string = '') => {
|
|
@@ -134,16 +134,9 @@ export const usePatientPaymentInfo = (patientUuid: string) => {
|
|
|
134
134
|
return paymentInformation;
|
|
135
135
|
};
|
|
136
136
|
|
|
137
|
-
export function
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
url = `${restBaseUrl}/stockmanagement/stockitem?v=default&limit=10&q=${searchVal}`;
|
|
141
|
-
} else {
|
|
142
|
-
url = `${apiBasePath}billableService?v=custom:(uuid,name,shortName,serviceStatus,serviceType:(display),servicePrices:(uuid,name,price,paymentMode))`;
|
|
143
|
-
}
|
|
144
|
-
const { data, error, isLoading, isValidating } = useSWR(searchVal ? url : null, openmrsFetch, {});
|
|
145
|
-
|
|
146
|
-
return { data: data?.data, error, isLoading: isLoading, isValidating };
|
|
137
|
+
export function useBillableServices() {
|
|
138
|
+
const url = `${apiBasePath}billableService?v=custom:(uuid,name,shortName,serviceStatus,serviceType:(display),servicePrices:(uuid,name,price,paymentMode))`;
|
|
139
|
+
return useOpenmrsFetchAll<BillableItem>(url);
|
|
147
140
|
}
|
|
148
141
|
|
|
149
142
|
export const processBillItems = (payload) => {
|
package/src/types/index.ts
CHANGED
|
@@ -52,19 +52,19 @@ interface Provider {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
export interface LineItem {
|
|
55
|
-
uuid
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
item: string;
|
|
60
|
-
billableService: string;
|
|
55
|
+
uuid?: string;
|
|
56
|
+
item?: string;
|
|
57
|
+
paymentStatus: string;
|
|
58
|
+
billableService?: string;
|
|
61
59
|
quantity: number;
|
|
62
60
|
price: number;
|
|
63
|
-
priceName
|
|
64
|
-
priceUuid
|
|
65
|
-
lineItemOrder
|
|
66
|
-
resourceVersion
|
|
67
|
-
|
|
61
|
+
priceName?: string;
|
|
62
|
+
priceUuid?: string;
|
|
63
|
+
lineItemOrder?: number;
|
|
64
|
+
resourceVersion?: string;
|
|
65
|
+
display?: string;
|
|
66
|
+
voided?: boolean;
|
|
67
|
+
voidReason?: string | null;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
interface PatientLink {
|
|
@@ -168,7 +168,7 @@ export type ServiceConcept = {
|
|
|
168
168
|
display: string;
|
|
169
169
|
};
|
|
170
170
|
|
|
171
|
-
export type
|
|
171
|
+
export type BillableItem = {
|
|
172
172
|
uuid: string;
|
|
173
173
|
id?: number;
|
|
174
174
|
name?: string;
|
|
@@ -177,6 +177,7 @@ export type BillabeItem = {
|
|
|
177
177
|
};
|
|
178
178
|
|
|
179
179
|
export type ServicePrice = {
|
|
180
|
+
name: string;
|
|
180
181
|
price: string;
|
|
181
182
|
uuid: string;
|
|
182
183
|
};
|
package/translations/am.json
CHANGED
package/translations/ar.json
CHANGED
package/translations/ar_SY.json
CHANGED
package/translations/bn.json
CHANGED
package/translations/de.json
CHANGED
package/translations/en.json
CHANGED
|
@@ -54,7 +54,6 @@
|
|
|
54
54
|
"cashPointUuid": "Cash Point UUID",
|
|
55
55
|
"cashPointUuidPlaceholder": "Enter UUID",
|
|
56
56
|
"checkFilters": "Check the filters above",
|
|
57
|
-
"clearSearchInput": "Clear search input",
|
|
58
57
|
"confirmDeleteMessage": "Are you sure you want to delete this payment mode? Proceed cautiously.",
|
|
59
58
|
"createdSuccessfully": "Billable service created successfully",
|
|
60
59
|
"currentPrice": "Current price",
|
|
@@ -117,7 +116,6 @@
|
|
|
117
116
|
"noMatchingItemsToDisplay": "No matching items to display",
|
|
118
117
|
"noMatchingServicesToDisplay": "No matching services to display",
|
|
119
118
|
"noResultsFor": "No results for",
|
|
120
|
-
"noResultsFound": "No results found",
|
|
121
119
|
"noServicesToDisplay": "There are no services to display",
|
|
122
120
|
"number": "No",
|
|
123
121
|
"ok": "OK",
|
|
@@ -148,7 +146,6 @@
|
|
|
148
146
|
"printReceipt": "Print receipt",
|
|
149
147
|
"processPayment": "Process Payment",
|
|
150
148
|
"quantity": "Quantity",
|
|
151
|
-
"quantityGreaterThanZero": "Quantity must be greater than zero",
|
|
152
149
|
"quantityRequired": "Quantity is required",
|
|
153
150
|
"referenceNumber": "Reference number",
|
|
154
151
|
"save": "Save",
|
|
@@ -160,13 +157,11 @@
|
|
|
160
157
|
"searchItems": "Search items and services",
|
|
161
158
|
"searchThisTable": "Search this table",
|
|
162
159
|
"selectBillableService": "Select a billable service...",
|
|
163
|
-
"selectCategory": "Select category",
|
|
164
160
|
"selectLocation": "Select Location",
|
|
165
161
|
"selectPatientCategory": "Select patient category",
|
|
166
162
|
"selectPaymentMethod": "Select payment method",
|
|
167
163
|
"sellingAmount": "Enter selling price",
|
|
168
164
|
"sellingPrice": "Selling Price",
|
|
169
|
-
"service": "Service",
|
|
170
165
|
"serviceMetrics": "Service Metrics",
|
|
171
166
|
"serviceName": "Service Name",
|
|
172
167
|
"serviceNameExceedsLimit": "Service Name exceeds the character limit of {{MAX_NAME_LENGTH}}.",
|
|
@@ -177,7 +172,6 @@
|
|
|
177
172
|
"shortName": "Short Name",
|
|
178
173
|
"shortNameExceedsLimit": "Short Name exceeds the character limit of {{MAX_NAME_LENGTH}}.",
|
|
179
174
|
"status": "Service Status",
|
|
180
|
-
"stockItem": "Stock Item",
|
|
181
175
|
"submitting": "Submitting...",
|
|
182
176
|
"success": "Success",
|
|
183
177
|
"total": "Total",
|
package/translations/en_US.json
CHANGED
package/translations/es.json
CHANGED