@blackcode_sa/metaestetics-api 1.5.10 → 1.5.12

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.
@@ -22,8 +22,11 @@ import {
22
22
  CertificationRequirement,
23
23
  } from "../types/static/certification.types";
24
24
  import { BaseService } from "../../services/base.service";
25
- import { SUBCATEGORIES_COLLECTION } from "../types/subcategory.types";
26
- import { CATEGORIES_COLLECTION } from "../types/category.types";
25
+ import { ProcedureFamily } from "../types/static/procedure-family.types";
26
+ import {
27
+ Practitioner,
28
+ PractitionerCertification,
29
+ } from "../../types/practitioner";
27
30
 
28
31
  /**
29
32
  * Default vrednosti za sertifikaciju
@@ -35,20 +38,23 @@ const DEFAULT_CERTIFICATION_REQUIREMENT: CertificationRequirement = {
35
38
 
36
39
  /**
37
40
  * Servis za upravljanje tehnologijama i njihovim zahtevima.
38
- * Tehnologije su treći nivo organizacije i pripadaju određenoj podkategoriji.
39
- * Svaka tehnologija može imati svoje specifične zahteve pre i posle procedure.
41
+ * Tehnologije su sada top-level kolekcija koja referencira svoju putanju u hijerarhiji
42
+ * kroz family, categoryId i subcategoryId.
40
43
  *
41
44
  * @example
42
45
  * const technologyService = new TechnologyService();
43
46
  *
44
47
  * // Kreiranje nove tehnologije
45
- * const technology = await technologyService.create(categoryId, subcategoryId, {
48
+ * const technology = await technologyService.create({
46
49
  * name: "Botulinum Toxin",
47
- * description: "Neurotoxin injections for wrinkle reduction"
50
+ * description: "Neurotoxin injections for wrinkle reduction",
51
+ * family: ProcedureFamily.AESTHETICS,
52
+ * categoryId: "category123",
53
+ * subcategoryId: "subcategory456"
48
54
  * });
49
55
  *
50
56
  * // Dodavanje zahteva
51
- * await technologyService.addRequirement(categoryId, subcategoryId, technology.id, {
57
+ * await technologyService.addRequirement(technology.id, {
52
58
  * type: "pre",
53
59
  * name: "Stay Hydrated",
54
60
  * description: "Drink plenty of water"
@@ -56,69 +62,108 @@ const DEFAULT_CERTIFICATION_REQUIREMENT: CertificationRequirement = {
56
62
  */
