@blackcode_sa/metaestetics-api 1.13.3 → 1.13.5

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 (293) hide show
  1. package/dist/admin/index.d.mts +15 -28
  2. package/dist/admin/index.d.ts +15 -28
  3. package/dist/index.d.mts +18 -30
  4. package/dist/index.d.ts +18 -30
  5. package/dist/index.js +11 -3
  6. package/dist/index.mjs +11 -3
  7. package/package.json +121 -119
  8. package/src/__mocks__/firstore.ts +10 -10
  9. package/src/admin/aggregation/README.md +79 -79
  10. package/src/admin/aggregation/appointment/README.md +128 -128
  11. package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +1984 -1984
  12. package/src/admin/aggregation/appointment/index.ts +1 -1
  13. package/src/admin/aggregation/clinic/README.md +52 -52
  14. package/src/admin/aggregation/clinic/clinic.aggregation.service.ts +703 -703
  15. package/src/admin/aggregation/clinic/index.ts +1 -1
  16. package/src/admin/aggregation/forms/README.md +13 -13
  17. package/src/admin/aggregation/forms/filled-forms.aggregation.service.ts +322 -322
  18. package/src/admin/aggregation/forms/index.ts +1 -1
  19. package/src/admin/aggregation/index.ts +8 -8
  20. package/src/admin/aggregation/patient/README.md +27 -27
  21. package/src/admin/aggregation/patient/index.ts +1 -1
  22. package/src/admin/aggregation/patient/patient.aggregation.service.ts +141 -141
  23. package/src/admin/aggregation/practitioner/README.md +42 -42
  24. package/src/admin/aggregation/practitioner/index.ts +1 -1
  25. package/src/admin/aggregation/practitioner/practitioner.aggregation.service.ts +433 -433
  26. package/src/admin/aggregation/practitioner-invite/index.ts +1 -1
  27. package/src/admin/aggregation/practitioner-invite/practitioner-invite.aggregation.service.ts +961 -961
  28. package/src/admin/aggregation/procedure/README.md +43 -43
  29. package/src/admin/aggregation/procedure/index.ts +1 -1
  30. package/src/admin/aggregation/procedure/procedure.aggregation.service.ts +702 -702
  31. package/src/admin/aggregation/reviews/index.ts +1 -1
  32. package/src/admin/aggregation/reviews/reviews.aggregation.service.ts +689 -689
  33. package/src/admin/analytics/analytics.admin.service.ts +278 -278
  34. package/src/admin/analytics/index.ts +2 -2
  35. package/src/admin/booking/README.md +125 -125
  36. package/src/admin/booking/booking.admin.ts +1037 -1037
  37. package/src/admin/booking/booking.calculator.ts +712 -712
  38. package/src/admin/booking/booking.types.ts +59 -59
  39. package/src/admin/booking/index.ts +3 -3
  40. package/src/admin/booking/timezones-problem.md +185 -185
  41. package/src/admin/calendar/README.md +7 -7
  42. package/src/admin/calendar/calendar.admin.service.ts +345 -345
  43. package/src/admin/calendar/index.ts +1 -1
  44. package/src/admin/documentation-templates/document-manager.admin.ts +260 -260
  45. package/src/admin/documentation-templates/index.ts +1 -1
  46. package/src/admin/free-consultation/free-consultation-utils.admin.ts +148 -148
  47. package/src/admin/free-consultation/index.ts +1 -1
  48. package/src/admin/index.ts +81 -81
  49. package/src/admin/logger/index.ts +78 -78
  50. package/src/admin/mailing/README.md +95 -95
  51. package/src/admin/mailing/appointment/appointment.mailing.service.ts +732 -732
  52. package/src/admin/mailing/appointment/index.ts +1 -1
  53. package/src/admin/mailing/appointment/templates/patient/appointment-confirmed.html +40 -40
  54. package/src/admin/mailing/base.mailing.service.ts +208 -208
  55. package/src/admin/mailing/index.ts +3 -3
  56. package/src/admin/mailing/practitionerInvite/existing-practitioner-invite.mailing.ts +611 -611
  57. package/src/admin/mailing/practitionerInvite/index.ts +2 -2
  58. package/src/admin/mailing/practitionerInvite/practitionerInvite.mailing.ts +395 -395
  59. package/src/admin/mailing/practitionerInvite/templates/existing-practitioner-invitation.template.ts +155 -155
  60. package/src/admin/mailing/practitionerInvite/templates/invitation.template.ts +101 -101
  61. package/src/admin/mailing/practitionerInvite/templates/invite-accepted-notification.template.ts +228 -228
  62. package/src/admin/mailing/practitionerInvite/templates/invite-rejected-notification.template.ts +242 -242
  63. package/src/admin/notifications/index.ts +1 -1
  64. package/src/admin/notifications/notifications.admin.ts +710 -710
  65. package/src/admin/requirements/README.md +128 -128
  66. package/src/admin/requirements/index.ts +1 -1
  67. package/src/admin/requirements/patient-requirements.admin.service.ts +475 -475
  68. package/src/admin/users/index.ts +1 -1
  69. package/src/admin/users/user-profile.admin.ts +405 -405
  70. package/src/backoffice/constants/certification.constants.ts +13 -13
  71. package/src/backoffice/constants/index.ts +1 -1
  72. package/src/backoffice/errors/backoffice.errors.ts +181 -181
  73. package/src/backoffice/errors/index.ts +1 -1
  74. package/src/backoffice/expo-safe/README.md +26 -26
  75. package/src/backoffice/expo-safe/index.ts +41 -41
  76. package/src/backoffice/index.ts +5 -5
  77. package/src/backoffice/services/FIXES_README.md +102 -102
  78. package/src/backoffice/services/README.md +57 -57
  79. package/src/backoffice/services/analytics.service.proposal.md +863 -863
  80. package/src/backoffice/services/analytics.service.summary.md +143 -143
  81. package/src/backoffice/services/brand.service.ts +256 -256
  82. package/src/backoffice/services/category.service.ts +384 -384
  83. package/src/backoffice/services/constants.service.ts +385 -385
  84. package/src/backoffice/services/documentation-template.service.ts +202 -202
  85. package/src/backoffice/services/index.ts +10 -10
  86. package/src/backoffice/services/migrate-products.ts +116 -116
  87. package/src/backoffice/services/product.service.ts +553 -553
  88. package/src/backoffice/services/requirement.service.ts +235 -235
  89. package/src/backoffice/services/subcategory.service.ts +461 -461
  90. package/src/backoffice/services/technology.service.ts +1151 -1151
  91. package/src/backoffice/types/README.md +12 -12
  92. package/src/backoffice/types/admin-constants.types.ts +69 -69
  93. package/src/backoffice/types/brand.types.ts +29 -29
  94. package/src/backoffice/types/category.types.ts +67 -67
  95. package/src/backoffice/types/documentation-templates.types.ts +28 -28
  96. package/src/backoffice/types/index.ts +10 -10
  97. package/src/backoffice/types/procedure-product.types.ts +38 -38
  98. package/src/backoffice/types/product.types.ts +240 -240
  99. package/src/backoffice/types/requirement.types.ts +63 -63
  100. package/src/backoffice/types/static/README.md +18 -18
  101. package/src/backoffice/types/static/blocking-condition.types.ts +21 -21
  102. package/src/backoffice/types/static/certification.types.ts +37 -37
  103. package/src/backoffice/types/static/contraindication.types.ts +19 -19
  104. package/src/backoffice/types/static/index.ts +6 -6
  105. package/src/backoffice/types/static/pricing.types.ts +16 -16
  106. package/src/backoffice/types/static/procedure-family.types.ts +14 -14
  107. package/src/backoffice/types/static/treatment-benefit.types.ts +22 -22
  108. package/src/backoffice/types/subcategory.types.ts +34 -34
  109. package/src/backoffice/types/technology.types.ts +168 -168
  110. package/src/backoffice/validations/index.ts +1 -1
  111. package/src/backoffice/validations/schemas.ts +164 -164
  112. package/src/config/__mocks__/firebase.ts +99 -99
  113. package/src/config/firebase.ts +78 -78
  114. package/src/config/index.ts +9 -9
  115. package/src/errors/auth.error.ts +6 -6
  116. package/src/errors/auth.errors.ts +200 -200
  117. package/src/errors/clinic.errors.ts +32 -32
  118. package/src/errors/firebase.errors.ts +47 -47
  119. package/src/errors/user.errors.ts +99 -99
  120. package/src/index.backup.ts +407 -407
  121. package/src/index.ts +6 -6
  122. package/src/locales/en.ts +31 -31
  123. package/src/recommender/admin/index.ts +1 -1
  124. package/src/recommender/admin/services/recommender.service.admin.ts +5 -5
  125. package/src/recommender/front/index.ts +1 -1
  126. package/src/recommender/front/services/onboarding.service.ts +5 -5
  127. package/src/recommender/front/services/recommender.service.ts +3 -3
  128. package/src/recommender/index.ts +1 -1
  129. package/src/services/PATIENTAUTH.MD +197 -197
  130. package/src/services/README.md +106 -106
  131. package/src/services/__tests__/auth/auth.mock.test.ts +17 -17
  132. package/src/services/__tests__/auth/auth.setup.ts +293 -293
  133. package/src/services/__tests__/auth.service.test.ts +346 -346
  134. package/src/services/__tests__/base.service.test.ts +77 -77
  135. package/src/services/__tests__/user.service.test.ts +528 -528
  136. package/src/services/analytics/ARCHITECTURE.md +199 -199
  137. package/src/services/analytics/CLOUD_FUNCTIONS.md +225 -225
  138. package/src/services/analytics/GROUPED_ANALYTICS.md +501 -501
  139. package/src/services/analytics/QUICK_START.md +393 -393
  140. package/src/services/analytics/README.md +304 -304
  141. package/src/services/analytics/SUMMARY.md +141 -141
  142. package/src/services/analytics/TRENDS.md +380 -380
  143. package/src/services/analytics/USAGE_GUIDE.md +518 -518
  144. package/src/services/analytics/analytics-cloud.service.ts +222 -222
  145. package/src/services/analytics/analytics.service.ts +2142 -2142
  146. package/src/services/analytics/index.ts +4 -4
  147. package/src/services/analytics/review-analytics.service.ts +941 -941
  148. package/src/services/analytics/utils/appointment-filtering.utils.ts +138 -138
  149. package/src/services/analytics/utils/cost-calculation.utils.ts +182 -182
  150. package/src/services/analytics/utils/grouping.utils.ts +434 -434
  151. package/src/services/analytics/utils/stored-analytics.utils.ts +347 -347
  152. package/src/services/analytics/utils/time-calculation.utils.ts +186 -186
  153. package/src/services/analytics/utils/trend-calculation.utils.ts +200 -200
  154. package/src/services/appointment/README.md +17 -17
  155. package/src/services/appointment/appointment.service.ts +2558 -2558
  156. package/src/services/appointment/index.ts +1 -1
  157. package/src/services/appointment/utils/appointment.utils.ts +552 -552
  158. package/src/services/appointment/utils/extended-procedure.utils.ts +314 -314
  159. package/src/services/appointment/utils/form-initialization.utils.ts +225 -225
  160. package/src/services/appointment/utils/recommended-procedure.utils.ts +195 -195
  161. package/src/services/appointment/utils/zone-management.utils.ts +353 -353
  162. package/src/services/appointment/utils/zone-photo.utils.ts +152 -152
  163. package/src/services/auth/auth.service.ts +989 -989
  164. package/src/services/auth/auth.v2.service.ts +961 -961
  165. package/src/services/auth/index.ts +7 -7
  166. package/src/services/auth/utils/error.utils.ts +90 -90
  167. package/src/services/auth/utils/firebase.utils.ts +49 -49
  168. package/src/services/auth/utils/index.ts +21 -21
  169. package/src/services/auth/utils/practitioner.utils.ts +125 -125
  170. package/src/services/base.service.ts +41 -41
  171. package/src/services/calendar/calendar.service.ts +1077 -1077
  172. package/src/services/calendar/calendar.v2.service.ts +1683 -1683
  173. package/src/services/calendar/calendar.v3.service.ts +313 -313
  174. package/src/services/calendar/externalCalendar.service.ts +178 -178
  175. package/src/services/calendar/index.ts +5 -5
  176. package/src/services/calendar/synced-calendars.service.ts +743 -743
  177. package/src/services/calendar/utils/appointment.utils.ts +265 -265
  178. package/src/services/calendar/utils/calendar-event.utils.ts +646 -646
  179. package/src/services/calendar/utils/clinic.utils.ts +237 -237
  180. package/src/services/calendar/utils/docs.utils.ts +157 -157
  181. package/src/services/calendar/utils/google-calendar.utils.ts +697 -697
  182. package/src/services/calendar/utils/index.ts +8 -8
  183. package/src/services/calendar/utils/patient.utils.ts +198 -198
  184. package/src/services/calendar/utils/practitioner.utils.ts +221 -221
  185. package/src/services/calendar/utils/synced-calendar.utils.ts +472 -472
  186. package/src/services/clinic/README.md +204 -204
  187. package/src/services/clinic/__tests__/clinic-admin.service.test.ts +287 -287
  188. package/src/services/clinic/__tests__/clinic-group.service.test.ts +352 -352
  189. package/src/services/clinic/__tests__/clinic.service.test.ts +354 -354
  190. package/src/services/clinic/billing-transactions.service.ts +217 -217
  191. package/src/services/clinic/clinic-admin.service.ts +202 -202
  192. package/src/services/clinic/clinic-group.service.ts +310 -310
  193. package/src/services/clinic/clinic.service.ts +708 -708
  194. package/src/services/clinic/index.ts +5 -5
  195. package/src/services/clinic/practitioner-invite.service.ts +519 -519
  196. package/src/services/clinic/utils/admin.utils.ts +551 -551
  197. package/src/services/clinic/utils/clinic-group.utils.ts +646 -646
  198. package/src/services/clinic/utils/clinic.utils.ts +949 -949
  199. package/src/services/clinic/utils/filter.utils.d.ts +23 -23
  200. package/src/services/clinic/utils/filter.utils.ts +446 -446
  201. package/src/services/clinic/utils/index.ts +11 -11
  202. package/src/services/clinic/utils/photos.utils.ts +188 -188
  203. package/src/services/clinic/utils/search.utils.ts +84 -84
  204. package/src/services/clinic/utils/tag.utils.ts +124 -124
  205. package/src/services/documentation-templates/documentation-template.service.ts +537 -537
  206. package/src/services/documentation-templates/filled-document.service.ts +587 -587
  207. package/src/services/documentation-templates/index.ts +2 -2
  208. package/src/services/index.ts +14 -14
  209. package/src/services/media/index.ts +1 -1
  210. package/src/services/media/media.service.ts +418 -418
  211. package/src/services/notifications/__tests__/notification.service.test.ts +242 -242
  212. package/src/services/notifications/index.ts +1 -1
  213. package/src/services/notifications/notification.service.ts +215 -215
  214. package/src/services/patient/README.md +48 -48
  215. package/src/services/patient/To-Do.md +43 -43
  216. package/src/services/patient/__tests__/patient.service.test.ts +294 -294
  217. package/src/services/patient/index.ts +2 -2
  218. package/src/services/patient/patient.service.ts +883 -883
  219. package/src/services/patient/patientRequirements.service.ts +285 -285
  220. package/src/services/patient/utils/aesthetic-analysis.utils.ts +176 -176
  221. package/src/services/patient/utils/clinic.utils.ts +80 -80
  222. package/src/services/patient/utils/docs.utils.ts +142 -142
  223. package/src/services/patient/utils/index.ts +9 -9
  224. package/src/services/patient/utils/location.utils.ts +126 -126
  225. package/src/services/patient/utils/medical-stuff.utils.ts +143 -143
  226. package/src/services/patient/utils/medical.utils.ts +458 -458
  227. package/src/services/patient/utils/practitioner.utils.ts +260 -260
  228. package/src/services/patient/utils/profile.utils.ts +510 -510
  229. package/src/services/patient/utils/sensitive.utils.ts +260 -260
  230. package/src/services/patient/utils/token.utils.ts +211 -211
  231. package/src/services/practitioner/README.md +145 -145
  232. package/src/services/practitioner/index.ts +1 -1
  233. package/src/services/practitioner/practitioner.service.ts +1742 -1742
  234. package/src/services/procedure/README.md +163 -163
  235. package/src/services/procedure/index.ts +1 -1
  236. package/src/services/procedure/procedure.service.ts +2200 -2191
  237. package/src/services/reviews/index.ts +1 -1
  238. package/src/services/reviews/reviews.service.ts +734 -734
  239. package/src/services/user/index.ts +1 -1
  240. package/src/services/user/user.service.ts +489 -489
  241. package/src/services/user/user.v2.service.ts +466 -466
  242. package/src/types/analytics/analytics.types.ts +597 -597
  243. package/src/types/analytics/grouped-analytics.types.ts +173 -173
  244. package/src/types/analytics/index.ts +4 -4
  245. package/src/types/analytics/stored-analytics.types.ts +137 -137
  246. package/src/types/appointment/index.ts +480 -480
  247. package/src/types/calendar/index.ts +258 -258
  248. package/src/types/calendar/synced-calendar.types.ts +66 -66
  249. package/src/types/clinic/index.ts +498 -489
  250. package/src/types/clinic/practitioner-invite.types.ts +91 -91
  251. package/src/types/clinic/preferences.types.ts +159 -159
  252. package/src/types/clinic/to-do +3 -3
  253. package/src/types/documentation-templates/index.ts +308 -308
  254. package/src/types/index.ts +47 -47
  255. package/src/types/notifications/README.md +77 -77
  256. package/src/types/notifications/index.ts +286 -286
  257. package/src/types/patient/aesthetic-analysis.types.ts +66 -66
  258. package/src/types/patient/allergies.ts +58 -58
  259. package/src/types/patient/index.ts +275 -275
  260. package/src/types/patient/medical-info.types.ts +152 -152
  261. package/src/types/patient/patient-requirements.ts +92 -92
  262. package/src/types/patient/token.types.ts +61 -61
  263. package/src/types/practitioner/index.ts +206 -206
  264. package/src/types/procedure/index.ts +181 -181
  265. package/src/types/profile/index.ts +39 -39
  266. package/src/types/reviews/index.ts +132 -132
  267. package/src/types/tz-lookup.d.ts +4 -4
  268. package/src/types/user/index.ts +38 -38
  269. package/src/utils/TIMESTAMPS.md +176 -176
  270. package/src/utils/TimestampUtils.ts +241 -241
  271. package/src/utils/index.ts +1 -1
  272. package/src/validations/appointment.schema.ts +574 -574
  273. package/src/validations/calendar.schema.ts +225 -225
  274. package/src/validations/clinic.schema.ts +494 -493
  275. package/src/validations/common.schema.ts +25 -25
  276. package/src/validations/documentation-templates/index.ts +1 -1
  277. package/src/validations/documentation-templates/template.schema.ts +220 -220
  278. package/src/validations/documentation-templates.schema.ts +10 -10
  279. package/src/validations/index.ts +20 -20
  280. package/src/validations/media.schema.ts +10 -10
  281. package/src/validations/notification.schema.ts +90 -90
  282. package/src/validations/patient/aesthetic-analysis.schema.ts +55 -55
  283. package/src/validations/patient/medical-info.schema.ts +125 -125
  284. package/src/validations/patient/patient-requirements.schema.ts +84 -84
  285. package/src/validations/patient/token.schema.ts +29 -29
  286. package/src/validations/patient.schema.ts +217 -217
  287. package/src/validations/practitioner.schema.ts +222 -222
  288. package/src/validations/procedure-product.schema.ts +41 -41
  289. package/src/validations/procedure.schema.ts +124 -124
  290. package/src/validations/profile-info.schema.ts +41 -41
  291. package/src/validations/reviews.schema.ts +195 -195
  292. package/src/validations/schemas.ts +104 -104
  293. 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
+