@blackcode_sa/metaestetics-api 1.12.67 → 1.12.68
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/backoffice/index.d.mts +40 -0
- package/dist/backoffice/index.d.ts +40 -0
- package/dist/backoffice/index.js +118 -18
- package/dist/backoffice/index.mjs +118 -20
- package/dist/index.d.mts +40 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +121 -21
- package/dist/index.mjs +121 -23
- package/package.json +1 -1
- package/src/backoffice/services/category.service.ts +49 -6
- package/src/backoffice/services/subcategory.service.ts +50 -6
- package/src/backoffice/services/technology.service.ts +53 -6
- package/src/services/procedure/procedure.service.ts +3 -3
|
@@ -23,6 +23,12 @@ import {
|
|
|
23
23
|
import { BaseService } from "../../services/base.service";
|
|
24
24
|
import { CATEGORIES_COLLECTION } from "../types/category.types";
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* ID of the free-consultation subcategory that should be hidden from admin backoffice.
|
|
28
|
+
* This subcategory is used internally for free consultation procedures.
|
|
29
|
+
*/
|
|
30
|
+
const EXCLUDED_SUBCATEGORY_ID = 'free-consultation';
|
|
31
|
+
|
|
26
32
|
/**
|
|
27
33
|
* Servis za upravljanje podkategorijama procedura.
|
|
28
34
|
* Podkategorije su drugi nivo organizacije i pripadaju određenoj kategoriji.
|
|
@@ -37,6 +43,14 @@ import { CATEGORIES_COLLECTION } from "../types/category.types";
|
|
|
37
43
|
* });
|
|
38
44
|
*/
|
|
39
45
|
export class SubcategoryService extends BaseService {
|
|
46
|
+
/**
|
|
47
|
+
* Filters out excluded subcategories from a list.
|
|
48
|
+
* @param subcategories - List of subcategories to filter
|
|
49
|
+
* @returns Filtered list without excluded subcategories
|
|
50
|
+
*/
|
|
51
|
+
private filterExcludedSubcategories(subcategories: Subcategory[]): Subcategory[] {
|
|
52
|
+
return subcategories.filter(sub => sub.id !== EXCLUDED_SUBCATEGORY_ID);
|
|
53
|
+
}
|
|
40
54
|
/**
|
|
41
55
|
* Vraća referencu na Firestore kolekciju podkategorija za određenu kategoriju
|
|
42
56
|
* @param categoryId - ID roditeljske kategorije
|
|
@@ -90,8 +104,10 @@ export class SubcategoryService extends BaseService {
|
|
|
90
104
|
const categoryId = categoryDoc.id;
|
|
91
105
|
const subcategoriesRef = this.getSubcategoriesRef(categoryId);
|
|
92
106
|
const q = query(subcategoriesRef, where("isActive", "==", active));
|
|
93
|
-
const snapshot = await
|
|
94
|
-
|
|
107
|
+
const snapshot = await getDocs(q);
|
|
108
|
+
// Filter out excluded subcategory and count
|
|
109
|
+
const filteredDocs = snapshot.docs.filter(doc => doc.id !== EXCLUDED_SUBCATEGORY_ID);
|
|
110
|
+
counts[categoryId] = filteredDocs.length;
|
|
95
111
|
}
|
|
96
112
|
|
|
97
113
|
return counts;
|
|
@@ -129,8 +145,9 @@ export class SubcategoryService extends BaseService {
|
|
|
129
145
|
...doc.data(),
|
|
130
146
|
} as Subcategory)
|
|
131
147
|
);
|
|
148
|
+
const filteredSubcategories = this.filterExcludedSubcategories(subcategories);
|
|
132
149
|
const newLastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
|
|
133
|
-
return { subcategories, lastVisible: newLastVisible };
|
|
150
|
+
return { subcategories: filteredSubcategories, lastVisible: newLastVisible };
|
|
134
151
|
}
|
|
135
152
|
|
|
136
153
|
/**
|
|
@@ -169,8 +186,9 @@ export class SubcategoryService extends BaseService {
|
|
|
169
186
|
...doc.data(),
|
|
170
187
|
} as Subcategory)
|
|
171
188
|
);
|
|
189
|
+
const filteredSubcategories = this.filterExcludedSubcategories(subcategories);
|
|
172
190
|
const newLastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
|
|
173
|
-
return { subcategories, lastVisible: newLastVisible };
|
|
191
|
+
return { subcategories: filteredSubcategories, lastVisible: newLastVisible };
|
|
174
192
|
}
|
|
175
193
|
|
|
176
194
|
/**
|
|
@@ -184,13 +202,14 @@ export class SubcategoryService extends BaseService {
|
|
|
184
202
|
where("isActive", "==", true)
|
|
185
203
|
);
|
|
186
204
|
const querySnapshot = await getDocs(q);
|
|
187
|
-
|
|
205
|
+
const subcategories = querySnapshot.docs.map(
|
|
188
206
|
(doc) =>
|
|
189
207
|
({
|
|
190
208
|
id: doc.id,
|
|
191
209
|
...doc.data(),
|
|
192
210
|
} as Subcategory)
|
|
193
211
|
);
|
|
212
|
+
return this.filterExcludedSubcategories(subcategories);
|
|
194
213
|
}
|
|
195
214
|
|
|
196
215
|
/**
|
|
@@ -203,13 +222,14 @@ export class SubcategoryService extends BaseService {
|
|
|
203
222
|
where("isActive", "==", true)
|
|
204
223
|
);
|
|
205
224
|
const querySnapshot = await getDocs(q);
|
|
206
|
-
|
|
225
|
+
const subcategories = querySnapshot.docs.map(
|
|
207
226
|
(doc) =>
|
|
208
227
|
({
|
|
209
228
|
id: doc.id,
|
|
210
229
|
...doc.data(),
|
|
211
230
|
} as Subcategory)
|
|
212
231
|
);
|
|
232
|
+
return this.filterExcludedSubcategories(subcategories);
|
|
213
233
|
}
|
|
214
234
|
|
|
215
235
|
/**
|
|
@@ -297,6 +317,26 @@ export class SubcategoryService extends BaseService {
|
|
|
297
317
|
* @returns Podkategorija ili null ako ne postoji
|
|
298
318
|
*/
|
|
299
319
|
async getById(categoryId: string, subcategoryId: string) {
|
|
320
|
+
// Prevent access to excluded subcategory
|
|
321
|
+
if (subcategoryId === EXCLUDED_SUBCATEGORY_ID) return null;
|
|
322
|
+
|
|
323
|
+
const docRef = doc(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
324
|
+
const docSnap = await getDoc(docRef);
|
|
325
|
+
if (!docSnap.exists()) return null;
|
|
326
|
+
return {
|
|
327
|
+
id: docSnap.id,
|
|
328
|
+
...docSnap.data(),
|
|
329
|
+
} as Subcategory;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Internal method to get subcategory by ID without filtering.
|
|
334
|
+
* Used internally for consultation procedures.
|
|
335
|
+
* @param categoryId - ID of the category
|
|
336
|
+
* @param subcategoryId - ID of the subcategory to get
|
|
337
|
+
* @returns Subcategory or null if not found
|
|
338
|
+
*/
|
|
339
|
+
async getByIdInternal(categoryId: string, subcategoryId: string): Promise<Subcategory | null> {
|
|
300
340
|
const docRef = doc(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
301
341
|
const docSnap = await getDoc(docRef);
|
|
302
342
|
if (!docSnap.exists()) return null;
|
|
@@ -322,6 +362,8 @@ export class SubcategoryService extends BaseService {
|
|
|
322
362
|
const querySnapshot = await getDocs(q);
|
|
323
363
|
if (querySnapshot.empty) return null;
|
|
324
364
|
const doc = querySnapshot.docs[0];
|
|
365
|
+
// Exclude free-consultation subcategory
|
|
366
|
+
if (doc.id === EXCLUDED_SUBCATEGORY_ID) return null;
|
|
325
367
|
return {
|
|
326
368
|
id: doc.id,
|
|
327
369
|
...doc.data(),
|
|
@@ -375,6 +417,8 @@ export class SubcategoryService extends BaseService {
|
|
|
375
417
|
if (snapshot.empty) break;
|
|
376
418
|
|
|
377
419
|
for (const d of snapshot.docs) {
|
|
420
|
+
// Exclude free-consultation subcategory from CSV export
|
|
421
|
+
if (d.id === EXCLUDED_SUBCATEGORY_ID) continue;
|
|
378
422
|
const subcategory = ({ id: d.id, ...d.data() } as unknown) as Subcategory;
|
|
379
423
|
rows.push(this.subcategoryToCsvRow(subcategory));
|
|
380
424
|
}
|
|
@@ -33,6 +33,12 @@ import { ProcedureFamily } from '../types/static/procedure-family.types';
|
|
|
33
33
|
import { Practitioner, PractitionerCertification } from '../../types/practitioner';
|
|
34
34
|
import { Product, PRODUCTS_COLLECTION } from '../types/product.types';
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* ID of the free-consultation-tech technology that should be hidden from admin backoffice.
|
|
38
|
+
* This technology is used internally for free consultation procedures.
|
|
39
|
+
*/
|
|
40
|
+
const EXCLUDED_TECHNOLOGY_ID = 'free-consultation-tech';
|
|
41
|
+
|
|
36
42
|
/**
|
|
37
43
|
* Default vrednosti za sertifikaciju
|
|
38
44
|
*/
|
|
@@ -45,6 +51,14 @@ const DEFAULT_CERTIFICATION_REQUIREMENT: CertificationRequirement = {
|
|
|
45
51
|
* Service for managing technologies.
|
|
46
52
|
*/
|
|
47
53
|
export class TechnologyService extends BaseService implements ITechnologyService {
|
|
54
|
+
/**
|
|
55
|
+
* Filters out excluded technologies from a list.
|
|
56
|
+
* @param technologies - List of technologies to filter
|
|
57
|
+
* @returns Filtered list without excluded technologies
|
|
58
|
+
*/
|
|
59
|
+
private filterExcludedTechnologies(technologies: Technology[]): Technology[] {
|
|
60
|
+
return technologies.filter(tech => tech.id !== EXCLUDED_TECHNOLOGY_ID);
|
|
61
|
+
}
|
|
48
62
|
/**
|
|
49
63
|
* Reference to the Firestore collection of technologies.
|
|
50
64
|
*/
|
|
@@ -100,6 +114,8 @@ export class TechnologyService extends BaseService implements ITechnologyService
|
|
|
100
114
|
const snapshot = await getDocs(q);
|
|
101
115
|
const counts: Record<string, number> = {};
|
|
102
116
|
snapshot.docs.forEach(doc => {
|
|
117
|
+
// Exclude free-consultation-tech from counts
|
|
118
|
+
if (doc.id === EXCLUDED_TECHNOLOGY_ID) return;
|
|
103
119
|
const tech = doc.data() as Technology;
|
|
104
120
|
counts[tech.subcategoryId] = (counts[tech.subcategoryId] || 0) + 1;
|
|
105
121
|
});
|
|
@@ -116,6 +132,8 @@ export class TechnologyService extends BaseService implements ITechnologyService
|
|
|
116
132
|
const snapshot = await getDocs(q);
|
|
117
133
|
const counts: Record<string, number> = {};
|
|
118
134
|
snapshot.docs.forEach(doc => {
|
|
135
|
+
// Exclude free-consultation-tech from counts
|
|
136
|
+
if (doc.id === EXCLUDED_TECHNOLOGY_ID) return;
|
|
119
137
|
const tech = doc.data() as Technology;
|
|
120
138
|
counts[tech.categoryId] = (counts[tech.categoryId] || 0) + 1;
|
|
121
139
|
});
|
|
@@ -151,8 +169,9 @@ export class TechnologyService extends BaseService implements ITechnologyService
|
|
|
151
169
|
...doc.data(),
|
|
152
170
|
} as Technology),
|
|
153
171
|
);
|
|
172
|
+
const filteredTechnologies = this.filterExcludedTechnologies(technologies);
|
|
154
173
|
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
155
|
-
return { technologies, lastVisible: newLastVisible };
|
|
174
|
+
return { technologies: filteredTechnologies, lastVisible: newLastVisible };
|
|
156
175
|
}
|
|
157
176
|
|
|
158
177
|
/**
|
|
@@ -187,8 +206,9 @@ export class TechnologyService extends BaseService implements ITechnologyService
|
|
|
187
206
|
...doc.data(),
|
|
188
207
|
} as Technology),
|
|
189
208
|
);
|
|
209
|
+
const filteredTechnologies = this.filterExcludedTechnologies(technologies);
|
|
190
210
|
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
191
|
-
return { technologies, lastVisible: newLastVisible };
|
|
211
|
+
return { technologies: filteredTechnologies, lastVisible: newLastVisible };
|
|
192
212
|
}
|
|
193
213
|
|
|
194
214
|
/**
|
|
@@ -223,8 +243,9 @@ export class TechnologyService extends BaseService implements ITechnologyService
|
|
|
223
243
|
...doc.data(),
|
|
224
244
|
} as Technology),
|
|
225
245
|
);
|
|
246
|
+
const filteredTechnologies = this.filterExcludedTechnologies(technologies);
|
|
226
247
|
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
227
|
-
return { technologies, lastVisible: newLastVisible };
|
|
248
|
+
return { technologies: filteredTechnologies, lastVisible: newLastVisible };
|
|
228
249
|
}
|
|
229
250
|
|
|
230
251
|
/**
|
|
@@ -300,6 +321,25 @@ export class TechnologyService extends BaseService implements ITechnologyService
|
|
|
300
321
|
* @returns The technology or null if it doesn't exist.
|
|
301
322
|
*/
|
|
302
323
|
async getById(id: string): Promise<Technology | null> {
|
|
324
|
+
// Prevent access to excluded technology
|
|
325
|
+
if (id === EXCLUDED_TECHNOLOGY_ID) return null;
|
|
326
|
+
|
|
327
|
+
const docRef = doc(this.technologiesRef, id);
|
|
328
|
+
const docSnap = await getDoc(docRef);
|
|
329
|
+
if (!docSnap.exists()) return null;
|
|
330
|
+
return {
|
|
331
|
+
id: docSnap.id,
|
|
332
|
+
...docSnap.data(),
|
|
333
|
+
} as Technology;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Internal method to get technology by ID without filtering.
|
|
338
|
+
* Used internally for consultation procedures.
|
|
339
|
+
* @param id - The ID of the requested technology
|
|
340
|
+
* @returns The technology or null if it doesn't exist
|
|
341
|
+
*/
|
|
342
|
+
async getByIdInternal(id: string): Promise<Technology | null> {
|
|
303
343
|
const docRef = doc(this.technologiesRef, id);
|
|
304
344
|
const docSnap = await getDoc(docRef);
|
|
305
345
|
if (!docSnap.exists()) return null;
|
|
@@ -324,6 +364,8 @@ export class TechnologyService extends BaseService implements ITechnologyService
|
|
|
324
364
|
const snapshot = await getDocs(q);
|
|
325
365
|
if (snapshot.empty) return null;
|
|
326
366
|
const doc = snapshot.docs[0];
|
|
367
|
+
// Exclude free-consultation-tech
|
|
368
|
+
if (doc.id === EXCLUDED_TECHNOLOGY_ID) return null;
|
|
327
369
|
return {
|
|
328
370
|
id: doc.id,
|
|
329
371
|
...doc.data(),
|
|
@@ -780,13 +822,14 @@ export class TechnologyService extends BaseService implements ITechnologyService
|
|
|
780
822
|
orderBy('name'),
|
|
781
823
|
);
|
|
782
824
|
const snapshot = await getDocs(q);
|
|
783
|
-
|
|
825
|
+
const technologies = snapshot.docs.map(
|
|
784
826
|
doc =>
|
|
785
827
|
({
|
|
786
828
|
id: doc.id,
|
|
787
829
|
...doc.data(),
|
|
788
830
|
} as Technology),
|
|
789
831
|
);
|
|
832
|
+
return this.filterExcludedTechnologies(technologies);
|
|
790
833
|
}
|
|
791
834
|
|
|
792
835
|
/**
|
|
@@ -806,13 +849,14 @@ export class TechnologyService extends BaseService implements ITechnologyService
|
|
|
806
849
|
orderBy('name'),
|
|
807
850
|
);
|
|
808
851
|
const snapshot = await getDocs(q);
|
|
809
|
-
|
|
852
|
+
const technologies = snapshot.docs.map(
|
|
810
853
|
doc =>
|
|
811
854
|
({
|
|
812
855
|
id: doc.id,
|
|
813
856
|
...doc.data(),
|
|
814
857
|
} as Technology),
|
|
815
858
|
);
|
|
859
|
+
return this.filterExcludedTechnologies(technologies);
|
|
816
860
|
}
|
|
817
861
|
|
|
818
862
|
/**
|
|
@@ -825,13 +869,14 @@ export class TechnologyService extends BaseService implements ITechnologyService
|
|
|
825
869
|
orderBy('name'),
|
|
826
870
|
);
|
|
827
871
|
const snapshot = await getDocs(q);
|
|
828
|
-
|
|
872
|
+
const technologies = snapshot.docs.map(
|
|
829
873
|
doc =>
|
|
830
874
|
({
|
|
831
875
|
id: doc.id,
|
|
832
876
|
...doc.data(),
|
|
833
877
|
} as Technology),
|
|
834
878
|
);
|
|
879
|
+
return this.filterExcludedTechnologies(technologies);
|
|
835
880
|
}
|
|
836
881
|
|
|
837
882
|
// ==========================================
|
|
@@ -1040,6 +1085,8 @@ export class TechnologyService extends BaseService implements ITechnologyService
|
|
|
1040
1085
|
if (snapshot.empty) break;
|
|
1041
1086
|
|
|
1042
1087
|
for (const d of snapshot.docs) {
|
|
1088
|
+
// Exclude free-consultation-tech from CSV export
|
|
1089
|
+
if (d.id === EXCLUDED_TECHNOLOGY_ID) continue;
|
|
1043
1090
|
const technology = ({ id: d.id, ...d.data() } as unknown) as Technology;
|
|
1044
1091
|
// Fetch products for this technology
|
|
1045
1092
|
const productNames = await this.getProductNamesForTechnology(technology.id!);
|
|
@@ -1497,9 +1497,9 @@ export class ProcedureService extends BaseService {
|
|
|
1497
1497
|
// Get references to related entities (Category, Subcategory, Technology)
|
|
1498
1498
|
// For consultation, we don't need a product
|
|
1499
1499
|
const [category, subcategory, technology] = await Promise.all([
|
|
1500
|
-
this.categoryService.
|
|
1501
|
-
this.subcategoryService.
|
|
1502
|
-
this.technologyService.
|
|
1500
|
+
this.categoryService.getByIdInternal(data.categoryId),
|
|
1501
|
+
this.subcategoryService.getByIdInternal(data.categoryId, data.subcategoryId),
|
|
1502
|
+
this.technologyService.getByIdInternal(data.technologyId),
|
|
1503
1503
|
]);
|
|
1504
1504
|
|
|
1505
1505
|
if (!category || !subcategory || !technology) {
|