@blackcode_sa/metaestetics-api 1.13.5 → 1.13.8
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 +20 -1
- package/dist/admin/index.d.ts +20 -1
- package/dist/admin/index.js +217 -1
- package/dist/admin/index.mjs +217 -1
- package/dist/index.d.mts +26 -3
- package/dist/index.d.ts +26 -3
- package/dist/index.js +168 -6
- package/dist/index.mjs +168 -6
- package/package.json +121 -121
- package/src/__mocks__/firstore.ts +10 -10
- package/src/admin/aggregation/README.md +79 -79
- package/src/admin/aggregation/appointment/README.md +128 -128
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +1984 -1984
- package/src/admin/aggregation/appointment/index.ts +1 -1
- package/src/admin/aggregation/clinic/README.md +52 -52
- package/src/admin/aggregation/clinic/clinic.aggregation.service.ts +966 -703
- package/src/admin/aggregation/clinic/index.ts +1 -1
- package/src/admin/aggregation/forms/README.md +13 -13
- package/src/admin/aggregation/forms/filled-forms.aggregation.service.ts +322 -322
- package/src/admin/aggregation/forms/index.ts +1 -1
- package/src/admin/aggregation/index.ts +8 -8
- package/src/admin/aggregation/patient/README.md +27 -27
- package/src/admin/aggregation/patient/index.ts +1 -1
- package/src/admin/aggregation/patient/patient.aggregation.service.ts +141 -141
- package/src/admin/aggregation/practitioner/README.md +42 -42
- package/src/admin/aggregation/practitioner/index.ts +1 -1
- package/src/admin/aggregation/practitioner/practitioner.aggregation.service.ts +433 -433
- package/src/admin/aggregation/practitioner-invite/index.ts +1 -1
- package/src/admin/aggregation/practitioner-invite/practitioner-invite.aggregation.service.ts +961 -961
- package/src/admin/aggregation/procedure/README.md +43 -43
- package/src/admin/aggregation/procedure/index.ts +1 -1
- package/src/admin/aggregation/procedure/procedure.aggregation.service.ts +702 -702
- package/src/admin/aggregation/reviews/index.ts +1 -1
- package/src/admin/aggregation/reviews/reviews.aggregation.service.ts +689 -689
- package/src/admin/analytics/analytics.admin.service.ts +278 -278
- package/src/admin/analytics/index.ts +2 -2
- package/src/admin/booking/README.md +125 -125
- package/src/admin/booking/booking.admin.ts +1037 -1037
- package/src/admin/booking/booking.calculator.ts +712 -712
- package/src/admin/booking/booking.types.ts +59 -59
- package/src/admin/booking/index.ts +3 -3
- package/src/admin/booking/timezones-problem.md +185 -185
- package/src/admin/calendar/README.md +7 -7
- package/src/admin/calendar/calendar.admin.service.ts +345 -345
- package/src/admin/calendar/index.ts +1 -1
- package/src/admin/documentation-templates/document-manager.admin.ts +260 -260
- package/src/admin/documentation-templates/index.ts +1 -1
- package/src/admin/free-consultation/free-consultation-utils.admin.ts +148 -148
- package/src/admin/free-consultation/index.ts +1 -1
- package/src/admin/index.ts +81 -81
- package/src/admin/logger/index.ts +78 -78
- package/src/admin/mailing/README.md +95 -95
- package/src/admin/mailing/appointment/appointment.mailing.service.ts +732 -732
- package/src/admin/mailing/appointment/index.ts +1 -1
- package/src/admin/mailing/appointment/templates/patient/appointment-confirmed.html +40 -40
- package/src/admin/mailing/base.mailing.service.ts +208 -208
- package/src/admin/mailing/index.ts +3 -3
- package/src/admin/mailing/practitionerInvite/existing-practitioner-invite.mailing.ts +611 -611
- package/src/admin/mailing/practitionerInvite/index.ts +2 -2
- package/src/admin/mailing/practitionerInvite/practitionerInvite.mailing.ts +395 -395
- package/src/admin/mailing/practitionerInvite/templates/existing-practitioner-invitation.template.ts +155 -155
- package/src/admin/mailing/practitionerInvite/templates/invitation.template.ts +101 -101
- package/src/admin/mailing/practitionerInvite/templates/invite-accepted-notification.template.ts +228 -228
- package/src/admin/mailing/practitionerInvite/templates/invite-rejected-notification.template.ts +242 -242
- package/src/admin/notifications/index.ts +1 -1
- package/src/admin/notifications/notifications.admin.ts +710 -710
- package/src/admin/requirements/README.md +128 -128
- package/src/admin/requirements/index.ts +1 -1
- package/src/admin/requirements/patient-requirements.admin.service.ts +475 -475
- package/src/admin/users/index.ts +1 -1
- package/src/admin/users/user-profile.admin.ts +405 -405
- package/src/backoffice/constants/certification.constants.ts +13 -13
- package/src/backoffice/constants/index.ts +1 -1
- package/src/backoffice/errors/backoffice.errors.ts +181 -181
- package/src/backoffice/errors/index.ts +1 -1
- package/src/backoffice/expo-safe/README.md +26 -26
- package/src/backoffice/expo-safe/index.ts +41 -41
- package/src/backoffice/index.ts +5 -5
- package/src/backoffice/services/FIXES_README.md +102 -102
- package/src/backoffice/services/README.md +57 -57
- package/src/backoffice/services/analytics.service.proposal.md +863 -863
- package/src/backoffice/services/analytics.service.summary.md +143 -143
- package/src/backoffice/services/brand.service.ts +256 -256
- package/src/backoffice/services/category.service.ts +384 -384
- package/src/backoffice/services/constants.service.ts +385 -385
- package/src/backoffice/services/documentation-template.service.ts +202 -202
- package/src/backoffice/services/index.ts +10 -10
- package/src/backoffice/services/migrate-products.ts +116 -116
- package/src/backoffice/services/product.service.ts +553 -553
- package/src/backoffice/services/requirement.service.ts +235 -235
- package/src/backoffice/services/subcategory.service.ts +461 -461
- package/src/backoffice/services/technology.service.ts +1151 -1151
- package/src/backoffice/types/README.md +12 -12
- package/src/backoffice/types/admin-constants.types.ts +69 -69
- package/src/backoffice/types/brand.types.ts +29 -29
- package/src/backoffice/types/category.types.ts +67 -67
- package/src/backoffice/types/documentation-templates.types.ts +28 -28
- package/src/backoffice/types/index.ts +10 -10
- package/src/backoffice/types/procedure-product.types.ts +38 -38
- package/src/backoffice/types/product.types.ts +240 -240
- package/src/backoffice/types/requirement.types.ts +63 -63
- package/src/backoffice/types/static/README.md +18 -18
- package/src/backoffice/types/static/blocking-condition.types.ts +21 -21
- package/src/backoffice/types/static/certification.types.ts +37 -37
- package/src/backoffice/types/static/contraindication.types.ts +19 -19
- package/src/backoffice/types/static/index.ts +6 -6
- package/src/backoffice/types/static/pricing.types.ts +16 -16
- package/src/backoffice/types/static/procedure-family.types.ts +14 -14
- package/src/backoffice/types/static/treatment-benefit.types.ts +22 -22
- package/src/backoffice/types/subcategory.types.ts +34 -34
- package/src/backoffice/types/technology.types.ts +168 -168
- package/src/backoffice/validations/index.ts +1 -1
- package/src/backoffice/validations/schemas.ts +164 -164
- package/src/config/__mocks__/firebase.ts +99 -99
- package/src/config/firebase.ts +78 -78
- package/src/config/index.ts +9 -9
- package/src/errors/auth.error.ts +6 -6
- package/src/errors/auth.errors.ts +211 -200
- package/src/errors/clinic.errors.ts +32 -32
- package/src/errors/firebase.errors.ts +47 -47
- package/src/errors/user.errors.ts +99 -99
- package/src/index.backup.ts +407 -407
- package/src/index.ts +6 -6
- package/src/locales/en.ts +31 -31
- package/src/recommender/admin/index.ts +1 -1
- package/src/recommender/admin/services/recommender.service.admin.ts +5 -5
- package/src/recommender/front/index.ts +1 -1
- package/src/recommender/front/services/onboarding.service.ts +5 -5
- package/src/recommender/front/services/recommender.service.ts +3 -3
- package/src/recommender/index.ts +1 -1
- package/src/services/PATIENTAUTH.MD +197 -197
- package/src/services/README.md +106 -106
- package/src/services/__tests__/auth/auth.mock.test.ts +17 -17
- package/src/services/__tests__/auth/auth.setup.ts +293 -293
- package/src/services/__tests__/auth.service.test.ts +346 -346
- package/src/services/__tests__/base.service.test.ts +77 -77
- package/src/services/__tests__/user.service.test.ts +528 -528
- package/src/services/analytics/ARCHITECTURE.md +199 -199
- package/src/services/analytics/CLOUD_FUNCTIONS.md +225 -225
- package/src/services/analytics/GROUPED_ANALYTICS.md +501 -501
- package/src/services/analytics/QUICK_START.md +393 -393
- package/src/services/analytics/README.md +304 -304
- package/src/services/analytics/SUMMARY.md +141 -141
- package/src/services/analytics/TRENDS.md +380 -380
- package/src/services/analytics/USAGE_GUIDE.md +518 -518
- package/src/services/analytics/analytics-cloud.service.ts +222 -222
- package/src/services/analytics/analytics.service.ts +2142 -2142
- package/src/services/analytics/index.ts +4 -4
- package/src/services/analytics/review-analytics.service.ts +941 -941
- package/src/services/analytics/utils/appointment-filtering.utils.ts +138 -138
- package/src/services/analytics/utils/cost-calculation.utils.ts +182 -182
- package/src/services/analytics/utils/grouping.utils.ts +434 -434
- package/src/services/analytics/utils/stored-analytics.utils.ts +347 -347
- package/src/services/analytics/utils/time-calculation.utils.ts +186 -186
- package/src/services/analytics/utils/trend-calculation.utils.ts +200 -200
- package/src/services/appointment/README.md +17 -17
- package/src/services/appointment/appointment.service.ts +2558 -2558
- package/src/services/appointment/index.ts +1 -1
- package/src/services/appointment/utils/appointment.utils.ts +552 -552
- package/src/services/appointment/utils/extended-procedure.utils.ts +314 -314
- package/src/services/appointment/utils/form-initialization.utils.ts +225 -225
- package/src/services/appointment/utils/recommended-procedure.utils.ts +195 -195
- package/src/services/appointment/utils/zone-management.utils.ts +353 -353
- package/src/services/appointment/utils/zone-photo.utils.ts +152 -152
- package/src/services/auth/auth.service.ts +1043 -989
- package/src/services/auth/auth.v2.service.ts +961 -961
- package/src/services/auth/index.ts +7 -7
- package/src/services/auth/utils/error.utils.ts +90 -90
- package/src/services/auth/utils/firebase.utils.ts +49 -49
- package/src/services/auth/utils/index.ts +21 -21
- package/src/services/auth/utils/practitioner.utils.ts +125 -125
- package/src/services/base.service.ts +41 -41
- package/src/services/calendar/calendar.service.ts +1077 -1077
- package/src/services/calendar/calendar.v2.service.ts +1683 -1683
- package/src/services/calendar/calendar.v3.service.ts +313 -313
- package/src/services/calendar/externalCalendar.service.ts +178 -178
- package/src/services/calendar/index.ts +5 -5
- package/src/services/calendar/synced-calendars.service.ts +743 -743
- package/src/services/calendar/utils/appointment.utils.ts +265 -265
- package/src/services/calendar/utils/calendar-event.utils.ts +646 -646
- package/src/services/calendar/utils/clinic.utils.ts +237 -237
- package/src/services/calendar/utils/docs.utils.ts +157 -157
- package/src/services/calendar/utils/google-calendar.utils.ts +697 -697
- package/src/services/calendar/utils/index.ts +8 -8
- package/src/services/calendar/utils/patient.utils.ts +198 -198
- package/src/services/calendar/utils/practitioner.utils.ts +221 -221
- package/src/services/calendar/utils/synced-calendar.utils.ts +472 -472
- package/src/services/clinic/README.md +204 -204
- package/src/services/clinic/__tests__/clinic-admin.service.test.ts +287 -287
- package/src/services/clinic/__tests__/clinic-group.service.test.ts +352 -352
- package/src/services/clinic/__tests__/clinic.service.test.ts +354 -354
- package/src/services/clinic/billing-transactions.service.ts +217 -217
- package/src/services/clinic/clinic-admin.service.ts +202 -202
- package/src/services/clinic/clinic-group.service.ts +310 -310
- package/src/services/clinic/clinic.service.ts +708 -708
- package/src/services/clinic/index.ts +5 -5
- package/src/services/clinic/practitioner-invite.service.ts +519 -519
- package/src/services/clinic/utils/admin.utils.ts +551 -551
- package/src/services/clinic/utils/clinic-group.utils.ts +646 -646
- package/src/services/clinic/utils/clinic.utils.ts +949 -949
- package/src/services/clinic/utils/filter.utils.d.ts +23 -23
- package/src/services/clinic/utils/filter.utils.ts +446 -446
- package/src/services/clinic/utils/index.ts +11 -11
- package/src/services/clinic/utils/photos.utils.ts +188 -188
- package/src/services/clinic/utils/search.utils.ts +84 -84
- package/src/services/clinic/utils/tag.utils.ts +124 -124
- package/src/services/documentation-templates/documentation-template.service.ts +537 -537
- package/src/services/documentation-templates/filled-document.service.ts +587 -587
- package/src/services/documentation-templates/index.ts +2 -2
- package/src/services/index.ts +14 -14
- package/src/services/media/index.ts +1 -1
- package/src/services/media/media.service.ts +418 -418
- package/src/services/notifications/__tests__/notification.service.test.ts +242 -242
- package/src/services/notifications/index.ts +1 -1
- package/src/services/notifications/notification.service.ts +215 -215
- package/src/services/patient/README.md +48 -48
- package/src/services/patient/To-Do.md +43 -43
- package/src/services/patient/__tests__/patient.service.test.ts +294 -294
- package/src/services/patient/index.ts +2 -2
- package/src/services/patient/patient.service.ts +883 -883
- package/src/services/patient/patientRequirements.service.ts +285 -285
- package/src/services/patient/utils/aesthetic-analysis.utils.ts +176 -176
- package/src/services/patient/utils/clinic.utils.ts +80 -80
- package/src/services/patient/utils/docs.utils.ts +142 -142
- package/src/services/patient/utils/index.ts +9 -9
- package/src/services/patient/utils/location.utils.ts +126 -126
- package/src/services/patient/utils/medical-stuff.utils.ts +143 -143
- package/src/services/patient/utils/medical.utils.ts +458 -458
- package/src/services/patient/utils/practitioner.utils.ts +260 -260
- package/src/services/patient/utils/profile.utils.ts +510 -510
- package/src/services/patient/utils/sensitive.utils.ts +260 -260
- package/src/services/patient/utils/token.utils.ts +211 -211
- package/src/services/practitioner/README.md +145 -145
- package/src/services/practitioner/index.ts +1 -1
- package/src/services/practitioner/practitioner.service.ts +1799 -1742
- package/src/services/procedure/README.md +163 -163
- package/src/services/procedure/index.ts +1 -1
- package/src/services/procedure/procedure.service.ts +2307 -2200
- package/src/services/reviews/index.ts +1 -1
- package/src/services/reviews/reviews.service.ts +734 -734
- package/src/services/user/index.ts +1 -1
- package/src/services/user/user.service.ts +489 -489
- package/src/services/user/user.v2.service.ts +466 -466
- package/src/types/analytics/analytics.types.ts +597 -597
- package/src/types/analytics/grouped-analytics.types.ts +173 -173
- package/src/types/analytics/index.ts +4 -4
- package/src/types/analytics/stored-analytics.types.ts +137 -137
- package/src/types/appointment/index.ts +480 -480
- package/src/types/calendar/index.ts +258 -258
- package/src/types/calendar/synced-calendar.types.ts +66 -66
- package/src/types/clinic/index.ts +498 -498
- package/src/types/clinic/practitioner-invite.types.ts +91 -91
- package/src/types/clinic/preferences.types.ts +159 -159
- package/src/types/clinic/to-do +3 -3
- package/src/types/documentation-templates/index.ts +308 -308
- package/src/types/index.ts +47 -47
- package/src/types/notifications/README.md +77 -77
- package/src/types/notifications/index.ts +286 -286
- package/src/types/patient/aesthetic-analysis.types.ts +66 -66
- package/src/types/patient/allergies.ts +58 -58
- package/src/types/patient/index.ts +275 -275
- package/src/types/patient/medical-info.types.ts +152 -152
- package/src/types/patient/patient-requirements.ts +92 -92
- package/src/types/patient/token.types.ts +61 -61
- package/src/types/practitioner/index.ts +206 -206
- package/src/types/procedure/index.ts +181 -181
- package/src/types/profile/index.ts +39 -39
- package/src/types/reviews/index.ts +132 -132
- package/src/types/tz-lookup.d.ts +4 -4
- package/src/types/user/index.ts +38 -38
- package/src/utils/TIMESTAMPS.md +176 -176
- package/src/utils/TimestampUtils.ts +241 -241
- package/src/utils/index.ts +1 -1
- package/src/validations/appointment.schema.ts +574 -574
- package/src/validations/calendar.schema.ts +225 -225
- package/src/validations/clinic.schema.ts +494 -494
- package/src/validations/common.schema.ts +25 -25
- package/src/validations/documentation-templates/index.ts +1 -1
- package/src/validations/documentation-templates/template.schema.ts +220 -220
- package/src/validations/documentation-templates.schema.ts +10 -10
- package/src/validations/index.ts +20 -20
- package/src/validations/media.schema.ts +10 -10
- package/src/validations/notification.schema.ts +90 -90
- package/src/validations/patient/aesthetic-analysis.schema.ts +55 -55
- package/src/validations/patient/medical-info.schema.ts +125 -125
- package/src/validations/patient/patient-requirements.schema.ts +84 -84
- package/src/validations/patient/token.schema.ts +29 -29
- package/src/validations/patient.schema.ts +217 -217
- package/src/validations/practitioner.schema.ts +222 -222
- package/src/validations/procedure-product.schema.ts +41 -41
- package/src/validations/procedure.schema.ts +124 -124
- package/src/validations/profile-info.schema.ts +41 -41
- package/src/validations/reviews.schema.ts +195 -195
- package/src/validations/schemas.ts +104 -104
- package/src/validations/shared.schema.ts +78 -78
|
@@ -1,501 +1,501 @@
|
|
|
1
|
-
# Grouped Analytics - Complete Guide
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
All analytics methods now support **consistent grouping** by clinic, practitioner, procedure, patient, or technology. This allows you to analyze metrics from any perspective:
|
|
6
|
-
|
|
7
|
-
- **By Clinic**: See how different clinics perform
|
|
8
|
-
- **By Practitioner**: Compare doctor performance
|
|
9
|
-
- **By Procedure**: Analyze procedure effectiveness (doctor-specific procedures)
|
|
10
|
-
- **By Technology**: Aggregate all procedures using the same technology across all doctors (e.g., all Botox treatments)
|
|
11
|
-
- **By Patient**: Understand patient behavior patterns
|
|
12
|
-
|
|
13
|
-
## Available Grouped Methods
|
|
14
|
-
|
|
15
|
-
### 1. **Revenue Metrics by Entity** 💰
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
// Revenue grouped by practitioner (doctor)
|
|
19
|
-
const revenueByDoctor = await analyticsService.getRevenueMetricsByEntity(
|
|
20
|
-
'practitioner',
|
|
21
|
-
{ start: new Date('2024-01-01'), end: new Date('2024-12-31') }
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
// Returns array:
|
|
25
|
-
// [
|
|
26
|
-
// {
|
|
27
|
-
// entityId: 'practitioner-123',
|
|
28
|
-
// entityName: 'Dr. Smith',
|
|
29
|
-
// entityType: 'practitioner',
|
|
30
|
-
// totalRevenue: 50000,
|
|
31
|
-
// averageRevenuePerAppointment: 500,
|
|
32
|
-
// totalAppointments: 100,
|
|
33
|
-
// completedAppointments: 95,
|
|
34
|
-
// currency: 'CHF',
|
|
35
|
-
// unpaidRevenue: 5000,
|
|
36
|
-
// refundedRevenue: 0,
|
|
37
|
-
// totalTax: 4000,
|
|
38
|
-
// totalSubtotal: 46000
|
|
39
|
-
// },
|
|
40
|
-
// ...
|
|
41
|
-
// ]
|
|
42
|
-
|
|
43
|
-
// Revenue grouped by clinic
|
|
44
|
-
const revenueByClinic = await analyticsService.getRevenueMetricsByEntity(
|
|
45
|
-
'clinic',
|
|
46
|
-
dateRange
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
// Revenue grouped by procedure
|
|
50
|
-
const revenueByProcedure = await analyticsService.getRevenueMetricsByEntity(
|
|
51
|
-
'procedure',
|
|
52
|
-
dateRange
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
// Revenue grouped by patient
|
|
56
|
-
const revenueByPatient = await analyticsService.getRevenueMetricsByEntity(
|
|
57
|
-
'patient',
|
|
58
|
-
dateRange
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
// Revenue grouped by technology (aggregates all procedures using same technology)
|
|
62
|
-
const revenueByTechnology = await analyticsService.getRevenueMetricsByEntity(
|
|
63
|
-
'technology',
|
|
64
|
-
dateRange
|
|
65
|
-
);
|
|
66
|
-
// Example: All Botox treatments across all doctors
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### 2. **Product Usage by Entity** 📦
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
// Product usage grouped by practitioner
|
|
73
|
-
const productUsageByDoctor = await analyticsService.getProductUsageMetricsByEntity(
|
|
74
|
-
'practitioner',
|
|
75
|
-
dateRange
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
// Returns array:
|
|
79
|
-
// [
|
|
80
|
-
// {
|
|
81
|
-
// entityId: 'practitioner-123',
|
|
82
|
-
// entityName: 'Dr. Smith',
|
|
83
|
-
// entityType: 'practitioner',
|
|
84
|
-
// totalProductsUsed: 15,
|
|
85
|
-
// uniqueProducts: 10,
|
|
86
|
-
// totalProductRevenue: 25000,
|
|
87
|
-
// totalProductQuantity: 500,
|
|
88
|
-
// averageProductsPerAppointment: 2.5,
|
|
89
|
-
// topProducts: [
|
|
90
|
-
// {
|
|
91
|
-
// productId: 'product-1',
|
|
92
|
-
// productName: 'Product A',
|
|
93
|
-
// brandName: 'Brand X',
|
|
94
|
-
// totalQuantity: 100,
|
|
95
|
-
// totalRevenue: 5000,
|
|
96
|
-
// usageCount: 50
|
|
97
|
-
// },
|
|
98
|
-
// ...
|
|
99
|
-
// ]
|
|
100
|
-
// },
|
|
101
|
-
// ...
|
|
102
|
-
// ]
|
|
103
|
-
|
|
104
|
-
// Product usage grouped by clinic, procedure, patient, or technology
|
|
105
|
-
const productUsageByClinic = await analyticsService.getProductUsageMetricsByEntity(
|
|
106
|
-
'clinic',
|
|
107
|
-
dateRange
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
// Product usage by technology (e.g., all Botox-related products)
|
|
111
|
-
const productUsageByTechnology = await analyticsService.getProductUsageMetricsByEntity(
|
|
112
|
-
'technology',
|
|
113
|
-
dateRange
|
|
114
|
-
);
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### 3. **Time Efficiency by Entity** ⏱️
|
|
118
|
-
|
|
119
|
-
```typescript
|
|
120
|
-
// Time efficiency grouped by practitioner
|
|
121
|
-
const timeEfficiencyByDoctor = await analyticsService.getTimeEfficiencyMetricsByEntity(
|
|
122
|
-
'practitioner',
|
|
123
|
-
dateRange
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
// Returns array:
|
|
127
|
-
// [
|
|
128
|
-
// {
|
|
129
|
-
// entityId: 'practitioner-123',
|
|
130
|
-
// entityName: 'Dr. Smith',
|
|
131
|
-
// entityType: 'practitioner',
|
|
132
|
-
// totalAppointments: 100,
|
|
133
|
-
// appointmentsWithActualTime: 95,
|
|
134
|
-
// averageBookedDuration: 60, // minutes
|
|
135
|
-
// averageActualDuration: 55, // minutes
|
|
136
|
-
// averageEfficiency: 91.67, // percentage
|
|
137
|
-
// totalOverrun: 500, // minutes
|
|
138
|
-
// totalUnderutilization: 200, // minutes
|
|
139
|
-
// averageOverrun: 5, // minutes
|
|
140
|
-
// averageUnderutilization: 2 // minutes
|
|
141
|
-
// },
|
|
142
|
-
// ...
|
|
143
|
-
// ]
|
|
144
|
-
|
|
145
|
-
// Time efficiency grouped by clinic, procedure, patient, or technology
|
|
146
|
-
const timeEfficiencyByClinic = await analyticsService.getTimeEfficiencyMetricsByEntity(
|
|
147
|
-
'clinic',
|
|
148
|
-
dateRange
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
// Time efficiency by technology (e.g., compare efficiency across all Botox vs. Filler treatments)
|
|
152
|
-
const timeEfficiencyByTechnology = await analyticsService.getTimeEfficiencyMetricsByEntity(
|
|
153
|
-
'technology',
|
|
154
|
-
dateRange
|
|
155
|
-
);
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### 4. **Patient Behavior by Entity** 👥
|
|
159
|
-
|
|
160
|
-
```typescript
|
|
161
|
-
// Patient behavior (no-shows, cancellations) grouped by practitioner
|
|
162
|
-
const patientBehaviorByDoctor = await analyticsService.getPatientBehaviorMetricsByEntity(
|
|
163
|
-
'practitioner',
|
|
164
|
-
dateRange
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
// Returns array:
|
|
168
|
-
// [
|
|
169
|
-
// {
|
|
170
|
-
// entityId: 'practitioner-123',
|
|
171
|
-
// entityName: 'Dr. Smith',
|
|
172
|
-
// entityType: 'practitioner',
|
|
173
|
-
// totalPatients: 50,
|
|
174
|
-
// patientsWithNoShows: 10,
|
|
175
|
-
// patientsWithCancellations: 15,
|
|
176
|
-
// averageNoShowRate: 8.5, // percentage
|
|
177
|
-
// averageCancellationRate: 12.3, // percentage
|
|
178
|
-
// topNoShowPatients: [
|
|
179
|
-
// {
|
|
180
|
-
// patientId: 'patient-1',
|
|
181
|
-
// patientName: 'John Doe',
|
|
182
|
-
// noShowCount: 3,
|
|
183
|
-
// totalAppointments: 10,
|
|
184
|
-
// noShowRate: 30.0
|
|
185
|
-
// },
|
|
186
|
-
// ...
|
|
187
|
-
// ],
|
|
188
|
-
// topCancellationPatients: [
|
|
189
|
-
// {
|
|
190
|
-
// patientId: 'patient-2',
|
|
191
|
-
// patientName: 'Jane Smith',
|
|
192
|
-
// cancellationCount: 5,
|
|
193
|
-
// totalAppointments: 15,
|
|
194
|
-
// cancellationRate: 33.3
|
|
195
|
-
// },
|
|
196
|
-
// ...
|
|
197
|
-
// ]
|
|
198
|
-
// },
|
|
199
|
-
// ...
|
|
200
|
-
// ]
|
|
201
|
-
|
|
202
|
-
// Patient behavior grouped by clinic or procedure
|
|
203
|
-
const patientBehaviorByClinic = await analyticsService.getPatientBehaviorMetricsByEntity(
|
|
204
|
-
'clinic',
|
|
205
|
-
dateRange
|
|
206
|
-
);
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### 5. **Cancellation Metrics by Entity** ❌
|
|
210
|
-
|
|
211
|
-
```typescript
|
|
212
|
-
// Already exists - cancellations grouped by entity
|
|
213
|
-
const cancellationsByDoctor = await analyticsService.getCancellationMetrics(
|
|
214
|
-
'practitioner',
|
|
215
|
-
dateRange
|
|
216
|
-
);
|
|
217
|
-
|
|
218
|
-
// Also supports: 'clinic', 'patient', 'procedure', 'technology'
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### 6. **No-Show Metrics by Entity** 🚫
|
|
222
|
-
|
|
223
|
-
```typescript
|
|
224
|
-
// Already exists - no-shows grouped by entity
|
|
225
|
-
const noShowsByDoctor = await analyticsService.getNoShowMetrics(
|
|
226
|
-
'practitioner',
|
|
227
|
-
dateRange
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
// Also supports: 'clinic', 'patient', 'procedure', 'technology'
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
## Real-World Use Cases
|
|
234
|
-
|
|
235
|
-
### Use Case 1: Revenue Comparison Across Doctors
|
|
236
|
-
|
|
237
|
-
```typescript
|
|
238
|
-
// Compare revenue generated by each doctor
|
|
239
|
-
const revenueByDoctor = await analyticsService.getRevenueMetricsByEntity(
|
|
240
|
-
'practitioner',
|
|
241
|
-
{ start: new Date('2024-01-01'), end: new Date('2024-12-31') }
|
|
242
|
-
);
|
|
243
|
-
|
|
244
|
-
// Sort by revenue (highest first)
|
|
245
|
-
const topPerformers = revenueByDoctor
|
|
246
|
-
.sort((a, b) => b.totalRevenue - a.totalRevenue)
|
|
247
|
-
.slice(0, 10);
|
|
248
|
-
|
|
249
|
-
console.log('Top 10 Revenue Generators:');
|
|
250
|
-
topPerformers.forEach((doctor, index) => {
|
|
251
|
-
console.log(`${index + 1}. ${doctor.entityName}: ${doctor.totalRevenue} ${doctor.currency}`);
|
|
252
|
-
console.log(` Avg per appointment: ${doctor.averageRevenuePerAppointment.toFixed(2)}`);
|
|
253
|
-
console.log(` Appointments: ${doctor.completedAppointments}`);
|
|
254
|
-
});
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
### Use Case 2: Product Usage by Procedure
|
|
258
|
-
|
|
259
|
-
```typescript
|
|
260
|
-
// See which products are used most for each procedure
|
|
261
|
-
const productUsageByProcedure = await analyticsService.getProductUsageMetricsByEntity(
|
|
262
|
-
'procedure',
|
|
263
|
-
dateRange
|
|
264
|
-
);
|
|
265
|
-
|
|
266
|
-
productUsageByProcedure.forEach(procedure => {
|
|
267
|
-
console.log(`\n${procedure.entityName}:`);
|
|
268
|
-
console.log(` Total Products Used: ${procedure.totalProductsUsed}`);
|
|
269
|
-
console.log(` Total Product Revenue: ${procedure.totalProductRevenue}`);
|
|
270
|
-
console.log(` Top Products:`);
|
|
271
|
-
procedure.topProducts.slice(0, 5).forEach(product => {
|
|
272
|
-
console.log(` - ${product.productName}: ${product.totalQuantity} units, ${product.totalRevenue} revenue`);
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
### Use Case 3: Time Efficiency by Clinic
|
|
278
|
-
|
|
279
|
-
```typescript
|
|
280
|
-
// Compare time efficiency across clinics
|
|
281
|
-
const timeEfficiencyByClinic = await analyticsService.getTimeEfficiencyMetricsByEntity(
|
|
282
|
-
'clinic',
|
|
283
|
-
dateRange
|
|
284
|
-
);
|
|
285
|
-
|
|
286
|
-
timeEfficiencyByClinic.forEach(clinic => {
|
|
287
|
-
console.log(`${clinic.entityName}:`);
|
|
288
|
-
console.log(` Efficiency: ${clinic.averageEfficiency.toFixed(1)}%`);
|
|
289
|
-
console.log(` Avg Booked: ${clinic.averageBookedDuration} min`);
|
|
290
|
-
console.log(` Avg Actual: ${clinic.averageActualDuration} min`);
|
|
291
|
-
console.log(` Avg Overrun: ${clinic.averageOverrun} min`);
|
|
292
|
-
});
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
### Use Case 4: Patient No-Show Patterns by Doctor
|
|
296
|
-
|
|
297
|
-
```typescript
|
|
298
|
-
// See which patients have highest no-show rates for each doctor
|
|
299
|
-
const patientBehaviorByDoctor = await analyticsService.getPatientBehaviorMetricsByEntity(
|
|
300
|
-
'practitioner',
|
|
301
|
-
dateRange
|
|
302
|
-
);
|
|
303
|
-
|
|
304
|
-
patientBehaviorByDoctor.forEach(doctor => {
|
|
305
|
-
console.log(`\n${doctor.entityName}:`);
|
|
306
|
-
console.log(` Total Patients: ${doctor.totalPatients}`);
|
|
307
|
-
console.log(` Patients with No-Shows: ${doctor.patientsWithNoShows}`);
|
|
308
|
-
console.log(` Average No-Show Rate: ${doctor.averageNoShowRate}%`);
|
|
309
|
-
console.log(` Top No-Show Patients:`);
|
|
310
|
-
doctor.topNoShowPatients.forEach(patient => {
|
|
311
|
-
console.log(` - ${patient.patientName}: ${patient.noShowRate.toFixed(1)}% (${patient.noShowCount}/${patient.totalAppointments})`);
|
|
312
|
-
});
|
|
313
|
-
});
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
### Use Case 5: Revenue by Patient
|
|
317
|
-
|
|
318
|
-
```typescript
|
|
319
|
-
// See which patients generate the most revenue
|
|
320
|
-
const revenueByPatient = await analyticsService.getRevenueMetricsByEntity(
|
|
321
|
-
'patient',
|
|
322
|
-
dateRange
|
|
323
|
-
);
|
|
324
|
-
|
|
325
|
-
const topPatients = revenueByPatient
|
|
326
|
-
.sort((a, b) => b.totalRevenue - a.totalRevenue)
|
|
327
|
-
.slice(0, 20);
|
|
328
|
-
|
|
329
|
-
console.log('Top 20 Patients by Revenue:');
|
|
330
|
-
topPatients.forEach((patient, index) => {
|
|
331
|
-
console.log(`${index + 1}. ${patient.entityName}: ${patient.totalRevenue} ${patient.currency}`);
|
|
332
|
-
console.log(` Appointments: ${patient.completedAppointments}`);
|
|
333
|
-
console.log(` Avg per appointment: ${patient.averageRevenuePerAppointment.toFixed(2)}`);
|
|
334
|
-
});
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### Use Case 6: Product Usage by Clinic
|
|
338
|
-
|
|
339
|
-
```typescript
|
|
340
|
-
// Compare product usage across clinics
|
|
341
|
-
const productUsageByClinic = await analyticsService.getProductUsageMetricsByEntity(
|
|
342
|
-
'clinic',
|
|
343
|
-
dateRange
|
|
344
|
-
);
|
|
345
|
-
|
|
346
|
-
productUsageByClinic.forEach(clinic => {
|
|
347
|
-
console.log(`\n${clinic.entityName}:`);
|
|
348
|
-
console.log(` Unique Products: ${clinic.uniqueProducts}`);
|
|
349
|
-
console.log(` Total Product Revenue: ${clinic.totalProductRevenue}`);
|
|
350
|
-
console.log(` Avg Products per Appointment: ${clinic.averageProductsPerAppointment.toFixed(2)}`);
|
|
351
|
-
console.log(` Top Products:`);
|
|
352
|
-
clinic.topProducts.forEach(product => {
|
|
353
|
-
console.log(` - ${product.productName}: ${product.totalQuantity} units`);
|
|
354
|
-
});
|
|
355
|
-
});
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
### Use Case 7: Combined Analysis - Doctor Performance Dashboard
|
|
359
|
-
|
|
360
|
-
```typescript
|
|
361
|
-
// Get multiple metrics for each doctor
|
|
362
|
-
const dateRange = { start: new Date('2024-01-01'), end: new Date('2024-12-31') };
|
|
363
|
-
|
|
364
|
-
const [
|
|
365
|
-
revenueByDoctor,
|
|
366
|
-
timeEfficiencyByDoctor,
|
|
367
|
-
cancellationsByDoctor,
|
|
368
|
-
noShowsByDoctor,
|
|
369
|
-
patientBehaviorByDoctor,
|
|
370
|
-
] = await Promise.all([
|
|
371
|
-
analyticsService.getRevenueMetricsByEntity('practitioner', dateRange),
|
|
372
|
-
analyticsService.getTimeEfficiencyMetricsByEntity('practitioner', dateRange),
|
|
373
|
-
analyticsService.getCancellationMetrics('practitioner', dateRange),
|
|
374
|
-
analyticsService.getNoShowMetrics('practitioner', dateRange),
|
|
375
|
-
analyticsService.getPatientBehaviorMetricsByEntity('practitioner', dateRange),
|
|
376
|
-
]);
|
|
377
|
-
|
|
378
|
-
// Combine into comprehensive doctor performance report
|
|
379
|
-
const doctorPerformance = revenueByDoctor.map(revenue => {
|
|
380
|
-
const timeEfficiency = timeEfficiencyByDoctor.find(t => t.entityId === revenue.entityId);
|
|
381
|
-
const cancellation = Array.isArray(cancellationsByDoctor)
|
|
382
|
-
? cancellationsByDoctor.find(c => c.entityId === revenue.entityId)
|
|
383
|
-
: null;
|
|
384
|
-
const noShow = Array.isArray(noShowsByDoctor)
|
|
385
|
-
? noShowsByDoctor.find(n => n.entityId === revenue.entityId)
|
|
386
|
-
: null;
|
|
387
|
-
const patientBehavior = patientBehaviorByDoctor.find(p => p.entityId === revenue.entityId);
|
|
388
|
-
|
|
389
|
-
return {
|
|
390
|
-
doctorId: revenue.entityId,
|
|
391
|
-
doctorName: revenue.entityName,
|
|
392
|
-
revenue: revenue.totalRevenue,
|
|
393
|
-
timeEfficiency: timeEfficiency?.averageEfficiency || 0,
|
|
394
|
-
cancellationRate: cancellation?.cancellationRate || 0,
|
|
395
|
-
noShowRate: noShow?.noShowRate || 0,
|
|
396
|
-
patientRetention: patientBehavior?.totalPatients || 0,
|
|
397
|
-
averageNoShowRate: patientBehavior?.averageNoShowRate || 0,
|
|
398
|
-
};
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
// Sort by revenue
|
|
402
|
-
doctorPerformance.sort((a, b) => b.revenue - a.revenue);
|
|
403
|
-
|
|
404
|
-
console.log('Doctor Performance Dashboard:');
|
|
405
|
-
doctorPerformance.forEach((doctor, index) => {
|
|
406
|
-
console.log(`\n${index + 1}. ${doctor.doctorName}`);
|
|
407
|
-
console.log(` Revenue: ${doctor.revenue} CHF`);
|
|
408
|
-
console.log(` Time Efficiency: ${doctor.timeEfficiency.toFixed(1)}%`);
|
|
409
|
-
console.log(` Cancellation Rate: ${doctor.cancellationRate.toFixed(1)}%`);
|
|
410
|
-
console.log(` No-Show Rate: ${doctor.noShowRate.toFixed(1)}%`);
|
|
411
|
-
console.log(` Patient Retention: ${doctor.patientRetention} patients`);
|
|
412
|
-
});
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
## Filtering Options
|
|
416
|
-
|
|
417
|
-
All grouped methods support additional filters:
|
|
418
|
-
|
|
419
|
-
```typescript
|
|
420
|
-
// Revenue by practitioner, but only for a specific clinic
|
|
421
|
-
const revenueByDoctor = await analyticsService.getRevenueMetricsByEntity(
|
|
422
|
-
'practitioner',
|
|
423
|
-
dateRange,
|
|
424
|
-
{ clinicBranchId: 'clinic-123' }
|
|
425
|
-
);
|
|
426
|
-
|
|
427
|
-
// Product usage by procedure, but only for a specific practitioner
|
|
428
|
-
const productUsageByProcedure = await analyticsService.getProductUsageMetricsByEntity(
|
|
429
|
-
'procedure',
|
|
430
|
-
dateRange,
|
|
431
|
-
{ practitionerId: 'practitioner-123' }
|
|
432
|
-
);
|
|
433
|
-
|
|
434
|
-
// Time efficiency by patient, but only for a specific procedure
|
|
435
|
-
const timeEfficiencyByPatient = await analyticsService.getTimeEfficiencyMetricsByEntity(
|
|
436
|
-
'patient',
|
|
437
|
-
dateRange,
|
|
438
|
-
{ procedureId: 'procedure-123' }
|
|
439
|
-
);
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
## Performance Notes
|
|
443
|
-
|
|
444
|
-
- **Pre-computed**: Grouped metrics can be cached (when using standard date ranges)
|
|
445
|
-
- **Efficient**: Single query, then grouping in memory
|
|
446
|
-
- **Scalable**: Works well even with large datasets
|
|
447
|
-
- **Flexible**: Combine multiple grouped queries for comprehensive analysis
|
|
448
|
-
|
|
449
|
-
### Use Case 8: Technology-Level Analysis (Aggregating Across Doctors)
|
|
450
|
-
|
|
451
|
-
```typescript
|
|
452
|
-
// Analyze all Botox treatments across all doctors
|
|
453
|
-
const revenueByTechnology = await analyticsService.getRevenueMetricsByEntity(
|
|
454
|
-
'technology',
|
|
455
|
-
dateRange
|
|
456
|
-
);
|
|
457
|
-
|
|
458
|
-
// Find Botox technology
|
|
459
|
-
const botoxMetrics = revenueByTechnology.find(
|
|
460
|
-
tech => tech.entityName.toLowerCase().includes('botox')
|
|
461
|
-
);
|
|
462
|
-
|
|
463
|
-
console.log(`Botox Revenue (All Doctors):`);
|
|
464
|
-
console.log(` Total Revenue: ${botoxMetrics.totalRevenue} ${botoxMetrics.currency}`);
|
|
465
|
-
console.log(` Total Appointments: ${botoxMetrics.completedAppointments}`);
|
|
466
|
-
console.log(` Avg per Appointment: ${botoxMetrics.averageRevenuePerAppointment.toFixed(2)}`);
|
|
467
|
-
|
|
468
|
-
// Compare no-show rates by technology
|
|
469
|
-
const noShowsByTechnology = await analyticsService.getNoShowMetrics(
|
|
470
|
-
'technology',
|
|
471
|
-
dateRange
|
|
472
|
-
);
|
|
473
|
-
|
|
474
|
-
noShowsByTechnology.forEach(tech => {
|
|
475
|
-
console.log(`${tech.entityName}:`);
|
|
476
|
-
console.log(` No-Show Rate: ${tech.noShowRate.toFixed(1)}%`);
|
|
477
|
-
console.log(` Total Appointments: ${tech.totalAppointments}`);
|
|
478
|
-
});
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
**Key Difference:**
|
|
482
|
-
- **Procedure grouping**: Analyzes specific procedure IDs (doctor-specific, e.g., "Dr. Smith's Botox Treatment")
|
|
483
|
-
- **Technology grouping**: Aggregates all procedures using the same technology across all doctors (e.g., all Botox treatments regardless of doctor)
|
|
484
|
-
|
|
485
|
-
## Summary
|
|
486
|
-
|
|
487
|
-
All analytics now support consistent grouping:
|
|
488
|
-
|
|
489
|
-
✅ **Revenue** - by clinic/practitioner/procedure/patient/technology
|
|
490
|
-
✅ **Product Usage** - by clinic/practitioner/procedure/patient/technology
|
|
491
|
-
✅ **Time Efficiency** - by clinic/practitioner/procedure/patient/technology
|
|
492
|
-
✅ **Patient Behavior** - by clinic/practitioner/procedure/technology
|
|
493
|
-
✅ **Cancellations** - by clinic/practitioner/patient/procedure/technology
|
|
494
|
-
✅ **No-Shows** - by clinic/practitioner/patient/procedure/technology
|
|
495
|
-
|
|
496
|
-
This gives you **complete flexibility** to analyze your data from any perspective!
|
|
497
|
-
|
|
498
|
-
**Note on Technology vs Procedure:**
|
|
499
|
-
- **Procedure**: Doctor-specific procedure (e.g., "Dr. Smith's Botox Treatment")
|
|
500
|
-
- **Technology**: Parent technology that groups all procedures using the same technology (e.g., "Botox" - includes all Botox procedures from all doctors)
|
|
501
|
-
|
|
1
|
+
# Grouped Analytics - Complete Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
All analytics methods now support **consistent grouping** by clinic, practitioner, procedure, patient, or technology. This allows you to analyze metrics from any perspective:
|
|
6
|
+
|
|
7
|
+
- **By Clinic**: See how different clinics perform
|
|
8
|
+
- **By Practitioner**: Compare doctor performance
|
|
9
|
+
- **By Procedure**: Analyze procedure effectiveness (doctor-specific procedures)
|
|
10
|
+
- **By Technology**: Aggregate all procedures using the same technology across all doctors (e.g., all Botox treatments)
|
|
11
|
+
- **By Patient**: Understand patient behavior patterns
|
|
12
|
+
|
|
13
|
+
## Available Grouped Methods
|
|
14
|
+
|
|
15
|
+
### 1. **Revenue Metrics by Entity** 💰
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// Revenue grouped by practitioner (doctor)
|
|
19
|
+
const revenueByDoctor = await analyticsService.getRevenueMetricsByEntity(
|
|
20
|
+
'practitioner',
|
|
21
|
+
{ start: new Date('2024-01-01'), end: new Date('2024-12-31') }
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
// Returns array:
|
|
25
|
+
// [
|
|
26
|
+
// {
|
|
27
|
+
// entityId: 'practitioner-123',
|
|
28
|
+
// entityName: 'Dr. Smith',
|
|
29
|
+
// entityType: 'practitioner',
|
|
30
|
+
// totalRevenue: 50000,
|
|
31
|
+
// averageRevenuePerAppointment: 500,
|
|
32
|
+
// totalAppointments: 100,
|
|
33
|
+
// completedAppointments: 95,
|
|
34
|
+
// currency: 'CHF',
|
|
35
|
+
// unpaidRevenue: 5000,
|
|
36
|
+
// refundedRevenue: 0,
|
|
37
|
+
// totalTax: 4000,
|
|
38
|
+
// totalSubtotal: 46000
|
|
39
|
+
// },
|
|
40
|
+
// ...
|
|
41
|
+
// ]
|
|
42
|
+
|
|
43
|
+
// Revenue grouped by clinic
|
|
44
|
+
const revenueByClinic = await analyticsService.getRevenueMetricsByEntity(
|
|
45
|
+
'clinic',
|
|
46
|
+
dateRange
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// Revenue grouped by procedure
|
|
50
|
+
const revenueByProcedure = await analyticsService.getRevenueMetricsByEntity(
|
|
51
|
+
'procedure',
|
|
52
|
+
dateRange
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// Revenue grouped by patient
|
|
56
|
+
const revenueByPatient = await analyticsService.getRevenueMetricsByEntity(
|
|
57
|
+
'patient',
|
|
58
|
+
dateRange
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
// Revenue grouped by technology (aggregates all procedures using same technology)
|
|
62
|
+
const revenueByTechnology = await analyticsService.getRevenueMetricsByEntity(
|
|
63
|
+
'technology',
|
|
64
|
+
dateRange
|
|
65
|
+
);
|
|
66
|
+
// Example: All Botox treatments across all doctors
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 2. **Product Usage by Entity** 📦
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// Product usage grouped by practitioner
|
|
73
|
+
const productUsageByDoctor = await analyticsService.getProductUsageMetricsByEntity(
|
|
74
|
+
'practitioner',
|
|
75
|
+
dateRange
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Returns array:
|
|
79
|
+
// [
|
|
80
|
+
// {
|
|
81
|
+
// entityId: 'practitioner-123',
|
|
82
|
+
// entityName: 'Dr. Smith',
|
|
83
|
+
// entityType: 'practitioner',
|
|
84
|
+
// totalProductsUsed: 15,
|
|
85
|
+
// uniqueProducts: 10,
|
|
86
|
+
// totalProductRevenue: 25000,
|
|
87
|
+
// totalProductQuantity: 500,
|
|
88
|
+
// averageProductsPerAppointment: 2.5,
|
|
89
|
+
// topProducts: [
|
|
90
|
+
// {
|
|
91
|
+
// productId: 'product-1',
|
|
92
|
+
// productName: 'Product A',
|
|
93
|
+
// brandName: 'Brand X',
|
|
94
|
+
// totalQuantity: 100,
|
|
95
|
+
// totalRevenue: 5000,
|
|
96
|
+
// usageCount: 50
|
|
97
|
+
// },
|
|
98
|
+
// ...
|
|
99
|
+
// ]
|
|
100
|
+
// },
|
|
101
|
+
// ...
|
|
102
|
+
// ]
|
|
103
|
+
|
|
104
|
+
// Product usage grouped by clinic, procedure, patient, or technology
|
|
105
|
+
const productUsageByClinic = await analyticsService.getProductUsageMetricsByEntity(
|
|
106
|
+
'clinic',
|
|
107
|
+
dateRange
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// Product usage by technology (e.g., all Botox-related products)
|
|
111
|
+
const productUsageByTechnology = await analyticsService.getProductUsageMetricsByEntity(
|
|
112
|
+
'technology',
|
|
113
|
+
dateRange
|
|
114
|
+
);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 3. **Time Efficiency by Entity** ⏱️
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
// Time efficiency grouped by practitioner
|
|
121
|
+
const timeEfficiencyByDoctor = await analyticsService.getTimeEfficiencyMetricsByEntity(
|
|
122
|
+
'practitioner',
|
|
123
|
+
dateRange
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
// Returns array:
|
|
127
|
+
// [
|
|
128
|
+
// {
|
|
129
|
+
// entityId: 'practitioner-123',
|
|
130
|
+
// entityName: 'Dr. Smith',
|
|
131
|
+
// entityType: 'practitioner',
|
|
132
|
+
// totalAppointments: 100,
|
|
133
|
+
// appointmentsWithActualTime: 95,
|
|
134
|
+
// averageBookedDuration: 60, // minutes
|
|
135
|
+
// averageActualDuration: 55, // minutes
|
|
136
|
+
// averageEfficiency: 91.67, // percentage
|
|
137
|
+
// totalOverrun: 500, // minutes
|
|
138
|
+
// totalUnderutilization: 200, // minutes
|
|
139
|
+
// averageOverrun: 5, // minutes
|
|
140
|
+
// averageUnderutilization: 2 // minutes
|
|
141
|
+
// },
|
|
142
|
+
// ...
|
|
143
|
+
// ]
|
|
144
|
+
|
|
145
|
+
// Time efficiency grouped by clinic, procedure, patient, or technology
|
|
146
|
+
const timeEfficiencyByClinic = await analyticsService.getTimeEfficiencyMetricsByEntity(
|
|
147
|
+
'clinic',
|
|
148
|
+
dateRange
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
// Time efficiency by technology (e.g., compare efficiency across all Botox vs. Filler treatments)
|
|
152
|
+
const timeEfficiencyByTechnology = await analyticsService.getTimeEfficiencyMetricsByEntity(
|
|
153
|
+
'technology',
|
|
154
|
+
dateRange
|
|
155
|
+
);
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### 4. **Patient Behavior by Entity** 👥
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
// Patient behavior (no-shows, cancellations) grouped by practitioner
|
|
162
|
+
const patientBehaviorByDoctor = await analyticsService.getPatientBehaviorMetricsByEntity(
|
|
163
|
+
'practitioner',
|
|
164
|
+
dateRange
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
// Returns array:
|
|
168
|
+
// [
|
|
169
|
+
// {
|
|
170
|
+
// entityId: 'practitioner-123',
|
|
171
|
+
// entityName: 'Dr. Smith',
|
|
172
|
+
// entityType: 'practitioner',
|
|
173
|
+
// totalPatients: 50,
|
|
174
|
+
// patientsWithNoShows: 10,
|
|
175
|
+
// patientsWithCancellations: 15,
|
|
176
|
+
// averageNoShowRate: 8.5, // percentage
|
|
177
|
+
// averageCancellationRate: 12.3, // percentage
|
|
178
|
+
// topNoShowPatients: [
|
|
179
|
+
// {
|
|
180
|
+
// patientId: 'patient-1',
|
|
181
|
+
// patientName: 'John Doe',
|
|
182
|
+
// noShowCount: 3,
|
|
183
|
+
// totalAppointments: 10,
|
|
184
|
+
// noShowRate: 30.0
|
|
185
|
+
// },
|
|
186
|
+
// ...
|
|
187
|
+
// ],
|
|
188
|
+
// topCancellationPatients: [
|
|
189
|
+
// {
|
|
190
|
+
// patientId: 'patient-2',
|
|
191
|
+
// patientName: 'Jane Smith',
|
|
192
|
+
// cancellationCount: 5,
|
|
193
|
+
// totalAppointments: 15,
|
|
194
|
+
// cancellationRate: 33.3
|
|
195
|
+
// },
|
|
196
|
+
// ...
|
|
197
|
+
// ]
|
|
198
|
+
// },
|
|
199
|
+
// ...
|
|
200
|
+
// ]
|
|
201
|
+
|
|
202
|
+
// Patient behavior grouped by clinic or procedure
|
|
203
|
+
const patientBehaviorByClinic = await analyticsService.getPatientBehaviorMetricsByEntity(
|
|
204
|
+
'clinic',
|
|
205
|
+
dateRange
|
|
206
|
+
);
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### 5. **Cancellation Metrics by Entity** ❌
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
// Already exists - cancellations grouped by entity
|
|
213
|
+
const cancellationsByDoctor = await analyticsService.getCancellationMetrics(
|
|
214
|
+
'practitioner',
|
|
215
|
+
dateRange
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
// Also supports: 'clinic', 'patient', 'procedure', 'technology'
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 6. **No-Show Metrics by Entity** 🚫
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// Already exists - no-shows grouped by entity
|
|
225
|
+
const noShowsByDoctor = await analyticsService.getNoShowMetrics(
|
|
226
|
+
'practitioner',
|
|
227
|
+
dateRange
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
// Also supports: 'clinic', 'patient', 'procedure', 'technology'
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Real-World Use Cases
|
|
234
|
+
|
|
235
|
+
### Use Case 1: Revenue Comparison Across Doctors
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
// Compare revenue generated by each doctor
|
|
239
|
+
const revenueByDoctor = await analyticsService.getRevenueMetricsByEntity(
|
|
240
|
+
'practitioner',
|
|
241
|
+
{ start: new Date('2024-01-01'), end: new Date('2024-12-31') }
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
// Sort by revenue (highest first)
|
|
245
|
+
const topPerformers = revenueByDoctor
|
|
246
|
+
.sort((a, b) => b.totalRevenue - a.totalRevenue)
|
|
247
|
+
.slice(0, 10);
|
|
248
|
+
|
|
249
|
+
console.log('Top 10 Revenue Generators:');
|
|
250
|
+
topPerformers.forEach((doctor, index) => {
|
|
251
|
+
console.log(`${index + 1}. ${doctor.entityName}: ${doctor.totalRevenue} ${doctor.currency}`);
|
|
252
|
+
console.log(` Avg per appointment: ${doctor.averageRevenuePerAppointment.toFixed(2)}`);
|
|
253
|
+
console.log(` Appointments: ${doctor.completedAppointments}`);
|
|
254
|
+
});
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Use Case 2: Product Usage by Procedure
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
// See which products are used most for each procedure
|
|
261
|
+
const productUsageByProcedure = await analyticsService.getProductUsageMetricsByEntity(
|
|
262
|
+
'procedure',
|
|
263
|
+
dateRange
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
productUsageByProcedure.forEach(procedure => {
|
|
267
|
+
console.log(`\n${procedure.entityName}:`);
|
|
268
|
+
console.log(` Total Products Used: ${procedure.totalProductsUsed}`);
|
|
269
|
+
console.log(` Total Product Revenue: ${procedure.totalProductRevenue}`);
|
|
270
|
+
console.log(` Top Products:`);
|
|
271
|
+
procedure.topProducts.slice(0, 5).forEach(product => {
|
|
272
|
+
console.log(` - ${product.productName}: ${product.totalQuantity} units, ${product.totalRevenue} revenue`);
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Use Case 3: Time Efficiency by Clinic
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
// Compare time efficiency across clinics
|
|
281
|
+
const timeEfficiencyByClinic = await analyticsService.getTimeEfficiencyMetricsByEntity(
|
|
282
|
+
'clinic',
|
|
283
|
+
dateRange
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
timeEfficiencyByClinic.forEach(clinic => {
|
|
287
|
+
console.log(`${clinic.entityName}:`);
|
|
288
|
+
console.log(` Efficiency: ${clinic.averageEfficiency.toFixed(1)}%`);
|
|
289
|
+
console.log(` Avg Booked: ${clinic.averageBookedDuration} min`);
|
|
290
|
+
console.log(` Avg Actual: ${clinic.averageActualDuration} min`);
|
|
291
|
+
console.log(` Avg Overrun: ${clinic.averageOverrun} min`);
|
|
292
|
+
});
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Use Case 4: Patient No-Show Patterns by Doctor
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
// See which patients have highest no-show rates for each doctor
|
|
299
|
+
const patientBehaviorByDoctor = await analyticsService.getPatientBehaviorMetricsByEntity(
|
|
300
|
+
'practitioner',
|
|
301
|
+
dateRange
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
patientBehaviorByDoctor.forEach(doctor => {
|
|
305
|
+
console.log(`\n${doctor.entityName}:`);
|
|
306
|
+
console.log(` Total Patients: ${doctor.totalPatients}`);
|
|
307
|
+
console.log(` Patients with No-Shows: ${doctor.patientsWithNoShows}`);
|
|
308
|
+
console.log(` Average No-Show Rate: ${doctor.averageNoShowRate}%`);
|
|
309
|
+
console.log(` Top No-Show Patients:`);
|
|
310
|
+
doctor.topNoShowPatients.forEach(patient => {
|
|
311
|
+
console.log(` - ${patient.patientName}: ${patient.noShowRate.toFixed(1)}% (${patient.noShowCount}/${patient.totalAppointments})`);
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Use Case 5: Revenue by Patient
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
// See which patients generate the most revenue
|
|
320
|
+
const revenueByPatient = await analyticsService.getRevenueMetricsByEntity(
|
|
321
|
+
'patient',
|
|
322
|
+
dateRange
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
const topPatients = revenueByPatient
|
|
326
|
+
.sort((a, b) => b.totalRevenue - a.totalRevenue)
|
|
327
|
+
.slice(0, 20);
|
|
328
|
+
|
|
329
|
+
console.log('Top 20 Patients by Revenue:');
|
|
330
|
+
topPatients.forEach((patient, index) => {
|
|
331
|
+
console.log(`${index + 1}. ${patient.entityName}: ${patient.totalRevenue} ${patient.currency}`);
|
|
332
|
+
console.log(` Appointments: ${patient.completedAppointments}`);
|
|
333
|
+
console.log(` Avg per appointment: ${patient.averageRevenuePerAppointment.toFixed(2)}`);
|
|
334
|
+
});
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Use Case 6: Product Usage by Clinic
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
// Compare product usage across clinics
|
|
341
|
+
const productUsageByClinic = await analyticsService.getProductUsageMetricsByEntity(
|
|
342
|
+
'clinic',
|
|
343
|
+
dateRange
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
productUsageByClinic.forEach(clinic => {
|
|
347
|
+
console.log(`\n${clinic.entityName}:`);
|
|
348
|
+
console.log(` Unique Products: ${clinic.uniqueProducts}`);
|
|
349
|
+
console.log(` Total Product Revenue: ${clinic.totalProductRevenue}`);
|
|
350
|
+
console.log(` Avg Products per Appointment: ${clinic.averageProductsPerAppointment.toFixed(2)}`);
|
|
351
|
+
console.log(` Top Products:`);
|
|
352
|
+
clinic.topProducts.forEach(product => {
|
|
353
|
+
console.log(` - ${product.productName}: ${product.totalQuantity} units`);
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Use Case 7: Combined Analysis - Doctor Performance Dashboard
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
// Get multiple metrics for each doctor
|
|
362
|
+
const dateRange = { start: new Date('2024-01-01'), end: new Date('2024-12-31') };
|
|
363
|
+
|
|
364
|
+
const [
|
|
365
|
+
revenueByDoctor,
|
|
366
|
+
timeEfficiencyByDoctor,
|
|
367
|
+
cancellationsByDoctor,
|
|
368
|
+
noShowsByDoctor,
|
|
369
|
+
patientBehaviorByDoctor,
|
|
370
|
+
] = await Promise.all([
|
|
371
|
+
analyticsService.getRevenueMetricsByEntity('practitioner', dateRange),
|
|
372
|
+
analyticsService.getTimeEfficiencyMetricsByEntity('practitioner', dateRange),
|
|
373
|
+
analyticsService.getCancellationMetrics('practitioner', dateRange),
|
|
374
|
+
analyticsService.getNoShowMetrics('practitioner', dateRange),
|
|
375
|
+
analyticsService.getPatientBehaviorMetricsByEntity('practitioner', dateRange),
|
|
376
|
+
]);
|
|
377
|
+
|
|
378
|
+
// Combine into comprehensive doctor performance report
|
|
379
|
+
const doctorPerformance = revenueByDoctor.map(revenue => {
|
|
380
|
+
const timeEfficiency = timeEfficiencyByDoctor.find(t => t.entityId === revenue.entityId);
|
|
381
|
+
const cancellation = Array.isArray(cancellationsByDoctor)
|
|
382
|
+
? cancellationsByDoctor.find(c => c.entityId === revenue.entityId)
|
|
383
|
+
: null;
|
|
384
|
+
const noShow = Array.isArray(noShowsByDoctor)
|
|
385
|
+
? noShowsByDoctor.find(n => n.entityId === revenue.entityId)
|
|
386
|
+
: null;
|
|
387
|
+
const patientBehavior = patientBehaviorByDoctor.find(p => p.entityId === revenue.entityId);
|
|
388
|
+
|
|
389
|
+
return {
|
|
390
|
+
doctorId: revenue.entityId,
|
|
391
|
+
doctorName: revenue.entityName,
|
|
392
|
+
revenue: revenue.totalRevenue,
|
|
393
|
+
timeEfficiency: timeEfficiency?.averageEfficiency || 0,
|
|
394
|
+
cancellationRate: cancellation?.cancellationRate || 0,
|
|
395
|
+
noShowRate: noShow?.noShowRate || 0,
|
|
396
|
+
patientRetention: patientBehavior?.totalPatients || 0,
|
|
397
|
+
averageNoShowRate: patientBehavior?.averageNoShowRate || 0,
|
|
398
|
+
};
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// Sort by revenue
|
|
402
|
+
doctorPerformance.sort((a, b) => b.revenue - a.revenue);
|
|
403
|
+
|
|
404
|
+
console.log('Doctor Performance Dashboard:');
|
|
405
|
+
doctorPerformance.forEach((doctor, index) => {
|
|
406
|
+
console.log(`\n${index + 1}. ${doctor.doctorName}`);
|
|
407
|
+
console.log(` Revenue: ${doctor.revenue} CHF`);
|
|
408
|
+
console.log(` Time Efficiency: ${doctor.timeEfficiency.toFixed(1)}%`);
|
|
409
|
+
console.log(` Cancellation Rate: ${doctor.cancellationRate.toFixed(1)}%`);
|
|
410
|
+
console.log(` No-Show Rate: ${doctor.noShowRate.toFixed(1)}%`);
|
|
411
|
+
console.log(` Patient Retention: ${doctor.patientRetention} patients`);
|
|
412
|
+
});
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Filtering Options
|
|
416
|
+
|
|
417
|
+
All grouped methods support additional filters:
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
// Revenue by practitioner, but only for a specific clinic
|
|
421
|
+
const revenueByDoctor = await analyticsService.getRevenueMetricsByEntity(
|
|
422
|
+
'practitioner',
|
|
423
|
+
dateRange,
|
|
424
|
+
{ clinicBranchId: 'clinic-123' }
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
// Product usage by procedure, but only for a specific practitioner
|
|
428
|
+
const productUsageByProcedure = await analyticsService.getProductUsageMetricsByEntity(
|
|
429
|
+
'procedure',
|
|
430
|
+
dateRange,
|
|
431
|
+
{ practitionerId: 'practitioner-123' }
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
// Time efficiency by patient, but only for a specific procedure
|
|
435
|
+
const timeEfficiencyByPatient = await analyticsService.getTimeEfficiencyMetricsByEntity(
|
|
436
|
+
'patient',
|
|
437
|
+
dateRange,
|
|
438
|
+
{ procedureId: 'procedure-123' }
|
|
439
|
+
);
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
## Performance Notes
|
|
443
|
+
|
|
444
|
+
- **Pre-computed**: Grouped metrics can be cached (when using standard date ranges)
|
|
445
|
+
- **Efficient**: Single query, then grouping in memory
|
|
446
|
+
- **Scalable**: Works well even with large datasets
|
|
447
|
+
- **Flexible**: Combine multiple grouped queries for comprehensive analysis
|
|
448
|
+
|
|
449
|
+
### Use Case 8: Technology-Level Analysis (Aggregating Across Doctors)
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
// Analyze all Botox treatments across all doctors
|
|
453
|
+
const revenueByTechnology = await analyticsService.getRevenueMetricsByEntity(
|
|
454
|
+
'technology',
|
|
455
|
+
dateRange
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
// Find Botox technology
|
|
459
|
+
const botoxMetrics = revenueByTechnology.find(
|
|
460
|
+
tech => tech.entityName.toLowerCase().includes('botox')
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
console.log(`Botox Revenue (All Doctors):`);
|
|
464
|
+
console.log(` Total Revenue: ${botoxMetrics.totalRevenue} ${botoxMetrics.currency}`);
|
|
465
|
+
console.log(` Total Appointments: ${botoxMetrics.completedAppointments}`);
|
|
466
|
+
console.log(` Avg per Appointment: ${botoxMetrics.averageRevenuePerAppointment.toFixed(2)}`);
|
|
467
|
+
|
|
468
|
+
// Compare no-show rates by technology
|
|
469
|
+
const noShowsByTechnology = await analyticsService.getNoShowMetrics(
|
|
470
|
+
'technology',
|
|
471
|
+
dateRange
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
noShowsByTechnology.forEach(tech => {
|
|
475
|
+
console.log(`${tech.entityName}:`);
|
|
476
|
+
console.log(` No-Show Rate: ${tech.noShowRate.toFixed(1)}%`);
|
|
477
|
+
console.log(` Total Appointments: ${tech.totalAppointments}`);
|
|
478
|
+
});
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
**Key Difference:**
|
|
482
|
+
- **Procedure grouping**: Analyzes specific procedure IDs (doctor-specific, e.g., "Dr. Smith's Botox Treatment")
|
|
483
|
+
- **Technology grouping**: Aggregates all procedures using the same technology across all doctors (e.g., all Botox treatments regardless of doctor)
|
|
484
|
+
|
|
485
|
+
## Summary
|
|
486
|
+
|
|
487
|
+
All analytics now support consistent grouping:
|
|
488
|
+
|
|
489
|
+
✅ **Revenue** - by clinic/practitioner/procedure/patient/technology
|
|
490
|
+
✅ **Product Usage** - by clinic/practitioner/procedure/patient/technology
|
|
491
|
+
✅ **Time Efficiency** - by clinic/practitioner/procedure/patient/technology
|
|
492
|
+
✅ **Patient Behavior** - by clinic/practitioner/procedure/technology
|
|
493
|
+
✅ **Cancellations** - by clinic/practitioner/patient/procedure/technology
|
|
494
|
+
✅ **No-Shows** - by clinic/practitioner/patient/procedure/technology
|
|
495
|
+
|
|
496
|
+
This gives you **complete flexibility** to analyze your data from any perspective!
|
|
497
|
+
|
|
498
|
+
**Note on Technology vs Procedure:**
|
|
499
|
+
- **Procedure**: Doctor-specific procedure (e.g., "Dr. Smith's Botox Treatment")
|
|
500
|
+
- **Technology**: Parent technology that groups all procedures using the same technology (e.g., "Botox" - includes all Botox procedures from all doctors)
|
|
501
|
+
|