@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.
Files changed (37) hide show
  1. package/.turbo/turbo-build.log +65 -58
  2. package/dist/300.js +1 -1
  3. package/dist/{475.js → 548.js} +1 -1
  4. package/dist/548.js.map +1 -0
  5. package/dist/kenyaemr-esm-billing-app.js +1 -1
  6. package/dist/kenyaemr-esm-billing-app.js.buildmanifest.json +26 -26
  7. package/dist/kenyaemr-esm-billing-app.js.map +1 -1
  8. package/dist/main.js +2 -2
  9. package/dist/main.js.map +1 -1
  10. package/dist/routes.json +1 -1
  11. package/package.json +1 -1
  12. package/src/benefits-package/forms/package-interventions.component.tsx +11 -16
  13. package/src/billable-services/bill-manager/modals/create-bill-item-modal.component.tsx +208 -0
  14. package/src/billable-services/bill-manager/modals/create-bill-item-modal.scss +26 -0
  15. package/src/billable-services/bill-manager/modals/refund-bill.modal.tsx +1 -1
  16. package/src/billable-services/bill-manager/workspaces/edit-bill/edit-bill-form.workspace.tsx +1 -1
  17. package/src/billable-services/bill-manager/workspaces/waive-bill/waive-bill-form.workspace.tsx +1 -1
  18. package/src/billable-services/billable-exemptions/billable-exemptions-viewer.component.tsx +12 -9
  19. package/src/billable-services/billable-service.resource.tsx +1 -1
  20. package/src/billable-services/billables/commodity/commodity-form.workspace.tsx +1 -1
  21. package/src/billable-services/billables/services/service-form.workspace.tsx +1 -1
  22. package/src/billable-services/billiable-item/drug-order/drug-order.component.tsx +0 -1
  23. package/src/billable-services/billiable-item/test-order/test-order-action.component.tsx +56 -13
  24. package/src/billable-services/billiable-item/test-order/test-order-action.resource.tsx +14 -3
  25. package/src/billable-services/billiable-item/test-order/test-order-action.test.tsx +51 -2
  26. package/src/billable-services/billiable-item/useBillableItem.tsx +16 -1
  27. package/src/billing-form/visit-attributes/visit-attributes-form.component.tsx +9 -3
  28. package/src/billing.resource.ts +1 -0
  29. package/src/claims/claims-management/main/claims-pre-auth-main.component.tsx +1 -1
  30. package/src/claims/claims-management/table/claims-list-table.component.tsx +1 -1
  31. package/src/claims/dashboard/form/claims-form.component.tsx +16 -15
  32. package/src/index.ts +3 -1
  33. package/src/invoice/invoice.component.tsx +1 -1
  34. package/src/invoice/payments/payment-form/payment-form.component.tsx +3 -5
  35. package/src/routes.json +4 -0
  36. package/translations/en.json +3 -0
  37. 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').mockReturnValueOnce({ isLoading: true, hasPendingPayment: false });
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').mockReturnValueOnce({ isLoading: false, hasPendingPayment: false });
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
- watch('policyNumber'),
59
- watch('exemptionCategory'),
60
- watch('insuranceScheme'),
64
+ policyNumber,
65
+ exemptionCategory,
66
+ insuranceScheme,
61
67
  ]);
62
68
 
63
69
  if (isLoadingPaymentModes) {
@@ -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
  )
@@ -20,7 +20,7 @@ const ClaimsManagementPreAuthRequest = () => {
20
20
  { value: 'cancelled', label: t('cancelled', 'Cancelled') },
21
21
  { value: 'entered-in-error', label: t('enteredInError', 'Entered in error') },
22
22
  ],
23
- [],
23
+ [t],
24
24
  );
25
25
 
26
26
  return (
@@ -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()).nonempty({ message: 'At least one intervention is required' }),
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 selectedPackageObservable = form.watch('package');
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={(e) => {
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
- {selectedPackageObservable && (
315
- <Column>
316
- <Layer className={styles.input}>
317
- <PackageInterventions
318
- category={packages.find((package_) => package_.uuid === selectedPackageObservable)?.packageCode ?? ''}
319
- patientUuid={patientUuid}
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?.length]);
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
- append({ method: null, amount: 0, referenceCode: '' });
37
- setFocus(`payment.${fields.length}.method`);
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
@@ -302,6 +302,10 @@
302
302
  {
303
303
  "name": "clock-in-modal",
304
304
  "component": "clockIn"
305
+ },
306
+ {
307
+ "name": "create-bill-item-modal",
308
+ "component": "createBillItemModal"
305
309
  }
306
310
  ]
307
311
  }
@@ -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",