@blackcode_sa/metaestetics-api 1.12.67 → 1.12.69
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 +34 -1
- package/dist/admin/index.d.ts +34 -1
- package/dist/admin/index.js +104 -0
- package/dist/admin/index.mjs +104 -0
- 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 +61 -2
- package/dist/index.d.ts +61 -2
- package/dist/index.js +249 -37
- package/dist/index.mjs +249 -39
- package/package.json +1 -1
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +140 -0
- package/src/backoffice/services/README.md +17 -0
- package/src/backoffice/services/analytics.service.proposal.md +859 -0
- package/src/backoffice/services/analytics.service.summary.md +143 -0
- 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/appointment/appointment.service.ts +59 -6
- package/src/services/procedure/procedure.service.ts +120 -7
- package/src/types/notifications/index.ts +21 -0
package/dist/index.js
CHANGED
|
@@ -188,13 +188,13 @@ var AppointmentStatus = /* @__PURE__ */ ((AppointmentStatus2) => {
|
|
|
188
188
|
AppointmentStatus2["RESCHEDULED_BY_CLINIC"] = "rescheduled_by_clinic";
|
|
189
189
|
return AppointmentStatus2;
|
|
190
190
|
})(AppointmentStatus || {});
|
|
191
|
-
var PaymentStatus = /* @__PURE__ */ ((
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return
|
|
191
|
+
var PaymentStatus = /* @__PURE__ */ ((PaymentStatus3) => {
|
|
192
|
+
PaymentStatus3["UNPAID"] = "unpaid";
|
|
193
|
+
PaymentStatus3["PAID"] = "paid";
|
|
194
|
+
PaymentStatus3["PARTIALLY_PAID"] = "partially_paid";
|
|
195
|
+
PaymentStatus3["REFUNDED"] = "refunded";
|
|
196
|
+
PaymentStatus3["NOT_APPLICABLE"] = "not_applicable";
|
|
197
|
+
return PaymentStatus3;
|
|
198
198
|
})(PaymentStatus || {});
|
|
199
199
|
var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
200
200
|
MediaType2["BEFORE_PHOTO"] = "before_photo";
|
|
@@ -3430,6 +3430,7 @@ var AppointmentService = class extends BaseService {
|
|
|
3430
3430
|
finalbilling: null,
|
|
3431
3431
|
finalizationNotes: null
|
|
3432
3432
|
};
|
|
3433
|
+
const shouldUpdatePaymentStatus = finalbilling.finalPrice > 0 && appointment.paymentStatus === "not_applicable" /* NOT_APPLICABLE */;
|
|
3433
3434
|
const updateData = {
|
|
3434
3435
|
metadata: {
|
|
3435
3436
|
selectedZones: currentMetadata.selectedZones,
|
|
@@ -3445,6 +3446,9 @@ var AppointmentService = class extends BaseService {
|
|
|
3445
3446
|
finalbilling,
|
|
3446
3447
|
finalizationNotes: currentMetadata.finalizationNotes
|
|
3447
3448
|
},
|
|
3449
|
+
...shouldUpdatePaymentStatus && {
|
|
3450
|
+
paymentStatus: "unpaid" /* UNPAID */
|
|
3451
|
+
},
|
|
3448
3452
|
updatedAt: (0, import_firestore11.serverTimestamp)()
|
|
3449
3453
|
};
|
|
3450
3454
|
return await this.updateAppointment(appointmentId, updateData);
|
|
@@ -3658,8 +3662,36 @@ var AppointmentService = class extends BaseService {
|
|
|
3658
3662
|
showCanceled: false,
|
|
3659
3663
|
showNoShow: false
|
|
3660
3664
|
});
|
|
3665
|
+
const now = /* @__PURE__ */ new Date();
|
|
3666
|
+
const allPastAppointments = await this.getPatientAppointments(patientId, {
|
|
3667
|
+
endDate: now,
|
|
3668
|
+
status: [
|
|
3669
|
+
"completed" /* COMPLETED */,
|
|
3670
|
+
"confirmed" /* CONFIRMED */,
|
|
3671
|
+
"checked_in" /* CHECKED_IN */,
|
|
3672
|
+
"in_progress" /* IN_PROGRESS */
|
|
3673
|
+
]
|
|
3674
|
+
});
|
|
3675
|
+
const appointmentsWithRecommendations = allPastAppointments.appointments.filter(
|
|
3676
|
+
(appointment) => {
|
|
3677
|
+
var _a2, _b2, _c2, _d;
|
|
3678
|
+
const endTime = ((_a2 = appointment.appointmentEndTime) == null ? void 0 : _a2.toMillis) ? appointment.appointmentEndTime.toMillis() : ((_b2 = appointment.appointmentEndTime) == null ? void 0 : _b2.seconds) ? appointment.appointmentEndTime.seconds * 1e3 : null;
|
|
3679
|
+
if (!endTime) return false;
|
|
3680
|
+
const isPastEndTime = endTime < now.getTime();
|
|
3681
|
+
const hasRecommendations = (((_d = (_c2 = appointment.metadata) == null ? void 0 : _c2.recommendedProcedures) == null ? void 0 : _d.length) || 0) > 0;
|
|
3682
|
+
return isPastEndTime && hasRecommendations;
|
|
3683
|
+
}
|
|
3684
|
+
);
|
|
3685
|
+
const allAppointmentsMap = /* @__PURE__ */ new Map();
|
|
3686
|
+
pastAppointments.appointments.forEach((apt) => {
|
|
3687
|
+
allAppointmentsMap.set(apt.id, apt);
|
|
3688
|
+
});
|
|
3689
|
+
appointmentsWithRecommendations.forEach((apt) => {
|
|
3690
|
+
allAppointmentsMap.set(apt.id, apt);
|
|
3691
|
+
});
|
|
3692
|
+
const allAppointments = Array.from(allAppointmentsMap.values());
|
|
3661
3693
|
const recommendations = [];
|
|
3662
|
-
for (const appointment of
|
|
3694
|
+
for (const appointment of allAppointments) {
|
|
3663
3695
|
if ((options == null ? void 0 : options.clinicBranchId) && appointment.clinicBranchId !== options.clinicBranchId) {
|
|
3664
3696
|
continue;
|
|
3665
3697
|
}
|
|
@@ -3696,9 +3728,6 @@ var AppointmentService = class extends BaseService {
|
|
|
3696
3728
|
return dateB - dateA;
|
|
3697
3729
|
});
|
|
3698
3730
|
const limitedRecommendations = (options == null ? void 0 : options.limit) ? recommendations.slice(0, options.limit) : recommendations;
|
|
3699
|
-
console.log(
|
|
3700
|
-
`[APPOINTMENT_SERVICE] Found ${limitedRecommendations.length} next steps recommendations for patient ${patientId}`
|
|
3701
|
-
);
|
|
3702
3731
|
return limitedRecommendations;
|
|
3703
3732
|
} catch (error) {
|
|
3704
3733
|
console.error(
|
|
@@ -3967,6 +3996,7 @@ var NotificationType = /* @__PURE__ */ ((NotificationType3) => {
|
|
|
3967
3996
|
NotificationType3["FORM_REMINDER"] = "formReminder";
|
|
3968
3997
|
NotificationType3["FORM_SUBMISSION_CONFIRMATION"] = "formSubmissionConfirmation";
|
|
3969
3998
|
NotificationType3["REVIEW_REQUEST"] = "reviewRequest";
|
|
3999
|
+
NotificationType3["PROCEDURE_RECOMMENDATION"] = "procedureRecommendation";
|
|
3970
4000
|
NotificationType3["PAYMENT_DUE"] = "paymentDue";
|
|
3971
4001
|
NotificationType3["PAYMENT_CONFIRMATION"] = "paymentConfirmation";
|
|
3972
4002
|
NotificationType3["PAYMENT_FAILED"] = "paymentFailed";
|
|
@@ -17491,6 +17521,10 @@ var ProcedureService = class extends BaseService {
|
|
|
17491
17521
|
console.log("[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search");
|
|
17492
17522
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
17493
17523
|
const constraints = getBaseConstraints();
|
|
17524
|
+
const hasNestedFilters = !!(filters.procedureTechnology || filters.procedureCategory || filters.procedureSubcategory);
|
|
17525
|
+
if (hasNestedFilters) {
|
|
17526
|
+
console.log("[PROCEDURE_SERVICE] Strategy 1: Has nested filters, will apply client-side after query");
|
|
17527
|
+
}
|
|
17494
17528
|
constraints.push((0, import_firestore55.where)("nameLower", ">=", searchTerm));
|
|
17495
17529
|
constraints.push((0, import_firestore55.where)("nameLower", "<=", searchTerm + "\uF8FF"));
|
|
17496
17530
|
constraints.push((0, import_firestore55.orderBy)("nameLower"));
|
|
@@ -17506,9 +17540,12 @@ var ProcedureService = class extends BaseService {
|
|
|
17506
17540
|
constraints.push((0, import_firestore55.limit)(filters.pagination || 10));
|
|
17507
17541
|
const q = (0, import_firestore55.query)((0, import_firestore55.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
17508
17542
|
const querySnapshot = await (0, import_firestore55.getDocs)(q);
|
|
17509
|
-
|
|
17543
|
+
let procedures = querySnapshot.docs.map(
|
|
17510
17544
|
(doc45) => ({ ...doc45.data(), id: doc45.id })
|
|
17511
17545
|
);
|
|
17546
|
+
if (hasNestedFilters) {
|
|
17547
|
+
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
17548
|
+
}
|
|
17512
17549
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
17513
17550
|
console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
|
|
17514
17551
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -17524,6 +17561,10 @@ var ProcedureService = class extends BaseService {
|
|
|
17524
17561
|
console.log("[PROCEDURE_SERVICE] Strategy 2: Trying name field search");
|
|
17525
17562
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
17526
17563
|
const constraints = getBaseConstraints();
|
|
17564
|
+
const hasNestedFilters = !!(filters.procedureTechnology || filters.procedureCategory || filters.procedureSubcategory);
|
|
17565
|
+
if (hasNestedFilters) {
|
|
17566
|
+
console.log("[PROCEDURE_SERVICE] Strategy 2: Has nested filters, will apply client-side after query");
|
|
17567
|
+
}
|
|
17527
17568
|
constraints.push((0, import_firestore55.where)("name", ">=", searchTerm));
|
|
17528
17569
|
constraints.push((0, import_firestore55.where)("name", "<=", searchTerm + "\uF8FF"));
|
|
17529
17570
|
constraints.push((0, import_firestore55.orderBy)("name"));
|
|
@@ -17539,9 +17580,12 @@ var ProcedureService = class extends BaseService {
|
|
|
17539
17580
|
constraints.push((0, import_firestore55.limit)(filters.pagination || 10));
|
|
17540
17581
|
const q = (0, import_firestore55.query)((0, import_firestore55.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
17541
17582
|
const querySnapshot = await (0, import_firestore55.getDocs)(q);
|
|
17542
|
-
|
|
17583
|
+
let procedures = querySnapshot.docs.map(
|
|
17543
17584
|
(doc45) => ({ ...doc45.data(), id: doc45.id })
|
|
17544
17585
|
);
|
|
17586
|
+
if (hasNestedFilters) {
|
|
17587
|
+
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
17588
|
+
}
|
|
17545
17589
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
17546
17590
|
console.log(`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`);
|
|
17547
17591
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -17554,9 +17598,47 @@ var ProcedureService = class extends BaseService {
|
|
|
17554
17598
|
}
|
|
17555
17599
|
try {
|
|
17556
17600
|
console.log(
|
|
17557
|
-
"[PROCEDURE_SERVICE] Strategy 3: Using createdAt orderBy with client-side filtering"
|
|
17601
|
+
"[PROCEDURE_SERVICE] Strategy 3: Using createdAt orderBy with client-side filtering",
|
|
17602
|
+
{
|
|
17603
|
+
procedureTechnology: filters.procedureTechnology,
|
|
17604
|
+
hasTechnologyFilter: !!filters.procedureTechnology
|
|
17605
|
+
}
|
|
17606
|
+
);
|
|
17607
|
+
const constraints = [];
|
|
17608
|
+
if (filters.isActive !== void 0) {
|
|
17609
|
+
constraints.push((0, import_firestore55.where)("isActive", "==", filters.isActive));
|
|
17610
|
+
} else {
|
|
17611
|
+
constraints.push((0, import_firestore55.where)("isActive", "==", true));
|
|
17612
|
+
}
|
|
17613
|
+
if (filters.procedureFamily) {
|
|
17614
|
+
constraints.push((0, import_firestore55.where)("family", "==", filters.procedureFamily));
|
|
17615
|
+
}
|
|
17616
|
+
if (filters.practitionerId) {
|
|
17617
|
+
constraints.push((0, import_firestore55.where)("practitionerId", "==", filters.practitionerId));
|
|
17618
|
+
}
|
|
17619
|
+
if (filters.clinicId) {
|
|
17620
|
+
constraints.push((0, import_firestore55.where)("clinicBranchId", "==", filters.clinicId));
|
|
17621
|
+
}
|
|
17622
|
+
if (filters.minPrice !== void 0) {
|
|
17623
|
+
constraints.push((0, import_firestore55.where)("price", ">=", filters.minPrice));
|
|
17624
|
+
}
|
|
17625
|
+
if (filters.maxPrice !== void 0) {
|
|
17626
|
+
constraints.push((0, import_firestore55.where)("price", "<=", filters.maxPrice));
|
|
17627
|
+
}
|
|
17628
|
+
if (filters.minRating !== void 0) {
|
|
17629
|
+
constraints.push((0, import_firestore55.where)("reviewInfo.averageRating", ">=", filters.minRating));
|
|
17630
|
+
}
|
|
17631
|
+
if (filters.maxRating !== void 0) {
|
|
17632
|
+
constraints.push((0, import_firestore55.where)("reviewInfo.averageRating", "<=", filters.maxRating));
|
|
17633
|
+
}
|
|
17634
|
+
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
17635
|
+
const benefitIdsToMatch = filters.treatmentBenefits;
|
|
17636
|
+
constraints.push((0, import_firestore55.where)("treatmentBenefitIds", "array-contains-any", benefitIdsToMatch));
|
|
17637
|
+
}
|
|
17638
|
+
console.log(
|
|
17639
|
+
"[PROCEDURE_SERVICE] Strategy 3 Firestore constraints (nested filters excluded):",
|
|
17640
|
+
constraints.map((c) => c.fieldPath || "unknown")
|
|
17558
17641
|
);
|
|
17559
|
-
const constraints = getBaseConstraints();
|
|
17560
17642
|
constraints.push((0, import_firestore55.orderBy)("createdAt", "desc"));
|
|
17561
17643
|
if (filters.lastDoc) {
|
|
17562
17644
|
if (typeof filters.lastDoc.data === "function") {
|
|
@@ -17573,7 +17655,20 @@ var ProcedureService = class extends BaseService {
|
|
|
17573
17655
|
let procedures = querySnapshot.docs.map(
|
|
17574
17656
|
(doc45) => ({ ...doc45.data(), id: doc45.id })
|
|
17575
17657
|
);
|
|
17658
|
+
console.log("[PROCEDURE_SERVICE] Before applyInMemoryFilters (Strategy 3):", {
|
|
17659
|
+
procedureCount: procedures.length,
|
|
17660
|
+
procedureTechnology: filters.procedureTechnology,
|
|
17661
|
+
filtersObject: {
|
|
17662
|
+
procedureTechnology: filters.procedureTechnology,
|
|
17663
|
+
procedureFamily: filters.procedureFamily,
|
|
17664
|
+
procedureCategory: filters.procedureCategory,
|
|
17665
|
+
procedureSubcategory: filters.procedureSubcategory
|
|
17666
|
+
}
|
|
17667
|
+
});
|
|
17576
17668
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
17669
|
+
console.log("[PROCEDURE_SERVICE] After applyInMemoryFilters (Strategy 3):", {
|
|
17670
|
+
procedureCount: procedures.length
|
|
17671
|
+
});
|
|
17577
17672
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
17578
17673
|
console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
|
|
17579
17674
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -17624,6 +17719,12 @@ var ProcedureService = class extends BaseService {
|
|
|
17624
17719
|
*/
|
|
17625
17720
|
applyInMemoryFilters(procedures, filters) {
|
|
17626
17721
|
let filteredProcedures = [...procedures];
|
|
17722
|
+
console.log("[PROCEDURE_SERVICE] applyInMemoryFilters called:", {
|
|
17723
|
+
procedureCount: procedures.length,
|
|
17724
|
+
procedureTechnology: filters.procedureTechnology,
|
|
17725
|
+
hasTechnologyFilter: !!filters.procedureTechnology,
|
|
17726
|
+
allFilterKeys: Object.keys(filters).filter((k) => filters[k] !== void 0 && filters[k] !== null)
|
|
17727
|
+
});
|
|
17627
17728
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
17628
17729
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
17629
17730
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
@@ -17699,6 +17800,7 @@ var ProcedureService = class extends BaseService {
|
|
|
17699
17800
|
);
|
|
17700
17801
|
}
|
|
17701
17802
|
if (filters.procedureTechnology) {
|
|
17803
|
+
const beforeCount = filteredProcedures.length;
|
|
17702
17804
|
filteredProcedures = filteredProcedures.filter(
|
|
17703
17805
|
(procedure) => {
|
|
17704
17806
|
var _a;
|
|
@@ -17706,8 +17808,18 @@ var ProcedureService = class extends BaseService {
|
|
|
17706
17808
|
}
|
|
17707
17809
|
);
|
|
17708
17810
|
console.log(
|
|
17709
|
-
`[PROCEDURE_SERVICE] Applied technology filter,
|
|
17811
|
+
`[PROCEDURE_SERVICE] Applied technology filter (${filters.procedureTechnology}), before: ${beforeCount}, after: ${filteredProcedures.length}`
|
|
17710
17812
|
);
|
|
17813
|
+
if (beforeCount > filteredProcedures.length) {
|
|
17814
|
+
const filteredOut = procedures.filter((p) => {
|
|
17815
|
+
var _a;
|
|
17816
|
+
return ((_a = p.technology) == null ? void 0 : _a.id) !== filters.procedureTechnology;
|
|
17817
|
+
}).slice(0, 3).map((p) => {
|
|
17818
|
+
var _a;
|
|
17819
|
+
return { id: p.id, techId: (_a = p.technology) == null ? void 0 : _a.id, name: p.name };
|
|
17820
|
+
});
|
|
17821
|
+
console.log("[PROCEDURE_SERVICE] Filtered out sample procedures:", filteredOut);
|
|
17822
|
+
}
|
|
17711
17823
|
}
|
|
17712
17824
|
if (filters.practitionerId) {
|
|
17713
17825
|
filteredProcedures = filteredProcedures.filter(
|
|
@@ -17811,9 +17923,9 @@ var ProcedureService = class extends BaseService {
|
|
|
17811
17923
|
var _a, _b;
|
|
17812
17924
|
const procedureId = this.generateId();
|
|
17813
17925
|
const [category, subcategory, technology] = await Promise.all([
|
|
17814
|
-
this.categoryService.
|
|
17815
|
-
this.subcategoryService.
|
|
17816
|
-
this.technologyService.
|
|
17926
|
+
this.categoryService.getByIdInternal(data.categoryId),
|
|
17927
|
+
this.subcategoryService.getByIdInternal(data.categoryId, data.subcategoryId),
|
|
17928
|
+
this.technologyService.getByIdInternal(data.technologyId)
|
|
17817
17929
|
]);
|
|
17818
17930
|
if (!category || !subcategory || !technology) {
|
|
17819
17931
|
throw new Error("One or more required base entities not found");
|
|
@@ -18750,7 +18862,16 @@ var import_firestore59 = require("firebase/firestore");
|
|
|
18750
18862
|
var CATEGORIES_COLLECTION = "backoffice_categories";
|
|
18751
18863
|
|
|
18752
18864
|
// src/backoffice/services/category.service.ts
|
|
18865
|
+
var EXCLUDED_CATEGORY_ID = "consultation";
|
|
18753
18866
|
var CategoryService = class extends BaseService {
|
|
18867
|
+
/**
|
|
18868
|
+
* Filters out excluded categories from a list.
|
|
18869
|
+
* @param categories - List of categories to filter
|
|
18870
|
+
* @returns Filtered list without excluded categories
|
|
18871
|
+
*/
|
|
18872
|
+
filterExcludedCategories(categories) {
|
|
18873
|
+
return categories.filter((cat) => cat.id !== EXCLUDED_CATEGORY_ID);
|
|
18874
|
+
}
|
|
18754
18875
|
/**
|
|
18755
18876
|
* Referenca na Firestore kolekciju kategorija
|
|
18756
18877
|
*/
|
|
@@ -18787,8 +18908,9 @@ var CategoryService = class extends BaseService {
|
|
|
18787
18908
|
(0, import_firestore59.where)("family", "==", family),
|
|
18788
18909
|
(0, import_firestore59.where)("isActive", "==", active)
|
|
18789
18910
|
);
|
|
18790
|
-
const snapshot = await (0, import_firestore59.
|
|
18791
|
-
|
|
18911
|
+
const snapshot = await (0, import_firestore59.getDocs)(q);
|
|
18912
|
+
const filteredDocs = snapshot.docs.filter((doc45) => doc45.id !== EXCLUDED_CATEGORY_ID);
|
|
18913
|
+
counts[family] = filteredDocs.length;
|
|
18792
18914
|
}
|
|
18793
18915
|
return counts;
|
|
18794
18916
|
}
|
|
@@ -18799,12 +18921,13 @@ var CategoryService = class extends BaseService {
|
|
|
18799
18921
|
async getAllForFilter() {
|
|
18800
18922
|
const q = (0, import_firestore59.query)(this.categoriesRef, (0, import_firestore59.where)("isActive", "==", true));
|
|
18801
18923
|
const snapshot = await (0, import_firestore59.getDocs)(q);
|
|
18802
|
-
|
|
18924
|
+
const categories = snapshot.docs.map(
|
|
18803
18925
|
(doc45) => ({
|
|
18804
18926
|
id: doc45.id,
|
|
18805
18927
|
...doc45.data()
|
|
18806
18928
|
})
|
|
18807
18929
|
);
|
|
18930
|
+
return this.filterExcludedCategories(categories);
|
|
18808
18931
|
}
|
|
18809
18932
|
/**
|
|
18810
18933
|
* Vraća sve kategorije za određenu familiju za potrebe filtera (bez paginacije)
|
|
@@ -18819,12 +18942,13 @@ var CategoryService = class extends BaseService {
|
|
|
18819
18942
|
(0, import_firestore59.orderBy)("name")
|
|
18820
18943
|
);
|
|
18821
18944
|
const snapshot = await (0, import_firestore59.getDocs)(q);
|
|
18822
|
-
|
|
18945
|
+
const categories = snapshot.docs.map(
|
|
18823
18946
|
(doc45) => ({
|
|
18824
18947
|
id: doc45.id,
|
|
18825
18948
|
...doc45.data()
|
|
18826
18949
|
})
|
|
18827
18950
|
);
|
|
18951
|
+
return this.filterExcludedCategories(categories);
|
|
18828
18952
|
}
|
|
18829
18953
|
/**
|
|
18830
18954
|
* Vraća sve kategorije sa paginacijom
|
|
@@ -18847,8 +18971,9 @@ var CategoryService = class extends BaseService {
|
|
|
18847
18971
|
...doc45.data()
|
|
18848
18972
|
})
|
|
18849
18973
|
);
|
|
18974
|
+
const filteredCategories = this.filterExcludedCategories(categories);
|
|
18850
18975
|
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
18851
|
-
return { categories, lastVisible: newLastVisible };
|
|
18976
|
+
return { categories: filteredCategories, lastVisible: newLastVisible };
|
|
18852
18977
|
}
|
|
18853
18978
|
/**
|
|
18854
18979
|
* Vraća sve aktivne kategorije za određenu familiju procedura sa paginacijom
|
|
@@ -18873,8 +18998,9 @@ var CategoryService = class extends BaseService {
|
|
|
18873
18998
|
...doc45.data()
|
|
18874
18999
|
})
|
|
18875
19000
|
);
|
|
19001
|
+
const filteredCategories = this.filterExcludedCategories(categories);
|
|
18876
19002
|
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
18877
|
-
return { categories, lastVisible: newLastVisible };
|
|
19003
|
+
return { categories: filteredCategories, lastVisible: newLastVisible };
|
|
18878
19004
|
}
|
|
18879
19005
|
/**
|
|
18880
19006
|
* Ažurira postojeću kategoriju
|
|
@@ -18911,6 +19037,22 @@ var CategoryService = class extends BaseService {
|
|
|
18911
19037
|
* @returns Kategorija ili null ako ne postoji
|
|
18912
19038
|
*/
|
|
18913
19039
|
async getById(id) {
|
|
19040
|
+
if (id === EXCLUDED_CATEGORY_ID) return null;
|
|
19041
|
+
const docRef = (0, import_firestore59.doc)(this.categoriesRef, id);
|
|
19042
|
+
const docSnap = await (0, import_firestore59.getDoc)(docRef);
|
|
19043
|
+
if (!docSnap.exists()) return null;
|
|
19044
|
+
return {
|
|
19045
|
+
id: docSnap.id,
|
|
19046
|
+
...docSnap.data()
|
|
19047
|
+
};
|
|
19048
|
+
}
|
|
19049
|
+
/**
|
|
19050
|
+
* Internal method to get category by ID without filtering.
|
|
19051
|
+
* Used internally for consultation procedures.
|
|
19052
|
+
* @param id - ID of the category to get
|
|
19053
|
+
* @returns Category or null if not found
|
|
19054
|
+
*/
|
|
19055
|
+
async getByIdInternal(id) {
|
|
18914
19056
|
const docRef = (0, import_firestore59.doc)(this.categoriesRef, id);
|
|
18915
19057
|
const docSnap = await (0, import_firestore59.getDoc)(docRef);
|
|
18916
19058
|
if (!docSnap.exists()) return null;
|
|
@@ -18936,6 +19078,7 @@ var CategoryService = class extends BaseService {
|
|
|
18936
19078
|
const snapshot = await (0, import_firestore59.getDocs)(q);
|
|
18937
19079
|
if (snapshot.empty) return null;
|
|
18938
19080
|
const doc45 = snapshot.docs[0];
|
|
19081
|
+
if (doc45.id === EXCLUDED_CATEGORY_ID) return null;
|
|
18939
19082
|
return {
|
|
18940
19083
|
id: doc45.id,
|
|
18941
19084
|
...doc45.data()
|
|
@@ -18973,6 +19116,7 @@ var CategoryService = class extends BaseService {
|
|
|
18973
19116
|
const snapshot = await (0, import_firestore59.getDocs)(q);
|
|
18974
19117
|
if (snapshot.empty) break;
|
|
18975
19118
|
for (const d of snapshot.docs) {
|
|
19119
|
+
if (d.id === EXCLUDED_CATEGORY_ID) continue;
|
|
18976
19120
|
const category = { id: d.id, ...d.data() };
|
|
18977
19121
|
rows.push(this.categoryToCsvRow(category));
|
|
18978
19122
|
}
|
|
@@ -19015,7 +19159,16 @@ var import_firestore60 = require("firebase/firestore");
|
|
|
19015
19159
|
var SUBCATEGORIES_COLLECTION = "subcategories";
|
|
19016
19160
|
|
|
19017
19161
|
// src/backoffice/services/subcategory.service.ts
|
|
19162
|
+
var EXCLUDED_SUBCATEGORY_ID = "free-consultation";
|
|
19018
19163
|
var SubcategoryService = class extends BaseService {
|
|
19164
|
+
/**
|
|
19165
|
+
* Filters out excluded subcategories from a list.
|
|
19166
|
+
* @param subcategories - List of subcategories to filter
|
|
19167
|
+
* @returns Filtered list without excluded subcategories
|
|
19168
|
+
*/
|
|
19169
|
+
filterExcludedSubcategories(subcategories) {
|
|
19170
|
+
return subcategories.filter((sub) => sub.id !== EXCLUDED_SUBCATEGORY_ID);
|
|
19171
|
+
}
|
|
19019
19172
|
/**
|
|
19020
19173
|
* Vraća referencu na Firestore kolekciju podkategorija za određenu kategoriju
|
|
19021
19174
|
* @param categoryId - ID roditeljske kategorije
|
|
@@ -19062,8 +19215,9 @@ var SubcategoryService = class extends BaseService {
|
|
|
19062
19215
|
const categoryId = categoryDoc.id;
|
|
19063
19216
|
const subcategoriesRef = this.getSubcategoriesRef(categoryId);
|
|
19064
19217
|
const q = (0, import_firestore60.query)(subcategoriesRef, (0, import_firestore60.where)("isActive", "==", active));
|
|
19065
|
-
const snapshot = await (0, import_firestore60.
|
|
19066
|
-
|
|
19218
|
+
const snapshot = await (0, import_firestore60.getDocs)(q);
|
|
19219
|
+
const filteredDocs = snapshot.docs.filter((doc45) => doc45.id !== EXCLUDED_SUBCATEGORY_ID);
|
|
19220
|
+
counts[categoryId] = filteredDocs.length;
|
|
19067
19221
|
}
|
|
19068
19222
|
return counts;
|
|
19069
19223
|
}
|
|
@@ -19089,8 +19243,9 @@ var SubcategoryService = class extends BaseService {
|
|
|
19089
19243
|
...doc45.data()
|
|
19090
19244
|
})
|
|
19091
19245
|
);
|
|
19246
|
+
const filteredSubcategories = this.filterExcludedSubcategories(subcategories);
|
|
19092
19247
|
const newLastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
|
|
19093
|
-
return { subcategories, lastVisible: newLastVisible };
|
|
19248
|
+
return { subcategories: filteredSubcategories, lastVisible: newLastVisible };
|
|
19094
19249
|
}
|
|
19095
19250
|
/**
|
|
19096
19251
|
* Vraća sve podkategorije sa paginacijom koristeći collection group query.
|
|
@@ -19119,8 +19274,9 @@ var SubcategoryService = class extends BaseService {
|
|
|
19119
19274
|
...doc45.data()
|
|
19120
19275
|
})
|
|
19121
19276
|
);
|
|
19277
|
+
const filteredSubcategories = this.filterExcludedSubcategories(subcategories);
|
|
19122
19278
|
const newLastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
|
|
19123
|
-
return { subcategories, lastVisible: newLastVisible };
|
|
19279
|
+
return { subcategories: filteredSubcategories, lastVisible: newLastVisible };
|
|
19124
19280
|
}
|
|
19125
19281
|
/**
|
|
19126
19282
|
* Vraća sve subkategorije za određenu kategoriju za potrebe filtera (bez paginacije)
|
|
@@ -19133,12 +19289,13 @@ var SubcategoryService = class extends BaseService {
|
|
|
19133
19289
|
(0, import_firestore60.where)("isActive", "==", true)
|
|
19134
19290
|
);
|
|
19135
19291
|
const querySnapshot = await (0, import_firestore60.getDocs)(q);
|
|
19136
|
-
|
|
19292
|
+
const subcategories = querySnapshot.docs.map(
|
|
19137
19293
|
(doc45) => ({
|
|
19138
19294
|
id: doc45.id,
|
|
19139
19295
|
...doc45.data()
|
|
19140
19296
|
})
|
|
19141
19297
|
);
|
|
19298
|
+
return this.filterExcludedSubcategories(subcategories);
|
|
19142
19299
|
}
|
|
19143
19300
|
/**
|
|
19144
19301
|
* Vraća sve subkategorije za potrebe filtera (bez paginacije)
|
|
@@ -19150,12 +19307,13 @@ var SubcategoryService = class extends BaseService {
|
|
|
19150
19307
|
(0, import_firestore60.where)("isActive", "==", true)
|
|
19151
19308
|
);
|
|
19152
19309
|
const querySnapshot = await (0, import_firestore60.getDocs)(q);
|
|
19153
|
-
|
|
19310
|
+
const subcategories = querySnapshot.docs.map(
|
|
19154
19311
|
(doc45) => ({
|
|
19155
19312
|
id: doc45.id,
|
|
19156
19313
|
...doc45.data()
|
|
19157
19314
|
})
|
|
19158
19315
|
);
|
|
19316
|
+
return this.filterExcludedSubcategories(subcategories);
|
|
19159
19317
|
}
|
|
19160
19318
|
/**
|
|
19161
19319
|
* Ažurira postojeću podkategoriju
|
|
@@ -19225,6 +19383,23 @@ var SubcategoryService = class extends BaseService {
|
|
|
19225
19383
|
* @returns Podkategorija ili null ako ne postoji
|
|
19226
19384
|
*/
|
|
19227
19385
|
async getById(categoryId, subcategoryId) {
|
|
19386
|
+
if (subcategoryId === EXCLUDED_SUBCATEGORY_ID) return null;
|
|
19387
|
+
const docRef = (0, import_firestore60.doc)(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
19388
|
+
const docSnap = await (0, import_firestore60.getDoc)(docRef);
|
|
19389
|
+
if (!docSnap.exists()) return null;
|
|
19390
|
+
return {
|
|
19391
|
+
id: docSnap.id,
|
|
19392
|
+
...docSnap.data()
|
|
19393
|
+
};
|
|
19394
|
+
}
|
|
19395
|
+
/**
|
|
19396
|
+
* Internal method to get subcategory by ID without filtering.
|
|
19397
|
+
* Used internally for consultation procedures.
|
|
19398
|
+
* @param categoryId - ID of the category
|
|
19399
|
+
* @param subcategoryId - ID of the subcategory to get
|
|
19400
|
+
* @returns Subcategory or null if not found
|
|
19401
|
+
*/
|
|
19402
|
+
async getByIdInternal(categoryId, subcategoryId) {
|
|
19228
19403
|
const docRef = (0, import_firestore60.doc)(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
19229
19404
|
const docSnap = await (0, import_firestore60.getDoc)(docRef);
|
|
19230
19405
|
if (!docSnap.exists()) return null;
|
|
@@ -19249,6 +19424,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
19249
19424
|
const querySnapshot = await (0, import_firestore60.getDocs)(q);
|
|
19250
19425
|
if (querySnapshot.empty) return null;
|
|
19251
19426
|
const doc45 = querySnapshot.docs[0];
|
|
19427
|
+
if (doc45.id === EXCLUDED_SUBCATEGORY_ID) return null;
|
|
19252
19428
|
return {
|
|
19253
19429
|
id: doc45.id,
|
|
19254
19430
|
...doc45.data()
|
|
@@ -19289,6 +19465,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
19289
19465
|
const snapshot = await (0, import_firestore60.getDocs)(q);
|
|
19290
19466
|
if (snapshot.empty) break;
|
|
19291
19467
|
for (const d of snapshot.docs) {
|
|
19468
|
+
if (d.id === EXCLUDED_SUBCATEGORY_ID) continue;
|
|
19292
19469
|
const subcategory = { id: d.id, ...d.data() };
|
|
19293
19470
|
rows.push(this.subcategoryToCsvRow(subcategory));
|
|
19294
19471
|
}
|
|
@@ -19331,11 +19508,20 @@ var import_firestore61 = require("firebase/firestore");
|
|
|
19331
19508
|
var PRODUCTS_COLLECTION = "products";
|
|
19332
19509
|
|
|
19333
19510
|
// src/backoffice/services/technology.service.ts
|
|
19511
|
+
var EXCLUDED_TECHNOLOGY_ID = "free-consultation-tech";
|
|
19334
19512
|
var DEFAULT_CERTIFICATION_REQUIREMENT = {
|
|
19335
19513
|
minimumLevel: "aesthetician" /* AESTHETICIAN */,
|
|
19336
19514
|
requiredSpecialties: []
|
|
19337
19515
|
};
|
|
19338
19516
|
var TechnologyService = class extends BaseService {
|
|
19517
|
+
/**
|
|
19518
|
+
* Filters out excluded technologies from a list.
|
|
19519
|
+
* @param technologies - List of technologies to filter
|
|
19520
|
+
* @returns Filtered list without excluded technologies
|
|
19521
|
+
*/
|
|
19522
|
+
filterExcludedTechnologies(technologies) {
|
|
19523
|
+
return technologies.filter((tech) => tech.id !== EXCLUDED_TECHNOLOGY_ID);
|
|
19524
|
+
}
|
|
19339
19525
|
/**
|
|
19340
19526
|
* Reference to the Firestore collection of technologies.
|
|
19341
19527
|
*/
|
|
@@ -19384,6 +19570,7 @@ var TechnologyService = class extends BaseService {
|
|
|
19384
19570
|
const snapshot = await (0, import_firestore61.getDocs)(q);
|
|
19385
19571
|
const counts = {};
|
|
19386
19572
|
snapshot.docs.forEach((doc45) => {
|
|
19573
|
+
if (doc45.id === EXCLUDED_TECHNOLOGY_ID) return;
|
|
19387
19574
|
const tech = doc45.data();
|
|
19388
19575
|
counts[tech.subcategoryId] = (counts[tech.subcategoryId] || 0) + 1;
|
|
19389
19576
|
});
|
|
@@ -19399,6 +19586,7 @@ var TechnologyService = class extends BaseService {
|
|
|
19399
19586
|
const snapshot = await (0, import_firestore61.getDocs)(q);
|
|
19400
19587
|
const counts = {};
|
|
19401
19588
|
snapshot.docs.forEach((doc45) => {
|
|
19589
|
+
if (doc45.id === EXCLUDED_TECHNOLOGY_ID) return;
|
|
19402
19590
|
const tech = doc45.data();
|
|
19403
19591
|
counts[tech.categoryId] = (counts[tech.categoryId] || 0) + 1;
|
|
19404
19592
|
});
|
|
@@ -19425,8 +19613,9 @@ var TechnologyService = class extends BaseService {
|
|
|
19425
19613
|
...doc45.data()
|
|
19426
19614
|
})
|
|
19427
19615
|
);
|
|
19616
|
+
const filteredTechnologies = this.filterExcludedTechnologies(technologies);
|
|
19428
19617
|
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
19429
|
-
return { technologies, lastVisible: newLastVisible };
|
|
19618
|
+
return { technologies: filteredTechnologies, lastVisible: newLastVisible };
|
|
19430
19619
|
}
|
|
19431
19620
|
/**
|
|
19432
19621
|
* Returns all technologies for a specific category with pagination.
|
|
@@ -19451,8 +19640,9 @@ var TechnologyService = class extends BaseService {
|
|
|
19451
19640
|
...doc45.data()
|
|
19452
19641
|
})
|
|
19453
19642
|
);
|
|
19643
|
+
const filteredTechnologies = this.filterExcludedTechnologies(technologies);
|
|
19454
19644
|
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
19455
|
-
return { technologies, lastVisible: newLastVisible };
|
|
19645
|
+
return { technologies: filteredTechnologies, lastVisible: newLastVisible };
|
|
19456
19646
|
}
|
|
19457
19647
|
/**
|
|
19458
19648
|
* Returns all technologies for a specific subcategory with pagination.
|
|
@@ -19477,8 +19667,9 @@ var TechnologyService = class extends BaseService {
|
|
|
19477
19667
|
...doc45.data()
|
|
19478
19668
|
})
|
|
19479
19669
|
);
|
|
19670
|
+
const filteredTechnologies = this.filterExcludedTechnologies(technologies);
|
|
19480
19671
|
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
19481
|
-
return { technologies, lastVisible: newLastVisible };
|
|
19672
|
+
return { technologies: filteredTechnologies, lastVisible: newLastVisible };
|
|
19482
19673
|
}
|
|
19483
19674
|
/**
|
|
19484
19675
|
* Updates an existing technology.
|
|
@@ -19536,6 +19727,22 @@ var TechnologyService = class extends BaseService {
|
|
|
19536
19727
|
* @returns The technology or null if it doesn't exist.
|
|
19537
19728
|
*/
|
|
19538
19729
|
async getById(id) {
|
|
19730
|
+
if (id === EXCLUDED_TECHNOLOGY_ID) return null;
|
|
19731
|
+
const docRef = (0, import_firestore61.doc)(this.technologiesRef, id);
|
|
19732
|
+
const docSnap = await (0, import_firestore61.getDoc)(docRef);
|
|
19733
|
+
if (!docSnap.exists()) return null;
|
|
19734
|
+
return {
|
|
19735
|
+
id: docSnap.id,
|
|
19736
|
+
...docSnap.data()
|
|
19737
|
+
};
|
|
19738
|
+
}
|
|
19739
|
+
/**
|
|
19740
|
+
* Internal method to get technology by ID without filtering.
|
|
19741
|
+
* Used internally for consultation procedures.
|
|
19742
|
+
* @param id - The ID of the requested technology
|
|
19743
|
+
* @returns The technology or null if it doesn't exist
|
|
19744
|
+
*/
|
|
19745
|
+
async getByIdInternal(id) {
|
|
19539
19746
|
const docRef = (0, import_firestore61.doc)(this.technologiesRef, id);
|
|
19540
19747
|
const docSnap = await (0, import_firestore61.getDoc)(docRef);
|
|
19541
19748
|
if (!docSnap.exists()) return null;
|
|
@@ -19559,6 +19766,7 @@ var TechnologyService = class extends BaseService {
|
|
|
19559
19766
|
const snapshot = await (0, import_firestore61.getDocs)(q);
|
|
19560
19767
|
if (snapshot.empty) return null;
|
|
19561
19768
|
const doc45 = snapshot.docs[0];
|
|
19769
|
+
if (doc45.id === EXCLUDED_TECHNOLOGY_ID) return null;
|
|
19562
19770
|
return {
|
|
19563
19771
|
id: doc45.id,
|
|
19564
19772
|
...doc45.data()
|
|
@@ -19924,12 +20132,13 @@ var TechnologyService = class extends BaseService {
|
|
|
19924
20132
|
(0, import_firestore61.orderBy)("name")
|
|
19925
20133
|
);
|
|
19926
20134
|
const snapshot = await (0, import_firestore61.getDocs)(q);
|
|
19927
|
-
|
|
20135
|
+
const technologies = snapshot.docs.map(
|
|
19928
20136
|
(doc45) => ({
|
|
19929
20137
|
id: doc45.id,
|
|
19930
20138
|
...doc45.data()
|
|
19931
20139
|
})
|
|
19932
20140
|
);
|
|
20141
|
+
return this.filterExcludedTechnologies(technologies);
|
|
19933
20142
|
}
|
|
19934
20143
|
/**
|
|
19935
20144
|
* Gets all active technologies for a subcategory for filter dropdowns.
|
|
@@ -19945,12 +20154,13 @@ var TechnologyService = class extends BaseService {
|
|
|
19945
20154
|
(0, import_firestore61.orderBy)("name")
|
|
19946
20155
|
);
|
|
19947
20156
|
const snapshot = await (0, import_firestore61.getDocs)(q);
|
|
19948
|
-
|
|
20157
|
+
const technologies = snapshot.docs.map(
|
|
19949
20158
|
(doc45) => ({
|
|
19950
20159
|
id: doc45.id,
|
|
19951
20160
|
...doc45.data()
|
|
19952
20161
|
})
|
|
19953
20162
|
);
|
|
20163
|
+
return this.filterExcludedTechnologies(technologies);
|
|
19954
20164
|
}
|
|
19955
20165
|
/**
|
|
19956
20166
|
* Gets all active technologies for filter dropdowns.
|
|
@@ -19962,12 +20172,13 @@ var TechnologyService = class extends BaseService {
|
|
|
19962
20172
|
(0, import_firestore61.orderBy)("name")
|
|
19963
20173
|
);
|
|
19964
20174
|
const snapshot = await (0, import_firestore61.getDocs)(q);
|
|
19965
|
-
|
|
20175
|
+
const technologies = snapshot.docs.map(
|
|
19966
20176
|
(doc45) => ({
|
|
19967
20177
|
id: doc45.id,
|
|
19968
20178
|
...doc45.data()
|
|
19969
20179
|
})
|
|
19970
20180
|
);
|
|
20181
|
+
return this.filterExcludedTechnologies(technologies);
|
|
19971
20182
|
}
|
|
19972
20183
|
// ==========================================
|
|
19973
20184
|
// NEW METHODS: Product assignment management
|
|
@@ -20133,6 +20344,7 @@ var TechnologyService = class extends BaseService {
|
|
|
20133
20344
|
const snapshot = await (0, import_firestore61.getDocs)(q);
|
|
20134
20345
|
if (snapshot.empty) break;
|
|
20135
20346
|
for (const d of snapshot.docs) {
|
|
20347
|
+
if (d.id === EXCLUDED_TECHNOLOGY_ID) continue;
|
|
20136
20348
|
const technology = { id: d.id, ...d.data() };
|
|
20137
20349
|
const productNames = await this.getProductNamesForTechnology(technology.id);
|
|
20138
20350
|
rows.push(this.technologyToCsvRow(technology, productNames));
|