@blackcode_sa/metaestetics-api 1.12.59 → 1.12.61

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 (267) hide show
  1. package/dist/admin/index.d.mts +36 -4
  2. package/dist/admin/index.d.ts +36 -4
  3. package/dist/admin/index.js +147 -26
  4. package/dist/admin/index.mjs +147 -26
  5. package/dist/index.d.mts +9 -1
  6. package/dist/index.d.ts +9 -1
  7. package/package.json +119 -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 +1844 -1689
  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 +641 -641
  33. package/src/admin/booking/README.md +125 -125
  34. package/src/admin/booking/booking.admin.ts +1037 -1037
  35. package/src/admin/booking/booking.calculator.ts +712 -712
  36. package/src/admin/booking/booking.types.ts +59 -59
  37. package/src/admin/booking/index.ts +3 -3
  38. package/src/admin/booking/timezones-problem.md +185 -185
  39. package/src/admin/calendar/README.md +7 -7
  40. package/src/admin/calendar/calendar.admin.service.ts +345 -345
  41. package/src/admin/calendar/index.ts +1 -1
  42. package/src/admin/documentation-templates/document-manager.admin.ts +260 -260
  43. package/src/admin/documentation-templates/index.ts +1 -1
  44. package/src/admin/free-consultation/free-consultation-utils.admin.ts +148 -148
  45. package/src/admin/free-consultation/index.ts +1 -1
  46. package/src/admin/index.ts +75 -75
  47. package/src/admin/logger/index.ts +78 -78
  48. package/src/admin/mailing/README.md +95 -95
  49. package/src/admin/mailing/appointment/appointment.mailing.service.ts +732 -732
  50. package/src/admin/mailing/appointment/index.ts +1 -1
  51. package/src/admin/mailing/appointment/templates/patient/appointment-confirmed.html +40 -40
  52. package/src/admin/mailing/base.mailing.service.ts +208 -208
  53. package/src/admin/mailing/index.ts +3 -3
  54. package/src/admin/mailing/practitionerInvite/existing-practitioner-invite.mailing.ts +611 -611
  55. package/src/admin/mailing/practitionerInvite/index.ts +2 -2
  56. package/src/admin/mailing/practitionerInvite/practitionerInvite.mailing.ts +395 -395
  57. package/src/admin/mailing/practitionerInvite/templates/existing-practitioner-invitation.template.ts +155 -155
  58. package/src/admin/mailing/practitionerInvite/templates/invitation.template.ts +101 -101
  59. package/src/admin/mailing/practitionerInvite/templates/invite-accepted-notification.template.ts +228 -228
  60. package/src/admin/mailing/practitionerInvite/templates/invite-rejected-notification.template.ts +242 -242
  61. package/src/admin/notifications/index.ts +1 -1
  62. package/src/admin/notifications/notifications.admin.ts +710 -710
  63. package/src/admin/requirements/README.md +128 -128
  64. package/src/admin/requirements/index.ts +1 -1
  65. package/src/admin/requirements/patient-requirements.admin.service.ts +475 -475
  66. package/src/admin/users/index.ts +1 -1
  67. package/src/admin/users/user-profile.admin.ts +405 -405
  68. package/src/backoffice/constants/certification.constants.ts +13 -13
  69. package/src/backoffice/constants/index.ts +1 -1
  70. package/src/backoffice/errors/backoffice.errors.ts +181 -181
  71. package/src/backoffice/errors/index.ts +1 -1
  72. package/src/backoffice/expo-safe/README.md +26 -26
  73. package/src/backoffice/expo-safe/index.ts +41 -41
  74. package/src/backoffice/index.ts +5 -5
  75. package/src/backoffice/services/FIXES_README.md +102 -102
  76. package/src/backoffice/services/README.md +40 -40
  77. package/src/backoffice/services/brand.service.ts +256 -256
  78. package/src/backoffice/services/category.service.ts +318 -318
  79. package/src/backoffice/services/constants.service.ts +385 -385
  80. package/src/backoffice/services/documentation-template.service.ts +202 -202
  81. package/src/backoffice/services/index.ts +8 -8
  82. package/src/backoffice/services/migrate-products.ts +116 -116
  83. package/src/backoffice/services/product.service.ts +553 -553
  84. package/src/backoffice/services/requirement.service.ts +235 -235
  85. package/src/backoffice/services/subcategory.service.ts +395 -395
  86. package/src/backoffice/services/technology.service.ts +1070 -1070
  87. package/src/backoffice/types/README.md +12 -12
  88. package/src/backoffice/types/admin-constants.types.ts +69 -69
  89. package/src/backoffice/types/brand.types.ts +29 -29
  90. package/src/backoffice/types/category.types.ts +62 -62
  91. package/src/backoffice/types/documentation-templates.types.ts +28 -28
  92. package/src/backoffice/types/index.ts +10 -10
  93. package/src/backoffice/types/procedure-product.types.ts +38 -38
  94. package/src/backoffice/types/product.types.ts +240 -240
  95. package/src/backoffice/types/requirement.types.ts +63 -63
  96. package/src/backoffice/types/static/README.md +18 -18
  97. package/src/backoffice/types/static/blocking-condition.types.ts +21 -21
  98. package/src/backoffice/types/static/certification.types.ts +37 -37
  99. package/src/backoffice/types/static/contraindication.types.ts +19 -19
  100. package/src/backoffice/types/static/index.ts +6 -6
  101. package/src/backoffice/types/static/pricing.types.ts +16 -16
  102. package/src/backoffice/types/static/procedure-family.types.ts +14 -14
  103. package/src/backoffice/types/static/treatment-benefit.types.ts +22 -22
  104. package/src/backoffice/types/subcategory.types.ts +34 -34
  105. package/src/backoffice/types/technology.types.ts +161 -161
  106. package/src/backoffice/validations/index.ts +1 -1
  107. package/src/backoffice/validations/schemas.ts +163 -163
  108. package/src/config/__mocks__/firebase.ts +99 -99
  109. package/src/config/firebase.ts +78 -78
  110. package/src/config/index.ts +9 -9
  111. package/src/errors/auth.error.ts +6 -6
  112. package/src/errors/auth.errors.ts +200 -200
  113. package/src/errors/clinic.errors.ts +32 -32
  114. package/src/errors/firebase.errors.ts +47 -47
  115. package/src/errors/user.errors.ts +99 -99
  116. package/src/index.backup.ts +407 -407
  117. package/src/index.ts +6 -6
  118. package/src/locales/en.ts +31 -31
  119. package/src/recommender/admin/index.ts +1 -1
  120. package/src/recommender/admin/services/recommender.service.admin.ts +5 -5
  121. package/src/recommender/front/index.ts +1 -1
  122. package/src/recommender/front/services/onboarding.service.ts +5 -5
  123. package/src/recommender/front/services/recommender.service.ts +3 -3
  124. package/src/recommender/index.ts +1 -1
  125. package/src/services/PATIENTAUTH.MD +197 -197
  126. package/src/services/README.md +106 -106
  127. package/src/services/__tests__/auth/auth.mock.test.ts +17 -17
  128. package/src/services/__tests__/auth/auth.setup.ts +293 -293
  129. package/src/services/__tests__/auth.service.test.ts +346 -346
  130. package/src/services/__tests__/base.service.test.ts +77 -77
  131. package/src/services/__tests__/user.service.test.ts +528 -528
  132. package/src/services/appointment/README.md +17 -17
  133. package/src/services/appointment/appointment.service.ts +2082 -2082
  134. package/src/services/appointment/index.ts +1 -1
  135. package/src/services/appointment/utils/appointment.utils.ts +552 -552
  136. package/src/services/appointment/utils/extended-procedure.utils.ts +314 -314
  137. package/src/services/appointment/utils/form-initialization.utils.ts +225 -225
  138. package/src/services/appointment/utils/recommended-procedure.utils.ts +195 -195
  139. package/src/services/appointment/utils/zone-management.utils.ts +353 -353
  140. package/src/services/appointment/utils/zone-photo.utils.ts +152 -152
  141. package/src/services/auth/auth.service.ts +989 -989
  142. package/src/services/auth/auth.v2.service.ts +961 -961
  143. package/src/services/auth/index.ts +7 -7
  144. package/src/services/auth/utils/error.utils.ts +90 -90
  145. package/src/services/auth/utils/firebase.utils.ts +49 -49
  146. package/src/services/auth/utils/index.ts +21 -21
  147. package/src/services/auth/utils/practitioner.utils.ts +125 -125
  148. package/src/services/base.service.ts +41 -41
  149. package/src/services/calendar/calendar.service.ts +1077 -1077
  150. package/src/services/calendar/calendar.v2.service.ts +1683 -1683
  151. package/src/services/calendar/calendar.v3.service.ts +313 -313
  152. package/src/services/calendar/externalCalendar.service.ts +178 -178
  153. package/src/services/calendar/index.ts +5 -5
  154. package/src/services/calendar/synced-calendars.service.ts +743 -743
  155. package/src/services/calendar/utils/appointment.utils.ts +265 -265
  156. package/src/services/calendar/utils/calendar-event.utils.ts +646 -646
  157. package/src/services/calendar/utils/clinic.utils.ts +237 -237
  158. package/src/services/calendar/utils/docs.utils.ts +157 -157
  159. package/src/services/calendar/utils/google-calendar.utils.ts +697 -697
  160. package/src/services/calendar/utils/index.ts +8 -8
  161. package/src/services/calendar/utils/patient.utils.ts +198 -198
  162. package/src/services/calendar/utils/practitioner.utils.ts +221 -221
  163. package/src/services/calendar/utils/synced-calendar.utils.ts +472 -472
  164. package/src/services/clinic/README.md +204 -204
  165. package/src/services/clinic/__tests__/clinic-admin.service.test.ts +287 -287
  166. package/src/services/clinic/__tests__/clinic-group.service.test.ts +352 -352
  167. package/src/services/clinic/__tests__/clinic.service.test.ts +354 -354
  168. package/src/services/clinic/billing-transactions.service.ts +217 -217
  169. package/src/services/clinic/clinic-admin.service.ts +202 -202
  170. package/src/services/clinic/clinic-group.service.ts +310 -310
  171. package/src/services/clinic/clinic.service.ts +708 -708
  172. package/src/services/clinic/index.ts +5 -5
  173. package/src/services/clinic/practitioner-invite.service.ts +519 -519
  174. package/src/services/clinic/utils/admin.utils.ts +551 -551
  175. package/src/services/clinic/utils/clinic-group.utils.ts +646 -646
  176. package/src/services/clinic/utils/clinic.utils.ts +949 -949
  177. package/src/services/clinic/utils/filter.utils.d.ts +23 -23
  178. package/src/services/clinic/utils/filter.utils.ts +446 -446
  179. package/src/services/clinic/utils/index.ts +11 -11
  180. package/src/services/clinic/utils/photos.utils.ts +188 -188
  181. package/src/services/clinic/utils/search.utils.ts +84 -84
  182. package/src/services/clinic/utils/tag.utils.ts +124 -124
  183. package/src/services/documentation-templates/documentation-template.service.ts +537 -537
  184. package/src/services/documentation-templates/filled-document.service.ts +587 -587
  185. package/src/services/documentation-templates/index.ts +2 -2
  186. package/src/services/index.ts +13 -13
  187. package/src/services/media/index.ts +1 -1
  188. package/src/services/media/media.service.ts +418 -418
  189. package/src/services/notifications/__tests__/notification.service.test.ts +242 -242
  190. package/src/services/notifications/index.ts +1 -1
  191. package/src/services/notifications/notification.service.ts +215 -215
  192. package/src/services/patient/README.md +48 -48
  193. package/src/services/patient/To-Do.md +43 -43
  194. package/src/services/patient/__tests__/patient.service.test.ts +294 -294
  195. package/src/services/patient/index.ts +2 -2
  196. package/src/services/patient/patient.service.ts +883 -883
  197. package/src/services/patient/patientRequirements.service.ts +285 -285
  198. package/src/services/patient/utils/aesthetic-analysis.utils.ts +176 -176
  199. package/src/services/patient/utils/clinic.utils.ts +80 -80
  200. package/src/services/patient/utils/docs.utils.ts +142 -142
  201. package/src/services/patient/utils/index.ts +9 -9
  202. package/src/services/patient/utils/location.utils.ts +126 -126
  203. package/src/services/patient/utils/medical-stuff.utils.ts +143 -143
  204. package/src/services/patient/utils/medical.utils.ts +458 -458
  205. package/src/services/patient/utils/practitioner.utils.ts +260 -260
  206. package/src/services/patient/utils/profile.utils.ts +510 -510
  207. package/src/services/patient/utils/sensitive.utils.ts +260 -260
  208. package/src/services/patient/utils/token.utils.ts +211 -211
  209. package/src/services/practitioner/README.md +145 -145
  210. package/src/services/practitioner/index.ts +1 -1
  211. package/src/services/practitioner/practitioner.service.ts +1742 -1742
  212. package/src/services/procedure/README.md +163 -163
  213. package/src/services/procedure/index.ts +1 -1
  214. package/src/services/procedure/procedure.service.ts +1682 -1682
  215. package/src/services/reviews/index.ts +1 -1
  216. package/src/services/reviews/reviews.service.ts +636 -636
  217. package/src/services/user/index.ts +1 -1
  218. package/src/services/user/user.service.ts +489 -489
  219. package/src/services/user/user.v2.service.ts +466 -466
  220. package/src/types/appointment/index.ts +453 -453
  221. package/src/types/calendar/index.ts +258 -258
  222. package/src/types/calendar/synced-calendar.types.ts +66 -66
  223. package/src/types/clinic/index.ts +489 -489
  224. package/src/types/clinic/practitioner-invite.types.ts +91 -91
  225. package/src/types/clinic/preferences.types.ts +159 -159
  226. package/src/types/clinic/to-do +3 -3
  227. package/src/types/documentation-templates/index.ts +308 -308
  228. package/src/types/index.ts +44 -44
  229. package/src/types/notifications/README.md +77 -77
  230. package/src/types/notifications/index.ts +265 -265
  231. package/src/types/patient/aesthetic-analysis.types.ts +66 -66
  232. package/src/types/patient/allergies.ts +58 -58
  233. package/src/types/patient/index.ts +273 -273
  234. package/src/types/patient/medical-info.types.ts +152 -152
  235. package/src/types/patient/patient-requirements.ts +92 -81
  236. package/src/types/patient/token.types.ts +61 -61
  237. package/src/types/practitioner/index.ts +206 -206
  238. package/src/types/procedure/index.ts +181 -181
  239. package/src/types/profile/index.ts +39 -39
  240. package/src/types/reviews/index.ts +130 -130
  241. package/src/types/tz-lookup.d.ts +4 -4
  242. package/src/types/user/index.ts +38 -38
  243. package/src/utils/TIMESTAMPS.md +176 -176
  244. package/src/utils/TimestampUtils.ts +241 -241
  245. package/src/utils/index.ts +1 -1
  246. package/src/validations/appointment.schema.ts +574 -574
  247. package/src/validations/calendar.schema.ts +225 -225
  248. package/src/validations/clinic.schema.ts +493 -493
  249. package/src/validations/common.schema.ts +25 -25
  250. package/src/validations/documentation-templates/index.ts +1 -1
  251. package/src/validations/documentation-templates/template.schema.ts +220 -220
  252. package/src/validations/documentation-templates.schema.ts +10 -10
  253. package/src/validations/index.ts +20 -20
  254. package/src/validations/media.schema.ts +10 -10
  255. package/src/validations/notification.schema.ts +90 -90
  256. package/src/validations/patient/aesthetic-analysis.schema.ts +55 -55
  257. package/src/validations/patient/medical-info.schema.ts +125 -125
  258. package/src/validations/patient/patient-requirements.schema.ts +84 -75
  259. package/src/validations/patient/token.schema.ts +29 -29
  260. package/src/validations/patient.schema.ts +216 -216
  261. package/src/validations/practitioner.schema.ts +222 -222
  262. package/src/validations/procedure-product.schema.ts +41 -41
  263. package/src/validations/procedure.schema.ts +124 -124
  264. package/src/validations/profile-info.schema.ts +41 -41
  265. package/src/validations/reviews.schema.ts +189 -189
  266. package/src/validations/schemas.ts +104 -104
  267. package/src/validations/shared.schema.ts +78 -78
