@blackcode_sa/metaestetics-api 1.12.68 → 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/index.d.mts +21 -2
- package/dist/index.d.ts +21 -2
- package/dist/index.js +128 -16
- package/dist/index.mjs +128 -16
- 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/services/appointment/appointment.service.ts +59 -6
- package/src/services/procedure/procedure.service.ts +117 -4
- 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(
|
package/dist/index.mjs
CHANGED
|
@@ -56,13 +56,13 @@ var AppointmentStatus = /* @__PURE__ */ ((AppointmentStatus2) => {
|
|
|
56
56
|
AppointmentStatus2["RESCHEDULED_BY_CLINIC"] = "rescheduled_by_clinic";
|
|
57
57
|
return AppointmentStatus2;
|
|
58
58
|
})(AppointmentStatus || {});
|
|
59
|
-
var PaymentStatus = /* @__PURE__ */ ((
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return
|
|
59
|
+
var PaymentStatus = /* @__PURE__ */ ((PaymentStatus3) => {
|
|
60
|
+
PaymentStatus3["UNPAID"] = "unpaid";
|
|
61
|
+
PaymentStatus3["PAID"] = "paid";
|
|
62
|
+
PaymentStatus3["PARTIALLY_PAID"] = "partially_paid";
|
|
63
|
+
PaymentStatus3["REFUNDED"] = "refunded";
|
|
64
|
+
PaymentStatus3["NOT_APPLICABLE"] = "not_applicable";
|
|
65
|
+
return PaymentStatus3;
|
|
66
66
|
})(PaymentStatus || {});
|
|
67
67
|
var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
68
68
|
MediaType2["BEFORE_PHOTO"] = "before_photo";
|
|
@@ -3329,6 +3329,7 @@ var AppointmentService = class extends BaseService {
|
|
|
3329
3329
|
finalbilling: null,
|
|
3330
3330
|
finalizationNotes: null
|
|
3331
3331
|
};
|
|
3332
|
+
const shouldUpdatePaymentStatus = finalbilling.finalPrice > 0 && appointment.paymentStatus === "not_applicable" /* NOT_APPLICABLE */;
|
|
3332
3333
|
const updateData = {
|
|
3333
3334
|
metadata: {
|
|
3334
3335
|
selectedZones: currentMetadata.selectedZones,
|
|
@@ -3344,6 +3345,9 @@ var AppointmentService = class extends BaseService {
|
|
|
3344
3345
|
finalbilling,
|
|
3345
3346
|
finalizationNotes: currentMetadata.finalizationNotes
|
|
3346
3347
|
},
|
|
3348
|
+
...shouldUpdatePaymentStatus && {
|
|
3349
|
+
paymentStatus: "unpaid" /* UNPAID */
|
|
3350
|
+
},
|
|
3347
3351
|
updatedAt: serverTimestamp7()
|
|
3348
3352
|
};
|
|
3349
3353
|
return await this.updateAppointment(appointmentId, updateData);
|
|
@@ -3557,8 +3561,36 @@ var AppointmentService = class extends BaseService {
|
|
|
3557
3561
|
showCanceled: false,
|
|
3558
3562
|
showNoShow: false
|
|
3559
3563
|
});
|
|
3564
|
+
const now = /* @__PURE__ */ new Date();
|
|
3565
|
+
const allPastAppointments = await this.getPatientAppointments(patientId, {
|
|
3566
|
+
endDate: now,
|
|
3567
|
+
status: [
|
|
3568
|
+
"completed" /* COMPLETED */,
|
|
3569
|
+
"confirmed" /* CONFIRMED */,
|
|
3570
|
+
"checked_in" /* CHECKED_IN */,
|
|
3571
|
+
"in_progress" /* IN_PROGRESS */
|
|
3572
|
+
]
|
|
3573
|
+
});
|
|
3574
|
+
const appointmentsWithRecommendations = allPastAppointments.appointments.filter(
|
|
3575
|
+
(appointment) => {
|
|
3576
|
+
var _a2, _b2, _c2, _d;
|
|
3577
|
+
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;
|
|
3578
|
+
if (!endTime) return false;
|
|
3579
|
+
const isPastEndTime = endTime < now.getTime();
|
|
3580
|
+
const hasRecommendations = (((_d = (_c2 = appointment.metadata) == null ? void 0 : _c2.recommendedProcedures) == null ? void 0 : _d.length) || 0) > 0;
|
|
3581
|
+
return isPastEndTime && hasRecommendations;
|
|
3582
|
+
}
|
|
3583
|
+
);
|
|
3584
|
+
const allAppointmentsMap = /* @__PURE__ */ new Map();
|
|
3585
|
+
pastAppointments.appointments.forEach((apt) => {
|
|
3586
|
+
allAppointmentsMap.set(apt.id, apt);
|
|
3587
|
+
});
|
|
3588
|
+
appointmentsWithRecommendations.forEach((apt) => {
|
|
3589
|
+
allAppointmentsMap.set(apt.id, apt);
|
|
3590
|
+
});
|
|
3591
|
+
const allAppointments = Array.from(allAppointmentsMap.values());
|
|
3560
3592
|
const recommendations = [];
|
|
3561
|
-
for (const appointment of
|
|
3593
|
+
for (const appointment of allAppointments) {
|
|
3562
3594
|
if ((options == null ? void 0 : options.clinicBranchId) && appointment.clinicBranchId !== options.clinicBranchId) {
|
|
3563
3595
|
continue;
|
|
3564
3596
|
}
|
|
@@ -3595,9 +3627,6 @@ var AppointmentService = class extends BaseService {
|
|
|
3595
3627
|
return dateB - dateA;
|
|
3596
3628
|
});
|
|
3597
3629
|
const limitedRecommendations = (options == null ? void 0 : options.limit) ? recommendations.slice(0, options.limit) : recommendations;
|
|
3598
|
-
console.log(
|
|
3599
|
-
`[APPOINTMENT_SERVICE] Found ${limitedRecommendations.length} next steps recommendations for patient ${patientId}`
|
|
3600
|
-
);
|
|
3601
3630
|
return limitedRecommendations;
|
|
3602
3631
|
} catch (error) {
|
|
3603
3632
|
console.error(
|
|
@@ -3885,6 +3914,7 @@ var NotificationType = /* @__PURE__ */ ((NotificationType3) => {
|
|
|
3885
3914
|
NotificationType3["FORM_REMINDER"] = "formReminder";
|
|
3886
3915
|
NotificationType3["FORM_SUBMISSION_CONFIRMATION"] = "formSubmissionConfirmation";
|
|
3887
3916
|
NotificationType3["REVIEW_REQUEST"] = "reviewRequest";
|
|
3917
|
+
NotificationType3["PROCEDURE_RECOMMENDATION"] = "procedureRecommendation";
|
|
3888
3918
|
NotificationType3["PAYMENT_DUE"] = "paymentDue";
|
|
3889
3919
|
NotificationType3["PAYMENT_CONFIRMATION"] = "paymentConfirmation";
|
|
3890
3920
|
NotificationType3["PAYMENT_FAILED"] = "paymentFailed";
|
|
@@ -17739,6 +17769,10 @@ var ProcedureService = class extends BaseService {
|
|
|
17739
17769
|
console.log("[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search");
|
|
17740
17770
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
17741
17771
|
const constraints = getBaseConstraints();
|
|
17772
|
+
const hasNestedFilters = !!(filters.procedureTechnology || filters.procedureCategory || filters.procedureSubcategory);
|
|
17773
|
+
if (hasNestedFilters) {
|
|
17774
|
+
console.log("[PROCEDURE_SERVICE] Strategy 1: Has nested filters, will apply client-side after query");
|
|
17775
|
+
}
|
|
17742
17776
|
constraints.push(where31("nameLower", ">=", searchTerm));
|
|
17743
17777
|
constraints.push(where31("nameLower", "<=", searchTerm + "\uF8FF"));
|
|
17744
17778
|
constraints.push(orderBy18("nameLower"));
|
|
@@ -17754,9 +17788,12 @@ var ProcedureService = class extends BaseService {
|
|
|
17754
17788
|
constraints.push(limit16(filters.pagination || 10));
|
|
17755
17789
|
const q = query31(collection31(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
17756
17790
|
const querySnapshot = await getDocs31(q);
|
|
17757
|
-
|
|
17791
|
+
let procedures = querySnapshot.docs.map(
|
|
17758
17792
|
(doc45) => ({ ...doc45.data(), id: doc45.id })
|
|
17759
17793
|
);
|
|
17794
|
+
if (hasNestedFilters) {
|
|
17795
|
+
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
17796
|
+
}
|
|
17760
17797
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
17761
17798
|
console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
|
|
17762
17799
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -17772,6 +17809,10 @@ var ProcedureService = class extends BaseService {
|
|
|
17772
17809
|
console.log("[PROCEDURE_SERVICE] Strategy 2: Trying name field search");
|
|
17773
17810
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
17774
17811
|
const constraints = getBaseConstraints();
|
|
17812
|
+
const hasNestedFilters = !!(filters.procedureTechnology || filters.procedureCategory || filters.procedureSubcategory);
|
|
17813
|
+
if (hasNestedFilters) {
|
|
17814
|
+
console.log("[PROCEDURE_SERVICE] Strategy 2: Has nested filters, will apply client-side after query");
|
|
17815
|
+
}
|
|
17775
17816
|
constraints.push(where31("name", ">=", searchTerm));
|
|
17776
17817
|
constraints.push(where31("name", "<=", searchTerm + "\uF8FF"));
|
|
17777
17818
|
constraints.push(orderBy18("name"));
|
|
@@ -17787,9 +17828,12 @@ var ProcedureService = class extends BaseService {
|
|
|
17787
17828
|
constraints.push(limit16(filters.pagination || 10));
|
|
17788
17829
|
const q = query31(collection31(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
17789
17830
|
const querySnapshot = await getDocs31(q);
|
|
17790
|
-
|
|
17831
|
+
let procedures = querySnapshot.docs.map(
|
|
17791
17832
|
(doc45) => ({ ...doc45.data(), id: doc45.id })
|
|
17792
17833
|
);
|
|
17834
|
+
if (hasNestedFilters) {
|
|
17835
|
+
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
17836
|
+
}
|
|
17793
17837
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
17794
17838
|
console.log(`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`);
|
|
17795
17839
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -17802,9 +17846,47 @@ var ProcedureService = class extends BaseService {
|
|
|
17802
17846
|
}
|
|
17803
17847
|
try {
|
|
17804
17848
|
console.log(
|
|
17805
|
-
"[PROCEDURE_SERVICE] Strategy 3: Using createdAt orderBy with client-side filtering"
|
|
17849
|
+
"[PROCEDURE_SERVICE] Strategy 3: Using createdAt orderBy with client-side filtering",
|
|
17850
|
+
{
|
|
17851
|
+
procedureTechnology: filters.procedureTechnology,
|
|
17852
|
+
hasTechnologyFilter: !!filters.procedureTechnology
|
|
17853
|
+
}
|
|
17854
|
+
);
|
|
17855
|
+
const constraints = [];
|
|
17856
|
+
if (filters.isActive !== void 0) {
|
|
17857
|
+
constraints.push(where31("isActive", "==", filters.isActive));
|
|
17858
|
+
} else {
|
|
17859
|
+
constraints.push(where31("isActive", "==", true));
|
|
17860
|
+
}
|
|
17861
|
+
if (filters.procedureFamily) {
|
|
17862
|
+
constraints.push(where31("family", "==", filters.procedureFamily));
|
|
17863
|
+
}
|
|
17864
|
+
if (filters.practitionerId) {
|
|
17865
|
+
constraints.push(where31("practitionerId", "==", filters.practitionerId));
|
|
17866
|
+
}
|
|
17867
|
+
if (filters.clinicId) {
|
|
17868
|
+
constraints.push(where31("clinicBranchId", "==", filters.clinicId));
|
|
17869
|
+
}
|
|
17870
|
+
if (filters.minPrice !== void 0) {
|
|
17871
|
+
constraints.push(where31("price", ">=", filters.minPrice));
|
|
17872
|
+
}
|
|
17873
|
+
if (filters.maxPrice !== void 0) {
|
|
17874
|
+
constraints.push(where31("price", "<=", filters.maxPrice));
|
|
17875
|
+
}
|
|
17876
|
+
if (filters.minRating !== void 0) {
|
|
17877
|
+
constraints.push(where31("reviewInfo.averageRating", ">=", filters.minRating));
|
|
17878
|
+
}
|
|
17879
|
+
if (filters.maxRating !== void 0) {
|
|
17880
|
+
constraints.push(where31("reviewInfo.averageRating", "<=", filters.maxRating));
|
|
17881
|
+
}
|
|
17882
|
+
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
17883
|
+
const benefitIdsToMatch = filters.treatmentBenefits;
|
|
17884
|
+
constraints.push(where31("treatmentBenefitIds", "array-contains-any", benefitIdsToMatch));
|
|
17885
|
+
}
|
|
17886
|
+
console.log(
|
|
17887
|
+
"[PROCEDURE_SERVICE] Strategy 3 Firestore constraints (nested filters excluded):",
|
|
17888
|
+
constraints.map((c) => c.fieldPath || "unknown")
|
|
17806
17889
|
);
|
|
17807
|
-
const constraints = getBaseConstraints();
|
|
17808
17890
|
constraints.push(orderBy18("createdAt", "desc"));
|
|
17809
17891
|
if (filters.lastDoc) {
|
|
17810
17892
|
if (typeof filters.lastDoc.data === "function") {
|
|
@@ -17821,7 +17903,20 @@ var ProcedureService = class extends BaseService {
|
|
|
17821
17903
|
let procedures = querySnapshot.docs.map(
|
|
17822
17904
|
(doc45) => ({ ...doc45.data(), id: doc45.id })
|
|
17823
17905
|
);
|
|
17906
|
+
console.log("[PROCEDURE_SERVICE] Before applyInMemoryFilters (Strategy 3):", {
|
|
17907
|
+
procedureCount: procedures.length,
|
|
17908
|
+
procedureTechnology: filters.procedureTechnology,
|
|
17909
|
+
filtersObject: {
|
|
17910
|
+
procedureTechnology: filters.procedureTechnology,
|
|
17911
|
+
procedureFamily: filters.procedureFamily,
|
|
17912
|
+
procedureCategory: filters.procedureCategory,
|
|
17913
|
+
procedureSubcategory: filters.procedureSubcategory
|
|
17914
|
+
}
|
|
17915
|
+
});
|
|
17824
17916
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
17917
|
+
console.log("[PROCEDURE_SERVICE] After applyInMemoryFilters (Strategy 3):", {
|
|
17918
|
+
procedureCount: procedures.length
|
|
17919
|
+
});
|
|
17825
17920
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
17826
17921
|
console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
|
|
17827
17922
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -17872,6 +17967,12 @@ var ProcedureService = class extends BaseService {
|
|
|
17872
17967
|
*/
|
|
17873
17968
|
applyInMemoryFilters(procedures, filters) {
|
|
17874
17969
|
let filteredProcedures = [...procedures];
|
|
17970
|
+
console.log("[PROCEDURE_SERVICE] applyInMemoryFilters called:", {
|
|
17971
|
+
procedureCount: procedures.length,
|
|
17972
|
+
procedureTechnology: filters.procedureTechnology,
|
|
17973
|
+
hasTechnologyFilter: !!filters.procedureTechnology,
|
|
17974
|
+
allFilterKeys: Object.keys(filters).filter((k) => filters[k] !== void 0 && filters[k] !== null)
|
|
17975
|
+
});
|
|
17875
17976
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
17876
17977
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
17877
17978
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
@@ -17947,6 +18048,7 @@ var ProcedureService = class extends BaseService {
|
|
|
17947
18048
|
);
|
|
17948
18049
|
}
|
|
17949
18050
|
if (filters.procedureTechnology) {
|
|
18051
|
+
const beforeCount = filteredProcedures.length;
|
|
17950
18052
|
filteredProcedures = filteredProcedures.filter(
|
|
17951
18053
|
(procedure) => {
|
|
17952
18054
|
var _a;
|
|
@@ -17954,8 +18056,18 @@ var ProcedureService = class extends BaseService {
|
|
|
17954
18056
|
}
|
|
17955
18057
|
);
|
|
17956
18058
|
console.log(
|
|
17957
|
-
`[PROCEDURE_SERVICE] Applied technology filter,
|
|
18059
|
+
`[PROCEDURE_SERVICE] Applied technology filter (${filters.procedureTechnology}), before: ${beforeCount}, after: ${filteredProcedures.length}`
|
|
17958
18060
|
);
|
|
18061
|
+
if (beforeCount > filteredProcedures.length) {
|
|
18062
|
+
const filteredOut = procedures.filter((p) => {
|
|
18063
|
+
var _a;
|
|
18064
|
+
return ((_a = p.technology) == null ? void 0 : _a.id) !== filters.procedureTechnology;
|
|
18065
|
+
}).slice(0, 3).map((p) => {
|
|
18066
|
+
var _a;
|
|
18067
|
+
return { id: p.id, techId: (_a = p.technology) == null ? void 0 : _a.id, name: p.name };
|
|
18068
|
+
});
|
|
18069
|
+
console.log("[PROCEDURE_SERVICE] Filtered out sample procedures:", filteredOut);
|
|
18070
|
+
}
|
|
17959
18071
|
}
|
|
17960
18072
|
if (filters.practitionerId) {
|
|
17961
18073
|
filteredProcedures = filteredProcedures.filter(
|
package/package.json
CHANGED