@openmrs/esm-billing-app 1.0.2-pre.76 → 1.0.2-pre.764
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/README.md +54 -9
- package/__mocks__/bills.mock.ts +12 -0
- package/__mocks__/react-i18next.js +6 -5
- package/dist/1119.js +1 -1
- package/dist/1146.js +1 -2
- package/dist/1146.js.map +1 -1
- package/dist/1197.js +1 -1
- package/dist/1856.js +1 -0
- package/dist/1856.js.map +1 -0
- package/dist/2146.js +1 -1
- package/dist/2177.js +2 -0
- package/dist/2177.js.LICENSE.txt +9 -0
- package/dist/2177.js.map +1 -0
- package/dist/2524.js +1 -0
- package/dist/2524.js.map +1 -0
- package/dist/2690.js +1 -1
- package/dist/3041.js +1 -0
- package/dist/3041.js.map +1 -0
- 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/4225.js +1 -0
- package/dist/4225.js.map +1 -0
- 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/4724.js +1 -0
- package/dist/4724.js.map +1 -0
- 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/5422.js +1 -0
- package/dist/5422.js.map +1 -0
- 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/6540.js +1 -1
- package/dist/6540.js.map +1 -1
- package/dist/6606.js +1 -0
- package/dist/6606.js.map +1 -0
- 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/7452.js +2 -0
- package/dist/7452.js.map +1 -0
- 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/890.js +1 -1
- package/dist/8930.js +2 -0
- package/dist/{6525.js.LICENSE.txt → 8930.js.LICENSE.txt} +16 -4
- package/dist/8930.js.map +1 -0
- package/dist/9214.js +1 -1
- package/dist/942.js +1 -0
- package/dist/942.js.map +1 -0
- package/dist/9538.js +1 -1
- package/dist/9569.js +1 -1
- package/dist/961.js +1 -1
- package/dist/961.js.map +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 +1 -1
- package/dist/openmrs-esm-billing-app.js.buildmanifest.json +368 -262
- package/dist/openmrs-esm-billing-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/e2e/README.md +19 -18
- package/e2e/specs/sample-test.spec.ts +0 -1
- package/package.json +10 -10
- package/src/bill-history/bill-history.component.tsx +17 -25
- package/src/bill-history/bill-history.scss +4 -94
- package/src/bill-history/bill-history.test.tsx +37 -78
- package/src/bill-item-actions/bill-item-actions.scss +0 -4
- package/src/bill-item-actions/{edit-bill-item.component.tsx → edit-bill-item.modal.tsx} +100 -78
- package/src/bill-item-actions/edit-bill-item.test.tsx +116 -31
- package/src/billable-services/bill-waiver/bill-selection.component.tsx +2 -2
- package/src/billable-services/bill-waiver/patient-bills.component.tsx +3 -3
- package/src/billable-services/billable-service.resource.ts +17 -9
- package/src/billable-services/billable-services-home.component.tsx +1 -1
- package/src/billable-services/billable-services.component.tsx +142 -145
- package/src/billable-services/billable-services.scss +3 -0
- package/src/billable-services/billable-services.test.tsx +2 -45
- package/src/billable-services/cash-point/add-cash-point.modal.tsx +168 -0
- package/src/billable-services/cash-point/cash-point-configuration.component.tsx +18 -192
- package/src/billable-services/cash-point/cash-point-configuration.scss +1 -5
- package/src/billable-services/create-edit/add-billable-service.component.tsx +345 -298
- package/src/billable-services/create-edit/add-billable-service.scss +5 -6
- package/src/billable-services/create-edit/add-billable-service.test.tsx +37 -36
- package/src/billable-services/create-edit/edit-billable-service.modal.tsx +51 -0
- package/src/billable-services/payment-modes/add-payment-mode.modal.tsx +121 -0
- package/src/billable-services/payment-modes/delete-payment-mode.modal.tsx +72 -0
- package/src/billable-services/payment-modes/payment-modes-config.component.tsx +125 -0
- package/src/billable-services/{payyment-modes → payment-modes}/payment-modes-config.scss +5 -4
- package/src/billing-form/billing-checkin-form.component.tsx +2 -3
- package/src/billing-form/billing-checkin-form.test.tsx +97 -24
- package/src/billing-form/billing-form.component.tsx +216 -269
- package/src/billing-form/billing-form.scss +143 -0
- package/src/billing.resource.ts +16 -19
- package/src/bills-table/bills-table.test.tsx +97 -53
- package/src/config-schema.ts +52 -24
- package/src/dashboard.meta.ts +4 -2
- package/src/helpers/functions.ts +5 -4
- package/src/index.ts +17 -6
- package/src/invoice/invoice-table.component.tsx +34 -68
- package/src/invoice/invoice-table.scss +1 -5
- package/src/invoice/invoice-table.test.tsx +20 -47
- package/src/invoice/invoice.component.tsx +36 -29
- package/src/invoice/invoice.scss +7 -4
- package/src/invoice/invoice.test.tsx +22 -48
- package/src/invoice/payments/payment-form/payment-form.component.tsx +31 -29
- package/src/invoice/payments/payment-form/payment-form.scss +5 -6
- package/src/invoice/payments/payment-form/payment-form.test.tsx +215 -67
- package/src/invoice/payments/payment-history/payment-history.component.tsx +6 -4
- package/src/invoice/payments/payment-history/payment-history.test.tsx +9 -14
- package/src/invoice/payments/payments.component.tsx +53 -65
- package/src/invoice/payments/payments.test.tsx +282 -0
- package/src/invoice/payments/utils.ts +5 -23
- package/src/invoice/printable-invoice/print-receipt.component.tsx +3 -2
- package/src/invoice/printable-invoice/print-receipt.test.tsx +14 -25
- package/src/invoice/printable-invoice/printable-footer.component.tsx +2 -2
- package/src/invoice/printable-invoice/printable-footer.test.tsx +4 -13
- package/src/invoice/printable-invoice/printable-invoice-header.component.tsx +12 -11
- package/src/invoice/printable-invoice/printable-invoice-header.test.tsx +16 -14
- package/src/invoice/printable-invoice/printable-invoice.component.tsx +19 -33
- package/src/metrics-cards/metrics-cards.test.tsx +18 -5
- package/src/modal/require-payment-modal.test.tsx +27 -22
- package/src/modal/{require-payment-modal.component.tsx → require-payment.modal.tsx} +17 -18
- package/src/routes.json +22 -2
- package/src/types/index.ts +26 -17
- package/translations/am.json +60 -18
- package/translations/ar.json +60 -18
- package/translations/ar_SY.json +60 -18
- package/translations/bn.json +65 -23
- package/translations/de.json +60 -18
- package/translations/en.json +70 -21
- package/translations/en_US.json +60 -18
- package/translations/es.json +60 -18
- package/translations/es_MX.json +60 -18
- package/translations/fr.json +73 -31
- package/translations/he.json +60 -18
- package/translations/hi.json +60 -18
- package/translations/hi_IN.json +60 -18
- package/translations/id.json +61 -19
- package/translations/it.json +96 -54
- package/translations/ka.json +61 -19
- package/translations/km.json +60 -18
- package/translations/ku.json +60 -18
- package/translations/ky.json +60 -18
- package/translations/lg.json +60 -18
- package/translations/ne.json +60 -18
- package/translations/pl.json +60 -18
- package/translations/pt.json +60 -18
- package/translations/pt_BR.json +60 -18
- package/translations/qu.json +60 -18
- package/translations/ro_RO.json +206 -164
- package/translations/ru_RU.json +60 -18
- package/translations/si.json +60 -18
- package/translations/sw.json +60 -18
- package/translations/sw_KE.json +60 -18
- package/translations/tr.json +60 -18
- package/translations/tr_TR.json +60 -18
- package/translations/uk.json +60 -18
- package/translations/uz.json +60 -18
- package/translations/uz@Latn.json +60 -18
- package/translations/uz_UZ.json +60 -18
- package/translations/vi.json +60 -18
- package/translations/zh.json +60 -18
- package/translations/zh_CN.json +117 -75
- package/dist/1146.js.LICENSE.txt +0 -21
- package/dist/2352.js +0 -1
- package/dist/2352.js.map +0 -1
- package/dist/246.js +0 -1
- package/dist/246.js.map +0 -1
- package/dist/6525.js +0 -2
- package/dist/6525.js.map +0 -1
- package/dist/8556.js +0 -2
- package/dist/8556.js.map +0 -1
- package/dist/8638.js +0 -1
- package/dist/8638.js.map +0 -1
- package/dist/9968.js +0 -1
- package/dist/9968.js.map +0 -1
- package/src/billable-services/payyment-modes/payment-modes-config.component.tsx +0 -280
- package/src/invoice/payments/payments.component.test.tsx +0 -121
- /package/dist/{8556.js.LICENSE.txt → 7452.js.LICENSE.txt} +0 -0
|
@@ -73,6 +73,9 @@
|
|
|
73
73
|
|
|
74
74
|
.grid {
|
|
75
75
|
margin: layout.$spacing-05;
|
|
76
|
+
display: flex;
|
|
77
|
+
flex-direction: column;
|
|
78
|
+
gap: layout.$spacing-05;
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
.row {
|
|
@@ -85,3 +88,143 @@
|
|
|
85
88
|
.spacer {
|
|
86
89
|
margin-top: layout.$spacing-05;
|
|
87
90
|
}
|
|
91
|
+
|
|
92
|
+
.selectedItemsContainer {
|
|
93
|
+
margin-top: layout.$spacing-05;
|
|
94
|
+
|
|
95
|
+
h4 {
|
|
96
|
+
margin-bottom: layout.$spacing-05;
|
|
97
|
+
color: $text-02;
|
|
98
|
+
font-size: 1rem;
|
|
99
|
+
font-weight: 600;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.itemCard {
|
|
103
|
+
border: 1px solid $ui-03;
|
|
104
|
+
border-radius: layout.$spacing-02;
|
|
105
|
+
padding: layout.$spacing-05;
|
|
106
|
+
margin-bottom: layout.$spacing-05;
|
|
107
|
+
background-color: $ui-01;
|
|
108
|
+
|
|
109
|
+
.itemHeader {
|
|
110
|
+
display: flex;
|
|
111
|
+
justify-content: space-between;
|
|
112
|
+
align-items: center;
|
|
113
|
+
margin-bottom: layout.$spacing-05;
|
|
114
|
+
|
|
115
|
+
.itemName {
|
|
116
|
+
font-weight: 600;
|
|
117
|
+
font-size: 1rem;
|
|
118
|
+
color: $text-02;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.itemControls {
|
|
123
|
+
display: flex;
|
|
124
|
+
flex-wrap: wrap;
|
|
125
|
+
gap: layout.$spacing-05;
|
|
126
|
+
margin-top: layout.$spacing-03;
|
|
127
|
+
align-items: flex-end; .controlSection {
|
|
128
|
+
display: flex;
|
|
129
|
+
flex-direction: column;
|
|
130
|
+
min-width: 0;
|
|
131
|
+
|
|
132
|
+
&:first-child {
|
|
133
|
+
flex: 1 1 auto;
|
|
134
|
+
min-width: 250px;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
&:nth-child(2) {
|
|
138
|
+
flex: 0 0 140px;
|
|
139
|
+
width: 140px;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
&:last-child {
|
|
143
|
+
flex: 0 0 180px;
|
|
144
|
+
width: 180px;
|
|
145
|
+
margin-left: auto;
|
|
146
|
+
text-align: right;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
label {
|
|
150
|
+
font-size: 0.875rem;
|
|
151
|
+
font-weight: 500;
|
|
152
|
+
margin-bottom: layout.$spacing-03;
|
|
153
|
+
color: $text-02;
|
|
154
|
+
white-space: nowrap;
|
|
155
|
+
overflow: hidden;
|
|
156
|
+
text-overflow: ellipsis;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
:global(.cds--list-box),
|
|
160
|
+
:global(.cds--number),
|
|
161
|
+
:global(.cds--combo-box),
|
|
162
|
+
:global(.cds--list-box__wrapper),
|
|
163
|
+
:global(.cds--list-box__field) {
|
|
164
|
+
width: 100% !important;
|
|
165
|
+
max-width: 100% !important;
|
|
166
|
+
min-width: 0 !important;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.priceDisplay,
|
|
170
|
+
.totalDisplay {
|
|
171
|
+
font-size: 0.875rem;
|
|
172
|
+
font-size: 0.875rem;
|
|
173
|
+
font-weight: 600;
|
|
174
|
+
color: $text-02;
|
|
175
|
+
padding: layout.$spacing-03 0;
|
|
176
|
+
word-break: break-word;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.grandTotal {
|
|
183
|
+
text-align: right;
|
|
184
|
+
padding: layout.$spacing-05;
|
|
185
|
+
border-top: 2px solid $interactive-01;
|
|
186
|
+
margin-top: layout.$spacing-05;
|
|
187
|
+
background-color: $ui-01;
|
|
188
|
+
font-size: 1.125rem;
|
|
189
|
+
font-weight: 600;
|
|
190
|
+
color: $text-02;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@media (max-width: 1056px) {
|
|
195
|
+
.selectedItemsContainer {
|
|
196
|
+
.itemCard {
|
|
197
|
+
.itemControls {
|
|
198
|
+
.controlSection {
|
|
199
|
+
&:nth-child(2) {
|
|
200
|
+
flex: 1 1 100%;
|
|
201
|
+
width: 100%;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
@media (max-width: 768px) {
|
|
210
|
+
.selectedItemsContainer {
|
|
211
|
+
.itemCard {
|
|
212
|
+
padding: layout.$spacing-04;
|
|
213
|
+
|
|
214
|
+
.itemControls {
|
|
215
|
+
flex-direction: column;
|
|
216
|
+
gap: layout.$spacing-03;
|
|
217
|
+
|
|
218
|
+
.controlSection {
|
|
219
|
+
&:first-child,
|
|
220
|
+
&:nth-child(2),
|
|
221
|
+
&:last-child {
|
|
222
|
+
flex: 1 1 100%;
|
|
223
|
+
width: 100%;
|
|
224
|
+
max-width: 100%;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
package/src/billing.resource.ts
CHANGED
|
@@ -3,9 +3,17 @@ import dayjs from 'dayjs';
|
|
|
3
3
|
import isEmpty from 'lodash-es/isEmpty';
|
|
4
4
|
import sortBy from 'lodash-es/sortBy';
|
|
5
5
|
import useSWR from 'swr';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
formatDate,
|
|
8
|
+
parseDate,
|
|
9
|
+
openmrsFetch,
|
|
10
|
+
useSession,
|
|
11
|
+
useVisit,
|
|
12
|
+
type SessionLocation,
|
|
13
|
+
useOpenmrsFetchAll,
|
|
14
|
+
} from '@openmrs/esm-framework';
|
|
7
15
|
import { apiBasePath, omrsDateFormat } from './constants';
|
|
8
|
-
import type {
|
|
16
|
+
import type { MappedBill, PatientInvoice, BillableItem } from './types';
|
|
9
17
|
import SelectedDateContext from './hooks/selectedDateContext';
|
|
10
18
|
|
|
11
19
|
export const useBills = (patientUuid: string = '', billStatus: string = '') => {
|
|
@@ -108,13 +116,9 @@ export const processBillPayment = (payload, billUuid: string) => {
|
|
|
108
116
|
});
|
|
109
117
|
};
|
|
110
118
|
|
|
111
|
-
export function useDefaultFacility() {
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const { data, isLoading } = useSWR<{ data: FacilityDetail }>(authenticated ? url : null, openmrsFetch);
|
|
116
|
-
|
|
117
|
-
return { data: data?.data, isLoading: isLoading };
|
|
119
|
+
export function useDefaultFacility(): { data: SessionLocation | null } {
|
|
120
|
+
const { sessionLocation } = useSession();
|
|
121
|
+
return { data: sessionLocation };
|
|
118
122
|
}
|
|
119
123
|
|
|
120
124
|
export const usePatientPaymentInfo = (patientUuid: string) => {
|
|
@@ -130,16 +134,9 @@ export const usePatientPaymentInfo = (patientUuid: string) => {
|
|
|
130
134
|
return paymentInformation;
|
|
131
135
|
};
|
|
132
136
|
|
|
133
|
-
export function
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
url = `${restBaseUrl}/stockmanagement/stockitem?v=default&limit=10&q=${searchVal}`;
|
|
137
|
-
} else {
|
|
138
|
-
url = `${apiBasePath}billableService?v=custom:(uuid,name,shortName,serviceStatus,serviceType:(display),servicePrices:(uuid,name,price,paymentMode))`;
|
|
139
|
-
}
|
|
140
|
-
const { data, error, isLoading, isValidating } = useSWR(searchVal ? url : null, openmrsFetch, {});
|
|
141
|
-
|
|
142
|
-
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);
|
|
143
140
|
}
|
|
144
141
|
|
|
145
142
|
export const processBillItems = (payload) => {
|
|
@@ -4,91 +4,126 @@ import { render, screen, waitFor } from '@testing-library/react';
|
|
|
4
4
|
import { useBills } from '../billing.resource';
|
|
5
5
|
import BillsTable from './bills-table.component';
|
|
6
6
|
|
|
7
|
-
jest.mock('
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
jest.mock('@openmrs/esm-framework', () => {
|
|
8
|
+
const actual = jest.requireActual('@openmrs/esm-framework');
|
|
9
|
+
return {
|
|
10
|
+
...actual,
|
|
11
|
+
ConfigurableLink: ({ children, to, templateParams }: any) => {
|
|
12
|
+
let resolvedTo = to as string;
|
|
13
|
+
if (templateParams) {
|
|
14
|
+
resolvedTo = resolvedTo
|
|
15
|
+
.replace('${patientUuid}', templateParams.patientUuid)
|
|
16
|
+
.replace('${uuid}', templateParams.uuid)
|
|
17
|
+
.replace('${openmrsSpaBase}', '/openmrs/spa');
|
|
18
|
+
}
|
|
19
|
+
resolvedTo = resolvedTo.replace(/^\/openmrs\/spa/, '');
|
|
20
|
+
return <a href={resolvedTo}>{children}</a>;
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
jest.mock('../billing.resource', () => ({
|
|
26
|
+
useBills: jest.fn(() => ({
|
|
27
|
+
bills: mockBillsData,
|
|
28
|
+
isLoading: false,
|
|
29
|
+
isValidating: false,
|
|
30
|
+
error: null,
|
|
31
|
+
})),
|
|
11
32
|
}));
|
|
12
33
|
|
|
34
|
+
const mockBills = jest.mocked(useBills);
|
|
35
|
+
|
|
13
36
|
const mockBillsData = [
|
|
14
37
|
{
|
|
15
38
|
uuid: '1',
|
|
39
|
+
id: 1,
|
|
16
40
|
patientName: 'John Doe',
|
|
17
41
|
identifier: '12345678',
|
|
18
42
|
visitType: 'Checkup',
|
|
19
43
|
patientUuid: 'uuid1',
|
|
20
44
|
dateCreated: '2024-01-01',
|
|
21
|
-
lineItems: [
|
|
45
|
+
lineItems: [
|
|
46
|
+
{
|
|
47
|
+
uuid: 'line-item-1',
|
|
48
|
+
display: 'Service 1 Line Item',
|
|
49
|
+
voided: false,
|
|
50
|
+
voidReason: null,
|
|
51
|
+
item: 'Service 1',
|
|
52
|
+
billableService: 'Service 1',
|
|
53
|
+
quantity: 1,
|
|
54
|
+
price: 100,
|
|
55
|
+
priceName: 'Standard Price',
|
|
56
|
+
priceUuid: 'price-1',
|
|
57
|
+
lineItemOrder: 1,
|
|
58
|
+
resourceVersion: '1.0',
|
|
59
|
+
paymentStatus: 'PENDING',
|
|
60
|
+
},
|
|
61
|
+
],
|
|
22
62
|
status: 'PENDING',
|
|
63
|
+
cashPointUuid: 'cash-point-1',
|
|
64
|
+
cashPointName: 'Main Cash Point',
|
|
65
|
+
cashPointLocation: 'Main Hospital',
|
|
66
|
+
cashier: { uuid: 'cashier-1', display: 'Jane Cashier', links: [] },
|
|
67
|
+
receiptNumber: 'RCP-001',
|
|
68
|
+
billingService: 'Service 1',
|
|
69
|
+
payments: [],
|
|
70
|
+
totalAmount: 100,
|
|
71
|
+
tenderedAmount: 0,
|
|
23
72
|
},
|
|
24
73
|
{
|
|
25
74
|
uuid: '2',
|
|
75
|
+
id: 2,
|
|
26
76
|
patientName: 'Mary Smith',
|
|
27
77
|
identifier: '98765432',
|
|
28
78
|
visitType: 'Wake up',
|
|
29
79
|
patientUuid: 'uuid2',
|
|
30
80
|
dateCreated: '2024-01-02',
|
|
31
|
-
lineItems: [
|
|
81
|
+
lineItems: [
|
|
82
|
+
{
|
|
83
|
+
uuid: 'line-item-2',
|
|
84
|
+
display: 'Service 2 Line Item',
|
|
85
|
+
voided: false,
|
|
86
|
+
voidReason: null,
|
|
87
|
+
item: 'Service 2',
|
|
88
|
+
billableService: 'Service 2',
|
|
89
|
+
quantity: 1,
|
|
90
|
+
price: 200,
|
|
91
|
+
priceName: 'Standard Price',
|
|
92
|
+
priceUuid: 'price-1',
|
|
93
|
+
lineItemOrder: 1,
|
|
94
|
+
resourceVersion: '1.0',
|
|
95
|
+
paymentStatus: 'PENDING',
|
|
96
|
+
},
|
|
97
|
+
],
|
|
32
98
|
status: 'PENDING',
|
|
99
|
+
cashPointUuid: 'cash-point-1',
|
|
100
|
+
cashPointName: 'Main Cash Point',
|
|
101
|
+
cashPointLocation: 'Main Hospital',
|
|
102
|
+
cashier: { uuid: 'cashier-1', display: 'Jane Cashier', links: [] },
|
|
103
|
+
receiptNumber: 'RCP-002',
|
|
104
|
+
billingService: 'Service 2',
|
|
105
|
+
payments: [],
|
|
106
|
+
totalAmount: 200,
|
|
107
|
+
tenderedAmount: 200,
|
|
33
108
|
},
|
|
34
109
|
];
|
|
35
110
|
|
|
36
|
-
jest.mock('../billing.resource', () => ({
|
|
37
|
-
useBills: jest.fn(() => ({
|
|
38
|
-
bills: mockBillsData,
|
|
39
|
-
isLoading: false,
|
|
40
|
-
isValidating: false,
|
|
41
|
-
error: null,
|
|
42
|
-
})),
|
|
43
|
-
}));
|
|
44
|
-
|
|
45
|
-
jest.mock('@openmrs/esm-patient-common-lib', () => ({
|
|
46
|
-
EmptyDataIllustration: jest.fn(() => <div>Empty state illustration</div>),
|
|
47
|
-
}));
|
|
48
|
-
|
|
49
|
-
jest.mock('@openmrs/esm-framework', () => ({
|
|
50
|
-
useLayoutType: jest.fn(() => 'desktop'),
|
|
51
|
-
isDesktop: jest.fn(() => true),
|
|
52
|
-
ErrorState: jest.fn(({ error }) => <div data-testid="error-state">{error?.message || error}</div>),
|
|
53
|
-
useConfig: jest.fn(() => ({
|
|
54
|
-
bills: {
|
|
55
|
-
pageSizes: [10, 20, 30, 40, 50],
|
|
56
|
-
pageSize: 10,
|
|
57
|
-
},
|
|
58
|
-
})),
|
|
59
|
-
usePagination: jest.fn().mockImplementation((data) => ({
|
|
60
|
-
currentPage: 1,
|
|
61
|
-
goTo: jest.fn(),
|
|
62
|
-
results: data,
|
|
63
|
-
paginated: true,
|
|
64
|
-
})),
|
|
65
|
-
ConfigurableLink: jest.fn(({ children, to, templateParams }) => {
|
|
66
|
-
const resolvedTo = '/home/billing/patient/' + templateParams.patientUuid + '/' + templateParams.uuid;
|
|
67
|
-
return <a href={resolvedTo}>{children}</a>;
|
|
68
|
-
}),
|
|
69
|
-
openmrsSpaBase: '',
|
|
70
|
-
}));
|
|
71
|
-
|
|
72
111
|
describe('BillsTable', () => {
|
|
73
|
-
const mockBills = useBills as jest.Mock;
|
|
74
|
-
let user;
|
|
75
|
-
|
|
76
112
|
beforeEach(() => {
|
|
77
|
-
user = userEvent.setup();
|
|
78
113
|
mockBills.mockImplementation(() => ({
|
|
79
114
|
bills: mockBillsData,
|
|
80
115
|
isLoading: false,
|
|
81
116
|
isValidating: false,
|
|
82
117
|
error: null,
|
|
118
|
+
mutate: jest.fn(),
|
|
83
119
|
}));
|
|
84
120
|
});
|
|
85
121
|
|
|
86
122
|
test('renders data table with pending bills', () => {
|
|
87
123
|
render(<BillsTable />);
|
|
88
124
|
|
|
89
|
-
expect(screen.getByText('
|
|
90
|
-
expect(screen.getByText('
|
|
91
|
-
|
|
125
|
+
expect(screen.getByText('Visit time')).toBeInTheDocument();
|
|
126
|
+
expect(screen.getByText('Identifier')).toBeInTheDocument();
|
|
92
127
|
expect(screen.getByText(/John Doe/)).toBeInTheDocument();
|
|
93
128
|
expect(screen.getByText('12345678')).toBeInTheDocument();
|
|
94
129
|
});
|
|
@@ -99,6 +134,7 @@ describe('BillsTable', () => {
|
|
|
99
134
|
isLoading: false,
|
|
100
135
|
isValidating: false,
|
|
101
136
|
error: null,
|
|
137
|
+
mutate: jest.fn(),
|
|
102
138
|
}));
|
|
103
139
|
|
|
104
140
|
render(<BillsTable />);
|
|
@@ -111,28 +147,33 @@ describe('BillsTable', () => {
|
|
|
111
147
|
isLoading: true,
|
|
112
148
|
isValidating: false,
|
|
113
149
|
error: null,
|
|
150
|
+
mutate: jest.fn(),
|
|
114
151
|
}));
|
|
115
152
|
|
|
116
153
|
render(<BillsTable />);
|
|
154
|
+
|
|
117
155
|
const dataTableSkeleton = screen.getByRole('table');
|
|
118
156
|
expect(dataTableSkeleton).toBeInTheDocument();
|
|
119
157
|
expect(dataTableSkeleton).toHaveClass('cds--skeleton cds--data-table cds--data-table--zebra');
|
|
120
158
|
});
|
|
121
159
|
|
|
122
|
-
test('should display
|
|
160
|
+
test('should display an error state if there is a problem loading bill data', () => {
|
|
123
161
|
mockBills.mockImplementationOnce(() => ({
|
|
124
162
|
bills: undefined,
|
|
125
163
|
isLoading: false,
|
|
126
164
|
isValidating: false,
|
|
127
165
|
error: new Error('Error in fetching data'),
|
|
166
|
+
mutate: jest.fn(),
|
|
128
167
|
}));
|
|
129
168
|
|
|
130
169
|
render(<BillsTable />);
|
|
131
|
-
|
|
170
|
+
|
|
171
|
+
expect(screen.getByText(/error state/i)).toBeInTheDocument();
|
|
132
172
|
expect(screen.queryByRole('table')).not.toBeInTheDocument();
|
|
133
173
|
});
|
|
134
174
|
|
|
135
175
|
test('should filter bills by search term', async () => {
|
|
176
|
+
const user = userEvent.setup();
|
|
136
177
|
render(<BillsTable />);
|
|
137
178
|
|
|
138
179
|
const searchInput = screen.getByRole('searchbox');
|
|
@@ -142,7 +183,6 @@ describe('BillsTable', () => {
|
|
|
142
183
|
expect(screen.getByText('Mary Smith')).toBeInTheDocument();
|
|
143
184
|
|
|
144
185
|
await user.type(searchInput, 'John Doe');
|
|
145
|
-
|
|
146
186
|
await waitFor(() => {
|
|
147
187
|
expect(screen.queryByText('Mary Smith')).not.toBeInTheDocument();
|
|
148
188
|
});
|
|
@@ -160,11 +200,14 @@ describe('BillsTable', () => {
|
|
|
160
200
|
});
|
|
161
201
|
|
|
162
202
|
test('should filter bills by payment status', async () => {
|
|
203
|
+
const user = userEvent.setup();
|
|
204
|
+
|
|
163
205
|
mockBills.mockImplementationOnce(() => ({
|
|
164
206
|
bills: mockBillsData.map((bill) => ({ ...bill, status: 'PENDING' })),
|
|
165
207
|
isLoading: false,
|
|
166
208
|
isValidating: false,
|
|
167
209
|
error: null,
|
|
210
|
+
mutate: jest.fn(),
|
|
168
211
|
}));
|
|
169
212
|
|
|
170
213
|
render(<BillsTable />);
|
|
@@ -175,7 +218,7 @@ describe('BillsTable', () => {
|
|
|
175
218
|
const paidBillsOption = screen.getAllByText('Paid bills')[0];
|
|
176
219
|
await user.click(paidBillsOption);
|
|
177
220
|
|
|
178
|
-
expect(screen.getByText('
|
|
221
|
+
expect(screen.getByText('No matching bills to display')).toBeInTheDocument();
|
|
179
222
|
});
|
|
180
223
|
|
|
181
224
|
test('should show loading state during background updates', () => {
|
|
@@ -184,6 +227,7 @@ describe('BillsTable', () => {
|
|
|
184
227
|
isLoading: false,
|
|
185
228
|
isValidating: true,
|
|
186
229
|
error: null,
|
|
230
|
+
mutate: jest.fn(),
|
|
187
231
|
}));
|
|
188
232
|
|
|
189
233
|
render(<BillsTable />);
|
package/src/config-schema.ts
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
|
-
import { Type } from '@openmrs/esm-framework';
|
|
2
|
-
|
|
3
|
-
export interface BillingConfig {}
|
|
1
|
+
import { Type, validators } from '@openmrs/esm-framework';
|
|
4
2
|
|
|
5
3
|
export const configSchema = {
|
|
4
|
+
logo: {
|
|
5
|
+
src: {
|
|
6
|
+
_type: Type.String,
|
|
7
|
+
_default: '',
|
|
8
|
+
_description: 'The path or URL to the logo image. If set to an empty string, the alt text will be used.',
|
|
9
|
+
_validators: [validators.isUrl],
|
|
10
|
+
},
|
|
11
|
+
alt: {
|
|
12
|
+
_type: Type.String,
|
|
13
|
+
_default: '',
|
|
14
|
+
_description:
|
|
15
|
+
'The alternative text for the logo image, displayed when the image cannot be loaded or on hover. If not provided and src is empty, the default OpenMRS SVG sprite will be used.',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
country: {
|
|
19
|
+
_type: Type.String,
|
|
20
|
+
_description: 'The text that gets printed on the top right of the invoice, typically the name of the country',
|
|
21
|
+
_default: 'Kenya',
|
|
22
|
+
},
|
|
6
23
|
patientCatergory: {
|
|
7
24
|
_type: Type.Object,
|
|
8
25
|
_description: 'Patient Category Custom UUIDs',
|
|
@@ -15,7 +32,6 @@ export const configSchema = {
|
|
|
15
32
|
formPayloadPending: '919b51c9-8e2e-468f-8354-181bf3e55786',
|
|
16
33
|
},
|
|
17
34
|
},
|
|
18
|
-
|
|
19
35
|
catergoryConcepts: {
|
|
20
36
|
_type: Type.Object,
|
|
21
37
|
_description: 'Patient Category Concept UUIDs',
|
|
@@ -25,7 +41,6 @@ export const configSchema = {
|
|
|
25
41
|
insuranceDetails: 'beac329b-f1dc-4a33-9e7c-d95821a137a6',
|
|
26
42
|
},
|
|
27
43
|
},
|
|
28
|
-
|
|
29
44
|
nonPayingPatientCategories: {
|
|
30
45
|
_type: Type.Object,
|
|
31
46
|
_description: 'Concept UUIDs for non-paying patient categories',
|
|
@@ -34,7 +49,6 @@ export const configSchema = {
|
|
|
34
49
|
student: '159465AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
35
50
|
},
|
|
36
51
|
},
|
|
37
|
-
|
|
38
52
|
postBilledItems: {
|
|
39
53
|
_type: Type.Object,
|
|
40
54
|
_description: 'Post Bill Items such as cashPoints, cashier, priceUUid when submitting a bill',
|
|
@@ -44,7 +58,6 @@ export const configSchema = {
|
|
|
44
58
|
priceUuid: '7b9171ac-d3c1-49b4-beff-c9902aee5245',
|
|
45
59
|
},
|
|
46
60
|
},
|
|
47
|
-
|
|
48
61
|
serviceTypes: {
|
|
49
62
|
_type: Type.Object,
|
|
50
63
|
_description: 'Post Bill Items such as cashPoints, cashier, priceUUid when submitting a bill',
|
|
@@ -52,34 +65,49 @@ export const configSchema = {
|
|
|
52
65
|
billableService: '21b8cf43-9f9f-4d02-9f4a-d710ece54261',
|
|
53
66
|
},
|
|
54
67
|
},
|
|
55
|
-
|
|
56
68
|
defaultCurrency: {
|
|
57
69
|
_type: Type.String,
|
|
58
70
|
_description: 'The default currency for the application. Specify the currency code (e.g., KES, UGX, GBP).',
|
|
59
71
|
_default: 'KES',
|
|
60
72
|
},
|
|
61
|
-
|
|
62
73
|
pageSize: {
|
|
63
74
|
_type: Type.Number,
|
|
64
75
|
_description: 'The default page size',
|
|
65
76
|
_default: 10,
|
|
66
77
|
},
|
|
67
|
-
|
|
68
|
-
showEditBillButton: {
|
|
69
|
-
_type: Type.Boolean,
|
|
70
|
-
_description: 'Whether to show the edit bill button or not.',
|
|
71
|
-
_default: false,
|
|
72
|
-
},
|
|
73
78
|
};
|
|
74
79
|
|
|
75
|
-
export interface
|
|
76
|
-
|
|
80
|
+
export interface BillingConfig {
|
|
81
|
+
logo: {
|
|
82
|
+
src: string;
|
|
83
|
+
alt: string;
|
|
84
|
+
};
|
|
85
|
+
country: string;
|
|
86
|
+
patientCatergory: {
|
|
87
|
+
paymentDetails: string;
|
|
88
|
+
paymentMethods: string;
|
|
89
|
+
policyNumber: string;
|
|
90
|
+
insuranceScheme: string;
|
|
91
|
+
patientCategory: string;
|
|
92
|
+
formPayloadPending: string;
|
|
93
|
+
};
|
|
94
|
+
catergoryConcepts: {
|
|
95
|
+
payingDetails: string;
|
|
96
|
+
nonPayingDetails: string;
|
|
97
|
+
insuranceDetails: string;
|
|
98
|
+
};
|
|
99
|
+
nonPayingPatientCategories: {
|
|
100
|
+
childUnder5: string;
|
|
101
|
+
student: string;
|
|
102
|
+
};
|
|
103
|
+
postBilledItems: {
|
|
104
|
+
cashPoint: string;
|
|
105
|
+
cashier: string;
|
|
106
|
+
priceUuid: string;
|
|
107
|
+
};
|
|
108
|
+
serviceTypes: {
|
|
109
|
+
billableService: string;
|
|
110
|
+
};
|
|
77
111
|
defaultCurrency: string;
|
|
78
|
-
|
|
79
|
-
pageSize;
|
|
80
|
-
object;
|
|
81
|
-
showEditBillButton: boolean;
|
|
82
|
-
postBilledItems: Object;
|
|
83
|
-
serviceTypes: Object;
|
|
84
|
-
nonPayingPatientCategories: Object;
|
|
112
|
+
pageSize: number;
|
|
85
113
|
}
|
package/src/dashboard.meta.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { type DashboardLinkConfig } from '@openmrs/esm-patient-common-lib';
|
|
2
|
+
|
|
3
|
+
export const dashboardMeta: DashboardLinkConfig & { slot: string; columns: number; hideDashboardTitle: boolean } = {
|
|
2
4
|
slot: 'patient-chart-billing-dashboard-slot',
|
|
3
5
|
columns: 1,
|
|
4
6
|
title: 'Billing history',
|
|
5
7
|
hideDashboardTitle: true,
|
|
6
|
-
icon: '',
|
|
8
|
+
icon: 'omrs-icon-money',
|
|
7
9
|
path: 'Billing history',
|
|
8
10
|
};
|
package/src/helpers/functions.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getCoreTranslation } from '@openmrs/esm-framework';
|
|
1
2
|
import { type Payment, type LineItem } from '../types';
|
|
2
3
|
|
|
3
4
|
// amount already paid
|
|
@@ -51,13 +52,13 @@ export const convertToCurrency = (amountToConvert: number, currencyType?: string
|
|
|
51
52
|
export const getGender = (gender: string, t) => {
|
|
52
53
|
switch (gender) {
|
|
53
54
|
case 'male':
|
|
54
|
-
return
|
|
55
|
+
return getCoreTranslation('male');
|
|
55
56
|
case 'female':
|
|
56
|
-
return
|
|
57
|
+
return getCoreTranslation('female');
|
|
57
58
|
case 'other':
|
|
58
|
-
return
|
|
59
|
+
return getCoreTranslation('other');
|
|
59
60
|
case 'unknown':
|
|
60
|
-
return
|
|
61
|
+
return getCoreTranslation('unknown');
|
|
61
62
|
default:
|
|
62
63
|
return gender;
|
|
63
64
|
}
|
package/src/index.ts
CHANGED
|
@@ -3,12 +3,17 @@ import { createDashboardLink } from '@openmrs/esm-patient-common-lib';
|
|
|
3
3
|
import { createLeftPanelLink } from './left-panel-link.component';
|
|
4
4
|
import { dashboardMeta } from './dashboard.meta';
|
|
5
5
|
import { defineConfigSchema, getAsyncLifecycle, getSyncLifecycle } from '@openmrs/esm-framework';
|
|
6
|
+
import AddCashPointModal from './billable-services/cash-point/add-cash-point.modal';
|
|
7
|
+
import AddPaymentModeModal from './billable-services/payment-modes/add-payment-mode.modal';
|
|
6
8
|
import appMenu from './billable-services/billable-services-menu-item/item.component';
|
|
7
9
|
import BillableServiceHome from './billable-services/billable-services-home.component';
|
|
8
10
|
import BillableServicesCardLink from './billable-services-admin-card-link.component';
|
|
9
11
|
import BillHistory from './bill-history/bill-history.component';
|
|
10
12
|
import BillingCheckInForm from './billing-form/billing-checkin-form.component';
|
|
11
|
-
import
|
|
13
|
+
import DeletePaymentModeModal from './billable-services/payment-modes/delete-payment-mode.modal';
|
|
14
|
+
import EditBillableServiceModal from './billable-services/create-edit/edit-billable-service.modal';
|
|
15
|
+
import EditBillLineItemModal from './bill-item-actions/edit-bill-item.modal';
|
|
16
|
+
import RequirePaymentModal from './modal/require-payment.modal';
|
|
12
17
|
import RootComponent from './root.component';
|
|
13
18
|
import ServiceMetrics from './billable-services/dashboard/service-metrics.component';
|
|
14
19
|
import VisitAttributeTags from './invoice/payments/visit-tags/visit-attribute.component';
|
|
@@ -35,6 +40,7 @@ export function startupApp() {
|
|
|
35
40
|
defineConfigSchema(moduleName, configSchema);
|
|
36
41
|
}
|
|
37
42
|
|
|
43
|
+
// t('billingHistory', 'Billing History')
|
|
38
44
|
export const billingSummaryDashboardLink = getSyncLifecycle(
|
|
39
45
|
createDashboardLink({ ...dashboardMeta, moduleName }),
|
|
40
46
|
options,
|
|
@@ -52,16 +58,21 @@ export const billingPatientSummary = getSyncLifecycle(BillHistory, options);
|
|
|
52
58
|
|
|
53
59
|
export const requirePaymentModal = getSyncLifecycle(RequirePaymentModal, options);
|
|
54
60
|
|
|
61
|
+
export const addPaymentModeModal = getSyncLifecycle(AddPaymentModeModal, options);
|
|
62
|
+
|
|
63
|
+
export const deletePaymentModeModal = getSyncLifecycle(DeletePaymentModeModal, options);
|
|
64
|
+
|
|
65
|
+
export const addCashPointModal = getSyncLifecycle(AddCashPointModal, options);
|
|
66
|
+
|
|
67
|
+
export const editBillableServiceModal = getSyncLifecycle(EditBillableServiceModal, options);
|
|
68
|
+
|
|
69
|
+
export const editBillLineItemModal = getSyncLifecycle(EditBillLineItemModal, options);
|
|
70
|
+
|
|
55
71
|
export const root = getSyncLifecycle(RootComponent, options);
|
|
56
72
|
|
|
57
73
|
export const serviceMetrics = getSyncLifecycle(ServiceMetrics, options);
|
|
58
74
|
|
|
59
75
|
export const visitAttributeTags = getSyncLifecycle(VisitAttributeTags, options);
|
|
60
76
|
|
|
61
|
-
export const editBillLineItemDialog = getAsyncLifecycle(() => import('./bill-item-actions/edit-bill-item.component'), {
|
|
62
|
-
featureName: 'edit bill line item',
|
|
63
|
-
moduleName,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
77
|
// t('billingForm', 'Billing form')
|
|
67
78
|
export const billingFormWorkspace = getAsyncLifecycle(() => import('./billing-form/billing-form.component'), options);
|