57
63
  export class TechnologyService extends BaseService {
58
64
  /**
59
- * Vraća referencu na Firestore kolekciju tehnologija za određenu podkategoriju
60
- * @param categoryId - ID kategorije
61
- * @param subcategoryId - ID podkategorije
65
+ * Vraća referencu na Firestore kolekciju tehnologija
62
66
  */
63
- private getTechnologiesRef(categoryId: string, subcategoryId: string) {
64
- return collection(
65
- this.db,
66
- CATEGORIES_COLLECTION,
67
- categoryId,
68
- SUBCATEGORIES_COLLECTION,
69
- subcategoryId,
70
- TECHNOLOGIES_COLLECTION
71
- );
67
+ private getTechnologiesRef() {
68
+ return collection(this.db, TECHNOLOGIES_COLLECTION);
72
69
  }
73
70
 
74
71
  /**
75
- * Kreira novu tehnologiju u okviru podkategorije
76
- * @param categoryId - ID kategorije
77
- * @param subcategoryId - ID podkategorije
72
+ * Kreira novu tehnologiju
78
73
  * @param technology - Podaci za novu tehnologiju
79
74
  * @returns Kreirana tehnologija sa generisanim ID-em
80
75
  */
81
- async create(
82
- categoryId: string,
83
- subcategoryId: string,
84
- technology: Omit<Technology, "id" | "createdAt" | "updatedAt">
85
- ) {
76
+ async create(technology: Omit<Technology, "id" | "createdAt" | "updatedAt">) {
86
77
  const now = new Date();
87
78
  const newTechnology: Omit<Technology, "id"> = {
88
79
  ...technology,
89
- subcategoryId,
90
80
  createdAt: now,
91
81
  updatedAt: now,
92
82
  isActive: true,
93
- requirements: {
83
+ requirements: technology.requirements || {
94
84
  pre: [],
95
85
  post: [],
96
86
  },
97
- blockingConditions: [],
98
- contraindications: [],
99
- benefits: [],
87
+ blockingConditions: technology.blockingConditions || [],
88
+ contraindications: technology.contraindications || [],
89
+ benefits: technology.benefits || [],
100
90
  certificationRequirement:
101
91
  technology.certificationRequirement ||
102
92
  DEFAULT_CERTIFICATION_REQUIREMENT,
103
93
  };
104
94
 
105
- const docRef = await addDoc(
106
- this.getTechnologiesRef(categoryId, subcategoryId),
107
- newTechnology
108
- );
95
+ const docRef = await addDoc(this.getTechnologiesRef(), newTechnology);
109
96
  return { id: docRef.id, ...newTechnology };
110
97
  }
111
98
 
112
99
  /**
113
- * Vraća sve aktivne tehnologije za određenu podkategoriju
100
+ * Vraća sve aktivne tehnologije
101
+ * @returns Lista aktivnih tehnologija
102
+ */
103
+ async getAll() {
104
+ const q = query(this.getTechnologiesRef(), where("isActive", "==", true));
105
+ const snapshot = await getDocs(q);
106
+ return snapshot.docs.map(
107
+ (doc) =>
108
+ ({
109
+ id: doc.id,
110
+ ...doc.data(),
111
+ } as Technology)
112
+ );
113
+ }
114
+
115
+ /**
116
+ * Vraća sve aktivne tehnologije za određenu familiju
117
+ * @param family - Familija procedura
118
+ * @returns Lista aktivnih tehnologija
119
+ */
120
+ async getAllByFamily(family: ProcedureFamily) {
121
+ const q = query(
122
+ this.getTechnologiesRef(),
123
+ where("isActive", "==", true),
124
+ where("family", "==", family)
125
+ );
126
+ const snapshot = await getDocs(q);
127
+ return snapshot.docs.map(
128
+ (doc) =>
129
+ ({
130
+ id: doc.id,
131
+ ...doc.data(),
132
+ } as Technology)
133
+ );
134
+ }
135
+
136
+ /**
137
+ * Vraća sve aktivne tehnologije za određenu kategoriju
114
138
  * @param categoryId - ID kategorije
139
+ * @returns Lista aktivnih tehnologija
140
+ */
141
+ async getAllByCategoryId(categoryId: string) {
142
+ const q = query(
143
+ this.getTechnologiesRef(),
144
+ where("isActive", "==", true),
145
+ where("categoryId", "==", categoryId)
146
+ );
147
+ const snapshot = await getDocs(q);
148
+ return snapshot.docs.map(
149
+ (doc) =>
150
+ ({
151
+ id: doc.id,
152
+ ...doc.data(),
153
+ } as Technology)
154
+ );
155
+ }
156
+
157
+ /**
158
+ * Vraća sve aktivne tehnologije za određenu podkategoriju
115
159
  * @param subcategoryId - ID podkategorije
116
160
  * @returns Lista aktivnih tehnologija
117
161
  */
118
- async getAllBySubcategoryId(categoryId: string, subcategoryId: string) {
162
+ async getAllBySubcategoryId(subcategoryId: string) {
119
163
  const q = query(
120
- this.getTechnologiesRef(categoryId, subcategoryId),
121
- where("isActive", "==", true)
164
+ this.getTechnologiesRef(),
165
+ where("isActive", "==", true),
166
+ where("subcategoryId", "==", subcategoryId)
122
167
  );
123
168
  const snapshot = await getDocs(q);
124
169
  return snapshot.docs.map(
@@ -132,63 +177,46 @@ export class TechnologyService extends BaseService {
132
177
 
133
178
  /**
134
179
  * Ažurira postojeću tehnologiju
135
- * @param categoryId - ID kategorije
136
- * @param subcategoryId - ID podkategorije
137
180
  * @param technologyId - ID tehnologije
138
181
  * @param technology - Novi podaci za tehnologiju
139
182
  * @returns Ažurirana tehnologija
140
183
  */
141
184
  async update(
142
- categoryId: string,
143
- subcategoryId: string,
144
185
  technologyId: string,
145
- technology: Partial<Omit<Technology, "id" | "createdAt" | "subcategoryId">>
186
+ technology: Partial<
187
+ Omit<
188
+ Technology,
189
+ "id" | "createdAt" | "family" | "categoryId" | "subcategoryId"
190
+ >
191
+ >
146
192
  ) {
147
193
  const updateData = {
148
194
  ...technology,
149
195
  updatedAt: new Date(),
150
196
  };
151
197
 
152
- const docRef = doc(
153
- this.getTechnologiesRef(categoryId, subcategoryId),
154
- technologyId
155
- );
198
+ const docRef = doc(this.getTechnologiesRef(), technologyId);
156
199
  await updateDoc(docRef, updateData);
157
- return this.getById(categoryId, subcategoryId, technologyId);
200
+ return this.getById(technologyId);
158
201
  }
159
202
 
160
203
  /**
161
204
  * Soft delete tehnologije (postavlja isActive na false)
162
- * @param categoryId - ID kategorije
163
- * @param subcategoryId - ID podkategorije
164
205
  * @param technologyId - ID tehnologije koja se briše
165
206
  */
166
- async delete(
167
- categoryId: string,
168
- subcategoryId: string,
169
- technologyId: string
170
- ) {
171
- await this.update(categoryId, subcategoryId, technologyId, {
207
+ async delete(technologyId: string) {
208
+ await this.update(technologyId, {
172
209
  isActive: false,
173
210
  });
174
211
  }
175
212
 
176
213
  /**
177
214
  * Vraća tehnologiju po ID-u
178
- * @param categoryId - ID kategorije
179
- * @param subcategoryId - ID podkategorije
180
215
  * @param technologyId - ID tražene tehnologije
181
216
  * @returns Tehnologija ili null ako ne postoji
182
217
  */
183
- async getById(
184
- categoryId: string,
185
- subcategoryId: string,
186
- technologyId: string
187
- ): Promise<Technology | null> {
188
- const docRef = doc(
189
- this.getTechnologiesRef(categoryId, subcategoryId),
190
- technologyId
191
- );
218
+ async getById(technologyId: string): Promise<Technology | null> {
219
+ const docRef = doc(this.getTechnologiesRef(), technologyId);
192
220
  const docSnap = await getDoc(docRef);
193
221
  if (!docSnap.exists()) return null;
194
222
  return {
@@ -199,22 +227,12 @@ export class TechnologyService extends BaseService {
199
227
 
200
228
  /**
201
229
  * Dodaje novi zahtev tehnologiji
202
- * @param categoryId - ID kategorije
203
- * @param subcategoryId - ID podkategorije
204
230
  * @param technologyId - ID tehnologije
205
231
  * @param requirement - Zahtev koji se dodaje
206
232
  * @returns Ažurirana tehnologija sa novim zahtevom
207
233
  */
208
- async addRequirement(
209
- categoryId: string,
210
- subcategoryId: string,
211
- technologyId: string,
212
- requirement: Requirement
213
- ) {
214
- const docRef = doc(
215
- this.getTechnologiesRef(categoryId, subcategoryId),
216
- technologyId
217
- );
234
+ async addRequirement(technologyId: string, requirement: Requirement) {
235
+ const docRef = doc(this.getTechnologiesRef(), technologyId);
218
236
 
219
237
  const requirementType =
220
238
  requirement.type === "pre" ? "requirements.pre" : "requirements.post";
@@ -224,27 +242,17 @@ export class TechnologyService extends BaseService {
224
242
  updatedAt: new Date(),
225
243
  });
226
244
 
227
- return this.getById(categoryId, subcategoryId, technologyId);
245
+ return this.getById(technologyId);
228
246
  }
229
247
 
230
248
  /**
231
249
  * Uklanja zahtev iz tehnologije
232
- * @param categoryId - ID kategorije
233
- * @param subcategoryId - ID podkategorije
234
250
  * @param technologyId - ID tehnologije
235
251
  * @param requirement - Zahtev koji se uklanja
236
252
  * @returns Ažurirana tehnologija bez uklonjenog zahteva
237
253
  */
238
- async removeRequirement(
239
- categoryId: string,
240
- subcategoryId: string,
241
- technologyId: string,
242
- requirement: Requirement
243
- ) {
244
- const docRef = doc(
245
- this.getTechnologiesRef(categoryId, subcategoryId),
246
- technologyId
247
- );
254
+ async removeRequirement(technologyId: string, requirement: Requirement) {
255
+ const docRef = doc(this.getTechnologiesRef(), technologyId);
248
256
 
249
257
  const requirementType =
250
258
  requirement.type === "pre" ? "requirements.pre" : "requirements.post";
@@ -254,28 +262,17 @@ export class TechnologyService extends BaseService {
254
262
  updatedAt: new Date(),
255
263
  });
256
264
 
257
- return this.getById(categoryId, subcategoryId, technologyId);
265
+ return this.getById(technologyId);
258
266
  }
259
267
 
260
268
  /**
261
269
  * Vraća sve zahteve za tehnologiju
262
- * @param categoryId - ID kategorije
263
- * @param subcategoryId - ID podkategorije
264
270
  * @param technologyId - ID tehnologije
265
271
  * @param type - Opcioni filter za tip zahteva (pre/post)
266
272
  * @returns Lista zahteva
267
273
  */
268
- async getRequirements(
269
- categoryId: string,
270
- subcategoryId: string,
271
- technologyId: string,
272
- type?: RequirementType
273
- ) {
274
- const technology = await this.getById(
275
- categoryId,
276
- subcategoryId,
277
- technologyId
278
- );
274
+ async getRequirements(technologyId: string, type?: RequirementType) {
275
+ const technology = await this.getById(technologyId);
279
276
  if (!technology || !technology.requirements) return [];
280
277
 
281
278
  if (type) {
@@ -287,300 +284,300 @@ export class TechnologyService extends BaseService {
287
284
 
288
285
  /**
289
286
  * Ažurira postojeći zahtev
290
- * @param categoryId - ID kategorije
291
- * @param subcategoryId - ID podkategorije
292
287
  * @param technologyId - ID tehnologije
293
288
  * @param oldRequirement - Stari zahtev koji se menja
294
289
  * @param newRequirement - Novi zahtev koji zamenjuje stari
295
290
  * @returns Ažurirana tehnologija
296
291
  */
297
292
  async updateRequirement(
298
- categoryId: string,
299
- subcategoryId: string,
300
293
  technologyId: string,
301
294
  oldRequirement: Requirement,
302
295
  newRequirement: Requirement
303
296
  ) {
304
- await this.removeRequirement(
305
- categoryId,
306
- subcategoryId,
307
- technologyId,
308
- oldRequirement
309
- );
310
- return this.addRequirement(
311
- categoryId,
312
- subcategoryId,
313
- technologyId,
314
- newRequirement
315
- );
297
+ await this.removeRequirement(technologyId, oldRequirement);
298
+ return this.addRequirement(technologyId, newRequirement);
316
299
  }
317
300
 
318
301
  /**
319
302
  * Dodaje blokirajući uslov tehnologiji
320
- * @param categoryId - ID kategorije
321
- * @param subcategoryId - ID podkategorije
322
303
  * @param technologyId - ID tehnologije
323
304
  * @param condition - Blokirajući uslov koji se dodaje
324
305
  * @returns Ažurirana tehnologija
325
306
  */
326
307
  async addBlockingCondition(
327
- categoryId: string,
328
- subcategoryId: string,
329
308
  technologyId: string,
330
309
  condition: BlockingCondition
331
310
  ) {
332
- const docRef = doc(
333
- this.getTechnologiesRef(categoryId, subcategoryId),
334
- technologyId
335
- );
311
+ const docRef = doc(this.getTechnologiesRef(), technologyId);
336
312
 
337
313
  await updateDoc(docRef, {
338
314
  blockingConditions: arrayUnion(condition),
339
315
  updatedAt: new Date(),
340
316
  });
341
317
 
342
- return this.getById(categoryId, subcategoryId, technologyId);
318
+ return this.getById(technologyId);
343
319
  }
344
320
 
345
321
  /**
346
322
  * Uklanja blokirajući uslov iz tehnologije
347
- * @param categoryId - ID kategorije
348
- * @param subcategoryId - ID podkategorije
349
323
  * @param technologyId - ID tehnologije
350
324
  * @param condition - Blokirajući uslov koji se uklanja
351
325
  * @returns Ažurirana tehnologija
352
326
  */
353
327
  async removeBlockingCondition(
354
- categoryId: string,
355
- subcategoryId: string,
356
328
  technologyId: string,
357
329
  condition: BlockingCondition
358
330
  ) {
359
- const docRef = doc(
360
- this.getTechnologiesRef(categoryId, subcategoryId),
361
- technologyId
362
- );
331
+ const docRef = doc(this.getTechnologiesRef(), technologyId);
363
332
 
364
333
  await updateDoc(docRef, {
365
334
  blockingConditions: arrayRemove(condition),
366
335
  updatedAt: new Date(),
367
336
  });
368
337
 
369
- return this.getById(categoryId, subcategoryId, technologyId);
338
+ return this.getById(technologyId);
370
339
  }
371
340
 
372
341
  /**
373
342
  * Dodaje kontraindikaciju tehnologiji
374
- * @param categoryId - ID kategorije
375
- * @param subcategoryId - ID podkategorije
376
343
  * @param technologyId - ID tehnologije
377
344
  * @param contraindication - Kontraindikacija koja se dodaje
378
345
  * @returns Ažurirana tehnologija
379
346
  */
380
347
  async addContraindication(
381
- categoryId: string,
382
- subcategoryId: string,
383
348
  technologyId: string,
384
349
  contraindication: Contraindication
385
350
  ) {
386
- const docRef = doc(
387
- this.getTechnologiesRef(categoryId, subcategoryId),
388
- technologyId
389
- );
351
+ const docRef = doc(this.getTechnologiesRef(), technologyId);
390
352
 
391
353
  await updateDoc(docRef, {
392
354
  contraindications: arrayUnion(contraindication),
393
355
  updatedAt: new Date(),
394
356
  });
395
357
 
396
- return this.getById(categoryId, subcategoryId, technologyId);
358
+ return this.getById(technologyId);
397
359
  }
398
360
 
399
361
  /**
400
362
  * Uklanja kontraindikaciju iz tehnologije
401
- * @param categoryId - ID kategorije
402
- * @param subcategoryId - ID podkategorije
403
363
  * @param technologyId - ID tehnologije
404
364
  * @param contraindication - Kontraindikacija koja se uklanja
405
365
  * @returns Ažurirana tehnologija
406
366
  */
407
367
  async removeContraindication(
408
- categoryId: string,
409
- subcategoryId: string,
410
368
  technologyId: string,
411
369
  contraindication: Contraindication
412
370
  ) {
413
- const docRef = doc(
414
- this.getTechnologiesRef(categoryId, subcategoryId),
415
- technologyId
416
- );
371
+ const docRef = doc(this.getTechnologiesRef(), technologyId);
417
372
 
418
373
  await updateDoc(docRef, {
419
374
  contraindications: arrayRemove(contraindication),
420
375
  updatedAt: new Date(),
421
376
  });
422
377
 
423
- return this.getById(categoryId, subcategoryId, technologyId);
378
+ return this.getById(technologyId);
424
379
  }
425
380
 
426
381
  /**
427
382
  * Dodaje benefit tehnologiji
428
- * @param categoryId - ID kategorije
429
- * @param subcategoryId - ID podkategorije
430
383
  * @param technologyId - ID tehnologije
431
384
  * @param benefit - Benefit koji se dodaje
432
385
  * @returns Ažurirana tehnologija
433
386
  */
434
- async addBenefit(
435
- categoryId: string,
436
- subcategoryId: string,
437
- technologyId: string,
438
- benefit: TreatmentBenefit
439
- ) {
440
- const docRef = doc(
441
- this.getTechnologiesRef(categoryId, subcategoryId),
442
- technologyId
443
- );
387
+ async addBenefit(technologyId: string, benefit: TreatmentBenefit) {
388
+ const docRef = doc(this.getTechnologiesRef(), technologyId);
444
389
 
445
390
  await updateDoc(docRef, {
446
391
  benefits: arrayUnion(benefit),
447
392
  updatedAt: new Date(),
448
393
  });
449
394
 
450
- return this.getById(categoryId, subcategoryId, technologyId);
395
+ return this.getById(technologyId);
451
396
  }
452
397
 
453
398
  /**
454
399
  * Uklanja benefit iz tehnologije
455
- * @param categoryId - ID kategorije
456
- * @param subcategoryId - ID podkategorije
457
400
  * @param technologyId - ID tehnologije
458
401
  * @param benefit - Benefit koji se uklanja
459
402
  * @returns Ažurirana tehnologija
460
403
  */
461
- async removeBenefit(
462
- categoryId: string,
463
- subcategoryId: string,
464
- technologyId: string,
465
- benefit: TreatmentBenefit
466
- ) {
467
- const docRef = doc(
468
- this.getTechnologiesRef(categoryId, subcategoryId),
469
- technologyId
470
- );
404
+ async removeBenefit(technologyId: string, benefit: TreatmentBenefit) {
405
+ const docRef = doc(this.getTechnologiesRef(), technologyId);
471
406
 
472
407
  await updateDoc(docRef, {
473
408
  benefits: arrayRemove(benefit),
474
409
  updatedAt: new Date(),
475
410
  });
476
411
 
477
- return this.getById(categoryId, subcategoryId, technologyId);
412
+ return this.getById(technologyId);
478
413
  }
479
414
 
480
415
  /**
481
416
  * Vraća sve blokirajuće uslove za tehnologiju
482
- * @param categoryId - ID kategorije
483
- * @param subcategoryId - ID podkategorije
484
417
  * @param technologyId - ID tehnologije
485
418
  * @returns Lista blokirajućih uslova
486
419
  */
487
- async getBlockingConditions(
488
- categoryId: string,
489
- subcategoryId: string,
490
- technologyId: string
491
- ) {
492
- const technology = await this.getById(
493
- categoryId,
494
- subcategoryId,
495
- technologyId
496
- );
420
+ async getBlockingConditions(technologyId: string) {
421
+ const technology = await this.getById(technologyId);
497
422
  return technology?.blockingConditions || [];
498
423
  }
499
424
 
500
425
  /**
501
426
  * Vraća sve kontraindikacije za tehnologiju
502
- * @param categoryId - ID kategorije
503
- * @param subcategoryId - ID podkategorije
504
427
  * @param technologyId - ID tehnologije
505
428
  * @returns Lista kontraindikacija
506
429
  */
507
- async getContraindications(
508
- categoryId: string,
509
- subcategoryId: string,
510
- technologyId: string
511
- ) {
512
- const technology = await this.getById(
513
- categoryId,
514
- subcategoryId,
515
- technologyId
516
- );
430
+ async getContraindications(technologyId: string) {
431
+ const technology = await this.getById(technologyId);
517
432
  return technology?.contraindications || [];
518
433
  }
519
434
 
520
435
  /**
521
436
  * Vraća sve benefite za tehnologiju
522
- * @param categoryId - ID kategorije
523
- * @param subcategoryId - ID podkategorije
524
437
  * @param technologyId - ID tehnologije
525
438
  * @returns Lista benefita
526
439
  */
527
- async getBenefits(
528
- categoryId: string,
529
- subcategoryId: string,
530
- technologyId: string
531
- ) {
532
- const technology = await this.getById(
533
- categoryId,
534
- subcategoryId,
535
- technologyId
536
- );
440
+ async getBenefits(technologyId: string) {
441
+ const technology = await this.getById(technologyId);
537
442
  return technology?.benefits || [];
538
443
  }
539
444
 
540
445
  /**
541
446
  * Ažurira zahteve sertifikacije za tehnologiju
542
- * @param categoryId - ID kategorije
543
- * @param subcategoryId - ID podkategorije
544
447
  * @param technologyId - ID tehnologije
545
448
  * @param certificationRequirement - Novi zahtevi sertifikacije
546
449
  * @returns Ažurirana tehnologija
547
450
  */
548
451
  async updateCertificationRequirement(
549
- categoryId: string,
550
- subcategoryId: string,
551
452
  technologyId: string,
552
453
  certificationRequirement: CertificationRequirement
553
454
  ) {
554
- const docRef = doc(
555
- this.getTechnologiesRef(categoryId, subcategoryId),
556
- technologyId
557
- );
455
+ const docRef = doc(this.getTechnologiesRef(), technologyId);
558
456
 
559
457
  await updateDoc(docRef, {
560
458
  certificationRequirement,
561
459
  updatedAt: new Date(),
562
460
  });
563
461
 
564
- return this.getById(categoryId, subcategoryId, technologyId);
462
+ return this.getById(technologyId);
565
463
  }
566
464
 
567
465
  /**
568
466
  * Vraća zahteve sertifikacije za tehnologiju
569
- * @param categoryId - ID kategorije
570
- * @param subcategoryId - ID podkategorije
571
467
  * @param technologyId - ID tehnologije
572
468
  * @returns Zahtevi sertifikacije ili null ako tehnologija ne postoji
573
469
  */
574
470
  async getCertificationRequirement(
575
- categoryId: string,
576
- subcategoryId: string,
577
471
  technologyId: string
578
472
  ): Promise<CertificationRequirement | null> {
579
- const technology = await this.getById(
580
- categoryId,
581
- subcategoryId,
582
- technologyId
583
- );
473
+ const technology = await this.getById(technologyId);
584
474
  return technology?.certificationRequirement || null;
585
475
  }
476
+
477
+ /**
478
+ * Proverava da li doktor ima odgovarajuću sertifikaciju za izvođenje tehnologije
479
+ *
480
+ * @param requiredCertification - Zahtevana sertifikacija za tehnologiju
481
+ * @param practitionerCertification - Sertifikacija zdravstvenog radnika
482
+ * @returns true ako zdravstveni radnik ima odgovarajuću sertifikaciju, false ako nema
483
+ *
484
+ * @example
485
+ * const isValid = technologyService.validateCertification(
486
+ * {
487
+ * minimumLevel: CertificationLevel.DOCTOR,
488
+ * requiredSpecialties: [CertificationSpecialty.INJECTABLES]
489
+ * },
490
+ * {
491
+ * level: CertificationLevel.SPECIALIST,
492
+ * specialties: [CertificationSpecialty.INJECTABLES, CertificationSpecialty.LASER]
493
+ * }
494
+ * );
495
+ */
496
+ validateCertification(
497
+ requiredCertification: CertificationRequirement,
498
+ practitionerCertification: PractitionerCertification
499
+ ): boolean {
500
+ // Provera nivoa sertifikacije
501
+ // Enum je definisan od najnižeg ka najvišem, pa možemo porediti brojeve
502
+ const doctorLevel = Object.values(CertificationLevel).indexOf(
503
+ practitionerCertification.level
504
+ );
505
+ const requiredLevel = Object.values(CertificationLevel).indexOf(
506
+ requiredCertification.minimumLevel
507
+ );
508
+
509
+ // Doktor mora imati nivo koji je jednak ili viši od zahtevanog
510
+ if (doctorLevel < requiredLevel) return false;
511
+
512
+ // Provera specijalizacija
513
+ const requiredSpecialties = requiredCertification.requiredSpecialties || [];
514
+ if (requiredSpecialties.length > 0) {
515
+ // Doktor mora imati sve zahtevane specijalizacije
516
+ const doctorSpecialties = practitionerCertification.specialties;
517
+ const hasAllRequiredSpecialties = requiredSpecialties.every(
518
+ (requiredSpecialty) => doctorSpecialties.includes(requiredSpecialty)
519
+ );
520
+
521
+ if (!hasAllRequiredSpecialties) return false;
522
+ }
523
+
524
+ return true;
525
+ }
526
+
527
+ /**
528
+ * Vraća sve tehnologije koje je zdravstveni radnik sertifikovan da izvodi
529
+ * zajedno sa listama dozvoljenih familija, kategorija i podkategorija
530
+ *
531
+ * @param practitioner - Profil zdravstvenog radnika
532
+ * @returns Objekat koji sadrži:
533
+ * - technologies: Lista tehnologija koje zdravstveni radnik može da izvodi
534
+ * - families: Lista familija procedura koje zdravstveni radnik može da izvodi
535
+ * - categories: Lista ID-eva kategorija koje zdravstveni radnik može da izvodi
536
+ * - subcategories: Lista ID-eva podkategorija koje zdravstveni radnik može da izvodi
537
+ *
538
+ * @example
539
+ * const practitioner = {
540
+ * certification: {
541
+ * level: CertificationLevel.DOCTOR,
542
+ * specialties: [CertificationSpecialty.INJECTABLES]
543
+ * }
544
+ * };
545
+ * const allowedTechnologies = await technologyService.getAllowedTechnologies(practitioner);
546
+ * console.log(allowedTechnologies.families); // [ProcedureFamily.AESTHETICS]
547
+ * console.log(allowedTechnologies.categories); // ["category1", "category2"]
548
+ * console.log(allowedTechnologies.subcategories); // ["subcategory1", "subcategory2"]
549
+ */
550
+ async getAllowedTechnologies(practitioner: Practitioner): Promise<{
551
+ technologies: Technology[];
552
+ families: ProcedureFamily[];
553
+ categories: string[];
554
+ subcategories: string[];
555
+ }> {
556
+ // Get all active technologies
557
+ const allTechnologies = await this.getAll();
558
+
559
+ // Filter technologies based on certification requirements
560
+ const allowedTechnologies = allTechnologies.filter((technology) =>
561
+ this.validateCertification(
562
+ technology.certificationRequirement,
563
+ practitioner.certification
564
+ )
565
+ );
566
+
567
+ // Extract unique families, categories, and subcategories
568
+ const families = [...new Set(allowedTechnologies.map((t) => t.family))];
569
+ const categories = [
570
+ ...new Set(allowedTechnologies.map((t) => t.categoryId)),
571
+ ];
572
+ const subcategories = [
573
+ ...new Set(allowedTechnologies.map((t) => t.subcategoryId)),
574
+ ];
575
+
576
+ return {
577
+ technologies: allowedTechnologies,
578
+ families,
579
+ categories,
580
+ subcategories,
581
+ };
582
+ }
586
583
  }