@blackcode_sa/metaestetics-api 1.12.64 → 1.12.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/index.d.mts +2 -0
- package/dist/admin/index.d.ts +2 -0
- package/dist/admin/index.js +45 -4
- package/dist/admin/index.mjs +45 -4
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +80 -11
- package/dist/index.mjs +80 -11
- package/package.json +119 -119
- package/src/__mocks__/firstore.ts +10 -10
- package/src/admin/aggregation/README.md +79 -79
- package/src/admin/aggregation/appointment/README.md +128 -128
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +1844 -1844
- package/src/admin/aggregation/appointment/index.ts +1 -1
- package/src/admin/aggregation/clinic/README.md +52 -52
- package/src/admin/aggregation/clinic/clinic.aggregation.service.ts +703 -703
- package/src/admin/aggregation/clinic/index.ts +1 -1
- package/src/admin/aggregation/forms/README.md +13 -13
- package/src/admin/aggregation/forms/filled-forms.aggregation.service.ts +322 -322
- package/src/admin/aggregation/forms/index.ts +1 -1
- package/src/admin/aggregation/index.ts +8 -8
- package/src/admin/aggregation/patient/README.md +27 -27
- package/src/admin/aggregation/patient/index.ts +1 -1
- package/src/admin/aggregation/patient/patient.aggregation.service.ts +141 -141
- package/src/admin/aggregation/practitioner/README.md +42 -42
- package/src/admin/aggregation/practitioner/index.ts +1 -1
- package/src/admin/aggregation/practitioner/practitioner.aggregation.service.ts +433 -433
- package/src/admin/aggregation/practitioner-invite/index.ts +1 -1
- package/src/admin/aggregation/practitioner-invite/practitioner-invite.aggregation.service.ts +961 -961
- package/src/admin/aggregation/procedure/README.md +43 -43
- package/src/admin/aggregation/procedure/index.ts +1 -1
- package/src/admin/aggregation/procedure/procedure.aggregation.service.ts +702 -702
- package/src/admin/aggregation/reviews/index.ts +1 -1
- package/src/admin/aggregation/reviews/reviews.aggregation.service.ts +689 -641
- package/src/admin/booking/README.md +125 -125
- package/src/admin/booking/booking.admin.ts +1037 -1037
- package/src/admin/booking/booking.calculator.ts +712 -712
- package/src/admin/booking/booking.types.ts +59 -59
- package/src/admin/booking/index.ts +3 -3
- package/src/admin/booking/timezones-problem.md +185 -185
- package/src/admin/calendar/README.md +7 -7
- package/src/admin/calendar/calendar.admin.service.ts +345 -345
- package/src/admin/calendar/index.ts +1 -1
- package/src/admin/documentation-templates/document-manager.admin.ts +260 -260
- package/src/admin/documentation-templates/index.ts +1 -1
- package/src/admin/free-consultation/free-consultation-utils.admin.ts +148 -148
- package/src/admin/free-consultation/index.ts +1 -1
- package/src/admin/index.ts +75 -75
- package/src/admin/logger/index.ts +78 -78
- package/src/admin/mailing/README.md +95 -95
- package/src/admin/mailing/appointment/appointment.mailing.service.ts +732 -732
- package/src/admin/mailing/appointment/index.ts +1 -1
- package/src/admin/mailing/appointment/templates/patient/appointment-confirmed.html +40 -40
- package/src/admin/mailing/base.mailing.service.ts +208 -208
- package/src/admin/mailing/index.ts +3 -3
- package/src/admin/mailing/practitionerInvite/existing-practitioner-invite.mailing.ts +611 -611
- package/src/admin/mailing/practitionerInvite/index.ts +2 -2
- package/src/admin/mailing/practitionerInvite/practitionerInvite.mailing.ts +395 -395
- package/src/admin/mailing/practitionerInvite/templates/existing-practitioner-invitation.template.ts +155 -155
- package/src/admin/mailing/practitionerInvite/templates/invitation.template.ts +101 -101
- package/src/admin/mailing/practitionerInvite/templates/invite-accepted-notification.template.ts +228 -228
- package/src/admin/mailing/practitionerInvite/templates/invite-rejected-notification.template.ts +242 -242
- package/src/admin/notifications/index.ts +1 -1
- package/src/admin/notifications/notifications.admin.ts +710 -710
- package/src/admin/requirements/README.md +128 -128
- package/src/admin/requirements/index.ts +1 -1
- package/src/admin/requirements/patient-requirements.admin.service.ts +475 -475
- package/src/admin/users/index.ts +1 -1
- package/src/admin/users/user-profile.admin.ts +405 -405
- package/src/backoffice/constants/certification.constants.ts +13 -13
- package/src/backoffice/constants/index.ts +1 -1
- package/src/backoffice/errors/backoffice.errors.ts +181 -181
- package/src/backoffice/errors/index.ts +1 -1
- package/src/backoffice/expo-safe/README.md +26 -26
- package/src/backoffice/expo-safe/index.ts +41 -41
- package/src/backoffice/index.ts +5 -5
- package/src/backoffice/services/FIXES_README.md +102 -102
- package/src/backoffice/services/README.md +40 -40
- package/src/backoffice/services/brand.service.ts +256 -256
- package/src/backoffice/services/category.service.ts +318 -318
- package/src/backoffice/services/constants.service.ts +385 -385
- package/src/backoffice/services/documentation-template.service.ts +202 -202
- package/src/backoffice/services/index.ts +10 -10
- package/src/backoffice/services/migrate-products.ts +116 -116
- package/src/backoffice/services/product.service.ts +553 -553
- package/src/backoffice/services/requirement.service.ts +235 -235
- package/src/backoffice/services/subcategory.service.ts +395 -395
- package/src/backoffice/services/technology.service.ts +1083 -1083
- package/src/backoffice/types/README.md +12 -12
- package/src/backoffice/types/admin-constants.types.ts +69 -69
- package/src/backoffice/types/brand.types.ts +29 -29
- package/src/backoffice/types/category.types.ts +62 -62
- package/src/backoffice/types/documentation-templates.types.ts +28 -28
- package/src/backoffice/types/index.ts +10 -10
- package/src/backoffice/types/procedure-product.types.ts +38 -38
- package/src/backoffice/types/product.types.ts +240 -240
- package/src/backoffice/types/requirement.types.ts +63 -63
- package/src/backoffice/types/static/README.md +18 -18
- package/src/backoffice/types/static/blocking-condition.types.ts +21 -21
- package/src/backoffice/types/static/certification.types.ts +37 -37
- package/src/backoffice/types/static/contraindication.types.ts +19 -19
- package/src/backoffice/types/static/index.ts +6 -6
- package/src/backoffice/types/static/pricing.types.ts +16 -16
- package/src/backoffice/types/static/procedure-family.types.ts +14 -14
- package/src/backoffice/types/static/treatment-benefit.types.ts +22 -22
- package/src/backoffice/types/subcategory.types.ts +34 -34
- package/src/backoffice/types/technology.types.ts +163 -163
- package/src/backoffice/validations/index.ts +1 -1
- package/src/backoffice/validations/schemas.ts +164 -164
- package/src/config/__mocks__/firebase.ts +99 -99
- package/src/config/firebase.ts +78 -78
- package/src/config/index.ts +9 -9
- package/src/errors/auth.error.ts +6 -6
- package/src/errors/auth.errors.ts +200 -200
- package/src/errors/clinic.errors.ts +32 -32
- package/src/errors/firebase.errors.ts +47 -47
- package/src/errors/user.errors.ts +99 -99
- package/src/index.backup.ts +407 -407
- package/src/index.ts +6 -6
- package/src/locales/en.ts +31 -31
- package/src/recommender/admin/index.ts +1 -1
- package/src/recommender/admin/services/recommender.service.admin.ts +5 -5
- package/src/recommender/front/index.ts +1 -1
- package/src/recommender/front/services/onboarding.service.ts +5 -5
- package/src/recommender/front/services/recommender.service.ts +3 -3
- package/src/recommender/index.ts +1 -1
- package/src/services/PATIENTAUTH.MD +197 -197
- package/src/services/README.md +106 -106
- package/src/services/__tests__/auth/auth.mock.test.ts +17 -17
- package/src/services/__tests__/auth/auth.setup.ts +293 -293
- package/src/services/__tests__/auth.service.test.ts +346 -346
- package/src/services/__tests__/base.service.test.ts +77 -77
- package/src/services/__tests__/user.service.test.ts +528 -528
- package/src/services/appointment/README.md +17 -17
- package/src/services/appointment/appointment.service.ts +2505 -2505
- package/src/services/appointment/index.ts +1 -1
- package/src/services/appointment/utils/appointment.utils.ts +552 -552
- package/src/services/appointment/utils/extended-procedure.utils.ts +314 -314
- package/src/services/appointment/utils/form-initialization.utils.ts +225 -225
- package/src/services/appointment/utils/recommended-procedure.utils.ts +195 -195
- package/src/services/appointment/utils/zone-management.utils.ts +353 -353
- package/src/services/appointment/utils/zone-photo.utils.ts +152 -152
- package/src/services/auth/auth.service.ts +989 -989
- package/src/services/auth/auth.v2.service.ts +961 -961
- package/src/services/auth/index.ts +7 -7
- package/src/services/auth/utils/error.utils.ts +90 -90
- package/src/services/auth/utils/firebase.utils.ts +49 -49
- package/src/services/auth/utils/index.ts +21 -21
- package/src/services/auth/utils/practitioner.utils.ts +125 -125
- package/src/services/base.service.ts +41 -41
- package/src/services/calendar/calendar.service.ts +1077 -1077
- package/src/services/calendar/calendar.v2.service.ts +1683 -1683
- package/src/services/calendar/calendar.v3.service.ts +313 -313
- package/src/services/calendar/externalCalendar.service.ts +178 -178
- package/src/services/calendar/index.ts +5 -5
- package/src/services/calendar/synced-calendars.service.ts +743 -743
- package/src/services/calendar/utils/appointment.utils.ts +265 -265
- package/src/services/calendar/utils/calendar-event.utils.ts +646 -646
- package/src/services/calendar/utils/clinic.utils.ts +237 -237
- package/src/services/calendar/utils/docs.utils.ts +157 -157
- package/src/services/calendar/utils/google-calendar.utils.ts +697 -697
- package/src/services/calendar/utils/index.ts +8 -8
- package/src/services/calendar/utils/patient.utils.ts +198 -198
- package/src/services/calendar/utils/practitioner.utils.ts +221 -221
- package/src/services/calendar/utils/synced-calendar.utils.ts +472 -472
- package/src/services/clinic/README.md +204 -204
- package/src/services/clinic/__tests__/clinic-admin.service.test.ts +287 -287
- package/src/services/clinic/__tests__/clinic-group.service.test.ts +352 -352
- package/src/services/clinic/__tests__/clinic.service.test.ts +354 -354
- package/src/services/clinic/billing-transactions.service.ts +217 -217
- package/src/services/clinic/clinic-admin.service.ts +202 -202
- package/src/services/clinic/clinic-group.service.ts +310 -310
- package/src/services/clinic/clinic.service.ts +708 -708
- package/src/services/clinic/index.ts +5 -5
- package/src/services/clinic/practitioner-invite.service.ts +519 -519
- package/src/services/clinic/utils/admin.utils.ts +551 -551
- package/src/services/clinic/utils/clinic-group.utils.ts +646 -646
- package/src/services/clinic/utils/clinic.utils.ts +949 -949
- package/src/services/clinic/utils/filter.utils.d.ts +23 -23
- package/src/services/clinic/utils/filter.utils.ts +446 -446
- package/src/services/clinic/utils/index.ts +11 -11
- package/src/services/clinic/utils/photos.utils.ts +188 -188
- package/src/services/clinic/utils/search.utils.ts +84 -84
- package/src/services/clinic/utils/tag.utils.ts +124 -124
- package/src/services/documentation-templates/documentation-template.service.ts +537 -537
- package/src/services/documentation-templates/filled-document.service.ts +587 -587
- package/src/services/documentation-templates/index.ts +2 -2
- package/src/services/index.ts +13 -13
- package/src/services/media/index.ts +1 -1
- package/src/services/media/media.service.ts +418 -418
- package/src/services/notifications/__tests__/notification.service.test.ts +242 -242
- package/src/services/notifications/index.ts +1 -1
- package/src/services/notifications/notification.service.ts +215 -215
- package/src/services/patient/README.md +48 -48
- package/src/services/patient/To-Do.md +43 -43
- package/src/services/patient/__tests__/patient.service.test.ts +294 -294
- package/src/services/patient/index.ts +2 -2
- package/src/services/patient/patient.service.ts +883 -883
- package/src/services/patient/patientRequirements.service.ts +285 -285
- package/src/services/patient/utils/aesthetic-analysis.utils.ts +176 -176
- package/src/services/patient/utils/clinic.utils.ts +80 -80
- package/src/services/patient/utils/docs.utils.ts +142 -142
- package/src/services/patient/utils/index.ts +9 -9
- package/src/services/patient/utils/location.utils.ts +126 -126
- package/src/services/patient/utils/medical-stuff.utils.ts +143 -143
- package/src/services/patient/utils/medical.utils.ts +458 -458
- package/src/services/patient/utils/practitioner.utils.ts +260 -260
- package/src/services/patient/utils/profile.utils.ts +510 -510
- package/src/services/patient/utils/sensitive.utils.ts +260 -260
- package/src/services/patient/utils/token.utils.ts +211 -211
- package/src/services/practitioner/README.md +145 -145
- package/src/services/practitioner/index.ts +1 -1
- package/src/services/practitioner/practitioner.service.ts +1742 -1742
- package/src/services/procedure/README.md +163 -163
- package/src/services/procedure/index.ts +1 -1
- package/src/services/procedure/procedure.service.ts +1715 -1682
- package/src/services/reviews/index.ts +1 -1
- package/src/services/reviews/reviews.service.ts +683 -636
- package/src/services/user/index.ts +1 -1
- package/src/services/user/user.service.ts +489 -489
- package/src/services/user/user.v2.service.ts +466 -466
- package/src/types/appointment/index.ts +480 -480
- package/src/types/calendar/index.ts +258 -258
- package/src/types/calendar/synced-calendar.types.ts +66 -66
- package/src/types/clinic/index.ts +489 -489
- package/src/types/clinic/practitioner-invite.types.ts +91 -91
- package/src/types/clinic/preferences.types.ts +159 -159
- package/src/types/clinic/to-do +3 -3
- package/src/types/documentation-templates/index.ts +308 -308
- package/src/types/index.ts +44 -44
- package/src/types/notifications/README.md +77 -77
- package/src/types/notifications/index.ts +265 -265
- package/src/types/patient/aesthetic-analysis.types.ts +66 -66
- package/src/types/patient/allergies.ts +58 -58
- package/src/types/patient/index.ts +275 -275
- package/src/types/patient/medical-info.types.ts +152 -152
- package/src/types/patient/patient-requirements.ts +92 -92
- package/src/types/patient/token.types.ts +61 -61
- package/src/types/practitioner/index.ts +206 -206
- package/src/types/procedure/index.ts +181 -181
- package/src/types/profile/index.ts +39 -39
- package/src/types/reviews/index.ts +132 -130
- package/src/types/tz-lookup.d.ts +4 -4
- package/src/types/user/index.ts +38 -38
- package/src/utils/TIMESTAMPS.md +176 -176
- package/src/utils/TimestampUtils.ts +241 -241
- package/src/utils/index.ts +1 -1
- package/src/validations/appointment.schema.ts +574 -574
- package/src/validations/calendar.schema.ts +225 -225
- package/src/validations/clinic.schema.ts +493 -493
- package/src/validations/common.schema.ts +25 -25
- package/src/validations/documentation-templates/index.ts +1 -1
- package/src/validations/documentation-templates/template.schema.ts +220 -220
- package/src/validations/documentation-templates.schema.ts +10 -10
- package/src/validations/index.ts +20 -20
- package/src/validations/media.schema.ts +10 -10
- package/src/validations/notification.schema.ts +90 -90
- package/src/validations/patient/aesthetic-analysis.schema.ts +55 -55
- package/src/validations/patient/medical-info.schema.ts +125 -125
- package/src/validations/patient/patient-requirements.schema.ts +84 -84
- package/src/validations/patient/token.schema.ts +29 -29
- package/src/validations/patient.schema.ts +217 -217
- package/src/validations/practitioner.schema.ts +222 -222
- package/src/validations/procedure-product.schema.ts +41 -41
- package/src/validations/procedure.schema.ts +124 -124
- package/src/validations/profile-info.schema.ts +41 -41
- package/src/validations/reviews.schema.ts +195 -189
- package/src/validations/schemas.ts +104 -104
- package/src/validations/shared.schema.ts +78 -78
|
@@ -1,202 +1,202 @@
|
|
|
1
|
-
import { Auth } from "firebase/auth";
|
|
2
|
-
import { Firestore } from "firebase/firestore";
|
|
3
|
-
import { FirebaseApp } from "firebase/app";
|
|
4
|
-
import { DocumentationTemplateService as ApiDocumentationTemplateService } from "../../services/documentation-templates";
|
|
5
|
-
import {
|
|
6
|
-
CreateDocumentTemplateData,
|
|
7
|
-
DocumentTemplate,
|
|
8
|
-
UpdateDocumentTemplateData,
|
|
9
|
-
} from "../../types/documentation-templates";
|
|
10
|
-
import { QueryDocumentSnapshot } from "firebase/firestore";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Service for managing documentation templates in the backoffice
|
|
14
|
-
*/
|
|
15
|
-
export class DocumentationTemplateServiceBackoffice {
|
|
16
|
-
private apiService: ApiDocumentationTemplateService;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Constructor for DocumentationTemplateService
|
|
20
|
-
* @param db - Firestore instance
|
|
21
|
-
* @param auth - Firebase Auth instance
|
|
22
|
-
* @param app - Firebase App instance
|
|
23
|
-
*/
|
|
24
|
-
constructor(
|
|
25
|
-
...args: ConstructorParameters<typeof ApiDocumentationTemplateService>
|
|
26
|
-
) {
|
|
27
|
-
this.apiService = new ApiDocumentationTemplateService(...args);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Create a new document template
|
|
32
|
-
* @param data - Template data
|
|
33
|
-
* @param userId - ID of the user creating the template
|
|
34
|
-
* @returns The created template
|
|
35
|
-
*/
|
|
36
|
-
async createTemplate(
|
|
37
|
-
data: CreateDocumentTemplateData,
|
|
38
|
-
userId: string
|
|
39
|
-
): Promise<DocumentTemplate> {
|
|
40
|
-
return this.apiService.createTemplate(data, userId);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Get a document template by ID
|
|
45
|
-
* @param templateId - ID of the template to retrieve
|
|
46
|
-
* @param version - Optional version number to retrieve (defaults to latest version)
|
|
47
|
-
* @returns The template or null if not found
|
|
48
|
-
*/
|
|
49
|
-
async getTemplateById(
|
|
50
|
-
templateId: string,
|
|
51
|
-
version?: number
|
|
52
|
-
): Promise<DocumentTemplate | null> {
|
|
53
|
-
return this.apiService.getTemplateById(templateId, version);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Update an existing document template
|
|
58
|
-
* @param templateId - ID of the template to update
|
|
59
|
-
* @param data - Updated template data
|
|
60
|
-
* @returns The updated template
|
|
61
|
-
*/
|
|
62
|
-
async updateTemplate(
|
|
63
|
-
templateId: string,
|
|
64
|
-
data: UpdateDocumentTemplateData
|
|
65
|
-
): Promise<DocumentTemplate> {
|
|
66
|
-
return this.apiService.updateTemplate(templateId, data);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Delete a document template
|
|
71
|
-
* @param templateId - ID of the template to delete
|
|
72
|
-
*/
|
|
73
|
-
async deleteTemplate(templateId: string): Promise<void> {
|
|
74
|
-
return this.apiService.deleteTemplate(templateId);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Get all active templates
|
|
79
|
-
* @param pageSize - Number of templates to retrieve
|
|
80
|
-
* @param lastDoc - Last document from previous page for pagination
|
|
81
|
-
* @returns Array of templates and the last document for pagination
|
|
82
|
-
*/
|
|
83
|
-
async getActiveTemplates(
|
|
84
|
-
pageSize = 20,
|
|
85
|
-
lastDoc?: QueryDocumentSnapshot<DocumentTemplate>
|
|
86
|
-
): Promise<{
|
|
87
|
-
templates: DocumentTemplate[];
|
|
88
|
-
lastDoc: QueryDocumentSnapshot<DocumentTemplate> | null;
|
|
89
|
-
}> {
|
|
90
|
-
return this.apiService.getActiveTemplates(pageSize, lastDoc);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Get all active templates with optional filters and pagination.
|
|
95
|
-
* @param options - Options for filtering and pagination.
|
|
96
|
-
* @returns A promise that resolves to the templates and the last visible document.
|
|
97
|
-
*/
|
|
98
|
-
async getTemplates(options: {
|
|
99
|
-
pageSize?: number;
|
|
100
|
-
lastDoc?: QueryDocumentSnapshot<DocumentTemplate>;
|
|
101
|
-
isUserForm?: boolean;
|
|
102
|
-
isRequired?: boolean;
|
|
103
|
-
sortingOrder?: number;
|
|
104
|
-
}): Promise<{
|
|
105
|
-
templates: DocumentTemplate[];
|
|
106
|
-
lastDoc: QueryDocumentSnapshot<DocumentTemplate> | null;
|
|
107
|
-
}> {
|
|
108
|
-
return this.apiService.getTemplates(options);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Get the total count of active templates with optional filters.
|
|
113
|
-
* @param options - Options for filtering.
|
|
114
|
-
* @returns A promise that resolves to the total count of templates.
|
|
115
|
-
*/
|
|
116
|
-
async getTemplatesCount(options: {
|
|
117
|
-
isUserForm?: boolean;
|
|
118
|
-
isRequired?: boolean;
|
|
119
|
-
sortingOrder?: number;
|
|
120
|
-
search?: string;
|
|
121
|
-
}): Promise<number> {
|
|
122
|
-
return this.apiService.getTemplatesCount(options);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Get all active templates without pagination for filtering purposes.
|
|
127
|
-
* @returns A promise that resolves to an array of all active templates.
|
|
128
|
-
*/
|
|
129
|
-
async getAllActiveTemplates(): Promise<DocumentTemplate[]> {
|
|
130
|
-
return this.apiService.getAllActiveTemplates();
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Searches for active templates by title.
|
|
135
|
-
* @param title - The title to search for.
|
|
136
|
-
* @returns A list of templates that match the search criteria.
|
|
137
|
-
*/
|
|
138
|
-
async search(title: string): Promise<DocumentTemplate[]> {
|
|
139
|
-
const { templates } = await this.apiService.getActiveTemplates(1000); // A large number to get all templates
|
|
140
|
-
return templates.filter((t) =>
|
|
141
|
-
t.title.toLowerCase().includes(title.toLowerCase())
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Get templates by tags
|
|
147
|
-
* @param tags - Tags to filter by
|
|
148
|
-
* @param pageSize - Number of templates to retrieve
|
|
149
|
-
* @param lastDoc - Last document from previous page for pagination
|
|
150
|
-
* @returns Array of templates and the last document for pagination
|
|
151
|
-
*/
|
|
152
|
-
async getTemplatesByTags(
|
|
153
|
-
tags: string[],
|
|
154
|
-
pageSize = 20,
|
|
155
|
-
lastDoc?: QueryDocumentSnapshot<DocumentTemplate>
|
|
156
|
-
): Promise<{
|
|
157
|
-
templates: DocumentTemplate[];
|
|
158
|
-
lastDoc: QueryDocumentSnapshot<DocumentTemplate> | null;
|
|
159
|
-
}> {
|
|
160
|
-
return this.apiService.getTemplatesByTags(tags, pageSize, lastDoc);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Get templates created by a specific user
|
|
165
|
-
* @param userId - ID of the user who created the templates
|
|
166
|
-
* @param pageSize - Number of templates to retrieve
|
|
167
|
-
* @param lastDoc - Last document from previous page for pagination
|
|
168
|
-
* @returns Array of templates and the last document for pagination
|
|
169
|
-
*/
|
|
170
|
-
async getTemplatesByCreator(
|
|
171
|
-
userId: string,
|
|
172
|
-
pageSize = 20,
|
|
173
|
-
lastDoc?: QueryDocumentSnapshot<DocumentTemplate>
|
|
174
|
-
): Promise<{
|
|
175
|
-
templates: DocumentTemplate[];
|
|
176
|
-
lastDoc: QueryDocumentSnapshot<DocumentTemplate> | null;
|
|
177
|
-
}> {
|
|
178
|
-
return this.apiService.getTemplatesByCreator(userId, pageSize, lastDoc);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Get a specific version of a template
|
|
183
|
-
* @param templateId - ID of the template
|
|
184
|
-
* @param versionNumber - Version number to retrieve
|
|
185
|
-
* @returns The template version or null if not found
|
|
186
|
-
*/
|
|
187
|
-
async getTemplateVersion(
|
|
188
|
-
templateId: string,
|
|
189
|
-
versionNumber: number
|
|
190
|
-
): Promise<DocumentTemplate | null> {
|
|
191
|
-
return this.apiService.getTemplateVersion(templateId, versionNumber);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Get all versions of a template
|
|
196
|
-
* @param templateId - ID of the template
|
|
197
|
-
* @returns Array of template versions
|
|
198
|
-
*/
|
|
199
|
-
async getTemplateVersions(templateId: string): Promise<DocumentTemplate[]> {
|
|
200
|
-
return this.apiService.getTemplateOldVersions(templateId);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
1
|
+
import { Auth } from "firebase/auth";
|
|
2
|
+
import { Firestore } from "firebase/firestore";
|
|
3
|
+
import { FirebaseApp } from "firebase/app";
|
|
4
|
+
import { DocumentationTemplateService as ApiDocumentationTemplateService } from "../../services/documentation-templates";
|
|
5
|
+
import {
|
|
6
|
+
CreateDocumentTemplateData,
|
|
7
|
+
DocumentTemplate,
|
|
8
|
+
UpdateDocumentTemplateData,
|
|
9
|
+
} from "../../types/documentation-templates";
|
|
10
|
+
import { QueryDocumentSnapshot } from "firebase/firestore";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Service for managing documentation templates in the backoffice
|
|
14
|
+
*/
|
|
15
|
+
export class DocumentationTemplateServiceBackoffice {
|
|
16
|
+
private apiService: ApiDocumentationTemplateService;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Constructor for DocumentationTemplateService
|
|
20
|
+
* @param db - Firestore instance
|
|
21
|
+
* @param auth - Firebase Auth instance
|
|
22
|
+
* @param app - Firebase App instance
|
|
23
|
+
*/
|
|
24
|
+
constructor(
|
|
25
|
+
...args: ConstructorParameters<typeof ApiDocumentationTemplateService>
|
|
26
|
+
) {
|
|
27
|
+
this.apiService = new ApiDocumentationTemplateService(...args);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Create a new document template
|
|
32
|
+
* @param data - Template data
|
|
33
|
+
* @param userId - ID of the user creating the template
|
|
34
|
+
* @returns The created template
|
|
35
|
+
*/
|
|
36
|
+
async createTemplate(
|
|
37
|
+
data: CreateDocumentTemplateData,
|
|
38
|
+
userId: string
|
|
39
|
+
): Promise<DocumentTemplate> {
|
|
40
|
+
return this.apiService.createTemplate(data, userId);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get a document template by ID
|
|
45
|
+
* @param templateId - ID of the template to retrieve
|
|
46
|
+
* @param version - Optional version number to retrieve (defaults to latest version)
|
|
47
|
+
* @returns The template or null if not found
|
|
48
|
+
*/
|
|
49
|
+
async getTemplateById(
|
|
50
|
+
templateId: string,
|
|
51
|
+
version?: number
|
|
52
|
+
): Promise<DocumentTemplate | null> {
|
|
53
|
+
return this.apiService.getTemplateById(templateId, version);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Update an existing document template
|
|
58
|
+
* @param templateId - ID of the template to update
|
|
59
|
+
* @param data - Updated template data
|
|
60
|
+
* @returns The updated template
|
|
61
|
+
*/
|
|
62
|
+
async updateTemplate(
|
|
63
|
+
templateId: string,
|
|
64
|
+
data: UpdateDocumentTemplateData
|
|
65
|
+
): Promise<DocumentTemplate> {
|
|
66
|
+
return this.apiService.updateTemplate(templateId, data);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Delete a document template
|
|
71
|
+
* @param templateId - ID of the template to delete
|
|
72
|
+
*/
|
|
73
|
+
async deleteTemplate(templateId: string): Promise<void> {
|
|
74
|
+
return this.apiService.deleteTemplate(templateId);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get all active templates
|
|
79
|
+
* @param pageSize - Number of templates to retrieve
|
|
80
|
+
* @param lastDoc - Last document from previous page for pagination
|
|
81
|
+
* @returns Array of templates and the last document for pagination
|
|
82
|
+
*/
|
|
83
|
+
async getActiveTemplates(
|
|
84
|
+
pageSize = 20,
|
|
85
|
+
lastDoc?: QueryDocumentSnapshot<DocumentTemplate>
|
|
86
|
+
): Promise<{
|
|
87
|
+
templates: DocumentTemplate[];
|
|
88
|
+
lastDoc: QueryDocumentSnapshot<DocumentTemplate> | null;
|
|
89
|
+
}> {
|
|
90
|
+
return this.apiService.getActiveTemplates(pageSize, lastDoc);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get all active templates with optional filters and pagination.
|
|
95
|
+
* @param options - Options for filtering and pagination.
|
|
96
|
+
* @returns A promise that resolves to the templates and the last visible document.
|
|
97
|
+
*/
|
|
98
|
+
async getTemplates(options: {
|
|
99
|
+
pageSize?: number;
|
|
100
|
+
lastDoc?: QueryDocumentSnapshot<DocumentTemplate>;
|
|
101
|
+
isUserForm?: boolean;
|
|
102
|
+
isRequired?: boolean;
|
|
103
|
+
sortingOrder?: number;
|
|
104
|
+
}): Promise<{
|
|
105
|
+
templates: DocumentTemplate[];
|
|
106
|
+
lastDoc: QueryDocumentSnapshot<DocumentTemplate> | null;
|
|
107
|
+
}> {
|
|
108
|
+
return this.apiService.getTemplates(options);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get the total count of active templates with optional filters.
|
|
113
|
+
* @param options - Options for filtering.
|
|
114
|
+
* @returns A promise that resolves to the total count of templates.
|
|
115
|
+
*/
|
|
116
|
+
async getTemplatesCount(options: {
|
|
117
|
+
isUserForm?: boolean;
|
|
118
|
+
isRequired?: boolean;
|
|
119
|
+
sortingOrder?: number;
|
|
120
|
+
search?: string;
|
|
121
|
+
}): Promise<number> {
|
|
122
|
+
return this.apiService.getTemplatesCount(options);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get all active templates without pagination for filtering purposes.
|
|
127
|
+
* @returns A promise that resolves to an array of all active templates.
|
|
128
|
+
*/
|
|
129
|
+
async getAllActiveTemplates(): Promise<DocumentTemplate[]> {
|
|
130
|
+
return this.apiService.getAllActiveTemplates();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Searches for active templates by title.
|
|
135
|
+
* @param title - The title to search for.
|
|
136
|
+
* @returns A list of templates that match the search criteria.
|
|
137
|
+
*/
|
|
138
|
+
async search(title: string): Promise<DocumentTemplate[]> {
|
|
139
|
+
const { templates } = await this.apiService.getActiveTemplates(1000); // A large number to get all templates
|
|
140
|
+
return templates.filter((t) =>
|
|
141
|
+
t.title.toLowerCase().includes(title.toLowerCase())
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get templates by tags
|
|
147
|
+
* @param tags - Tags to filter by
|
|
148
|
+
* @param pageSize - Number of templates to retrieve
|
|
149
|
+
* @param lastDoc - Last document from previous page for pagination
|
|
150
|
+
* @returns Array of templates and the last document for pagination
|
|
151
|
+
*/
|
|
152
|
+
async getTemplatesByTags(
|
|
153
|
+
tags: string[],
|
|
154
|
+
pageSize = 20,
|
|
155
|
+
lastDoc?: QueryDocumentSnapshot<DocumentTemplate>
|
|
156
|
+
): Promise<{
|
|
157
|
+
templates: DocumentTemplate[];
|
|
158
|
+
lastDoc: QueryDocumentSnapshot<DocumentTemplate> | null;
|
|
159
|
+
}> {
|
|
160
|
+
return this.apiService.getTemplatesByTags(tags, pageSize, lastDoc);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Get templates created by a specific user
|
|
165
|
+
* @param userId - ID of the user who created the templates
|
|
166
|
+
* @param pageSize - Number of templates to retrieve
|
|
167
|
+
* @param lastDoc - Last document from previous page for pagination
|
|
168
|
+
* @returns Array of templates and the last document for pagination
|
|
169
|
+
*/
|
|
170
|
+
async getTemplatesByCreator(
|
|
171
|
+
userId: string,
|
|
172
|
+
pageSize = 20,
|
|
173
|
+
lastDoc?: QueryDocumentSnapshot<DocumentTemplate>
|
|
174
|
+
): Promise<{
|
|
175
|
+
templates: DocumentTemplate[];
|
|
176
|
+
lastDoc: QueryDocumentSnapshot<DocumentTemplate> | null;
|
|
177
|
+
}> {
|
|
178
|
+
return this.apiService.getTemplatesByCreator(userId, pageSize, lastDoc);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get a specific version of a template
|
|
183
|
+
* @param templateId - ID of the template
|
|
184
|
+
* @param versionNumber - Version number to retrieve
|
|
185
|
+
* @returns The template version or null if not found
|
|
186
|
+
*/
|
|
187
|
+
async getTemplateVersion(
|
|
188
|
+
templateId: string,
|
|
189
|
+
versionNumber: number
|
|
190
|
+
): Promise<DocumentTemplate | null> {
|
|
191
|
+
return this.apiService.getTemplateVersion(templateId, versionNumber);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Get all versions of a template
|
|
196
|
+
* @param templateId - ID of the template
|
|
197
|
+
* @returns Array of template versions
|
|
198
|
+
*/
|
|
199
|
+
async getTemplateVersions(templateId: string): Promise<DocumentTemplate[]> {
|
|
200
|
+
return this.apiService.getTemplateOldVersions(templateId);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export * from "./brand.service";
|
|
2
|
-
export * from "./category.service";
|
|
3
|
-
export * from "./documentation-template.service";
|
|
4
|
-
export * from "./product.service";
|
|
5
|
-
export * from "./requirement.service";
|
|
6
|
-
export * from "./subcategory.service";
|
|
7
|
-
export * from "./technology.service";
|
|
8
|
-
export * from "./constants.service";
|
|
9
|
-
|
|
10
|
-
// Re-export MediaService from main services for backoffice use
|
|
1
|
+
export * from "./brand.service";
|
|
2
|
+
export * from "./category.service";
|
|
3
|
+
export * from "./documentation-template.service";
|
|
4
|
+
export * from "./product.service";
|
|
5
|
+
export * from "./requirement.service";
|
|
6
|
+
export * from "./subcategory.service";
|
|
7
|
+
export * from "./technology.service";
|
|
8
|
+
export * from "./constants.service";
|
|
9
|
+
|
|
10
|
+
// Re-export MediaService from main services for backoffice use
|
|
11
11
|
export { MediaService, MediaAccessLevel, type MediaMetadata, type MediaResource } from "../../services/media/media.service";
|
|
@@ -1,116 +1,116 @@
|
|
|
1
|
-
import * as admin from 'firebase-admin';
|
|
2
|
-
import { Product } from '../types/product.types';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Migration script to copy existing products from technology subcollections
|
|
6
|
-
* to the new top-level products collection
|
|
7
|
-
*
|
|
8
|
-
* Usage: Run this once to migrate existing data
|
|
9
|
-
*/
|
|
10
|
-
export async function migrateProductsToTopLevel(db: admin.firestore.Firestore) {
|
|
11
|
-
console.log('🚀 Starting product migration...');
|
|
12
|
-
|
|
13
|
-
// Get all technologies
|
|
14
|
-
const technologiesSnapshot = await db.collection('technologies').get();
|
|
15
|
-
|
|
16
|
-
const productMap = new Map<string, {
|
|
17
|
-
product: any;
|
|
18
|
-
technologyIds: string[];
|
|
19
|
-
}>();
|
|
20
|
-
|
|
21
|
-
let totalProcessed = 0;
|
|
22
|
-
|
|
23
|
-
// Step 1: Collect all products from all technology subcollections
|
|
24
|
-
for (const techDoc of technologiesSnapshot.docs) {
|
|
25
|
-
const technologyId = techDoc.id;
|
|
26
|
-
console.log(`📦 Processing technology: ${technologyId}`);
|
|
27
|
-
|
|
28
|
-
const productsSnapshot = await db
|
|
29
|
-
.collection('technologies')
|
|
30
|
-
.doc(technologyId)
|
|
31
|
-
.collection('products')
|
|
32
|
-
.get();
|
|
33
|
-
|
|
34
|
-
for (const productDoc of productsSnapshot.docs) {
|
|
35
|
-
const productId = productDoc.id;
|
|
36
|
-
const productData = productDoc.data();
|
|
37
|
-
|
|
38
|
-
totalProcessed++;
|
|
39
|
-
|
|
40
|
-
// Deduplicate by name + brandId
|
|
41
|
-
const key = `${productData.name}_${productData.brandId}`;
|
|
42
|
-
|
|
43
|
-
if (productMap.has(key)) {
|
|
44
|
-
// Product already exists, just add this technology
|
|
45
|
-
productMap.get(key)!.technologyIds.push(technologyId);
|
|
46
|
-
} else {
|
|
47
|
-
// New product
|
|
48
|
-
productMap.set(key, {
|
|
49
|
-
product: productData,
|
|
50
|
-
technologyIds: [technologyId],
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
console.log(`✅ Found ${productMap.size} unique products from ${totalProcessed} total entries`);
|
|
57
|
-
|
|
58
|
-
// Step 2: Create products in top-level collection
|
|
59
|
-
const batch = db.batch();
|
|
60
|
-
let batchCount = 0;
|
|
61
|
-
const MAX_BATCH_SIZE = 500;
|
|
62
|
-
let createdCount = 0;
|
|
63
|
-
|
|
64
|
-
for (const [key, { product, technologyIds }] of productMap.entries()) {
|
|
65
|
-
const productRef = db.collection('products').doc();
|
|
66
|
-
|
|
67
|
-
const migratedProduct: any = {
|
|
68
|
-
...product,
|
|
69
|
-
assignedTechnologyIds: technologyIds, // Track all assigned technologies
|
|
70
|
-
migratedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
71
|
-
migrationKey: key, // For debugging
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
batch.set(productRef, migratedProduct);
|
|
75
|
-
createdCount++;
|
|
76
|
-
batchCount++;
|
|
77
|
-
|
|
78
|
-
if (batchCount >= MAX_BATCH_SIZE) {
|
|
79
|
-
await batch.commit();
|
|
80
|
-
console.log(`💾 Committed batch of ${batchCount} products (${createdCount}/${productMap.size})`);
|
|
81
|
-
batchCount = 0;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (batchCount > 0) {
|
|
86
|
-
await batch.commit();
|
|
87
|
-
console.log(`💾 Committed final batch of ${batchCount} products`);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
console.log('✅ Migration complete!');
|
|
91
|
-
console.log(`📊 Summary:`);
|
|
92
|
-
console.log(` - Products processed: ${totalProcessed}`);
|
|
93
|
-
console.log(` - Unique products created: ${createdCount}`);
|
|
94
|
-
console.log(` - Average technologies per product: ${(createdCount > 0 ? totalProcessed / createdCount : 0).toFixed(2)}`);
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
totalProcessed,
|
|
98
|
-
uniqueCreated: createdCount,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Run migration (for testing)
|
|
104
|
-
*/
|
|
105
|
-
if (require.main === module) {
|
|
106
|
-
(async () => {
|
|
107
|
-
try {
|
|
108
|
-
await migrateProductsToTopLevel(admin.firestore());
|
|
109
|
-
process.exit(0);
|
|
110
|
-
} catch (error) {
|
|
111
|
-
console.error('❌ Migration failed:', error);
|
|
112
|
-
process.exit(1);
|
|
113
|
-
}
|
|
114
|
-
})();
|
|
115
|
-
}
|
|
116
|
-
|
|
1
|
+
import * as admin from 'firebase-admin';
|
|
2
|
+
import { Product } from '../types/product.types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Migration script to copy existing products from technology subcollections
|
|
6
|
+
* to the new top-level products collection
|
|
7
|
+
*
|
|
8
|
+
* Usage: Run this once to migrate existing data
|
|
9
|
+
*/
|
|
10
|
+
export async function migrateProductsToTopLevel(db: admin.firestore.Firestore) {
|
|
11
|
+
console.log('🚀 Starting product migration...');
|
|
12
|
+
|
|
13
|
+
// Get all technologies
|
|
14
|
+
const technologiesSnapshot = await db.collection('technologies').get();
|
|
15
|
+
|
|
16
|
+
const productMap = new Map<string, {
|
|
17
|
+
product: any;
|
|
18
|
+
technologyIds: string[];
|
|
19
|
+
}>();
|
|
20
|
+
|
|
21
|
+
let totalProcessed = 0;
|
|
22
|
+
|
|
23
|
+
// Step 1: Collect all products from all technology subcollections
|
|
24
|
+
for (const techDoc of technologiesSnapshot.docs) {
|
|
25
|
+
const technologyId = techDoc.id;
|
|
26
|
+
console.log(`📦 Processing technology: ${technologyId}`);
|
|
27
|
+
|
|
28
|
+
const productsSnapshot = await db
|
|
29
|
+
.collection('technologies')
|
|
30
|
+
.doc(technologyId)
|
|
31
|
+
.collection('products')
|
|
32
|
+
.get();
|
|
33
|
+
|
|
34
|
+
for (const productDoc of productsSnapshot.docs) {
|
|
35
|
+
const productId = productDoc.id;
|
|
36
|
+
const productData = productDoc.data();
|
|
37
|
+
|
|
38
|
+
totalProcessed++;
|
|
39
|
+
|
|
40
|
+
// Deduplicate by name + brandId
|
|
41
|
+
const key = `${productData.name}_${productData.brandId}`;
|
|
42
|
+
|
|
43
|
+
if (productMap.has(key)) {
|
|
44
|
+
// Product already exists, just add this technology
|
|
45
|
+
productMap.get(key)!.technologyIds.push(technologyId);
|
|
46
|
+
} else {
|
|
47
|
+
// New product
|
|
48
|
+
productMap.set(key, {
|
|
49
|
+
product: productData,
|
|
50
|
+
technologyIds: [technologyId],
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log(`✅ Found ${productMap.size} unique products from ${totalProcessed} total entries`);
|
|
57
|
+
|
|
58
|
+
// Step 2: Create products in top-level collection
|
|
59
|
+
const batch = db.batch();
|
|
60
|
+
let batchCount = 0;
|
|
61
|
+
const MAX_BATCH_SIZE = 500;
|
|
62
|
+
let createdCount = 0;
|
|
63
|
+
|
|
64
|
+
for (const [key, { product, technologyIds }] of productMap.entries()) {
|
|
65
|
+
const productRef = db.collection('products').doc();
|
|
66
|
+
|
|
67
|
+
const migratedProduct: any = {
|
|
68
|
+
...product,
|
|
69
|
+
assignedTechnologyIds: technologyIds, // Track all assigned technologies
|
|
70
|
+
migratedAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
71
|
+
migrationKey: key, // For debugging
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
batch.set(productRef, migratedProduct);
|
|
75
|
+
createdCount++;
|
|
76
|
+
batchCount++;
|
|
77
|
+
|
|
78
|
+
if (batchCount >= MAX_BATCH_SIZE) {
|
|
79
|
+
await batch.commit();
|
|
80
|
+
console.log(`💾 Committed batch of ${batchCount} products (${createdCount}/${productMap.size})`);
|
|
81
|
+
batchCount = 0;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (batchCount > 0) {
|
|
86
|
+
await batch.commit();
|
|
87
|
+
console.log(`💾 Committed final batch of ${batchCount} products`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log('✅ Migration complete!');
|
|
91
|
+
console.log(`📊 Summary:`);
|
|
92
|
+
console.log(` - Products processed: ${totalProcessed}`);
|
|
93
|
+
console.log(` - Unique products created: ${createdCount}`);
|
|
94
|
+
console.log(` - Average technologies per product: ${(createdCount > 0 ? totalProcessed / createdCount : 0).toFixed(2)}`);
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
totalProcessed,
|
|
98
|
+
uniqueCreated: createdCount,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Run migration (for testing)
|
|
104
|
+
*/
|
|
105
|
+
if (require.main === module) {
|
|
106
|
+
(async () => {
|
|
107
|
+
try {
|
|
108
|
+
await migrateProductsToTopLevel(admin.firestore());
|
|
109
|
+
process.exit(0);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.error('❌ Migration failed:', error);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
})();
|
|
115
|
+
}
|
|
116
|
+
|