@@ -1,310 +1,310 @@
1
- import {
2
- collection,
3
- doc,
4
- getDoc,
5
- getDocs,
6
- query,
7
- where,
8
- updateDoc,
9
- setDoc,
10
- deleteDoc,
11
- Timestamp,
12
- serverTimestamp,
13
- FieldValue,
14
- } from 'firebase/firestore';
15
- import { BaseService } from '../base.service';
16
- import {
17
- ClinicGroup,
18
- CreateClinicGroupData,
19
- CLINIC_GROUPS_COLLECTION,
20
- AdminToken,
21
- AdminTokenStatus,
22
- CreateAdminTokenData,
23
- ClinicGroupSetupData,
24
- UpdateClinicGroupData,
25
- BillingTransaction,
26
- BillingTransactionType,
27
- } from '../../types/clinic';
28
- import { ClinicAdminService } from './clinic-admin.service';
29
- import { BillingTransactionsService } from './billing-transactions.service';
30
- import { geohashForLocation } from 'geofire-common';
31
- import { clinicGroupSchema, createClinicGroupSchema } from '../../validations/clinic.schema';
32
- import { z } from 'zod';
33
- import { Auth } from 'firebase/auth';
34
- import { Firestore } from 'firebase/firestore';
35
- import { FirebaseApp } from 'firebase/app';
36
- import * as ClinicGroupUtils from './utils/clinic-group.utils';
37
- import { uploadPhoto } from './utils/photos.utils';
38
-
39
- export class ClinicGroupService extends BaseService {
40
- private clinicAdminService: ClinicAdminService;
41
- private billingTransactionsService: BillingTransactionsService;
42
-
43
- constructor(db: Firestore, auth: Auth, app: FirebaseApp, clinicAdminService: ClinicAdminService) {
44
- super(db, auth, app);
45
- this.clinicAdminService = clinicAdminService;
46
- this.billingTransactionsService = new BillingTransactionsService(db, auth, app);
47
- }
48
-
49
- /**
50
- * Kreira novu grupaciju klinika
51
- */
52
- async createClinicGroup(
53
- data: CreateClinicGroupData,
54
- ownerId: string,
55
- isDefault: boolean = false,
56
- ): Promise<ClinicGroup> {
57
- return ClinicGroupUtils.createClinicGroup(
58
- this.db,
59
- data,
60
- ownerId,
61
- isDefault,
62
- this.clinicAdminService,
63
- this.app,
64
- );
65
- }
66
-
67
- /**
68
- * Dohvata grupaciju klinika po ID-u
69
- */
70
- async getClinicGroup(groupId: string): Promise<ClinicGroup | null> {
71
- return ClinicGroupUtils.getClinicGroup(this.db, groupId);
72
- }
73
-
74
- /**
75
- * Dohvata sve aktivne grupacije klinika
76
- */
77
- async getAllActiveGroups(): Promise<ClinicGroup[]> {
78
- return ClinicGroupUtils.getAllActiveGroups(this.db);
79
- }
80
-
81
- /**
82
- * Ažurira grupaciju klinika
83
- */
84
- async updateClinicGroup(groupId: string, data: Partial<ClinicGroup>): Promise<ClinicGroup> {
85
- return ClinicGroupUtils.updateClinicGroup(this.db, groupId, data, this.app);
86
- }
87
-
88
- /**
89
- * Dodaje admina u grupaciju
90
- */
91
- async addAdminToGroup(groupId: string, adminId: string): Promise<void> {
92
- return ClinicGroupUtils.addAdminToGroup(this.db, groupId, adminId, this.app);
93
- }
94
-
95
- /**
96
- * Uklanja admina iz grupacije
97
- */
98
- async removeAdminFromGroup(groupId: string, adminId: string): Promise<void> {
99
- return ClinicGroupUtils.removeAdminFromGroup(this.db, groupId, adminId, this.app);
100
- }
101
-
102
- /**
103
- * Deaktivira grupaciju klinika
104
- */
105
- async deactivateClinicGroup(groupId: string): Promise<void> {
106
- return ClinicGroupUtils.deactivateClinicGroup(this.db, groupId, this.app);
107
- }
108
-
109
- /**
110
- * Sets up additional clinic group information after initial creation
111
- *
112
- * @param groupId - The ID of the clinic group to set up
113
- * @param setupData - The setup data for the clinic group
114
- * @returns The updated clinic group
115
- */
116
- async setupClinicGroup(groupId: string, setupData: ClinicGroupSetupData): Promise<ClinicGroup> {
117
- console.log('[CLINIC_GROUP] Setting up clinic group', { groupId });
118
-
119
- // Get the clinic group
120
- const clinicGroup = await this.getClinicGroup(groupId);
121
- if (!clinicGroup) {
122
- console.error('[CLINIC_GROUP] Clinic group not found', { groupId });
123
- throw new Error(`Clinic group with ID ${groupId} not found`);
124
- }
125
-
126
- // Process logo if it's a data URL
127
- let logoUrl = setupData.logo;
128
- if (logoUrl && typeof logoUrl === 'string' && logoUrl.startsWith('data:')) {
129
- console.log('[CLINIC_GROUP] Processing logo in setupClinicGroup');
130
- try {
131
- const uploadedLogoUrl = await uploadPhoto(
132
- logoUrl,
133
- 'clinic-groups',
134
- groupId,
135
- 'logo',
136
- this.app,
137
- );
138
- console.log('[CLINIC_GROUP] Logo processed in setupClinicGroup', {
139
- uploadedLogoUrl,
140
- });
141
-
142
- // Replace the data URL with the uploaded URL if upload was successful
143
- if (uploadedLogoUrl !== null) {
144
- logoUrl = uploadedLogoUrl;
145
- }
146
- } catch (error) {
147
- console.error('[CLINIC_GROUP] Error processing logo in setupClinicGroup:', error);
148
- // Continue with update even if logo upload fails
149
- }
150
- }
151
-
152
- // Update the clinic group with the setup data
153
- const updateData = {
154
- languages: setupData.languages,
155
- practiceType: setupData.practiceType,
156
- description: setupData.description,
157
- logo: logoUrl,
158
- calendarSyncEnabled: setupData.calendarSyncEnabled,
159
- autoConfirmAppointments: setupData.autoConfirmAppointments,
160
- businessIdentificationNumber: setupData.businessIdentificationNumber,
161
- };
162
-
163
- console.log('[CLINIC_GROUP] Updating clinic group with setup data');
164
-
165
- // Update the clinic group
166
- return this.updateClinicGroup(groupId, updateData);
167
- }
168
-
169
- /**
170
- * Kreira admin token za grupaciju
171
- */
172
- async createAdminToken(
173
- groupId: string,
174
- creatorAdminId: string,
175
- data?: CreateAdminTokenData,
176
- ): Promise<AdminToken> {
177
- return ClinicGroupUtils.createAdminToken(this.db, groupId, creatorAdminId, this.app, data);
178
- }
179
-
180
- /**
181
- * Verifikuje i koristi admin token
182
- */
183
- async verifyAndUseAdminToken(groupId: string, token: string, userRef: string): Promise<boolean> {
184
- return ClinicGroupUtils.verifyAndUseAdminToken(this.db, groupId, token, userRef, this.app);
185
- }
186
-
187
- /**
188
- * Briše admin token
189
- */
190
- async deleteAdminToken(groupId: string, tokenId: string, adminId: string): Promise<void> {
191
- return ClinicGroupUtils.deleteAdminToken(this.db, groupId, tokenId, adminId, this.app);
192
- }
193
-
194
- /**
195
- * Dohvata aktivne admin tokene
196
- */
197
- async getActiveAdminTokens(groupId: string, adminId: string): Promise<AdminToken[]> {
198
- return ClinicGroupUtils.getActiveAdminTokens(this.db, groupId, adminId, this.app);
199
- }
200
-
201
- // TODO: Add a method to get all admin tokens for a clinic group (not just active ones)
202
-
203
- // TODO: Refactor admin token methods not to add tokens to the clinicGroup document,
204
- // but to add them to a subcollection called adminTokens that belongs to a specific clinicGroup document
205
-
206
- // TODO: Add granular control over admin permissions, e.g. only allow admins to manage certain clinics to tokens directly
207
- // TODO: Generally refactor admin tokens and invites, also create cloud function to send invites and send updates when sombody uses the token
208
-
209
- /**
210
- * Updates the onboarding status for a clinic group
211
- *
212
- * @param groupId - The ID of the clinic group to update
213
- * @param onboardingData - The onboarding data to update
214
- * @returns The updated clinic group
215
- */
216
- async setOnboarding(
217
- groupId: string,
218
- onboardingData: {
219
- completed?: boolean;
220
- step?: number;
221
- },
222
- ): Promise<ClinicGroup> {
223
- console.log('[CLINIC_GROUP] Updating onboarding status', {
224
- groupId,
225
- onboardingData,
226
- });
227
-
228
- return this.updateClinicGroup(groupId, {
229
- onboarding: onboardingData,
230
- });
231
- }
232
-
233
- /**
234
- * Sets the current onboarding step for a clinic group
235
- *
236
- * @param groupId - The ID of the clinic group to update
237
- * @param step - The current onboarding step number
238
- * @returns The updated clinic group
239
- */
240
- async setOnboardingStep(groupId: string, step: number): Promise<ClinicGroup> {
241
- console.log('[CLINIC_GROUP] Setting onboarding step', { groupId, step });
242
-
243
- return this.setOnboarding(groupId, { step, completed: false });
244
- }
245
-
246
- /**
247
- * Marks the onboarding process as completed for a clinic group
248
- *
249
- * @param groupId - The ID of the clinic group to update
250
- * @returns The updated clinic group
251
- */
252
- async completeOnboarding(groupId: string): Promise<ClinicGroup> {
253
- console.log('[CLINIC_GROUP] Completing onboarding', { groupId });
254
-
255
- return this.setOnboarding(groupId, { completed: true });
256
- }
257
-
258
- /**
259
- * Get billing transactions for a clinic group
260
- *
261
- * @param groupId - The clinic group ID
262
- * @param options - Query options for pagination and filtering
263
- * @returns Promise with billing transactions and pagination info
264
- */
265
- async getBillingTransactions(
266
- groupId: string,
267
- options: {
268
- limit?: number;
269
- startAfter?: any;
270
- transactionType?: BillingTransactionType;
271
- } = {},
272
- ): Promise<{
273
- transactions: BillingTransaction[];
274
- lastDoc: any;
275
- hasMore: boolean;
276
- }> {
277
- return this.billingTransactionsService.getBillingTransactions(groupId, options);
278
- }
279
-
280
- /**
281
- * Get recent billing transactions for a clinic group (last 10)
282
- *
283
- * @param groupId - The clinic group ID
284
- * @returns Promise with recent billing transactions
285
- */
286
- async getRecentBillingTransactions(groupId: string): Promise<BillingTransaction[]> {
287
- return this.billingTransactionsService.getRecentBillingTransactions(groupId);
288
- }
289
-
290
- /**
291
- * Get subscription-related billing transactions for a clinic group
292
- *
293
- * @param groupId - The clinic group ID
294
- * @param options - Query options for pagination
295
- * @returns Promise with subscription transactions and pagination info
296
- */
297
- async getSubscriptionTransactions(
298
- groupId: string,
299
- options: {
300
- limit?: number;
301
- startAfter?: any;
302
- } = {},
303
- ): Promise<{
304
- transactions: BillingTransaction[];
305
- lastDoc: any;
306
- hasMore: boolean;
307
- }> {
308
- return this.billingTransactionsService.getSubscriptionTransactions(groupId, options);
309
- }
310
- }
1
+ import {
2
+ collection,
3
+ doc,
4
+ getDoc,
5
+ getDocs,
6
+ query,
7
+ where,
8
+ updateDoc,
9
+ setDoc,
10
+ deleteDoc,
11
+ Timestamp,
12
+ serverTimestamp,
13
+ FieldValue,
14
+ } from 'firebase/firestore';
15
+ import { BaseService } from '../base.service';
16
+ import {
17
+ ClinicGroup,
18
+ CreateClinicGroupData,
19
+ CLINIC_GROUPS_COLLECTION,
20
+ AdminToken,
21
+ AdminTokenStatus,
22
+ CreateAdminTokenData,
23
+ ClinicGroupSetupData,
24
+ UpdateClinicGroupData,
25
+ BillingTransaction,
26
+ BillingTransactionType,
27
+ } from '../../types/clinic';
28
+ import { ClinicAdminService } from './clinic-admin.service';
29
+ import { BillingTransactionsService } from './billing-transactions.service';
30
+ import { geohashForLocation } from 'geofire-common';
31
+ import { clinicGroupSchema, createClinicGroupSchema } from '../../validations/clinic.schema';
32
+ import { z } from 'zod';
33
+ import { Auth } from 'firebase/auth';
34
+ import { Firestore } from 'firebase/firestore';
35
+ import { FirebaseApp } from 'firebase/app';
36
+ import * as ClinicGroupUtils from './utils/clinic-group.utils';
37
+ import { uploadPhoto } from './utils/photos.utils';
38
+
39
+ export class ClinicGroupService extends BaseService {
40
+ private clinicAdminService: ClinicAdminService;
41
+ private billingTransactionsService: BillingTransactionsService;
42
+
43
+ constructor(db: Firestore, auth: Auth, app: FirebaseApp, clinicAdminService: ClinicAdminService) {
44
+ super(db, auth, app);
45
+ this.clinicAdminService = clinicAdminService;
46
+ this.billingTransactionsService = new BillingTransactionsService(db, auth, app);
47
+ }
48
+
49
+ /**
50
+ * Kreira novu grupaciju klinika
51
+ */
52
+ async createClinicGroup(
53
+ data: CreateClinicGroupData,
54
+ ownerId: string,
55
+ isDefault: boolean = false,
56
+ ): Promise<ClinicGroup> {
57
+ return ClinicGroupUtils.createClinicGroup(
58
+ this.db,
59
+ data,
60
+ ownerId,
61
+ isDefault,
62
+ this.clinicAdminService,
63
+ this.app,
64
+ );
65
+ }
66
+
67
+ /**
68
+ * Dohvata grupaciju klinika po ID-u
69
+ */
70
+ async getClinicGroup(groupId: string): Promise<ClinicGroup | null> {
71
+ return ClinicGroupUtils.getClinicGroup(this.db, groupId);
72
+ }
73
+
74
+ /**
75
+ * Dohvata sve aktivne grupacije klinika
76
+ */
77
+ async getAllActiveGroups(): Promise<ClinicGroup[]> {
78
+ return ClinicGroupUtils.getAllActiveGroups(this.db);
79
+ }
80
+
81
+ /**
82
+ * Ažurira grupaciju klinika
83
+ */
84
+ async updateClinicGroup(groupId: string, data: Partial<ClinicGroup>): Promise<ClinicGroup> {
85
+ return ClinicGroupUtils.updateClinicGroup(this.db, groupId, data, this.app);
86
+ }
87
+
88
+ /**
89
+ * Dodaje admina u grupaciju
90
+ */
91
+ async addAdminToGroup(groupId: string, adminId: string): Promise<void> {
92
+ return ClinicGroupUtils.addAdminToGroup(this.db, groupId, adminId, this.app);
93
+ }
94
+
95
+ /**
96
+ * Uklanja admina iz grupacije
97
+ */
98
+ async removeAdminFromGroup(groupId: string, adminId: string): Promise<void> {
99
+ return ClinicGroupUtils.removeAdminFromGroup(this.db, groupId, adminId, this.app);
100
+ }
101
+
102
+ /**
103
+ * Deaktivira grupaciju klinika
104
+ */
105
+ async deactivateClinicGroup(groupId: string): Promise<void> {
106
+ return ClinicGroupUtils.deactivateClinicGroup(this.db, groupId, this.app);
107
+ }
108
+
109
+ /**
110
+ * Sets up additional clinic group information after initial creation
111
+ *
112
+ * @param groupId - The ID of the clinic group to set up
113
+ * @param setupData - The setup data for the clinic group
114
+ * @returns The updated clinic group
115
+ */
116
+ async setupClinicGroup(groupId: string, setupData: ClinicGroupSetupData): Promise<ClinicGroup> {
117
+ console.log('[CLINIC_GROUP] Setting up clinic group', { groupId });
118
+
119
+ // Get the clinic group
120
+ const clinicGroup = await this.getClinicGroup(groupId);
121
+ if (!clinicGroup) {
122
+ console.error('[CLINIC_GROUP] Clinic group not found', { groupId });
123
+ throw new Error(`Clinic group with ID ${groupId} not found`);
124
+ }
125
+
126
+ // Process logo if it's a data URL
127
+ let logoUrl = setupData.logo;
128
+ if (logoUrl && typeof logoUrl === 'string' && logoUrl.startsWith('data:')) {
129
+ console.log('[CLINIC_GROUP] Processing logo in setupClinicGroup');
130
+ try {
131
+ const uploadedLogoUrl = await uploadPhoto(
132
+ logoUrl,
133
+ 'clinic-groups',
134
+ groupId,
135
+ 'logo',
136
+ this.app,
137
+ );
138
+ console.log('[CLINIC_GROUP] Logo processed in setupClinicGroup', {
139
+ uploadedLogoUrl,
140
+ });
141
+
142
+ // Replace the data URL with the uploaded URL if upload was successful
143
+ if (uploadedLogoUrl !== null) {
144
+ logoUrl = uploadedLogoUrl;
145
+ }
146
+ } catch (error) {
147
+ console.error('[CLINIC_GROUP] Error processing logo in setupClinicGroup:', error);
148
+ // Continue with update even if logo upload fails
149
+ }
150
+ }
151
+
152
+ // Update the clinic group with the setup data
153
+ const updateData = {
154
+ languages: setupData.languages,
155
+ practiceType: setupData.practiceType,
156
+ description: setupData.description,
157
+ logo: logoUrl,
158
+ calendarSyncEnabled: setupData.calendarSyncEnabled,
159
+ autoConfirmAppointments: setupData.autoConfirmAppointments,
160
+ businessIdentificationNumber: setupData.businessIdentificationNumber,
161
+ };
162
+
163
+ console.log('[CLINIC_GROUP] Updating clinic group with setup data');
164
+
165
+ // Update the clinic group
166
+ return this.updateClinicGroup(groupId, updateData);
167
+ }
168
+
169
+ /**
170
+ * Kreira admin token za grupaciju
171
+ */
172
+ async createAdminToken(
173
+ groupId: string,
174
+ creatorAdminId: string,
175
+ data?: CreateAdminTokenData,
176
+ ): Promise<AdminToken> {
177
+ return ClinicGroupUtils.createAdminToken(this.db, groupId, creatorAdminId, this.app, data);
178
+ }
179
+
180
+ /**
181
+ * Verifikuje i koristi admin token
182
+ */
183
+ async verifyAndUseAdminToken(groupId: string, token: string, userRef: string): Promise<boolean> {
184
+ return ClinicGroupUtils.verifyAndUseAdminToken(this.db, groupId, token, userRef, this.app);
185
+ }
186
+
187
+ /**
188
+ * Briše admin token
189
+ */
190
+ async deleteAdminToken(groupId: string, tokenId: string, adminId: string): Promise<void> {
191
+ return ClinicGroupUtils.deleteAdminToken(this.db, groupId, tokenId, adminId, this.app);
192
+ }
193
+
194
+ /**
195
+ * Dohvata aktivne admin tokene
196
+ */
197
+ async getActiveAdminTokens(groupId: string, adminId: string): Promise<AdminToken[]> {
198
+ return ClinicGroupUtils.getActiveAdminTokens(this.db, groupId, adminId, this.app);
199
+ }
200
+
201
+ // TODO: Add a method to get all admin tokens for a clinic group (not just active ones)
202
+
203
+ // TODO: Refactor admin token methods not to add tokens to the clinicGroup document,
204
+ // but to add them to a subcollection called adminTokens that belongs to a specific clinicGroup document
205
+
206
+ // TODO: Add granular control over admin permissions, e.g. only allow admins to manage certain clinics to tokens directly
207
+ // TODO: Generally refactor admin tokens and invites, also create cloud function to send invites and send updates when sombody uses the token
208
+
209
+ /**
210
+ * Updates the onboarding status for a clinic group
211
+ *
212
+ * @param groupId - The ID of the clinic group to update
213
+ * @param onboardingData - The onboarding data to update
214
+ * @returns The updated clinic group
215
+ */
216
+ async setOnboarding(
217
+ groupId: string,
218
+ onboardingData: {
219
+ completed?: boolean;
220
+ step?: number;
221
+ },
222
+ ): Promise<ClinicGroup> {
223
+ console.log('[CLINIC_GROUP] Updating onboarding status', {
224
+ groupId,
225
+ onboardingData,
226
+ });
227
+
228
+ return this.updateClinicGroup(groupId, {
229
+ onboarding: onboardingData,
230
+ });
231
+ }
232
+
233
+ /**
234
+ * Sets the current onboarding step for a clinic group
235
+ *
236
+ * @param groupId - The ID of the clinic group to update
237
+ * @param step - The current onboarding step number
238
+ * @returns The updated clinic group
239
+ */
240
+ async setOnboardingStep(groupId: string, step: number): Promise<ClinicGroup> {
241
+ console.log('[CLINIC_GROUP] Setting onboarding step', { groupId, step });
242
+
243
+ return this.setOnboarding(groupId, { step, completed: false });
244
+ }
245
+
246
+ /**
247
+ * Marks the onboarding process as completed for a clinic group
248
+ *
249
+ * @param groupId - The ID of the clinic group to update
250
+ * @returns The updated clinic group
251
+ */
252
+ async completeOnboarding(groupId: string): Promise<ClinicGroup> {
253
+ console.log('[CLINIC_GROUP] Completing onboarding', { groupId });
254
+
255
+ return this.setOnboarding(groupId, { completed: true });
256
+ }
257
+
258
+ /**
259
+ * Get billing transactions for a clinic group
260
+ *
261
+ * @param groupId - The clinic group ID
262
+ * @param options - Query options for pagination and filtering
263
+ * @returns Promise with billing transactions and pagination info
264
+ */
265
+ async getBillingTransactions(
266
+ groupId: string,
267
+ options: {
268
+ limit?: number;
269
+ startAfter?: any;
270
+ transactionType?: BillingTransactionType;
271
+ } = {},
272
+ ): Promise<{
273
+ transactions: BillingTransaction[];
274
+ lastDoc: any;
275
+ hasMore: boolean;
276
+ }> {
277
+ return this.billingTransactionsService.getBillingTransactions(groupId, options);
278
+ }
279
+
280
+ /**
281
+ * Get recent billing transactions for a clinic group (last 10)
282
+ *
283
+ * @param groupId - The clinic group ID
284
+ * @returns Promise with recent billing transactions
285
+ */
286
+ async getRecentBillingTransactions(groupId: string): Promise<BillingTransaction[]> {
287
+ return this.billingTransactionsService.getRecentBillingTransactions(groupId);
288
+ }
289
+
290
+ /**
291
+ * Get subscription-related billing transactions for a clinic group
292
+ *
293
+ * @param groupId - The clinic group ID
294
+ * @param options - Query options for pagination
295
+ * @returns Promise with subscription transactions and pagination info
296
+ */
297
+ async getSubscriptionTransactions(
298
+ groupId: string,
299
+ options: {
300
+ limit?: number;
301
+ startAfter?: any;
302
+ } = {},
303
+ ): Promise<{
304
+ transactions: BillingTransaction[];
305
+ lastDoc: any;
306
+ hasMore: boolean;
307
+ }> {
308
+ return this.billingTransactionsService.getSubscriptionTransactions(groupId, options);
309
+ }
310
+ }