@blackcode_sa/metaestetics-api 1.12.68 → 1.13.0
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/dist/admin/index.d.mts +801 -2
- package/dist/admin/index.d.ts +801 -2
- package/dist/admin/index.js +2332 -153
- package/dist/admin/index.mjs +2321 -153
- package/dist/index.d.mts +1057 -2
- package/dist/index.d.ts +1057 -2
- package/dist/index.js +4150 -2117
- package/dist/index.mjs +3832 -1810
- package/package.json +1 -1
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +140 -0
- package/src/admin/analytics/analytics.admin.service.ts +278 -0
- package/src/admin/analytics/index.ts +2 -0
- package/src/admin/index.ts +6 -0
- package/src/backoffice/services/README.md +17 -0
- package/src/backoffice/services/analytics.service.proposal.md +863 -0
- package/src/backoffice/services/analytics.service.summary.md +143 -0
- package/src/services/analytics/ARCHITECTURE.md +199 -0
- package/src/services/analytics/CLOUD_FUNCTIONS.md +225 -0
- package/src/services/analytics/GROUPED_ANALYTICS.md +501 -0
- package/src/services/analytics/QUICK_START.md +393 -0
- package/src/services/analytics/README.md +287 -0
- package/src/services/analytics/SUMMARY.md +141 -0
- package/src/services/analytics/USAGE_GUIDE.md +518 -0
- package/src/services/analytics/analytics-cloud.service.ts +222 -0
- package/src/services/analytics/analytics.service.ts +1632 -0
- package/src/services/analytics/index.ts +3 -0
- package/src/services/analytics/utils/appointment-filtering.utils.ts +138 -0
- package/src/services/analytics/utils/cost-calculation.utils.ts +154 -0
- package/src/services/analytics/utils/grouping.utils.ts +394 -0
- package/src/services/analytics/utils/stored-analytics.utils.ts +347 -0
- package/src/services/analytics/utils/time-calculation.utils.ts +186 -0
- package/src/services/appointment/appointment.service.ts +50 -6
- package/src/services/index.ts +1 -0
- package/src/types/analytics/analytics.types.ts +500 -0
- package/src/types/analytics/grouped-analytics.types.ts +148 -0
- package/src/types/analytics/index.ts +4 -0
- package/src/types/analytics/stored-analytics.types.ts +137 -0
- package/src/types/index.ts +3 -0
- package/src/types/notifications/index.ts +21 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
import { Timestamp } from 'firebase/firestore';
|
|
2
|
+
import { AppointmentStatus, PaymentStatus } from '../appointment';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Base metrics interface with common properties
|
|
6
|
+
*/
|
|
7
|
+
export interface BaseMetrics {
|
|
8
|
+
total: number;
|
|
9
|
+
dateRange?: { start: Date; end: Date };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Date range filter for analytics queries
|
|
14
|
+
*/
|
|
15
|
+
export interface AnalyticsDateRange {
|
|
16
|
+
start: Date;
|
|
17
|
+
end: Date;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Common filters for analytics queries
|
|
22
|
+
*/
|
|
23
|
+
export interface AnalyticsFilters {
|
|
24
|
+
clinicBranchId?: string;
|
|
25
|
+
practitionerId?: string;
|
|
26
|
+
procedureId?: string;
|
|
27
|
+
patientId?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Grouping period for trend analysis
|
|
32
|
+
*/
|
|
33
|
+
export type GroupingPeriod = 'day' | 'week' | 'month';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Entity type for grouping analytics
|
|
37
|
+
*/
|
|
38
|
+
export type EntityType = 'clinic' | 'practitioner' | 'patient' | 'procedure' | 'technology';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Practitioner Analytics
|
|
42
|
+
* Comprehensive metrics for a practitioner's performance
|
|
43
|
+
*/
|
|
44
|
+
export interface PractitionerAnalytics extends BaseMetrics {
|
|
45
|
+
practitionerId: string;
|
|
46
|
+
practitionerName: string;
|
|
47
|
+
totalAppointments: number;
|
|
48
|
+
completedAppointments: number;
|
|
49
|
+
canceledAppointments: number;
|
|
50
|
+
noShowAppointments: number;
|
|
51
|
+
pendingAppointments: number;
|
|
52
|
+
confirmedAppointments: number;
|
|
53
|
+
cancellationRate: number; // percentage
|
|
54
|
+
noShowRate: number; // percentage
|
|
55
|
+
averageBookedTime: number; // minutes
|
|
56
|
+
averageActualTime: number; // minutes
|
|
57
|
+
timeEfficiency: number; // percentage
|
|
58
|
+
totalRevenue: number;
|
|
59
|
+
averageRevenuePerAppointment: number;
|
|
60
|
+
currency: string;
|
|
61
|
+
topProcedures: Array<{
|
|
62
|
+
procedureId: string;
|
|
63
|
+
procedureName: string;
|
|
64
|
+
count: number;
|
|
65
|
+
revenue: number;
|
|
66
|
+
}>;
|
|
67
|
+
patientRetentionRate: number; // percentage
|
|
68
|
+
uniquePatients: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Procedure Analytics
|
|
73
|
+
* Comprehensive metrics for procedure performance
|
|
74
|
+
*/
|
|
75
|
+
export interface ProcedureAnalytics extends BaseMetrics {
|
|
76
|
+
procedureId: string;
|
|
77
|
+
procedureName: string;
|
|
78
|
+
procedureFamily: string;
|
|
79
|
+
categoryName: string;
|
|
80
|
+
subcategoryName: string;
|
|
81
|
+
technologyName: string;
|
|
82
|
+
totalAppointments: number;
|
|
83
|
+
completedAppointments: number;
|
|
84
|
+
canceledAppointments: number;
|
|
85
|
+
noShowAppointments: number;
|
|
86
|
+
cancellationRate: number; // percentage
|
|
87
|
+
noShowRate: number; // percentage
|
|
88
|
+
averageCost: number;
|
|
89
|
+
totalRevenue: number;
|
|
90
|
+
averageRevenuePerAppointment: number;
|
|
91
|
+
currency: string;
|
|
92
|
+
averageBookedDuration: number; // minutes
|
|
93
|
+
averageActualDuration: number; // minutes
|
|
94
|
+
productUsage: Array<{
|
|
95
|
+
productId: string;
|
|
96
|
+
productName: string;
|
|
97
|
+
brandName: string;
|
|
98
|
+
totalQuantity: number;
|
|
99
|
+
totalRevenue: number;
|
|
100
|
+
usageCount: number;
|
|
101
|
+
}>;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Time Efficiency Metrics
|
|
106
|
+
* Analysis of booked time vs actual time spent
|
|
107
|
+
*/
|
|
108
|
+
export interface TimeEfficiencyMetrics {
|
|
109
|
+
totalAppointments: number;
|
|
110
|
+
appointmentsWithActualTime: number;
|
|
111
|
+
averageBookedDuration: number; // minutes
|
|
112
|
+
averageActualDuration: number; // minutes
|
|
113
|
+
averageEfficiency: number; // percentage
|
|
114
|
+
totalOverrun: number; // minutes
|
|
115
|
+
totalUnderutilization: number; // minutes
|
|
116
|
+
averageOverrun: number; // minutes
|
|
117
|
+
averageUnderutilization: number; // minutes
|
|
118
|
+
efficiencyDistribution: Array<{
|
|
119
|
+
range: string; // e.g., "0-50%", "50-75%", "75-100%", "100%+"
|
|
120
|
+
count: number;
|
|
121
|
+
percentage: number;
|
|
122
|
+
}>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Cancellation Metrics
|
|
127
|
+
* Analysis of appointment cancellations
|
|
128
|
+
*/
|
|
129
|
+
export interface CancellationMetrics {
|
|
130
|
+
entityId: string;
|
|
131
|
+
entityName: string;
|
|
132
|
+
entityType: EntityType;
|
|
133
|
+
totalAppointments: number;
|
|
134
|
+
canceledAppointments: number;
|
|
135
|
+
cancellationRate: number; // percentage
|
|
136
|
+
canceledByPatient: number;
|
|
137
|
+
canceledByClinic: number;
|
|
138
|
+
canceledByPractitioner: number;
|
|
139
|
+
canceledRescheduled: number;
|
|
140
|
+
averageCancellationLeadTime: number; // hours
|
|
141
|
+
cancellationReasons: Array<{
|
|
142
|
+
reason: string;
|
|
143
|
+
count: number;
|
|
144
|
+
percentage: number;
|
|
145
|
+
}>;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* No-Show Metrics
|
|
150
|
+
* Analysis of appointment no-shows
|
|
151
|
+
*/
|
|
152
|
+
export interface NoShowMetrics {
|
|
153
|
+
entityId: string;
|
|
154
|
+
entityName: string;
|
|
155
|
+
entityType: EntityType;
|
|
156
|
+
totalAppointments: number;
|
|
157
|
+
noShowAppointments: number;
|
|
158
|
+
noShowRate: number; // percentage
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Revenue Metrics
|
|
163
|
+
* Financial analysis and revenue tracking
|
|
164
|
+
*/
|
|
165
|
+
export interface RevenueMetrics {
|
|
166
|
+
totalRevenue: number;
|
|
167
|
+
averageRevenuePerAppointment: number;
|
|
168
|
+
totalAppointments: number;
|
|
169
|
+
completedAppointments: number;
|
|
170
|
+
currency: string;
|
|
171
|
+
revenueByStatus: Partial<Record<AppointmentStatus, number>>;
|
|
172
|
+
revenueByPaymentStatus: Partial<Record<PaymentStatus, number>>;
|
|
173
|
+
unpaidRevenue: number;
|
|
174
|
+
refundedRevenue: number;
|
|
175
|
+
totalTax: number;
|
|
176
|
+
totalSubtotal: number;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Revenue Trend
|
|
181
|
+
* Revenue data over time
|
|
182
|
+
*/
|
|
183
|
+
export interface RevenueTrend {
|
|
184
|
+
period: string; // e.g., "2024-01-01", "2024-W01", "2024-01"
|
|
185
|
+
startDate: Date;
|
|
186
|
+
endDate: Date;
|
|
187
|
+
revenue: number;
|
|
188
|
+
appointmentCount: number;
|
|
189
|
+
averageRevenue: number;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Duration Trend
|
|
194
|
+
* Appointment duration trends over time
|
|
195
|
+
*/
|
|
196
|
+
export interface DurationTrend {
|
|
197
|
+
period: string;
|
|
198
|
+
startDate: Date;
|
|
199
|
+
endDate: Date;
|
|
200
|
+
averageBookedDuration: number; // minutes
|
|
201
|
+
averageActualDuration: number; // minutes
|
|
202
|
+
averageEfficiency: number; // percentage
|
|
203
|
+
appointmentCount: number;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Product Usage Metrics
|
|
208
|
+
* Analysis of product usage in appointments
|
|
209
|
+
*/
|
|
210
|
+
export interface ProductUsageMetrics {
|
|
211
|
+
productId: string;
|
|
212
|
+
productName: string;
|
|
213
|
+
brandId: string;
|
|
214
|
+
brandName: string;
|
|
215
|
+
totalQuantity: number;
|
|
216
|
+
totalRevenue: number;
|
|
217
|
+
averagePrice: number;
|
|
218
|
+
currency: string;
|
|
219
|
+
usageCount: number; // number of appointments using this product
|
|
220
|
+
averageQuantityPerAppointment: number;
|
|
221
|
+
usageByProcedure: Array<{
|
|
222
|
+
procedureId: string;
|
|
223
|
+
procedureName: string;
|
|
224
|
+
count: number;
|
|
225
|
+
totalQuantity: number;
|
|
226
|
+
}>;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Product Revenue Metrics
|
|
231
|
+
* Revenue contribution by product
|
|
232
|
+
*/
|
|
233
|
+
export interface ProductRevenueMetrics {
|
|
234
|
+
productId: string;
|
|
235
|
+
productName: string;
|
|
236
|
+
brandName: string;
|
|
237
|
+
totalRevenue: number;
|
|
238
|
+
currency: string;
|
|
239
|
+
usageCount: number;
|
|
240
|
+
averageRevenuePerUsage: number;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Product Usage by Procedure
|
|
245
|
+
* Product usage patterns for specific procedures
|
|
246
|
+
*/
|
|
247
|
+
export interface ProductUsageByProcedure {
|
|
248
|
+
procedureId: string;
|
|
249
|
+
procedureName: string;
|
|
250
|
+
products: Array<{
|
|
251
|
+
productId: string;
|
|
252
|
+
productName: string;
|
|
253
|
+
brandName: string;
|
|
254
|
+
totalQuantity: number;
|
|
255
|
+
totalRevenue: number;
|
|
256
|
+
usageCount: number;
|
|
257
|
+
}>;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Patient Analytics
|
|
262
|
+
* Comprehensive patient metrics
|
|
263
|
+
*/
|
|
264
|
+
export interface PatientAnalytics {
|
|
265
|
+
patientId: string;
|
|
266
|
+
patientName: string;
|
|
267
|
+
totalAppointments: number;
|
|
268
|
+
completedAppointments: number;
|
|
269
|
+
canceledAppointments: number;
|
|
270
|
+
noShowAppointments: number;
|
|
271
|
+
cancellationRate: number; // percentage
|
|
272
|
+
noShowRate: number; // percentage
|
|
273
|
+
totalRevenue: number;
|
|
274
|
+
averageRevenuePerAppointment: number;
|
|
275
|
+
currency: string;
|
|
276
|
+
lifetimeValue: number;
|
|
277
|
+
firstAppointmentDate: Date | null;
|
|
278
|
+
lastAppointmentDate: Date | null;
|
|
279
|
+
averageDaysBetweenAppointments: number | null;
|
|
280
|
+
uniquePractitioners: number;
|
|
281
|
+
uniqueClinics: number;
|
|
282
|
+
favoriteProcedures: Array<{
|
|
283
|
+
procedureId: string;
|
|
284
|
+
procedureName: string;
|
|
285
|
+
count: number;
|
|
286
|
+
}>;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Patient Lifetime Value Metrics
|
|
291
|
+
* Patient value analysis
|
|
292
|
+
*/
|
|
293
|
+
export interface PatientLifetimeValueMetrics {
|
|
294
|
+
totalPatients: number;
|
|
295
|
+
averageLifetimeValue: number;
|
|
296
|
+
currency: string;
|
|
297
|
+
topPatients: Array<{
|
|
298
|
+
patientId: string;
|
|
299
|
+
patientName: string;
|
|
300
|
+
lifetimeValue: number;
|
|
301
|
+
appointmentCount: number;
|
|
302
|
+
}>;
|
|
303
|
+
valueDistribution: Array<{
|
|
304
|
+
range: string; // e.g., "0-500", "500-1000", "1000+"
|
|
305
|
+
count: number;
|
|
306
|
+
percentage: number;
|
|
307
|
+
}>;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Patient Retention Metrics
|
|
312
|
+
* Patient retention and return analysis
|
|
313
|
+
*/
|
|
314
|
+
export interface PatientRetentionMetrics {
|
|
315
|
+
totalPatients: number;
|
|
316
|
+
newPatients: number;
|
|
317
|
+
returningPatients: number;
|
|
318
|
+
retentionRate: number; // percentage
|
|
319
|
+
averageAppointmentsPerPatient: number;
|
|
320
|
+
patientsByAppointmentCount: Array<{
|
|
321
|
+
appointmentCount: number;
|
|
322
|
+
patientCount: number;
|
|
323
|
+
percentage: number;
|
|
324
|
+
}>;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Cost Per Patient Metrics
|
|
329
|
+
* Cost analysis per patient
|
|
330
|
+
*/
|
|
331
|
+
export interface CostPerPatientMetrics {
|
|
332
|
+
totalPatients: number;
|
|
333
|
+
totalRevenue: number;
|
|
334
|
+
averageCostPerPatient: number;
|
|
335
|
+
currency: string;
|
|
336
|
+
costDistribution: Array<{
|
|
337
|
+
range: string;
|
|
338
|
+
patientCount: number;
|
|
339
|
+
percentage: number;
|
|
340
|
+
}>;
|
|
341
|
+
patientCosts?: Array<{
|
|
342
|
+
patientId: string;
|
|
343
|
+
patientName: string;
|
|
344
|
+
totalCost: number;
|
|
345
|
+
appointmentCount: number;
|
|
346
|
+
averageCost: number;
|
|
347
|
+
}>;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Payment Status Breakdown
|
|
352
|
+
* Analysis of payment statuses
|
|
353
|
+
*/
|
|
354
|
+
export interface PaymentStatusBreakdown {
|
|
355
|
+
totalAppointments: number;
|
|
356
|
+
byStatus: Partial<Record<PaymentStatus, {
|
|
357
|
+
count: number;
|
|
358
|
+
percentage: number;
|
|
359
|
+
totalRevenue: number;
|
|
360
|
+
}>>;
|
|
361
|
+
unpaidCount: number;
|
|
362
|
+
unpaidRevenue: number;
|
|
363
|
+
paidCount: number;
|
|
364
|
+
paidRevenue: number;
|
|
365
|
+
partiallyPaidCount: number;
|
|
366
|
+
partiallyPaidRevenue: number;
|
|
367
|
+
refundedCount: number;
|
|
368
|
+
refundedRevenue: number;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Clinic Analytics
|
|
373
|
+
* Comprehensive clinic performance metrics
|
|
374
|
+
*/
|
|
375
|
+
export interface ClinicAnalytics {
|
|
376
|
+
clinicBranchId: string;
|
|
377
|
+
clinicName: string;
|
|
378
|
+
totalAppointments: number;
|
|
379
|
+
completedAppointments: number;
|
|
380
|
+
canceledAppointments: number;
|
|
381
|
+
noShowAppointments: number;
|
|
382
|
+
cancellationRate: number; // percentage
|
|
383
|
+
noShowRate: number; // percentage
|
|
384
|
+
totalRevenue: number;
|
|
385
|
+
averageRevenuePerAppointment: number;
|
|
386
|
+
currency: string;
|
|
387
|
+
practitionerCount: number;
|
|
388
|
+
patientCount: number;
|
|
389
|
+
procedureCount: number;
|
|
390
|
+
topPractitioners: Array<{
|
|
391
|
+
practitionerId: string;
|
|
392
|
+
practitionerName: string;
|
|
393
|
+
appointmentCount: number;
|
|
394
|
+
revenue: number;
|
|
395
|
+
}>;
|
|
396
|
+
topProcedures: Array<{
|
|
397
|
+
procedureId: string;
|
|
398
|
+
procedureName: string;
|
|
399
|
+
appointmentCount: number;
|
|
400
|
+
revenue: number;
|
|
401
|
+
}>;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Clinic Comparison Metrics
|
|
406
|
+
* Comparison data for multiple clinics
|
|
407
|
+
*/
|
|
408
|
+
export interface ClinicComparisonMetrics {
|
|
409
|
+
clinicBranchId: string;
|
|
410
|
+
clinicName: string;
|
|
411
|
+
totalAppointments: number;
|
|
412
|
+
completedAppointments: number;
|
|
413
|
+
cancellationRate: number;
|
|
414
|
+
noShowRate: number;
|
|
415
|
+
totalRevenue: number;
|
|
416
|
+
averageRevenuePerAppointment: number;
|
|
417
|
+
practitionerCount: number;
|
|
418
|
+
patientCount: number;
|
|
419
|
+
efficiency: number; // percentage
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Procedure Popularity
|
|
424
|
+
* Popularity metrics for procedures
|
|
425
|
+
*/
|
|
426
|
+
export interface ProcedurePopularity {
|
|
427
|
+
procedureId: string;
|
|
428
|
+
procedureName: string;
|
|
429
|
+
categoryName: string;
|
|
430
|
+
subcategoryName: string;
|
|
431
|
+
technologyName: string;
|
|
432
|
+
appointmentCount: number;
|
|
433
|
+
completedCount: number;
|
|
434
|
+
rank: number;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Procedure Profitability
|
|
439
|
+
* Profitability metrics for procedures
|
|
440
|
+
*/
|
|
441
|
+
export interface ProcedureProfitability {
|
|
442
|
+
procedureId: string;
|
|
443
|
+
procedureName: string;
|
|
444
|
+
categoryName: string;
|
|
445
|
+
subcategoryName: string;
|
|
446
|
+
technologyName: string;
|
|
447
|
+
totalRevenue: number;
|
|
448
|
+
averageRevenue: number;
|
|
449
|
+
appointmentCount: number;
|
|
450
|
+
rank: number;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Cancellation Reason Statistics
|
|
455
|
+
* Breakdown of cancellation reasons
|
|
456
|
+
*/
|
|
457
|
+
export interface CancellationReasonStats {
|
|
458
|
+
reason: string;
|
|
459
|
+
count: number;
|
|
460
|
+
percentage: number;
|
|
461
|
+
averageLeadTime: number; // hours
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Dashboard Analytics
|
|
466
|
+
* Comprehensive dashboard data aggregation
|
|
467
|
+
*/
|
|
468
|
+
export interface DashboardAnalytics {
|
|
469
|
+
overview: {
|
|
470
|
+
totalAppointments: number;
|
|
471
|
+
completedAppointments: number;
|
|
472
|
+
canceledAppointments: number;
|
|
473
|
+
noShowAppointments: number;
|
|
474
|
+
pendingAppointments: number;
|
|
475
|
+
confirmedAppointments: number;
|
|
476
|
+
totalRevenue: number;
|
|
477
|
+
averageRevenuePerAppointment: number;
|
|
478
|
+
currency: string;
|
|
479
|
+
uniquePatients: number;
|
|
480
|
+
uniquePractitioners: number;
|
|
481
|
+
uniqueProcedures: number;
|
|
482
|
+
cancellationRate: number;
|
|
483
|
+
noShowRate: number;
|
|
484
|
+
};
|
|
485
|
+
practitionerMetrics: PractitionerAnalytics[];
|
|
486
|
+
procedureMetrics: ProcedureAnalytics[];
|
|
487
|
+
cancellationMetrics: CancellationMetrics;
|
|
488
|
+
noShowMetrics: NoShowMetrics;
|
|
489
|
+
revenueTrends: RevenueTrend[];
|
|
490
|
+
timeEfficiency: TimeEfficiencyMetrics;
|
|
491
|
+
topProducts: ProductUsageMetrics[];
|
|
492
|
+
recentActivity: Array<{
|
|
493
|
+
type: 'appointment' | 'cancellation' | 'completion' | 'no_show';
|
|
494
|
+
date: Date;
|
|
495
|
+
description: string;
|
|
496
|
+
entityId?: string;
|
|
497
|
+
entityName?: string;
|
|
498
|
+
}>;
|
|
499
|
+
}
|
|
500
|
+
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { EntityType } from './analytics.types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base interface for grouped analytics results
|
|
5
|
+
* All grouped analytics share common entity identification
|
|
6
|
+
*/
|
|
7
|
+
export interface GroupedAnalyticsBase {
|
|
8
|
+
entityId: string;
|
|
9
|
+
entityName: string;
|
|
10
|
+
entityType: EntityType;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Grouped Revenue Metrics
|
|
15
|
+
* Revenue analytics grouped by clinic, practitioner, procedure, or patient
|
|
16
|
+
*/
|
|
17
|
+
export interface GroupedRevenueMetrics extends GroupedAnalyticsBase {
|
|
18
|
+
totalRevenue: number;
|
|
19
|
+
averageRevenuePerAppointment: number;
|
|
20
|
+
totalAppointments: number;
|
|
21
|
+
completedAppointments: number;
|
|
22
|
+
currency: string;
|
|
23
|
+
unpaidRevenue: number;
|
|
24
|
+
refundedRevenue: number;
|
|
25
|
+
totalTax: number;
|
|
26
|
+
totalSubtotal: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Grouped Product Usage Metrics
|
|
31
|
+
* Product usage analytics grouped by clinic, practitioner, procedure, or patient
|
|
32
|
+
*/
|
|
33
|
+
export interface GroupedProductUsageMetrics extends GroupedAnalyticsBase {
|
|
34
|
+
totalProductsUsed: number;
|
|
35
|
+
uniqueProducts: number;
|
|
36
|
+
totalProductRevenue: number;
|
|
37
|
+
totalProductQuantity: number;
|
|
38
|
+
averageProductsPerAppointment: number;
|
|
39
|
+
topProducts: Array<{
|
|
40
|
+
productId: string;
|
|
41
|
+
productName: string;
|
|
42
|
+
brandName: string;
|
|
43
|
+
totalQuantity: number;
|
|
44
|
+
totalRevenue: number;
|
|
45
|
+
usageCount: number;
|
|
46
|
+
}>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Grouped Patient Retention Metrics
|
|
51
|
+
* Patient retention analytics grouped by clinic, practitioner, or procedure
|
|
52
|
+
*/
|
|
53
|
+
export interface GroupedPatientRetentionMetrics extends GroupedAnalyticsBase {
|
|
54
|
+
totalPatients: number;
|
|
55
|
+
newPatients: number;
|
|
56
|
+
returningPatients: number;
|
|
57
|
+
retentionRate: number; // percentage
|
|
58
|
+
averageAppointmentsPerPatient: number;
|
|
59
|
+
patientsByAppointmentCount: Array<{
|
|
60
|
+
appointmentCount: number;
|
|
61
|
+
patientCount: number;
|
|
62
|
+
percentage: number;
|
|
63
|
+
}>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Grouped Time Efficiency Metrics
|
|
68
|
+
* Time efficiency analytics grouped by clinic, practitioner, procedure, or patient
|
|
69
|
+
*/
|
|
70
|
+
export interface GroupedTimeEfficiencyMetrics extends GroupedAnalyticsBase {
|
|
71
|
+
totalAppointments: number;
|
|
72
|
+
appointmentsWithActualTime: number;
|
|
73
|
+
averageBookedDuration: number; // minutes
|
|
74
|
+
averageActualDuration: number; // minutes
|
|
75
|
+
averageEfficiency: number; // percentage
|
|
76
|
+
totalOverrun: number; // minutes
|
|
77
|
+
totalUnderutilization: number; // minutes
|
|
78
|
+
averageOverrun: number; // minutes
|
|
79
|
+
averageUnderutilization: number; // minutes
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Grouped Patient Behavior Metrics
|
|
84
|
+
* Patient behavior (no-show, cancellation) grouped by clinic, practitioner, or procedure
|
|
85
|
+
*/
|
|
86
|
+
export interface GroupedPatientBehaviorMetrics extends GroupedAnalyticsBase {
|
|
87
|
+
totalPatients: number;
|
|
88
|
+
patientsWithNoShows: number;
|
|
89
|
+
patientsWithCancellations: number;
|
|
90
|
+
averageNoShowRate: number; // percentage (average across patients)
|
|
91
|
+
averageCancellationRate: number; // percentage (average across patients)
|
|
92
|
+
topNoShowPatients: Array<{
|
|
93
|
+
patientId: string;
|
|
94
|
+
patientName: string;
|
|
95
|
+
noShowCount: number;
|
|
96
|
+
totalAppointments: number;
|
|
97
|
+
noShowRate: number;
|
|
98
|
+
}>;
|
|
99
|
+
topCancellationPatients: Array<{
|
|
100
|
+
patientId: string;
|
|
101
|
+
patientName: string;
|
|
102
|
+
cancellationCount: number;
|
|
103
|
+
totalAppointments: number;
|
|
104
|
+
cancellationRate: number;
|
|
105
|
+
}>;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Grouped Procedure Performance Metrics
|
|
110
|
+
* Procedure performance grouped by clinic or practitioner
|
|
111
|
+
*/
|
|
112
|
+
export interface GroupedProcedurePerformanceMetrics extends GroupedAnalyticsBase {
|
|
113
|
+
totalProcedures: number;
|
|
114
|
+
totalAppointments: number;
|
|
115
|
+
completedAppointments: number;
|
|
116
|
+
totalRevenue: number;
|
|
117
|
+
averageRevenuePerProcedure: number;
|
|
118
|
+
topProcedures: Array<{
|
|
119
|
+
procedureId: string;
|
|
120
|
+
procedureName: string;
|
|
121
|
+
appointmentCount: number;
|
|
122
|
+
revenue: number;
|
|
123
|
+
cancellationRate: number;
|
|
124
|
+
noShowRate: number;
|
|
125
|
+
}>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Grouped Practitioner Performance Metrics
|
|
130
|
+
* Practitioner performance grouped by clinic
|
|
131
|
+
*/
|
|
132
|
+
export interface GroupedPractitionerPerformanceMetrics extends GroupedAnalyticsBase {
|
|
133
|
+
totalPractitioners: number;
|
|
134
|
+
totalAppointments: number;
|
|
135
|
+
completedAppointments: number;
|
|
136
|
+
totalRevenue: number;
|
|
137
|
+
averageRevenuePerPractitioner: number;
|
|
138
|
+
topPractitioners: Array<{
|
|
139
|
+
practitionerId: string;
|
|
140
|
+
practitionerName: string;
|
|
141
|
+
appointmentCount: number;
|
|
142
|
+
revenue: number;
|
|
143
|
+
cancellationRate: number;
|
|
144
|
+
noShowRate: number;
|
|
145
|
+
timeEfficiency: number;
|
|
146
|
+
}>;
|
|
147
|
+
}
|
|
148
|
+
|