@kenyaemr/esm-billing-app 5.4.1-pre.1935 → 5.4.1-pre.1941

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 (49) hide show
  1. package/.turbo/turbo-build.log +70 -70
  2. package/dist/22.js +1 -0
  3. package/dist/22.js.map +1 -0
  4. package/dist/300.js +1 -1
  5. package/dist/423.js +1 -0
  6. package/dist/423.js.map +1 -0
  7. package/dist/917.js +2 -0
  8. package/dist/917.js.map +1 -0
  9. package/dist/kenyaemr-esm-billing-app.js +1 -1
  10. package/dist/kenyaemr-esm-billing-app.js.buildmanifest.json +84 -84
  11. package/dist/kenyaemr-esm-billing-app.js.map +1 -1
  12. package/dist/main.js +2 -2
  13. package/dist/main.js.map +1 -1
  14. package/dist/routes.json +1 -1
  15. package/package.json +1 -1
  16. package/src/benefits-package/benefits-package.resources.tsx +1 -1
  17. package/src/benefits-package/forms/benefit-pre-auth-form.workspace.tsx +8 -52
  18. package/src/benefits-package/forms/{package-interventions.component.tsx → interventions-form.component.tsx} +25 -13
  19. package/src/benefits-package/forms/packages-and-interventions-form.component.tsx +72 -0
  20. package/src/billable-services/billiable-item/order-actions/components/base-order-button.component.tsx +42 -0
  21. package/src/billable-services/billiable-item/order-actions/components/lab-order-button.component.tsx +51 -0
  22. package/src/billable-services/billiable-item/order-actions/components/medication-order-button.component.tsx +84 -0
  23. package/src/billable-services/billiable-item/order-actions/components/order-action-button.component.tsx +29 -0
  24. package/src/billable-services/billiable-item/order-actions/hooks/useBillStatus.ts +12 -0
  25. package/src/billable-services/billiable-item/order-actions/hooks/useLabOrderAction.ts +27 -0
  26. package/src/billable-services/billiable-item/order-actions/hooks/useMedicationOrderAction.ts +106 -0
  27. package/src/billable-services/billiable-item/order-actions/hooks/useModalHandler.ts +66 -0
  28. package/src/billable-services/billiable-item/order-actions/styles/order-action.scss +0 -0
  29. package/src/billing-form/billing-checkin-form.component.tsx +6 -1
  30. package/src/billing-form/check-in-form.utils.tsx +2 -0
  31. package/src/billing-form/visit-attributes/visit-attributes-form.component.tsx +13 -3
  32. package/src/claims/dashboard/form/claims-form.component.tsx +28 -59
  33. package/src/claims/dashboard/form/claims-form.resource.ts +18 -2
  34. package/src/config-schema.ts +6 -0
  35. package/src/constants.ts +1 -0
  36. package/src/hooks/useInterventions.ts +19 -21
  37. package/src/index.ts +2 -2
  38. package/src/routes.json +3 -3
  39. package/src/types/index.ts +1 -0
  40. package/translations/en.json +2 -5
  41. package/dist/138.js +0 -2
  42. package/dist/138.js.map +0 -1
  43. package/dist/202.js +0 -1
  44. package/dist/202.js.map +0 -1
  45. package/dist/614.js +0 -1
  46. package/dist/614.js.map +0 -1
  47. package/src/billable-services/billiable-item/test-order/test-order-action.component.tsx +0 -134
  48. package/src/billable-services/billiable-item/test-order/test-order-action.test.tsx +0 -178
  49. /package/dist/{138.js.LICENSE.txt → 917.js.LICENSE.txt} +0 -0
