@kenyaemr/esm-billing-app 5.3.8-pre.1599 → 5.3.9-pre.1620

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.
@@ -4,6 +4,7 @@ import useSWR from 'swr';
4
4
  import { mapBillProperties } from '../billing.resource';
5
5
  import { BillingConfig } from '../config-schema';
6
6
  import { BillingPromptType, MappedBill, PatientInvoice } from '../types';
7
+ import dayjs from 'dayjs';
7
8
 
8
9
  interface BillingPromptResult {
9
10
  shouldShowBillingPrompt: boolean;
@@ -11,6 +12,12 @@ interface BillingPromptResult {
11
12
  error: Error | null;
12
13
  currentVisit: Visit | null;
13
14
  bills: Array<MappedBill>;
15
+ billingDuration?: {
16
+ isWithinPromptDuration: boolean;
17
+ hoursSinceLastBill: number;
18
+ lastDateBilled: Date;
19
+ mostRecentBill: MappedBill;
20
+ };
14
21
  }
15
22
 
16
23
  // Constants
@@ -80,7 +87,7 @@ const hasOnlyOrderBills = (bills: Array<MappedBill>): boolean => {
80
87
  * 1. The current visit is not an inpatient visit
81
88
  * 2. The patient has a positive bill balance
82
89
  * 3. The payment method is not in the excluded payment methods list
83
- * 4. For patient-chart, prompt is not shown if the line items in the bill are only orders
90
+ * 4. For patient-chart, prompt is not shown if the line items in the bill are only orders and the billing duration is within the prompt duration
84
91
  *
85
92
  * @param patientUuid - The UUID of the patient to check billing status for
86
93
  * @returns {BillingPromptResult} An object containing:
@@ -89,6 +96,7 @@ const hasOnlyOrderBills = (bills: Array<MappedBill>): boolean => {
89
96
  * - error: any error that occurred during data fetching
90
97
  * - currentVisit: the current visit object or null
91
98
  * - bills: array of the patient's bills
99
+ * - billingDuration: an object containing billing duration information
92
100
  */
93
101
  export const useBillingPrompt = (
94
102
  patientUuid: string,
@@ -100,28 +108,42 @@ export const useBillingPrompt = (
100
108
 
101
109
  const { paymentMethodsUuidsThatShouldNotShowPrompt, inPatientVisitTypeUuid } = config;
102
110
 
111
+ const hasLoaded = isLoadingBills && isLoadingVisit;
103
112
  const isExcludedPaymentMethod = checkPaymentMethodExclusion(currentVisit, paymentMethodsUuidsThatShouldNotShowPrompt);
104
-
105
113
  const patientBillBalance = calculateBillBalance(bills);
106
114
  const hasOnlyOrders = hasOnlyOrderBills(bills);
115
+ const billingDuration = checkBillingDuration(bills, config);
107
116
 
108
117
  if (promptType === 'patient-chart' && hasOnlyOrders) {
109
118
  return {
110
119
  shouldShowBillingPrompt: false,
111
- isLoading: isLoadingBills || isLoadingVisit,
120
+ isLoading: hasLoaded,
121
+ error,
122
+ currentVisit,
123
+ bills,
124
+ billingDuration,
125
+ };
126
+ }
127
+
128
+ if (promptType === 'patient-chart' && config.promptDuration.enable && !billingDuration.isWithinPromptDuration) {
129
+ return {
130
+ shouldShowBillingPrompt: false,
131
+ isLoading: hasLoaded,
112
132
  error,
113
133
  currentVisit,
114
134
  bills,
135
+ billingDuration,
115
136
  };
116
137
  }
117
138
 
118
139
  return {
119
140
  shouldShowBillingPrompt:
120
141
  !isExcludedPaymentMethod && shouldShowPrompt(currentVisit, patientBillBalance, inPatientVisitTypeUuid),
121
- isLoading: isLoadingBills || isLoadingVisit,
142
+ isLoading: hasLoaded,
122
143
  error,
123
144
  currentVisit,
124
145
  bills,
146
+ billingDuration,
125
147
  };
126
148
  };
127
149
 
@@ -160,3 +182,56 @@ export const usePatientBills = (patientUuid: string) => {
160
182
  mutate,
161
183
  };
162
184
  };
185
+
186
+ /**
187
+ * Checks if bills are within the configured prompt duration and provides billing timing information
188
+ *
189
+ * @param {Array<MappedBill>} bills - Array of patient bills containing dateCreated timestamps
190
+ * @param {Object} config - Configuration object containing prompt duration settings
191
+ * @param {number} config.promptDuration - Maximum number of hours to show prompt after bill creation
192
+ *
193
+ * @returns {Object} Billing duration information
194
+ * @returns {boolean} returns.isWithinPromptDuration - Whether the most recent bill is within prompt duration
195
+ * @returns {number} returns.hoursSinceLastBill - Hours elapsed since most recent bill
196
+ * @returns {string} returns.lastDateBilled - ISO timestamp of most recent bill
197
+ * @returns {MappedBill} returns.mostRecentBill - The most recent bill object
198
+ *
199
+ * @throws {Error} When bills array is empty or promptDuration is not configured
200
+ *
201
+ * @example
202
+ * const bills = [{ dateCreated: '2023-01-01T10:00:00Z' }];
203
+ * const config = { promptDuration: 24 };
204
+ * const result = checkBillingDuration(bills, config);
205
+ * // Returns: {
206
+ * // isWithinPromptDuration: true,
207
+ * // hoursSinceLastBill: 5,
208
+ * // lastDateBilled: '2023-01-01T10:00:00Z',
209
+ * // mostRecentBill: { dateCreated: '2023-01-01T10:00:00Z' }
210
+ * // }
211
+ */
212
+ const checkBillingDuration = (bills: Array<MappedBill> = [], config: BillingConfig) => {
213
+ if (!config?.promptDuration?.enable) {
214
+ return {
215
+ isWithinPromptDuration: false,
216
+ hoursSinceLastBill: 0,
217
+ lastDateBilled: new Date(),
218
+ mostRecentBill: null,
219
+ };
220
+ }
221
+
222
+ const sortedBills = [...bills].sort((a, b) => dayjs(b.dateCreated).diff(dayjs(a.dateCreated)));
223
+
224
+ const mostRecentBill = sortedBills[0];
225
+ const lastDateBilled = new Date(mostRecentBill?.dateCreatedUnformatted);
226
+ const currentDate = new Date();
227
+
228
+ // Calculate hours since last bill
229
+ const hoursSinceLastBill = dayjs(currentDate).diff(dayjs(lastDateBilled), 'hour');
230
+
231
+ return {
232
+ isWithinPromptDuration: hoursSinceLastBill <= config.promptDuration.duration,
233
+ hoursSinceLastBill,
234
+ lastDateBilled,
235
+ mostRecentBill,
236
+ };
237
+ };
@@ -97,6 +97,7 @@ interface AttributeType {
97
97
  foreignKey?: string | null;
98
98
  regExp?: string | null;
99
99
  required: boolean;
100
+ value?: string;
100
101
  }
101
102
 
102
103
  interface Attribute {