@kenyaemr/esm-billing-app 5.4.1-pre.1801 → 5.4.1-pre.1821
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 +65 -58
- package/dist/300.js +1 -1
- package/dist/{475.js → 548.js} +1 -1
- package/dist/548.js.map +1 -0
- package/dist/kenyaemr-esm-billing-app.js +1 -1
- package/dist/kenyaemr-esm-billing-app.js.buildmanifest.json +26 -26
- package/dist/kenyaemr-esm-billing-app.js.map +1 -1
- package/dist/main.js +2 -2
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/benefits-package/forms/package-interventions.component.tsx +11 -16
- package/src/billable-services/bill-manager/modals/create-bill-item-modal.component.tsx +208 -0
- package/src/billable-services/bill-manager/modals/create-bill-item-modal.scss +26 -0
- package/src/billable-services/bill-manager/modals/refund-bill.modal.tsx +1 -1
- package/src/billable-services/bill-manager/workspaces/edit-bill/edit-bill-form.workspace.tsx +1 -1
- package/src/billable-services/bill-manager/workspaces/waive-bill/waive-bill-form.workspace.tsx +1 -1
- package/src/billable-services/billable-exemptions/billable-exemptions-viewer.component.tsx +12 -9
- package/src/billable-services/billable-service.resource.tsx +1 -1
- package/src/billable-services/billables/commodity/commodity-form.workspace.tsx +1 -1
- package/src/billable-services/billables/services/service-form.workspace.tsx +1 -1
- package/src/billable-services/billiable-item/drug-order/drug-order.component.tsx +0 -1
- package/src/billable-services/billiable-item/test-order/test-order-action.component.tsx +56 -13
- package/src/billable-services/billiable-item/test-order/test-order-action.resource.tsx +14 -3
- package/src/billable-services/billiable-item/test-order/test-order-action.test.tsx +51 -2
- package/src/billable-services/billiable-item/useBillableItem.tsx +16 -1
- package/src/billing-form/visit-attributes/visit-attributes-form.component.tsx +9 -3
- package/src/billing.resource.ts +1 -0
- package/src/claims/claims-management/main/claims-pre-auth-main.component.tsx +1 -1
- package/src/claims/claims-management/table/claims-list-table.component.tsx +1 -1
- package/src/claims/dashboard/form/claims-form.component.tsx +16 -15
- package/src/index.ts +3 -1
- package/src/invoice/invoice.component.tsx +1 -1
- package/src/invoice/payments/payment-form/payment-form.component.tsx +3 -5
- package/src/routes.json +4 -0
- package/translations/en.json +3 -0
- package/dist/475.js.map +0 -1
|
@@ -6,8 +6,12 @@ import * as resource from './test-order-action.resource';
|
|
|
6
6
|
import userEvent from '@testing-library/user-event';
|
|
7
7
|
import { launchWorkspace, showModal } from '@openmrs/esm-framework';
|
|
8
8
|
import { createMedicationDispenseProps } from './dispense.resource';
|
|
9
|
+
import { useStockItemQuantity } from '../useBillableItem';
|
|
9
10
|
|
|
10
11
|
jest.mock('./test-order-action.resource');
|
|
12
|
+
jest.mock('../useBillableItem', () => ({
|
|
13
|
+
useStockItemQuantity: jest.fn(),
|
|
14
|
+
}));
|
|
11
15
|
|
|
12
16
|
const mockTestProps = {
|
|
13
17
|
order: { uuid: '123', patient: { uuid: '456' } } as Order,
|
|
@@ -75,13 +79,31 @@ describe('TestOrderAction', () => {
|
|
|
75
79
|
});
|
|
76
80
|
|
|
77
81
|
test('should render loading when isLoading is true', () => {
|
|
78
|
-
jest.spyOn(resource, 'useTestOrderBillStatus').
|
|
82
|
+
jest.spyOn(resource, 'useTestOrderBillStatus').mockReturnValue({ isLoading: true, hasPendingPayment: false });
|
|
83
|
+
jest.spyOn(resource, 'useOrderBill').mockReturnValue({
|
|
84
|
+
itemHasBill: [],
|
|
85
|
+
});
|
|
86
|
+
(useStockItemQuantity as jest.Mock).mockReturnValue({
|
|
87
|
+
stockItemQuantity: 5,
|
|
88
|
+
stockItemUuid: 'some-uuid',
|
|
89
|
+
isLoading: false,
|
|
90
|
+
error: undefined,
|
|
91
|
+
});
|
|
79
92
|
render(<TestOrderAction {...testProps} />);
|
|
80
93
|
expect(screen.getByText('Verifying bill status...')).toBeInTheDocument();
|
|
81
94
|
});
|
|
82
95
|
|
|
83
96
|
test("should display `Unsettled bill for test` when there's a pending payment", () => {
|
|
84
97
|
jest.spyOn(resource, 'useTestOrderBillStatus').mockReturnValueOnce({ isLoading: false, hasPendingPayment: true });
|
|
98
|
+
jest.spyOn(resource, 'useOrderBill').mockReturnValueOnce({
|
|
99
|
+
itemHasBill: [],
|
|
100
|
+
});
|
|
101
|
+
(useStockItemQuantity as jest.Mock).mockReturnValueOnce({
|
|
102
|
+
stockItemQuantity: 5,
|
|
103
|
+
stockItemUuid: 'some-uuid',
|
|
104
|
+
isLoading: false,
|
|
105
|
+
error: undefined,
|
|
106
|
+
});
|
|
85
107
|
render(<TestOrderAction {...testProps} />);
|
|
86
108
|
expect(screen.getByText('Unsettled bill')).toBeInTheDocument();
|
|
87
109
|
});
|
|
@@ -89,6 +111,15 @@ describe('TestOrderAction', () => {
|
|
|
89
111
|
test("should display `Pick Lab Request` when there's no pending payment", async () => {
|
|
90
112
|
const user = userEvent.setup();
|
|
91
113
|
jest.spyOn(resource, 'useTestOrderBillStatus').mockReturnValueOnce({ isLoading: false, hasPendingPayment: false });
|
|
114
|
+
jest.spyOn(resource, 'useOrderBill').mockReturnValueOnce({
|
|
115
|
+
itemHasBill: [],
|
|
116
|
+
});
|
|
117
|
+
(useStockItemQuantity as jest.Mock).mockReturnValueOnce({
|
|
118
|
+
stockItemQuantity: 5,
|
|
119
|
+
stockItemUuid: 'some-uuid',
|
|
120
|
+
isLoading: false,
|
|
121
|
+
error: undefined,
|
|
122
|
+
});
|
|
92
123
|
render(<TestOrderAction {...testProps} />);
|
|
93
124
|
const pickLabRequestMenuItem = screen.getByText('Pick Lab Request');
|
|
94
125
|
await user.click(pickLabRequestMenuItem);
|
|
@@ -101,7 +132,16 @@ describe('TestOrderAction', () => {
|
|
|
101
132
|
});
|
|
102
133
|
|
|
103
134
|
test('should not render the dispense form if closeable is false', () => {
|
|
104
|
-
jest.spyOn(resource, 'useTestOrderBillStatus').
|
|
135
|
+
jest.spyOn(resource, 'useTestOrderBillStatus').mockReturnValue({ isLoading: false, hasPendingPayment: false });
|
|
136
|
+
jest.spyOn(resource, 'useOrderBill').mockReturnValue({
|
|
137
|
+
itemHasBill: [],
|
|
138
|
+
});
|
|
139
|
+
(useStockItemQuantity as jest.Mock).mockReturnValue({
|
|
140
|
+
stockItemQuantity: 5,
|
|
141
|
+
stockItemUuid: 'some-uuid',
|
|
142
|
+
isLoading: false,
|
|
143
|
+
error: undefined,
|
|
144
|
+
});
|
|
105
145
|
render(<TestOrderAction {...testProps} closeable={false} />);
|
|
106
146
|
expect(screen.queryByText('Dispense')).not.toBeInTheDocument();
|
|
107
147
|
});
|
|
@@ -109,6 +149,15 @@ describe('TestOrderAction', () => {
|
|
|
109
149
|
test('should launch the dispense form when dispense order is part of props', async () => {
|
|
110
150
|
const user = userEvent.setup();
|
|
111
151
|
jest.spyOn(resource, 'useTestOrderBillStatus').mockReturnValueOnce({ isLoading: false, hasPendingPayment: false });
|
|
152
|
+
jest.spyOn(resource, 'useOrderBill').mockReturnValueOnce({
|
|
153
|
+
itemHasBill: [],
|
|
154
|
+
});
|
|
155
|
+
(useStockItemQuantity as jest.Mock).mockReturnValueOnce({
|
|
156
|
+
stockItemQuantity: 5,
|
|
157
|
+
stockItemUuid: 'some-uuid',
|
|
158
|
+
isLoading: false,
|
|
159
|
+
error: undefined,
|
|
160
|
+
});
|
|
112
161
|
render(<TestOrderAction {...mockTestProps} />);
|
|
113
162
|
const dispenseButton = screen.getByRole('button', { name: 'Dispense' });
|
|
114
163
|
expect(dispenseButton).toBeInTheDocument();
|
|
@@ -39,10 +39,25 @@ export const useSockItemInventory = (stockItemId: string) => {
|
|
|
39
39
|
const { data, error, isLoading } = useSWR<{
|
|
40
40
|
data: { results: Array<{ quantityUoM: string; quantity: number; partyName: string }> };
|
|
41
41
|
}>(url, openmrsFetch);
|
|
42
|
-
|
|
43
42
|
return {
|
|
44
43
|
stockItem: (data?.data?.results as Array<any>) ?? [],
|
|
45
44
|
isLoading: isLoading,
|
|
46
45
|
error,
|
|
47
46
|
};
|
|
48
47
|
};
|
|
48
|
+
|
|
49
|
+
export const useStockItemQuantity = (drugUuid: string) => {
|
|
50
|
+
const url = `/ws/rest/v1/stockmanagement/stockiteminventory?v=default&limit=10&totalCount=true&drugUuid=${drugUuid}`;
|
|
51
|
+
const { data, error, isLoading } = useSWR<{
|
|
52
|
+
data: {
|
|
53
|
+
results: Array<{ quantityUoM: string; quantity: number; partyName: string; stockItemUuid: string }>;
|
|
54
|
+
total: number;
|
|
55
|
+
};
|
|
56
|
+
}>(url, openmrsFetch);
|
|
57
|
+
return {
|
|
58
|
+
stockItemQuantity: data?.data?.total ?? 0,
|
|
59
|
+
stockItemUuid: data?.data?.results[0]?.stockItemUuid ?? '',
|
|
60
|
+
isLoading: isLoading,
|
|
61
|
+
error,
|
|
62
|
+
};
|
|
63
|
+
};
|
|
@@ -48,6 +48,12 @@ const VisitAttributesForm: React.FC<VisitAttributesFormProps> = ({ setAttributes
|
|
|
48
48
|
}));
|
|
49
49
|
}, [visitAttributeTypes, getValues]);
|
|
50
50
|
|
|
51
|
+
const [policyNumber, exemptionCategory, insuranceScheme] = watch([
|
|
52
|
+
'policyNumber',
|
|
53
|
+
'exemptionCategory',
|
|
54
|
+
'insuranceScheme',
|
|
55
|
+
]);
|
|
56
|
+
|
|
51
57
|
useEffect(() => {
|
|
52
58
|
setAttributes(createVisitAttributesPayload());
|
|
53
59
|
}, [
|
|
@@ -55,9 +61,9 @@ const VisitAttributesForm: React.FC<VisitAttributesFormProps> = ({ setAttributes
|
|
|
55
61
|
paymentMethods,
|
|
56
62
|
setAttributes,
|
|
57
63
|
createVisitAttributesPayload,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
64
|
+
policyNumber,
|
|
65
|
+
exemptionCategory,
|
|
66
|
+
insuranceScheme,
|
|
61
67
|
]);
|
|
62
68
|
|
|
63
69
|
if (isLoadingPaymentModes) {
|
package/src/billing.resource.ts
CHANGED
|
@@ -275,6 +275,7 @@ export const billingFormSchema = z.object({
|
|
|
275
275
|
priceName: z.string().optional().default('Default'),
|
|
276
276
|
priceUuid: z.string().uuid(),
|
|
277
277
|
lineItemOrder: z.number().optional().default(0),
|
|
278
|
+
order: z.string().optional().default(''),
|
|
278
279
|
paymentStatus: z.enum(['PENDING']),
|
|
279
280
|
}),
|
|
280
281
|
)
|
|
@@ -37,7 +37,7 @@ const ClaimsManagementTable: React.FC = () => {
|
|
|
37
37
|
{ value: 'CHECKED', label: t('checked', 'Checked') },
|
|
38
38
|
{ value: 'VALUATED', label: t('valuated', 'Valuated') },
|
|
39
39
|
],
|
|
40
|
-
[],
|
|
40
|
+
[t],
|
|
41
41
|
);
|
|
42
42
|
const [pageSize, setPageSize] = useState(5);
|
|
43
43
|
const filterClaims = (claim) => {
|
|
@@ -45,7 +45,9 @@ const ClaimsFormSchema = z.object({
|
|
|
45
45
|
treatmentStart: z.string().nonempty({ message: 'Treatment start date is required' }),
|
|
46
46
|
treatmentEnd: z.string().nonempty({ message: 'Treatment end date is required' }),
|
|
47
47
|
package: z.string().min(1, 'Package Required'),
|
|
48
|
-
interventions: z.array(z.string()).
|
|
48
|
+
interventions: z.array(z.string()).min(1, {
|
|
49
|
+
message: 'At least one intervention is required',
|
|
50
|
+
}),
|
|
49
51
|
provider: z.string().nonempty({ message: 'provider is provider' }),
|
|
50
52
|
});
|
|
51
53
|
|
|
@@ -97,6 +99,11 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
97
99
|
reset,
|
|
98
100
|
} = form;
|
|
99
101
|
|
|
102
|
+
const handleInterventionsChange = (e: { selectedItem: string }) => {
|
|
103
|
+
form.setValue('interventions', []);
|
|
104
|
+
setValue('package', e.selectedItem);
|
|
105
|
+
};
|
|
106
|
+
|
|
100
107
|
const onSubmit = async (data: z.infer<typeof ClaimsFormSchema>) => {
|
|
101
108
|
setLoading(true);
|
|
102
109
|
const providedItems = selectedLineItems.reduce((acc, item) => {
|
|
@@ -163,7 +170,7 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
163
170
|
setLoading(false);
|
|
164
171
|
}
|
|
165
172
|
};
|
|
166
|
-
const
|
|
173
|
+
const selectedPackage = packages.find((package_) => package_.uuid === form.watch('package'))?.packageCode ?? '';
|
|
167
174
|
|
|
168
175
|
useEffect(() => {
|
|
169
176
|
setValue('diagnoses', diagnoses?.map((d) => d.id) ?? ([] as any));
|
|
@@ -297,9 +304,7 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
297
304
|
invalidText={form.formState.errors[field.name]?.message}
|
|
298
305
|
id="package"
|
|
299
306
|
titleText={t('package', 'Package')}
|
|
300
|
-
onChange={
|
|
301
|
-
field.onChange(e.selectedItem);
|
|
302
|
-
}}
|
|
307
|
+
onChange={handleInterventionsChange}
|
|
303
308
|
initialSelectedItem={field.value}
|
|
304
309
|
label="Choose package"
|
|
305
310
|
items={packages.map((r) => r.uuid)}
|
|
@@ -311,16 +316,12 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
|
|
|
311
316
|
/>
|
|
312
317
|
</Layer>
|
|
313
318
|
</Column>
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
/>
|
|
321
|
-
</Layer>
|
|
322
|
-
</Column>
|
|
323
|
-
)}
|
|
319
|
+
|
|
320
|
+
<Column>
|
|
321
|
+
<Layer className={styles.input}>
|
|
322
|
+
<PackageInterventions key={selectedPackage} category={selectedPackage} patientUuid={patientUuid} />
|
|
323
|
+
</Layer>
|
|
324
|
+
</Column>
|
|
324
325
|
|
|
325
326
|
<Column>
|
|
326
327
|
<Layer className={styles.input}>
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineConfigSchema, getSyncLifecycle, registerFeatureFlag } from '@openmrs/esm-framework';
|
|
1
|
+
import { defineConfigSchema, getAsyncLifecycle, getSyncLifecycle, registerFeatureFlag } from '@openmrs/esm-framework';
|
|
2
2
|
import { createDashboardGroup, createDashboardLink } from '@openmrs/esm-patient-common-lib';
|
|
3
3
|
import BenefitsPackage from './benefits-package/benefits-package.component';
|
|
4
4
|
import Benefits from './benefits-package/benefits/benefits.component';
|
|
@@ -12,6 +12,7 @@ import WaiveBillActionButton from './billable-services/bill-manager/bill-actions
|
|
|
12
12
|
import { DeleteBillModal } from './billable-services/bill-manager/modals/delete-bill.modal';
|
|
13
13
|
import { RefundBillModal } from './billable-services/bill-manager/modals/refund-bill.modal';
|
|
14
14
|
import { DeleteBillableServiceModal } from './billable-services/bill-manager/modals/serviceItemCard.component';
|
|
15
|
+
import CreateBillItemModal from './billable-services/bill-manager/modals/create-bill-item-modal.component';
|
|
15
16
|
import CancelBillWorkspace from './billable-services/bill-manager/workspaces/cancel-bill/cancel-bill.workspace';
|
|
16
17
|
import { EditBillForm } from './billable-services/bill-manager/workspaces/edit-bill/edit-bill-form.workspace';
|
|
17
18
|
import { WaiveBillForm } from './billable-services/bill-manager/workspaces/waive-bill/waive-bill-form.workspace';
|
|
@@ -156,6 +157,7 @@ export const root = getSyncLifecycle(rootComponent, options);
|
|
|
156
157
|
export const billingPatientSummary = getSyncLifecycle(BillHistory, options);
|
|
157
158
|
export const billingCheckInForm = getSyncLifecycle(BillingCheckInForm, options);
|
|
158
159
|
export const deleteBillableServiceModal = getSyncLifecycle(DeleteBillableServiceModal, options);
|
|
160
|
+
export const createBillItemModal = getSyncLifecycle(CreateBillItemModal, options);
|
|
159
161
|
|
|
160
162
|
export const billingForm = getSyncLifecycle(BillingForm, options);
|
|
161
163
|
export const requirePaymentModal = getSyncLifecycle(RequirePaymentModal, options);
|
|
@@ -85,7 +85,7 @@ const Invoice: React.FC = () => {
|
|
|
85
85
|
useEffect(() => {
|
|
86
86
|
const paidLineItems = bill?.lineItems?.filter((item) => item.paymentStatus === 'PAID') ?? [];
|
|
87
87
|
setSelectedLineItems(paidLineItems);
|
|
88
|
-
}, [bill?.lineItems
|
|
88
|
+
}, [bill?.lineItems]);
|
|
89
89
|
|
|
90
90
|
const invoiceDetails = {
|
|
91
91
|
'Total Amount': convertToCurrency(bill?.totalAmount),
|
|
@@ -32,11 +32,9 @@ const PaymentForm: React.FC<PaymentFormProps> = ({ disablePayment, amountDue, ap
|
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
const handleAppendPaymentMode = useCallback(() => {
|
|
35
|
-
{
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
}, [append]);
|
|
35
|
+
append({ method: null, amount: 0, referenceCode: '' });
|
|
36
|
+
setFocus(`payment.${fields.length}.method`);
|
|
37
|
+
}, [append, fields.length, setFocus]);
|
|
40
38
|
|
|
41
39
|
const handleRemovePaymentMode = useCallback((index) => remove(index), [remove]);
|
|
42
40
|
|
package/src/routes.json
CHANGED
package/translations/en.json
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"attributeRetired": "Attribute retired",
|
|
23
23
|
"attributeRetiredReason": "Attribute retired reason",
|
|
24
24
|
"benefits": "Benefits",
|
|
25
|
+
"bill": "Bill",
|
|
25
26
|
"billableExemptionAdministration": "Exemption Administration",
|
|
26
27
|
"billableServicesError": "Billable services error",
|
|
27
28
|
"billAmount": "Bill Amount",
|
|
@@ -55,6 +56,7 @@
|
|
|
55
56
|
"chargeItemsDescription": "Charge Items and Services Dashboard",
|
|
56
57
|
"checked": "Checked",
|
|
57
58
|
"checkFilters": "Check the filters above",
|
|
59
|
+
"chooseInterventions": "Choose interventions",
|
|
58
60
|
"claim": "Process claims",
|
|
59
61
|
"claimCode": "Claim Code",
|
|
60
62
|
"claimedAmount": "Claimed Amount",
|
|
@@ -176,6 +178,7 @@
|
|
|
176
178
|
"noTransactionHistory": "No transaction history",
|
|
177
179
|
"noTransactionHistorySubtitle": "No transaction history loaded for the selected filters",
|
|
178
180
|
"notSearchedState": "Please search for a patient in the input above",
|
|
181
|
+
"outOfStock": "Out of Stock",
|
|
179
182
|
"overflowMenu": "Overflow menu",
|
|
180
183
|
"overPayment": "Over payment",
|
|
181
184
|
"overPaymentSubtitle": "Amount paid {{totalAmountTendered}} should not be greater than amount due {{selectedLineItemsAmountDue}} for selected line items",
|