@@ -0,0 +1,106 @@
1
+ import { useTranslation } from 'react-i18next';
2
+ import { useStockItemQuantity } from '../../useBillableItem';
3
+ import { useBillableServices } from '../../../billable-service.resource';
4
+
5
+ import { useBillStatus } from './useBillStatus';
6
+ import { createMedicationDispenseProps } from '../../test-order/dispense.resource';
7
+
8
+ interface MedicationRequest {
9
+ request: fhir.MedicationRequest;
10
+ }
11
+
12
+ export function useMedicationOrderAction(medicationRequestBundle?: MedicationRequest) {
13
+ const { t } = useTranslation();
14
+ const request = medicationRequestBundle?.request;
15
+ const orderUuid = request?.id;
16
+ const patientUuid = request?.subject?.reference?.split('/')[1];
17
+ const drugUuid = request?.medicationReference?.reference?.split('/')[1];
18
+
19
+ const { isLoading, hasPendingPayment, itemHasBill } = useBillStatus(orderUuid, patientUuid);
20
+ const { stockItemQuantity, stockItemUuid } = useStockItemQuantity(drugUuid);
21
+ const { billableServices } = useBillableServices();
22
+
23
+ const billableItem =
24
+ billableServices?.filter((service) => {
25
+ const stockItem = service?.stockItem.split(':')[0];
26
+ return stockItem === stockItemUuid;
27
+ }) || [];
28
+
29
+ const dispenseFormProps = medicationRequestBundle ? createMedicationDispenseProps({ medicationRequestBundle }) : null;
30
+
31
+ const shouldShowBillModal = stockItemQuantity > 0 && itemHasBill.length < 1 && billableItem.length > 0;
32
+ const isDisabled = hasPendingPayment || (stockItemQuantity < 1 && !!drugUuid);
33
+
34
+ // Modification is allowed only when:
35
+ // 1. There are no pending payments
36
+ // 2. Stock item is available (quantity > 0)
37
+ // 3. Item hasn't been billed yet (no existing bills)
38
+ // 4. Item exists in billable items list
39
+ const shouldAllowModify =
40
+ !hasPendingPayment && stockItemQuantity > 0 && itemHasBill.length < 1 && billableItem.length > 0;
41
+
42
+ const getButtonText = () => {
43
+ if (hasPendingPayment) {
44
+ return t('unsettledBill', 'Unsettled bill');
45
+ }
46
+
47
+ if (stockItemQuantity < 1 && drugUuid) {
48
+ return t('outOfStock', 'Out of Stock');
49
+ }
50
+
51
+ if (shouldShowBillModal) {
52
+ return t('bill', 'Bill');
53
+ }
54
+
55
+ return t('dispense', 'Dispense');
56
+ };
57
+
58
+ return {
59
+ isLoading,
60
+ isDisabled,
61
+ buttonText: getButtonText(),
62
+ shouldShowBillModal,
63
+ dispenseFormProps,
64
+ orderUuid,
65
+ patientUuid,
66
+ billableItem,
67
+ itemHasBill,
68
+ medicationRequestBundle,
69
+ hasPendingPayment,
70
+ shouldAllowModify,
71
+ };
72
+ }
73
+
74
+ import { useMemo } from 'react';
75
+ import { FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
76
+ import { Order } from '@openmrs/esm-patient-common-lib';
77
+ import useSWR from 'swr';
78
+
79
+ const customRepresentation =
80
+ 'custom:(uuid,dosingType,orderNumber,accessionNumber,' +
81
+ 'patient:ref,action,careSetting:ref,previousOrder:ref,dateActivated,scheduledDate,dateStopped,autoExpireDate,' +
82
+ 'orderType:ref,encounter:ref,orderer:(uuid,display,person:(display)),orderReason,orderReasonNonCoded,orderType,urgency,instructions,' +
83
+ 'commentToFulfiller,drug:(uuid,display,strength,dosageForm:(display,uuid),concept),dose,doseUnits:ref,' +
84
+ 'frequency:ref,asNeeded,asNeededCondition,quantity,quantityUnits:ref,numRefills,dosingInstructions,' +
85
+ 'duration,durationUnits:ref,route:ref,brandName,dispenseAsWritten)';
86
+
87
+ /**
88
+ * Hook to get a single order by UUID.
89
+ *
90
+ * @param orderUuid The UUID of the order to fetch.
91
+ */
92
+ export function useOrderByUuid(orderUuid: string) {
93
+ const ordersUrl = useMemo(
94
+ () => (orderUuid ? `${restBaseUrl}/order/${orderUuid}?v=${customRepresentation}` : null),
95
+ [orderUuid],
96
+ );
97
+ const { data, error, isLoading, isValidating, mutate } = useSWR<FetchResponse<Order>, Error>(ordersUrl, openmrsFetch);
98
+
99
+ return {
100
+ data: data?.data,
101
+ error,
102
+ isLoading,
103
+ isValidating,
104
+ mutate,
105
+ };
106
+ }
@@ -0,0 +1,66 @@
1
+ import { launchWorkspace } from '@openmrs/esm-framework';
2
+ import { Order } from '@openmrs/esm-patient-common-lib';
3
+ import { useCallback } from 'react';
4
+ import { mutate } from 'swr';
5
+
6
+ export function useModalHandler(mutateUrl?: string) {
7
+ const handleModalClose = useCallback(() => {
8
+ if (!mutateUrl) {
9
+ return;
10
+ }
11
+
12
+ mutate((key) => typeof key === 'string' && key.startsWith(mutateUrl), undefined, {
13
+ revalidate: true,
14
+ });
15
+ }, [mutateUrl]);
16
+
17
+ return {
18
+ handleModalClose,
19
+ };
20
+ }
21
+
22
+ export const launchPrescriptionEditWorkspace = (order: Order, patientUuid: string) => {
23
+ const newItem = {
24
+ uuid: order.uuid,
25
+ display: order.drug?.display,
26
+ previousOrder: order.uuid,
27
+ startDate: new Date(),
28
+ action: 'REVISE',
29
+ drug: order.drug,
30
+ dosage: order.dose,
31
+ unit: {
32
+ value: order.doseUnits?.display,
33
+ valueCoded: order.doseUnits?.uuid,
34
+ },
35
+ frequency: {
36
+ valueCoded: order.frequency?.uuid,
37
+ value: order.frequency?.display,
38
+ },
39
+ route: {
40
+ valueCoded: order.route?.uuid,
41
+ value: order.route?.display,
42
+ },
43
+ commonMedicationName: order.drug?.display,
44
+ isFreeTextDosage: order.dosingType === 'org.openmrs.FreeTextDosingInstructions',
45
+ freeTextDosage: order.dosingType === 'org.openmrs.FreeTextDosingInstructions' ? order.dosingInstructions : '',
46
+ patientInstructions: order.dosingType !== 'org.openmrs.FreeTextDosingInstructions' ? order.dosingInstructions : '',
47
+ asNeeded: order.asNeeded,
48
+ asNeededCondition: order.asNeededCondition,
49
+ duration: order.duration,
50
+ durationUnit: {
51
+ valueCoded: order.durationUnits?.uuid,
52
+ value: order.durationUnits?.display,
53
+ },
54
+ pillsDispensed: order.quantity,
55
+ numRefills: order.numRefills,
56
+ indication: order.orderReasonNonCoded,
57
+ orderer: order.orderer?.uuid,
58
+ careSetting: order.careSetting?.uuid,
59
+ quantityUnits: {
60
+ value: order.quantityUnits?.display,
61
+ valueCoded: order.quantityUnits?.uuid,
62
+ },
63
+ };
64
+
65
+ launchWorkspace('add-drug-order', { patientUuid, order: newItem });
66
+ };
@@ -6,13 +6,14 @@ import { FormProvider, useForm } from 'react-hook-form';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { createPatientBill, useBillableItems, useCashPoint } from '../billing.resource';
8
8
  import { BillingConfig } from '../config-schema';
9
- import { EXEMPTED_PAYMENT_STATUS, PENDING_PAYMENT_STATUS } from '../constants';
9
+ import { EXEMPTED_PAYMENT_STATUS, PENDING_PAYMENT_STATUS, SHA_INSURANCE_SCHEME } from '../constants';
10
10
  import { BillingService } from '../types';
11
11
  import styles from './billing-checkin-form.scss';
12
12
  import { visitAttributesFormSchema, VisitAttributesFormValue } from './check-in-form.utils';
13
13
  import { hasPatientBeenExempted } from './helper';
14
14
  import SHANumberValidity from './social-health-authority/sha-number-validity.component';
15
15
  import VisitAttributesForm from './visit-attributes/visit-attributes-form.component';
16
+ import SHABenefitPackangesAndInterventions from '../benefits-package/forms/packages-and-interventions-form.component';
16
17
 
17
18
  type BillingCheckInFormProps = {
18
19
  patientUuid: string;
@@ -36,11 +37,14 @@ const BillingCheckInForm: React.FC<BillingCheckInFormProps> = ({ patientUuid, se
36
37
  insuranceScheme: '',
37
38
  policyNumber: '',
38
39
  exemptionCategory: '',
40
+ interventions: [],
41
+ packages: [],
39
42
  },
40
43
  resolver: zodResolver(visitAttributesFormSchema),
41
44
  });
42
45
  const isPatientExemptedValue = formMethods.watch('isPatientExempted');
43
46
  const paymentMethod = formMethods.watch('paymentMethods');
47
+ const isInsuranceSchemeSha = formMethods.watch('insuranceScheme') === SHA_INSURANCE_SCHEME;
44
48
 
45
49
  const handleCreateBill = useCallback((createBillPayload) => {
46
50
  createPatientBill(createBillPayload).then(
@@ -125,6 +129,7 @@ const BillingCheckInForm: React.FC<BillingCheckInFormProps> = ({ patientUuid, se
125
129
  <FormProvider {...formMethods}>
126
130
  <VisitAttributesForm setAttributes={setAttributes} />
127
131
  {hieFeatureFlags && <SHANumberValidity paymentMethod={attributes} patientUuid={patientUuid} />}
132
+ {hieFeatureFlags && isInsuranceSchemeSha && <SHABenefitPackangesAndInterventions patientUuid={patientUuid} />}
128
133
  {paymentMethod && (
129
134
  <section className={styles.sectionContainer}>
130
135
  <div className={styles.sectionTitle}>{t('billing', 'Billing')}</div>
@@ -6,6 +6,8 @@ export const visitAttributesFormSchema = z.object({
6
6
  insuranceScheme: z.string().optional(),
7
7
  policyNumber: z.string().optional(),
8
8
  exemptionCategory: z.string().optional(),
9
+ packages: z.array(z.string()).nonempty('Require atleast 1 package'),
10
+ interventions: z.array(z.string()).nonempty('Require atleast 1 intervention'),
9
11
  });
10
12
 
11
13
  export type VisitAttributesFormValue = z.infer<typeof visitAttributesFormSchema>;
@@ -16,7 +16,7 @@ const VisitAttributesForm: React.FC<VisitAttributesFormProps> = ({ setAttributes
16
16
  const { t } = useTranslation();
17
17
  const { insuranceSchemes } = useConfig<BillingConfig>();
18
18
  const { visitAttributeTypes, patientExemptionCategories, insurancePaymentMethod } = useConfig<BillingConfig>();
19
- const { setValue, watch, control, getValues } = useFormContext<VisitAttributesFormValue>();
19
+ const { setValue, watch, control, getValues, resetField } = useFormContext<VisitAttributesFormValue>();
20
20
  const { paymentModes, isLoading: isLoadingPaymentModes } = usePaymentModes();
21
21
  const [isPatientExempted, paymentMethods] = watch(['isPatientExempted', 'paymentMethods']);
22
22
  const resetFormFieldsForNonExemptedPatients = useCallback(() => {
@@ -24,7 +24,9 @@ const VisitAttributesForm: React.FC<VisitAttributesFormProps> = ({ setAttributes
24
24
  setValue('policyNumber', '');
25
25
  setValue('exemptionCategory', '');
26
26
  setValue('paymentMethods', '');
27
- }, [setValue]);
27
+ resetField('packages');
28
+ resetField('interventions');
29
+ }, [setValue, resetField]);
28
30
 
29
31
  useEffect(() => {
30
32
  resetFormFieldsForNonExemptedPatients();
@@ -38,6 +40,10 @@ const VisitAttributesForm: React.FC<VisitAttributesFormProps> = ({ setAttributes
38
40
  { uuid: visitAttributeTypes.policyNumber, value: values.policyNumber },
39
41
  { uuid: visitAttributeTypes.insuranceScheme, value: values.insuranceScheme },
40
42
  { uuid: visitAttributeTypes.exemptionCategory, value: values.exemptionCategory },
43
+ {
44
+ uuid: visitAttributeTypes.shaBenefitPackagesAndInterventions,
45
+ value: JSON.stringify({ packages: values.packages, interventions: values.interventions }),
46
+ },
41
47
  ];
42
48
  const visitAttributesPayload = formPayload.filter(
43
49
  (item) => item.value !== undefined && item.value !== null && item.value !== '',
@@ -48,10 +54,12 @@ const VisitAttributesForm: React.FC<VisitAttributesFormProps> = ({ setAttributes
48
54
  }));
49
55
  }, [visitAttributeTypes, getValues]);
50
56
 
51
- const [policyNumber, exemptionCategory, insuranceScheme] = watch([
57
+ const [policyNumber, exemptionCategory, insuranceScheme, interventions, packages] = watch([
52
58
  'policyNumber',
53
59
  'exemptionCategory',
54
60
  'insuranceScheme',
61
+ 'interventions',
62
+ 'packages',
55
63
  ]);
56
64
 
57
65
  useEffect(() => {
@@ -64,6 +72,8 @@ const VisitAttributesForm: React.FC<VisitAttributesFormProps> = ({ setAttributes
64
72
  policyNumber,
65
73
  exemptionCategory,
66
74
  insuranceScheme,
75
+ interventions,
76
+ packages,
67
77
  ]);
68
78
 
69
79
  if (isLoadingPaymentModes) {
@@ -15,21 +15,21 @@ import {
15
15
  TextInputSkeleton,
16
16
  } from '@carbon/react';
17
17
  import { zodResolver } from '@hookform/resolvers/zod';
18
- import { navigate, showSnackbar, useSession } from '@openmrs/esm-framework';
19
- import React, { useEffect, useState } from 'react';
18
+ import { navigate, showSnackbar, useConfig, useSession } from '@openmrs/esm-framework';
19
+ import React, { useEffect, useMemo, useState } from 'react';
20
20
  import { Controller, FormProvider, useForm } from 'react-hook-form';
21
21
  import { useTranslation } from 'react-i18next';
22
22
  import { useParams } from 'react-router-dom';
23
23
  import { z } from 'zod';
24
- import PackageInterventions from '../../../benefits-package/forms/package-interventions.component';
24
+ import { BillingConfig } from '../../../config-schema';
25
25
  import { formatDate } from '../../../helpers/functions';
26
26
  import { useSystemSetting } from '../../../hooks/getMflCode';
27
- import usePackages from '../../../hooks/usePackages';
28
27
  import usePatientDiagnosis from '../../../hooks/usePatientDiagnosis';
28
+ import useProvider from '../../../hooks/useProvider';
29
29
  import { LineItem, MappedBill } from '../../../types';
30
- import { processClaims, useVisit } from './claims-form.resource';
30
+ import { processClaims, SHAPackagesAndInterventionVisitAttribute, useVisit } from './claims-form.resource';
31
31
  import styles from './claims-form.scss';
32
- import useProvider from '../../../hooks/useProvider';
32
+ import SHABenefitPackangesAndInterventions from '../../../benefits-package/forms/packages-and-interventions-form.component';
33
33
 
34
34
  type ClaimsFormProps = {
35
35
  bill: MappedBill;
@@ -44,7 +44,7 @@ const ClaimsFormSchema = z.object({
44
44
  facility: z.string().nonempty({ message: 'Facility is required' }),
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
- package: z.string().min(1, 'Package Required'),
47
+ packages: z.array(z.string()).nonempty({ message: 'At least one package is required' }),
48
48
  interventions: z.array(z.string()).min(1, {
49
49
  message: 'At least one intervention is required',
50
50
  }),
@@ -57,11 +57,23 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
57
57
  const { patientUuid, billUuid } = useParams();
58
58
  const { visits: recentVisit, error: visitError, isLoading: visitLoading } = useVisit(patientUuid);
59
59
  const { diagnoses, error: diagnosisError, isLoading: diagnosisLoading } = usePatientDiagnosis(patientUuid);
60
- const { error: packagesError, isLoading: packagesLoading, packages } = usePackages();
61
60
  const {
62
61
  currentProvider: { uuid: providerUuid },
63
62
  } = useSession();
64
63
  const { providerLoading: providerLoading, provider, error: providerError } = useProvider(providerUuid);
64
+ const { visitAttributeTypes } = useConfig<BillingConfig>();
65
+ const packagesAndinterventions = useMemo(() => {
66
+ if (recentVisit) {
67
+ const values = recentVisit.attributes?.find(
68
+ (attr) => attr.attributeType.uuid === visitAttributeTypes.shaBenefitPackagesAndInterventions,
69
+ )?.value;
70
+ if (values) {
71
+ const payload: SHAPackagesAndInterventionVisitAttribute = JSON.parse(values);
72
+ return payload;
73
+ }
74
+ }
75
+ return null;
76
+ }, [recentVisit, visitAttributeTypes]);
65
77
 
66
78
  const encounterUuid = recentVisit?.encounters[0]?.uuid;
67
79
  const visitTypeUuid = recentVisit?.visitType.uuid;
@@ -85,7 +97,7 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
85
97
  facility: `${recentVisit?.location?.display || ''} - ${mflCodeValue || ''}`,
86
98
  treatmentStart: recentVisit?.startDatetime ? formatDate(recentVisit.startDatetime) : '',
87
99
  treatmentEnd: recentVisit?.stopDatetime ? formatDate(recentVisit.stopDatetime) : '',
88
- package: '',
100
+ packages: [],
89
101
  interventions: [],
90
102
  provider: providerUuid,
91
103
  },
@@ -99,11 +111,6 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
99
111
  reset,
100
112
  } = form;
101
113
 
102
- const handleInterventionsChange = (e: { selectedItem: string }) => {
103
- form.setValue('interventions', []);
104
- setValue('package', e.selectedItem);
105
- };
106
-
107
114
  const onSubmit = async (data: z.infer<typeof ClaimsFormSchema>) => {
108
115
  setLoading(true);
109
116
  const providedItems = selectedLineItems.reduce((acc, item) => {
@@ -139,7 +146,7 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
139
146
  use: 'claim',
140
147
  insurer: 'SHA',
141
148
  billNumber: billUuid,
142
- packages: [data.package],
149
+ packages: data.packages,
143
150
  interventions: data.interventions,
144
151
  };
145
152
  try {
@@ -170,7 +177,6 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
170
177
  setLoading(false);
171
178
  }
172
179
  };
173
- const selectedPackage = packages.find((package_) => package_.uuid === form.watch('package'))?.packageCode ?? '';
174
180
 
175
181
  useEffect(() => {
176
182
  setValue('diagnoses', diagnoses?.map((d) => d.id) ?? ([] as any));
@@ -178,9 +184,11 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
178
184
  setValue('facility', `${recentVisit?.location?.display || ''} - ${mflCodeValue || ''}`);
179
185
  setValue('treatmentStart', recentVisit?.startDatetime ? formatDate(recentVisit.startDatetime) : '');
180
186
  setValue('treatmentEnd', recentVisit?.stopDatetime ? formatDate(recentVisit.stopDatetime) : '');
181
- }, [diagnoses, recentVisit, mflCodeValue, setValue, provider]);
187
+ setValue('packages', (packagesAndinterventions?.packages ?? []) as any);
188
+ setValue('interventions', (packagesAndinterventions?.interventions ?? []) as any);
189
+ }, [diagnoses, recentVisit, mflCodeValue, setValue, provider, packagesAndinterventions]);
182
190
 
183
- if (visitLoading || diagnosisLoading || packagesLoading || providerLoading) {
191
+ if (visitLoading || diagnosisLoading || providerLoading) {
184
192
  return (
185
193
  <Layer className={styles.loading}>
186
194
  {Array.from({ length: 6 }).map((_, index) => (
@@ -190,7 +198,7 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
190
198
  );
191
199
  }
192
200
 
193
- if (visitError || diagnosisError || packagesError || providerError) {
201
+ if (visitError || diagnosisError || providerError) {
194
202
  return (
195
203
  <Layer className={styles.loading}>
196
204
  <InlineNotification
@@ -198,7 +206,6 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
198
206
  subtitle={
199
207
  visitError?.message ??
200
208
  diagnosisError?.message ??
201
- packagesError?.message ??
202
209
  providerError?.message ??
203
210
  'Error occured while loading claims form'
204
211
  }
@@ -284,45 +291,7 @@ const ClaimsForm: React.FC<ClaimsFormProps> = ({ bill, selectedLineItems }) => {
284
291
  </Layer>
285
292
  </Column>
286
293
  </Row>
287
- <Column>
288
- <Layer className={styles.input}>
289
- <Controller
290
- control={form.control}
291
- name="package"
292
- render={({ field }) => (
293
- <>
294
- {packagesError ? (
295
- <InlineNotification
296
- kind="error"
297
- subtitle={t('errorFetchingPackages', 'Error fetching packeges')}
298
- lowContrast
299
- />
300
- ) : (
301
- <Dropdown
302
- ref={field.ref}
303
- invalid={form.formState.errors[field.name]?.message}
304
- invalidText={form.formState.errors[field.name]?.message}
305
- id="package"
306
- titleText={t('package', 'Package')}
307
- onChange={handleInterventionsChange}
308
- initialSelectedItem={field.value}
309
- label="Choose package"
310
- items={packages.map((r) => r.uuid)}
311
- itemToString={(item) => packages.find((r) => r.uuid === item)?.packageName ?? ''}
312
- />
313
- )}
314
- </>
315
- )}
316
- />
317
- </Layer>
318
- </Column>
319
-
320
- <Column>
321
- <Layer className={styles.input}>
322
- <PackageInterventions key={selectedPackage} category={selectedPackage} patientUuid={patientUuid} />
323
- </Layer>
324
- </Column>
325
-
294
+ <SHABenefitPackangesAndInterventions patientUuid={patientUuid} />
326
295
  <Column>
327
296
  <Layer className={styles.input}>
328
297
  <Controller
@@ -13,11 +13,27 @@ interface ProvidersResponse {
13
13
  results: Provider[];
14
14
  }
15
15
 
16
+ interface ExtendedVisit extends Visit {
17
+ attributes: Array<{
18
+ uuid: string;
19
+ display: string;
20
+ attributeType: {
21
+ uuid: string;
22
+ display: string;
23
+ };
24
+ value: string;
25
+ }>;
26
+ }
27
+ export interface SHAPackagesAndInterventionVisitAttribute {
28
+ packages: Array<string>;
29
+ interventions: Array<string>;
30
+ }
31
+
16
32
  export function useVisit(patientUuid: string) {
17
33
  const customRepresentation =
18
- 'custom:(uuid,patient,encounters:(uuid,diagnoses:(uuid,display,certainty,diagnosis:(coded:(uuid,display))),encounterDatetime,encounterType:(uuid,display),encounterProviders:(uuid,display,provider:(uuid,person:(uuid,display)))),location:(uuid,name,display),visitType:(uuid,name,display),startDatetime,stopDatetime)&limit=1';
34
+ 'custom:(uuid,patient,encounters:(uuid,diagnoses:(uuid,display,certainty,diagnosis:(coded:(uuid,display))),encounterDatetime,encounterType:(uuid,display),encounterProviders:(uuid,display,provider:(uuid,person:(uuid,display)))),location:(uuid,name,display),visitType:(uuid,name,display),startDatetime,stopDatetime,attributes)&limit=1';
19
35
 
20
- const { data, error, isLoading, isValidating, mutate } = useSWR<{ data: { results: Array<Visit> } }, Error>(
36
+ const { data, error, isLoading, isValidating, mutate } = useSWR<{ data: { results: Array<ExtendedVisit> } }, Error>(
21
37
  `${restBaseUrl}/visit?patient=${patientUuid}&v=${customRepresentation}`,
22
38
  openmrsFetch,
23
39
  );
@@ -8,6 +8,7 @@ export interface BillingConfig {
8
8
  policyNumber: string;
9
9
  exemptionCategory: string;
10
10
  billPaymentStatus: string;
11
+ shaBenefitPackagesAndInterventions: string;
11
12
  };
12
13
  insurancePaymentMethod: string;
13
14
  inPatientVisitTypeUuid: string;
@@ -96,6 +97,11 @@ export const configSchema: ConfigSchema = {
96
97
  _description: 'The bill payment status visit attribute uuid',
97
98
  _default: '919b51c9-8e2e-468f-8354-181bf3e55786',
98
99
  },
100
+ shaBenefitPackagesAndInterventions: {
101
+ _type: Type.String,
102
+ _description: 'JSON String of SHA Benefit Packages and Interventions for this visit',
103
+ _default: '338725fa-3790-4679-98b9-be623214ee29',
104
+ },
99
105
  },
100
106
  insurancePaymentMethod: {
101
107
  _type: Type.String,
package/src/constants.ts CHANGED
@@ -20,3 +20,4 @@ export const colorsArray = [
20
20
  // Size in MegaBits
21
21
  export const MAX_ALLOWED_FILE_SIZE = 2097152;
22
22
  export const PAYMENT_MODE_ATTRIBUTE_FORMATS = ['java.lang.String', 'java.lang.Integer', 'java.lang.Double'];
23
+ export const SHA_INSURANCE_SCHEME = 'SHA';
@@ -10,20 +10,6 @@ export type InterventionsFilter = {
10
10
  applicable_gender?: 'MALE' | 'FEMALE';
11
11
  };
12
12
 
13
- export const toQueryParams = (q: Record<string, any>) => {
14
- return (
15
- '?' +
16
- Object.entries(q)
17
- .reduce((prev, [key, val]) => {
18
- if (val !== undefined && val !== null) {
19
- return [...prev, `${key}=${val}`];
20
- }
21
- return prev;
22
- }, [])
23
- .join('&')
24
- );
25
- };
26
-
27
13
  type Data = {
28
14
  status: string;
29
15
  data: Array<{
@@ -56,17 +42,18 @@ export const useInterventions = (filters: InterventionsFilter) => {
56
42
  };
57
43
 
58
44
  const { error: facilityLevelError, isLoading: isLoadingFacilityLevel, level } = useFacilityLevel();
59
-
60
- const url = `${restBaseUrl}/kenyaemr/sha-interventions${toQueryParams({
45
+ const urlParams = new URLSearchParams({
61
46
  ...filters,
62
- synchronize: false,
63
- })}`;
47
+ synchronize: 'false',
48
+ });
49
+ const url = `${restBaseUrl}/kenyaemr/sha-interventions?${urlParams.toString()}`;
64
50
  const { isLoading, error, data } = useSWR<FetchResponse<Data>>(url, openmrsFetch);
65
51
  const interventions = useMemo(() => {
52
+ const packageCodes = filters.package_code?.split(',') || [];
66
53
  return data?.data?.data
67
54
  ?.filter((d) => {
68
55
  // 1. Filter by package code (only if defined)
69
- if (filters.package_code && d.interventionPackage !== filters.package_code) {
56
+ if (packageCodes.length > 0 && !packageCodes.includes(d.interventionPackage)) {
70
57
  return false;
71
58
  }
72
59
 
@@ -106,12 +93,23 @@ export const useInterventions = (filters: InterventionsFilter) => {
106
93
  interventionCode,
107
94
  subCategoryBenefitsPackage: interventionSubPackage,
108
95
  interventionName,
96
+ interventionPackage,
109
97
  })) as SHAIntervention[];
110
98
  }, [data, filters, level]); // Ensure proper memoization
111
-
99
+ const allInterventions = useMemo(() => {
100
+ return (data?.data?.data ?? []).map(
101
+ ({ interventionCode, interventionName, interventionPackage, interventionSubPackage }) => ({
102
+ interventionCode,
103
+ subCategoryBenefitsPackage: interventionSubPackage,
104
+ interventionName,
105
+ interventionPackage,
106
+ }),
107
+ ) as SHAIntervention[];
108
+ }, [data]);
112
109
  return {
113
110
  isLoading: isLoading || isLoadingFacilityLevel,
114
- interventions,
111
+ interventions: interventions ?? [],
112
+ allInterventions,
115
113
  error: error || facilityLevelError,
116
114
  };
117
115
  };
package/src/index.ts CHANGED
@@ -23,7 +23,6 @@ import ImagingOrder from './billable-services/billiable-item/test-order/imaging-
23
23
  import LabOrder from './billable-services/billiable-item/test-order/lab-order.component';
24
24
  import PriceInfoOrder from './billable-services/billiable-item/test-order/price-info-order.componet';
25
25
  import ProcedureOrder from './billable-services/billiable-item/test-order/procedure-order.component';
26
- import TestOrderAction from './billable-services/billiable-item/test-order/test-order-action.component';
27
26
  import { BulkImportBillableServices } from './billable-services/bulk-import-billable-service.modal';
28
27
  import BillingCheckInForm from './billing-form/billing-checkin-form.component';
29
28
  import BillingForm from './billing-form/billing-form.component';
@@ -42,6 +41,7 @@ import { ClockIn } from './payment-points/payment-point/clock-in.modal';
42
41
  import { ClockOut } from './payment-points/payment-point/clock-out.modal';
43
42
  import RequirePaymentModal from './prompt-payment/prompt-payment-modal.component';
44
43
  import rootComponent from './root.component';
44
+ import OrderActionButton from './billable-services/billiable-item/order-actions/components/order-action-button.component';
45
45
 
46
46
  const moduleName = '@kenyaemr/esm-billing-app';
47
47
 
@@ -169,7 +169,7 @@ export const priceInfoOrder = getSyncLifecycle(PriceInfoOrder, options);
169
169
  export const procedureOrder = getSyncLifecycle(ProcedureOrder, options);
170
170
  export const imagingOrder = getSyncLifecycle(ImagingOrder, options);
171
171
  export const drugOrder = getSyncLifecycle(DrugOrder, options);
172
- export const testOrderAction = getSyncLifecycle(TestOrderAction, options);
172
+ export const orderActionButton = getSyncLifecycle(OrderActionButton, options);
173
173
 
174
174
  // bill manager modals
175
175
  export const deleteBillModal = getSyncLifecycle(DeleteBillModal, options);
package/src/routes.json CHANGED
@@ -135,9 +135,9 @@
135
135
  "slot": "medication-info-slot"
136
136
  },
137
137
  {
138
- "name": "billing-test-order-action",
139
- "component": "testOrderAction",
140
- "slot": "tests-ordered-actions-slot",
138
+ "name": "order-action-button",
139
+ "component": "orderActionButton",
140
+ "slot": "prescription-action-button-slot",
141
141
  "order": 0
142
142
  },
143
143
  {
@@ -493,6 +493,7 @@ export type PaymentMode = {
493
493
 
494
494
  export type SHAIntervention = {
495
495
  interventionCode: string;
496
+ interventionPackage: string;
496
497
  shaCategory: string;
497
498
  accessCode: string;
498
499
  subCategoryBenefitsPackage: string;