@blackcode_sa/metaestetics-api 1.15.14 → 1.15.17
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 +377 -222
- package/dist/admin/index.d.ts +377 -222
- package/dist/admin/index.js +625 -206
- package/dist/admin/index.mjs +624 -206
- package/dist/backoffice/index.d.mts +24 -0
- package/dist/backoffice/index.d.ts +24 -0
- package/dist/index.d.mts +376 -9
- package/dist/index.d.ts +376 -9
- package/dist/index.js +2228 -1581
- package/dist/index.mjs +1544 -892
- package/package.json +1 -1
- package/src/admin/aggregation/appointment/README.md +24 -2
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +46 -0
- package/src/admin/booking/README.md +61 -2
- package/src/admin/booking/booking.admin.ts +257 -0
- package/src/admin/booking/booking.calculator.ts +139 -1
- package/src/admin/booking/booking.types.ts +17 -0
- package/src/admin/calendar/README.md +56 -1
- package/src/admin/calendar/index.ts +1 -0
- package/src/admin/calendar/resource-calendar.admin.ts +198 -0
- package/src/config/index.ts +1 -0
- package/src/config/tiers.config.ts +121 -5
- package/src/services/index.ts +1 -0
- package/src/services/plan-config.service.ts +55 -0
- package/src/services/resource/README.md +119 -0
- package/src/services/resource/index.ts +1 -0
- package/src/services/resource/resource.service.ts +555 -0
- package/src/services/tier-enforcement.ts +16 -11
- package/src/types/appointment/index.ts +7 -0
- package/src/types/calendar/index.ts +1 -0
- package/src/types/clinic/index.ts +1 -0
- package/src/types/clinic/rbac.types.ts +3 -2
- package/src/types/index.ts +6 -0
- package/src/types/procedure/index.ts +6 -0
- package/src/types/resource/README.md +153 -0
- package/src/types/resource/index.ts +199 -0
- package/src/types/system/index.ts +1 -0
- package/src/types/system/planConfig.types.ts +86 -0
- package/src/validations/README.md +94 -0
- package/src/validations/index.ts +1 -0
- package/src/validations/procedure.schema.ts +12 -0
- package/src/validations/resource.schema.ts +57 -0
package/dist/admin/index.js
CHANGED
|
@@ -262,6 +262,7 @@ __export(index_exports, {
|
|
|
262
262
|
PractitionerTokenStatus: () => PractitionerTokenStatus,
|
|
263
263
|
ProcedureAggregationService: () => ProcedureAggregationService,
|
|
264
264
|
REVENUE_ANALYTICS_SUBCOLLECTION: () => REVENUE_ANALYTICS_SUBCOLLECTION,
|
|
265
|
+
ResourceCalendarAdminService: () => ResourceCalendarAdminService,
|
|
265
266
|
ReviewsAggregationService: () => ReviewsAggregationService,
|
|
266
267
|
SubscriptionStatus: () => SubscriptionStatus,
|
|
267
268
|
TIME_EFFICIENCY_ANALYTICS_SUBCOLLECTION: () => TIME_EFFICIENCY_ANALYTICS_SUBCOLLECTION,
|
|
@@ -498,6 +499,7 @@ var BillingTransactionType = /* @__PURE__ */ ((BillingTransactionType2) => {
|
|
|
498
499
|
BillingTransactionType2["SUBSCRIPTION_CANCELED"] = "subscription_canceled";
|
|
499
500
|
BillingTransactionType2["SUBSCRIPTION_REACTIVATED"] = "subscription_reactivated";
|
|
500
501
|
BillingTransactionType2["SUBSCRIPTION_DELETED"] = "subscription_deleted";
|
|
502
|
+
BillingTransactionType2["ADDON_PURCHASED"] = "addon_purchased";
|
|
501
503
|
return BillingTransactionType2;
|
|
502
504
|
})(BillingTransactionType || {});
|
|
503
505
|
|
|
@@ -601,7 +603,7 @@ var PatientRequirementOverallStatus = /* @__PURE__ */ ((PatientRequirementOveral
|
|
|
601
603
|
var PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME = "patientRequirements";
|
|
602
604
|
|
|
603
605
|
// src/admin/aggregation/appointment/appointment.aggregation.service.ts
|
|
604
|
-
var
|
|
606
|
+
var admin7 = __toESM(require("firebase-admin"));
|
|
605
607
|
|
|
606
608
|
// src/backoffice/types/requirement.types.ts
|
|
607
609
|
var REQUIREMENTS_COLLECTION = "backoffice_requirements";
|
|
@@ -620,6 +622,11 @@ var DOCUMENTATION_TEMPLATES_COLLECTION = "documentation-templates";
|
|
|
620
622
|
var USER_FORMS_SUBCOLLECTION = "user-forms";
|
|
621
623
|
var DOCTOR_FORMS_SUBCOLLECTION = "doctor-forms";
|
|
622
624
|
|
|
625
|
+
// src/types/resource/index.ts
|
|
626
|
+
var RESOURCES_COLLECTION = "resources";
|
|
627
|
+
var RESOURCE_INSTANCES_SUBCOLLECTION = "instances";
|
|
628
|
+
var RESOURCE_CALENDAR_SUBCOLLECTION = "calendar";
|
|
629
|
+
|
|
623
630
|
// src/types/reviews/index.ts
|
|
624
631
|
var REVIEWS_COLLECTION = "reviews";
|
|
625
632
|
|
|
@@ -698,9 +705,9 @@ var Logger = class {
|
|
|
698
705
|
|
|
699
706
|
// src/admin/notifications/notifications.admin.ts
|
|
700
707
|
var NotificationsAdmin = class {
|
|
701
|
-
constructor(
|
|
708
|
+
constructor(firestore20) {
|
|
702
709
|
this.expo = new import_expo_server_sdk.Expo();
|
|
703
|
-
this.db =
|
|
710
|
+
this.db = firestore20 || admin2.firestore();
|
|
704
711
|
}
|
|
705
712
|
/**
|
|
706
713
|
* Dohvata notifikaciju po ID-u
|
|
@@ -1292,8 +1299,8 @@ var NotificationsAdmin = class {
|
|
|
1292
1299
|
|
|
1293
1300
|
// src/admin/requirements/patient-requirements.admin.service.ts
|
|
1294
1301
|
var PatientRequirementsAdminService = class {
|
|
1295
|
-
constructor(
|
|
1296
|
-
this.db =
|
|
1302
|
+
constructor(firestore20) {
|
|
1303
|
+
this.db = firestore20 || admin3.firestore();
|
|
1297
1304
|
this.notificationsAdmin = new NotificationsAdmin(this.db);
|
|
1298
1305
|
}
|
|
1299
1306
|
/**
|
|
@@ -1621,8 +1628,8 @@ var PatientRequirementsAdminService = class {
|
|
|
1621
1628
|
// src/admin/calendar/calendar.admin.service.ts
|
|
1622
1629
|
var admin4 = __toESM(require("firebase-admin"));
|
|
1623
1630
|
var CalendarAdminService = class {
|
|
1624
|
-
constructor(
|
|
1625
|
-
this.db =
|
|
1631
|
+
constructor(firestore20) {
|
|
1632
|
+
this.db = firestore20 || admin4.firestore();
|
|
1626
1633
|
Logger.info("[CalendarAdminService] Initialized.");
|
|
1627
1634
|
}
|
|
1628
1635
|
/**
|
|
@@ -1896,11 +1903,163 @@ var CalendarAdminService = class {
|
|
|
1896
1903
|
}
|
|
1897
1904
|
};
|
|
1898
1905
|
|
|
1906
|
+
// src/admin/calendar/resource-calendar.admin.ts
|
|
1907
|
+
var admin5 = __toESM(require("firebase-admin"));
|
|
1908
|
+
var ResourceCalendarAdminService = class {
|
|
1909
|
+
constructor(firestore20) {
|
|
1910
|
+
this.db = firestore20 || admin5.firestore();
|
|
1911
|
+
Logger.info("[ResourceCalendarAdminService] Initialized.");
|
|
1912
|
+
}
|
|
1913
|
+
/**
|
|
1914
|
+
* Builds the Firestore document path for a resource calendar event.
|
|
1915
|
+
*/
|
|
1916
|
+
getResourceCalendarEventPath(clinicBranchId, booking) {
|
|
1917
|
+
return `${CLINICS_COLLECTION}/${clinicBranchId}/${RESOURCES_COLLECTION}/${booking.resourceId}/${RESOURCE_INSTANCES_SUBCOLLECTION}/${booking.resourceInstanceId}/${RESOURCE_CALENDAR_SUBCOLLECTION}/${booking.calendarEventId}`;
|
|
1918
|
+
}
|
|
1919
|
+
/**
|
|
1920
|
+
* Updates the status of all resource calendar events associated with a given appointment.
|
|
1921
|
+
*
|
|
1922
|
+
* @param appointment - The appointment object containing resourceBookings.
|
|
1923
|
+
* @param newStatus - The new CalendarEventStatus to set.
|
|
1924
|
+
*/
|
|
1925
|
+
async updateResourceBookingEventsStatus(appointment, newStatus) {
|
|
1926
|
+
const resourceBookings = appointment.resourceBookings;
|
|
1927
|
+
if (!resourceBookings || resourceBookings.length === 0) {
|
|
1928
|
+
Logger.debug(
|
|
1929
|
+
`[ResourceCalendarAdminService] No resource bookings on appointment ${appointment.id}, skipping status update.`
|
|
1930
|
+
);
|
|
1931
|
+
return;
|
|
1932
|
+
}
|
|
1933
|
+
Logger.info(
|
|
1934
|
+
`[ResourceCalendarAdminService] Updating ${resourceBookings.length} resource calendar event(s) to ${newStatus} for appointment ${appointment.id}`
|
|
1935
|
+
);
|
|
1936
|
+
const batch = this.db.batch();
|
|
1937
|
+
const serverTimestamp = admin5.firestore.FieldValue.serverTimestamp();
|
|
1938
|
+
for (const booking of resourceBookings) {
|
|
1939
|
+
const eventPath = this.getResourceCalendarEventPath(
|
|
1940
|
+
appointment.clinicBranchId,
|
|
1941
|
+
booking
|
|
1942
|
+
);
|
|
1943
|
+
const eventRef = this.db.doc(eventPath);
|
|
1944
|
+
batch.update(eventRef, {
|
|
1945
|
+
status: newStatus,
|
|
1946
|
+
updatedAt: serverTimestamp
|
|
1947
|
+
});
|
|
1948
|
+
Logger.debug(
|
|
1949
|
+
`[ResourceCalendarAdminService] Added status update for resource event ${booking.calendarEventId} (${booking.resourceName} / ${booking.resourceInstanceLabel})`
|
|
1950
|
+
);
|
|
1951
|
+
}
|
|
1952
|
+
try {
|
|
1953
|
+
await batch.commit();
|
|
1954
|
+
Logger.info(
|
|
1955
|
+
`[ResourceCalendarAdminService] Successfully updated ${resourceBookings.length} resource calendar event statuses for appointment ${appointment.id}.`
|
|
1956
|
+
);
|
|
1957
|
+
} catch (error) {
|
|
1958
|
+
Logger.error(
|
|
1959
|
+
`[ResourceCalendarAdminService] Error updating resource calendar event statuses for appointment ${appointment.id}:`,
|
|
1960
|
+
error
|
|
1961
|
+
);
|
|
1962
|
+
throw error;
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
/**
|
|
1966
|
+
* Updates the eventTime (start and end) of all resource calendar events
|
|
1967
|
+
* associated with a given appointment.
|
|
1968
|
+
*
|
|
1969
|
+
* @param appointment - The appointment object containing resourceBookings.
|
|
1970
|
+
* @param newEventTime - The new event time with admin Timestamps.
|
|
1971
|
+
*/
|
|
1972
|
+
async updateResourceBookingEventsTime(appointment, newEventTime) {
|
|
1973
|
+
const resourceBookings = appointment.resourceBookings;
|
|
1974
|
+
if (!resourceBookings || resourceBookings.length === 0) {
|
|
1975
|
+
Logger.debug(
|
|
1976
|
+
`[ResourceCalendarAdminService] No resource bookings on appointment ${appointment.id}, skipping time update.`
|
|
1977
|
+
);
|
|
1978
|
+
return;
|
|
1979
|
+
}
|
|
1980
|
+
Logger.info(
|
|
1981
|
+
`[ResourceCalendarAdminService] Updating ${resourceBookings.length} resource calendar event time(s) for appointment ${appointment.id}`
|
|
1982
|
+
);
|
|
1983
|
+
const batch = this.db.batch();
|
|
1984
|
+
const serverTimestamp = admin5.firestore.FieldValue.serverTimestamp();
|
|
1985
|
+
for (const booking of resourceBookings) {
|
|
1986
|
+
const eventPath = this.getResourceCalendarEventPath(
|
|
1987
|
+
appointment.clinicBranchId,
|
|
1988
|
+
booking
|
|
1989
|
+
);
|
|
1990
|
+
const eventRef = this.db.doc(eventPath);
|
|
1991
|
+
batch.update(eventRef, {
|
|
1992
|
+
eventTime: {
|
|
1993
|
+
start: newEventTime.start,
|
|
1994
|
+
end: newEventTime.end
|
|
1995
|
+
},
|
|
1996
|
+
updatedAt: serverTimestamp
|
|
1997
|
+
});
|
|
1998
|
+
Logger.debug(
|
|
1999
|
+
`[ResourceCalendarAdminService] Added time update for resource event ${booking.calendarEventId} (${booking.resourceName} / ${booking.resourceInstanceLabel})`
|
|
2000
|
+
);
|
|
2001
|
+
}
|
|
2002
|
+
try {
|
|
2003
|
+
await batch.commit();
|
|
2004
|
+
Logger.info(
|
|
2005
|
+
`[ResourceCalendarAdminService] Successfully updated ${resourceBookings.length} resource calendar event times for appointment ${appointment.id}.`
|
|
2006
|
+
);
|
|
2007
|
+
} catch (error) {
|
|
2008
|
+
Logger.error(
|
|
2009
|
+
`[ResourceCalendarAdminService] Error updating resource calendar event times for appointment ${appointment.id}:`,
|
|
2010
|
+
error
|
|
2011
|
+
);
|
|
2012
|
+
throw error;
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
/**
|
|
2016
|
+
* Deletes all resource calendar events associated with a given appointment.
|
|
2017
|
+
*
|
|
2018
|
+
* @param appointment - The appointment object containing resourceBookings.
|
|
2019
|
+
*/
|
|
2020
|
+
async deleteResourceBookingEvents(appointment) {
|
|
2021
|
+
const resourceBookings = appointment.resourceBookings;
|
|
2022
|
+
if (!resourceBookings || resourceBookings.length === 0) {
|
|
2023
|
+
Logger.debug(
|
|
2024
|
+
`[ResourceCalendarAdminService] No resource bookings on appointment ${appointment.id}, skipping deletion.`
|
|
2025
|
+
);
|
|
2026
|
+
return;
|
|
2027
|
+
}
|
|
2028
|
+
Logger.info(
|
|
2029
|
+
`[ResourceCalendarAdminService] Deleting ${resourceBookings.length} resource calendar event(s) for appointment ${appointment.id}`
|
|
2030
|
+
);
|
|
2031
|
+
const batch = this.db.batch();
|
|
2032
|
+
for (const booking of resourceBookings) {
|
|
2033
|
+
const eventPath = this.getResourceCalendarEventPath(
|
|
2034
|
+
appointment.clinicBranchId,
|
|
2035
|
+
booking
|
|
2036
|
+
);
|
|
2037
|
+
const eventRef = this.db.doc(eventPath);
|
|
2038
|
+
batch.delete(eventRef);
|
|
2039
|
+
Logger.debug(
|
|
2040
|
+
`[ResourceCalendarAdminService] Added deletion for resource event ${booking.calendarEventId} (${booking.resourceName} / ${booking.resourceInstanceLabel})`
|
|
2041
|
+
);
|
|
2042
|
+
}
|
|
2043
|
+
try {
|
|
2044
|
+
await batch.commit();
|
|
2045
|
+
Logger.info(
|
|
2046
|
+
`[ResourceCalendarAdminService] Successfully deleted ${resourceBookings.length} resource calendar events for appointment ${appointment.id}.`
|
|
2047
|
+
);
|
|
2048
|
+
} catch (error) {
|
|
2049
|
+
Logger.error(
|
|
2050
|
+
`[ResourceCalendarAdminService] Error deleting resource calendar events for appointment ${appointment.id}:`,
|
|
2051
|
+
error
|
|
2052
|
+
);
|
|
2053
|
+
throw error;
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
};
|
|
2057
|
+
|
|
1899
2058
|
// src/admin/mailing/appointment/appointment.mailing.service.ts
|
|
1900
2059
|
var import_luxon = require("luxon");
|
|
1901
2060
|
|
|
1902
2061
|
// src/admin/mailing/base.mailing.service.ts
|
|
1903
|
-
var
|
|
2062
|
+
var admin6 = __toESM(require("firebase-admin"));
|
|
1904
2063
|
var BaseMailingService = class {
|
|
1905
2064
|
// Expecting the new mailgun.js client
|
|
1906
2065
|
/**
|
|
@@ -1908,9 +2067,9 @@ var BaseMailingService = class {
|
|
|
1908
2067
|
* @param firestore Firestore instance provided by the caller
|
|
1909
2068
|
* @param mailgunClient Mailgun client instance (mailgun.js v10+) provided by the caller
|
|
1910
2069
|
*/
|
|
1911
|
-
constructor(
|
|
2070
|
+
constructor(firestore20, mailgunClient) {
|
|
1912
2071
|
var _a;
|
|
1913
|
-
this.db =
|
|
2072
|
+
this.db = firestore20;
|
|
1914
2073
|
this.mailgunClient = mailgunClient;
|
|
1915
2074
|
if (!this.db) {
|
|
1916
2075
|
Logger.error("[BaseMailingService] No Firestore instance provided");
|
|
@@ -2010,7 +2169,7 @@ var BaseMailingService = class {
|
|
|
2010
2169
|
status: error.status,
|
|
2011
2170
|
stack: error.stack
|
|
2012
2171
|
} : null,
|
|
2013
|
-
sentAt:
|
|
2172
|
+
sentAt: admin6.firestore.FieldValue.serverTimestamp()
|
|
2014
2173
|
});
|
|
2015
2174
|
Logger.info(
|
|
2016
2175
|
`[BaseMailingService] Email log recorded. Success: ${success}`
|
|
@@ -2717,8 +2876,8 @@ var appointmentRescheduledProposalTemplate = `
|
|
|
2717
2876
|
</html>
|
|
2718
2877
|
`;
|
|
2719
2878
|
var AppointmentMailingService = class extends BaseMailingService {
|
|
2720
|
-
constructor(
|
|
2721
|
-
super(
|
|
2879
|
+
constructor(firestore20, mailgunClient) {
|
|
2880
|
+
super(firestore20, mailgunClient);
|
|
2722
2881
|
this.DEFAULT_MAILGUN_DOMAIN = "mg.metaesthetics.net";
|
|
2723
2882
|
Logger.info("[AppointmentMailingService] Initialized.");
|
|
2724
2883
|
}
|
|
@@ -3158,8 +3317,8 @@ var AppointmentAggregationService = class {
|
|
|
3158
3317
|
* @param mailgunClient - An initialized Mailgun client instance.
|
|
3159
3318
|
* @param firestore Optional Firestore instance. If not provided, it uses the default admin SDK instance.
|
|
3160
3319
|
*/
|
|
3161
|
-
constructor(mailgunClient,
|
|
3162
|
-
this.db =
|
|
3320
|
+
constructor(mailgunClient, firestore20) {
|
|
3321
|
+
this.db = firestore20 || admin7.firestore();
|
|
3163
3322
|
this.appointmentMailingService = new AppointmentMailingService(
|
|
3164
3323
|
this.db,
|
|
3165
3324
|
mailgunClient
|
|
@@ -3167,6 +3326,7 @@ var AppointmentAggregationService = class {
|
|
|
3167
3326
|
);
|
|
3168
3327
|
this.notificationsAdmin = new NotificationsAdmin(this.db);
|
|
3169
3328
|
this.calendarAdminService = new CalendarAdminService(this.db);
|
|
3329
|
+
this.resourceCalendarAdminService = new ResourceCalendarAdminService(this.db);
|
|
3170
3330
|
this.patientRequirementsAdminService = new PatientRequirementsAdminService(this.db);
|
|
3171
3331
|
Logger.info("[AppointmentAggregationService] Initialized.");
|
|
3172
3332
|
}
|
|
@@ -3308,6 +3468,10 @@ var AppointmentAggregationService = class {
|
|
|
3308
3468
|
after,
|
|
3309
3469
|
"confirmed" /* CONFIRMED */
|
|
3310
3470
|
);
|
|
3471
|
+
await this.resourceCalendarAdminService.updateResourceBookingEventsStatus(
|
|
3472
|
+
after,
|
|
3473
|
+
"confirmed" /* CONFIRMED */
|
|
3474
|
+
);
|
|
3311
3475
|
if ((patientSensitiveInfo == null ? void 0 : patientSensitiveInfo.email) && patientProfile) {
|
|
3312
3476
|
Logger.info(
|
|
3313
3477
|
`[AggService] Sending appointment confirmed email to patient ${patientSensitiveInfo.email}`
|
|
@@ -3358,6 +3522,10 @@ var AppointmentAggregationService = class {
|
|
|
3358
3522
|
after,
|
|
3359
3523
|
"confirmed" /* CONFIRMED */
|
|
3360
3524
|
);
|
|
3525
|
+
await this.resourceCalendarAdminService.updateResourceBookingEventsStatus(
|
|
3526
|
+
after,
|
|
3527
|
+
"confirmed" /* CONFIRMED */
|
|
3528
|
+
);
|
|
3361
3529
|
if ((patientSensitiveInfo == null ? void 0 : patientSensitiveInfo.email) && patientProfile) {
|
|
3362
3530
|
Logger.info(
|
|
3363
3531
|
`[AggService] Sending appointment confirmed email to patient ${patientSensitiveInfo.email}`
|
|
@@ -3425,6 +3593,10 @@ var AppointmentAggregationService = class {
|
|
|
3425
3593
|
after,
|
|
3426
3594
|
calendarStatus(after.status)
|
|
3427
3595
|
);
|
|
3596
|
+
await this.resourceCalendarAdminService.updateResourceBookingEventsStatus(
|
|
3597
|
+
after,
|
|
3598
|
+
calendarStatus(after.status)
|
|
3599
|
+
);
|
|
3428
3600
|
if ((patientSensitiveInfo == null ? void 0 : patientSensitiveInfo.email) && patientProfile) {
|
|
3429
3601
|
Logger.info(
|
|
3430
3602
|
`[AggService] Sending appointment cancellation email to patient ${patientSensitiveInfo.email}`
|
|
@@ -3471,6 +3643,10 @@ var AppointmentAggregationService = class {
|
|
|
3471
3643
|
after,
|
|
3472
3644
|
"completed" /* COMPLETED */
|
|
3473
3645
|
);
|
|
3646
|
+
await this.resourceCalendarAdminService.updateResourceBookingEventsStatus(
|
|
3647
|
+
after,
|
|
3648
|
+
"completed" /* COMPLETED */
|
|
3649
|
+
);
|
|
3474
3650
|
if ((patientSensitiveInfo == null ? void 0 : patientSensitiveInfo.email) && patientProfile) {
|
|
3475
3651
|
Logger.info(
|
|
3476
3652
|
`[AggService] Sending review request email to patient ${patientSensitiveInfo.email}`
|
|
@@ -3501,6 +3677,14 @@ var AppointmentAggregationService = class {
|
|
|
3501
3677
|
after,
|
|
3502
3678
|
"pending" /* PENDING */
|
|
3503
3679
|
);
|
|
3680
|
+
await this.resourceCalendarAdminService.updateResourceBookingEventsTime(after, {
|
|
3681
|
+
start: after.appointmentStartTime,
|
|
3682
|
+
end: after.appointmentEndTime
|
|
3683
|
+
});
|
|
3684
|
+
await this.resourceCalendarAdminService.updateResourceBookingEventsStatus(
|
|
3685
|
+
after,
|
|
3686
|
+
"pending" /* PENDING */
|
|
3687
|
+
);
|
|
3504
3688
|
if ((patientSensitiveInfo == null ? void 0 : patientSensitiveInfo.email) && patientProfile) {
|
|
3505
3689
|
Logger.info(
|
|
3506
3690
|
`[AggService] Sending reschedule proposal email to patient ${patientSensitiveInfo.email}`
|
|
@@ -3544,6 +3728,10 @@ var AppointmentAggregationService = class {
|
|
|
3544
3728
|
start: after.appointmentStartTime,
|
|
3545
3729
|
end: after.appointmentEndTime
|
|
3546
3730
|
});
|
|
3731
|
+
await this.resourceCalendarAdminService.updateResourceBookingEventsTime(after, {
|
|
3732
|
+
start: after.appointmentStartTime,
|
|
3733
|
+
end: after.appointmentEndTime
|
|
3734
|
+
});
|
|
3547
3735
|
} else {
|
|
3548
3736
|
Logger.warn(
|
|
3549
3737
|
`[AggService] Independent time change detected for ${after.id} with status ${after.status}. Review implications for requirements and calendar.`
|
|
@@ -3588,6 +3776,7 @@ var AppointmentAggregationService = class {
|
|
|
3588
3776
|
);
|
|
3589
3777
|
}
|
|
3590
3778
|
await this.calendarAdminService.deleteAppointmentCalendarEvents(deletedAppointment);
|
|
3779
|
+
await this.resourceCalendarAdminService.deleteResourceBookingEvents(deletedAppointment);
|
|
3591
3780
|
}
|
|
3592
3781
|
// --- Helper Methods for Aggregation Logic ---
|
|
3593
3782
|
/**
|
|
@@ -3679,7 +3868,7 @@ var AppointmentAggregationService = class {
|
|
|
3679
3868
|
} else if (template.timeframe.unit === "hours" /* HOURS */) {
|
|
3680
3869
|
dueDateTime.setHours(dueDateTime.getHours() - notifyAtValue);
|
|
3681
3870
|
}
|
|
3682
|
-
dueTime =
|
|
3871
|
+
dueTime = admin7.firestore.Timestamp.fromDate(dueDateTime);
|
|
3683
3872
|
}
|
|
3684
3873
|
const actionableWindowHours = template.importance === "high" ? 1 : template.importance === "medium" ? 4 : 15;
|
|
3685
3874
|
const instructionObject = {
|
|
@@ -3694,7 +3883,7 @@ var AppointmentAggregationService = class {
|
|
|
3694
3883
|
status: "pendingNotification" /* PENDING_NOTIFICATION */,
|
|
3695
3884
|
originalNotifyAtValue: notifyAtValue,
|
|
3696
3885
|
originalTimeframeUnit: template.timeframe.unit,
|
|
3697
|
-
updatedAt:
|
|
3886
|
+
updatedAt: admin7.firestore.Timestamp.now()
|
|
3698
3887
|
// Use current server timestamp
|
|
3699
3888
|
};
|
|
3700
3889
|
return instructionObject;
|
|
@@ -3713,8 +3902,8 @@ var AppointmentAggregationService = class {
|
|
|
3713
3902
|
overallStatus: "active" /* ACTIVE */,
|
|
3714
3903
|
instructions,
|
|
3715
3904
|
// Timestamps - cast to any to satisfy client-side Timestamp type for now
|
|
3716
|
-
createdAt:
|
|
3717
|
-
updatedAt:
|
|
3905
|
+
createdAt: admin7.firestore.FieldValue.serverTimestamp(),
|
|
3906
|
+
updatedAt: admin7.firestore.FieldValue.serverTimestamp()
|
|
3718
3907
|
};
|
|
3719
3908
|
Logger.debug(
|
|
3720
3909
|
`[AggService] Setting data for requirement: ${JSON.stringify({
|
|
@@ -4064,7 +4253,7 @@ var AppointmentAggregationService = class {
|
|
|
4064
4253
|
} else if (template.timeframe.unit === "hours" /* HOURS */) {
|
|
4065
4254
|
dueDateTime.setHours(dueDateTime.getHours() + notifyAtValue);
|
|
4066
4255
|
}
|
|
4067
|
-
dueTime =
|
|
4256
|
+
dueTime = admin7.firestore.Timestamp.fromDate(dueDateTime);
|
|
4068
4257
|
}
|
|
4069
4258
|
const actionableWindowHours = template.importance === "high" ? 1 : template.importance === "medium" ? 4 : 15;
|
|
4070
4259
|
const instructionObject = {
|
|
@@ -4078,7 +4267,7 @@ var AppointmentAggregationService = class {
|
|
|
4078
4267
|
status: "pendingNotification" /* PENDING_NOTIFICATION */,
|
|
4079
4268
|
originalNotifyAtValue: notifyAtValue,
|
|
4080
4269
|
originalTimeframeUnit: template.timeframe.unit,
|
|
4081
|
-
updatedAt:
|
|
4270
|
+
updatedAt: admin7.firestore.Timestamp.now(),
|
|
4082
4271
|
notificationId: void 0,
|
|
4083
4272
|
actionTakenAt: void 0
|
|
4084
4273
|
};
|
|
@@ -4097,8 +4286,8 @@ var AppointmentAggregationService = class {
|
|
|
4097
4286
|
instructions,
|
|
4098
4287
|
sourceProcedures: reqWithSource.sourceProcedures,
|
|
4099
4288
|
// Track which procedures this requirement comes from
|
|
4100
|
-
createdAt:
|
|
4101
|
-
updatedAt:
|
|
4289
|
+
createdAt: admin7.firestore.FieldValue.serverTimestamp(),
|
|
4290
|
+
updatedAt: admin7.firestore.FieldValue.serverTimestamp()
|
|
4102
4291
|
};
|
|
4103
4292
|
Logger.debug(
|
|
4104
4293
|
`[AggService] Setting data for requirement: ${JSON.stringify({
|
|
@@ -4258,7 +4447,7 @@ var AppointmentAggregationService = class {
|
|
|
4258
4447
|
if (instance.overallStatus !== newOverallStatus && instance.overallStatus !== "failedToProcess" /* FAILED_TO_PROCESS */) {
|
|
4259
4448
|
batch.update(doc3.ref, {
|
|
4260
4449
|
overallStatus: newOverallStatus,
|
|
4261
|
-
updatedAt:
|
|
4450
|
+
updatedAt: admin7.firestore.FieldValue.serverTimestamp()
|
|
4262
4451
|
// Cast for now
|
|
4263
4452
|
// Potentially also cancel individual instructions if not handled by another trigger
|
|
4264
4453
|
// instructions: instance.instructions.map(instr => ({ ...instr, status: PatientInstructionStatus.CANCELLED, updatedAt: admin.firestore.FieldValue.serverTimestamp() as any }))
|
|
@@ -4334,17 +4523,17 @@ var AppointmentAggregationService = class {
|
|
|
4334
4523
|
if (!hasDoctor || !hasClinic) {
|
|
4335
4524
|
const patientRef = this.db.collection(PATIENTS_COLLECTION).doc(patientProfile.id);
|
|
4336
4525
|
const updateData = {
|
|
4337
|
-
updatedAt:
|
|
4526
|
+
updatedAt: admin7.firestore.FieldValue.serverTimestamp()
|
|
4338
4527
|
};
|
|
4339
4528
|
if (!hasDoctor) {
|
|
4340
4529
|
Logger.debug(
|
|
4341
4530
|
`[AggService] Adding practitioner ${practitionerId} to patient ${patientProfile.id}`
|
|
4342
4531
|
);
|
|
4343
|
-
updateData.doctorIds =
|
|
4532
|
+
updateData.doctorIds = admin7.firestore.FieldValue.arrayUnion(practitionerId);
|
|
4344
4533
|
}
|
|
4345
4534
|
if (!hasClinic) {
|
|
4346
4535
|
Logger.debug(`[AggService] Adding clinic ${clinicId} to patient ${patientProfile.id}`);
|
|
4347
|
-
updateData.clinicIds =
|
|
4536
|
+
updateData.clinicIds = admin7.firestore.FieldValue.arrayUnion(clinicId);
|
|
4348
4537
|
}
|
|
4349
4538
|
await patientRef.update(updateData);
|
|
4350
4539
|
Logger.info(
|
|
@@ -4394,16 +4583,16 @@ var AppointmentAggregationService = class {
|
|
|
4394
4583
|
Logger.debug(
|
|
4395
4584
|
`[AggService] Removing practitioner ${practitionerId} from patient ${patientProfile.id}`
|
|
4396
4585
|
);
|
|
4397
|
-
updateData.doctorIds =
|
|
4586
|
+
updateData.doctorIds = admin7.firestore.FieldValue.arrayRemove(practitionerId);
|
|
4398
4587
|
updateNeeded = true;
|
|
4399
4588
|
}
|
|
4400
4589
|
if (activeClinicAppointments === 0 && ((_b = patientProfile.clinicIds) == null ? void 0 : _b.includes(clinicId))) {
|
|
4401
4590
|
Logger.debug(`[AggService] Removing clinic ${clinicId} from patient ${patientProfile.id}`);
|
|
4402
|
-
updateData.clinicIds =
|
|
4591
|
+
updateData.clinicIds = admin7.firestore.FieldValue.arrayRemove(clinicId);
|
|
4403
4592
|
updateNeeded = true;
|
|
4404
4593
|
}
|
|
4405
4594
|
if (updateNeeded) {
|
|
4406
|
-
updateData.updatedAt =
|
|
4595
|
+
updateData.updatedAt = admin7.firestore.FieldValue.serverTimestamp();
|
|
4407
4596
|
await patientRef.update(updateData);
|
|
4408
4597
|
Logger.info(`[AggService] Successfully removed links from patient ${patientProfile.id}`);
|
|
4409
4598
|
} else {
|
|
@@ -4694,7 +4883,7 @@ var AppointmentAggregationService = class {
|
|
|
4694
4883
|
userId: after.patientId,
|
|
4695
4884
|
userRole: "patient" /* PATIENT */,
|
|
4696
4885
|
notificationType: "procedureRecommendation" /* PROCEDURE_RECOMMENDATION */,
|
|
4697
|
-
notificationTime:
|
|
4886
|
+
notificationTime: admin7.firestore.Timestamp.now(),
|
|
4698
4887
|
notificationTokens: (patientProfile == null ? void 0 : patientProfile.expoTokens) || [],
|
|
4699
4888
|
title: "New Procedure Recommendation",
|
|
4700
4889
|
body: `${((_c = after.practitionerInfo) == null ? void 0 : _c.name) || "Your doctor"} recommended "${recommendation.procedure.procedureName}" for you. Suggested timeframe: in ${timeframeText}`,
|
|
@@ -4740,15 +4929,15 @@ var AppointmentAggregationService = class {
|
|
|
4740
4929
|
};
|
|
4741
4930
|
|
|
4742
4931
|
// src/admin/aggregation/clinic/clinic.aggregation.service.ts
|
|
4743
|
-
var
|
|
4932
|
+
var admin8 = __toESM(require("firebase-admin"));
|
|
4744
4933
|
var CALENDAR_SUBCOLLECTION_ID = "calendar";
|
|
4745
4934
|
var ClinicAggregationService = class {
|
|
4746
4935
|
/**
|
|
4747
4936
|
* Constructor for ClinicAggregationService.
|
|
4748
4937
|
* @param firestore Optional Firestore instance. If not provided, it uses the default admin SDK instance.
|
|
4749
4938
|
*/
|
|
4750
|
-
constructor(
|
|
4751
|
-
this.db =
|
|
4939
|
+
constructor(firestore20) {
|
|
4940
|
+
this.db = firestore20 || admin8.firestore();
|
|
4752
4941
|
}
|
|
4753
4942
|
/**
|
|
4754
4943
|
* Adds clinic information to a clinic group when a new clinic is created
|
|
@@ -4771,9 +4960,9 @@ var ClinicAggregationService = class {
|
|
|
4771
4960
|
);
|
|
4772
4961
|
try {
|
|
4773
4962
|
await groupRef.update({
|
|
4774
|
-
clinicsInfo:
|
|
4775
|
-
clinicIds:
|
|
4776
|
-
updatedAt:
|
|
4963
|
+
clinicsInfo: admin8.firestore.FieldValue.arrayUnion(clinicInfo),
|
|
4964
|
+
clinicIds: admin8.firestore.FieldValue.arrayUnion(clinicId),
|
|
4965
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
4777
4966
|
});
|
|
4778
4967
|
console.log(
|
|
4779
4968
|
`[ClinicAggregationService] Successfully added ClinicInfo (ID: ${clinicId}) to Clinic Group ${clinicGroupId}.`
|
|
@@ -4818,7 +5007,7 @@ var ClinicAggregationService = class {
|
|
|
4818
5007
|
const updatedClinicsInfo = [...filteredClinicsInfo, clinicInfo];
|
|
4819
5008
|
batch.update(practitionerRef, {
|
|
4820
5009
|
clinicsInfo: updatedClinicsInfo,
|
|
4821
|
-
updatedAt:
|
|
5010
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
4822
5011
|
});
|
|
4823
5012
|
}
|
|
4824
5013
|
}
|
|
@@ -4856,7 +5045,7 @@ var ClinicAggregationService = class {
|
|
|
4856
5045
|
const procedureRef = this.db.collection(PROCEDURES_COLLECTION).doc(procedureId);
|
|
4857
5046
|
batch.update(procedureRef, {
|
|
4858
5047
|
clinicInfo,
|
|
4859
|
-
updatedAt:
|
|
5048
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
4860
5049
|
});
|
|
4861
5050
|
}
|
|
4862
5051
|
try {
|
|
@@ -4900,7 +5089,7 @@ var ClinicAggregationService = class {
|
|
|
4900
5089
|
const updatedClinicsInfo = [...filteredClinicsInfo, clinicInfo];
|
|
4901
5090
|
await groupRef.update({
|
|
4902
5091
|
clinicsInfo: updatedClinicsInfo,
|
|
4903
|
-
updatedAt:
|
|
5092
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
4904
5093
|
});
|
|
4905
5094
|
console.log(
|
|
4906
5095
|
`[ClinicAggregationService] Successfully updated ClinicInfo (ID: ${clinicId}) in Clinic Group ${clinicGroupId}.`
|
|
@@ -4959,7 +5148,7 @@ var ClinicAggregationService = class {
|
|
|
4959
5148
|
console.log(
|
|
4960
5149
|
`[ClinicAggregationService] Querying upcoming calendar events via collection group '${CALENDAR_SUBCOLLECTION_ID}' for clinic ${clinicId} to update location.`
|
|
4961
5150
|
);
|
|
4962
|
-
const now =
|
|
5151
|
+
const now = admin8.firestore.Timestamp.now();
|
|
4963
5152
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID).where("clinicBranchId", "==", clinicId).where("eventTime.start", ">", now);
|
|
4964
5153
|
try {
|
|
4965
5154
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -4976,7 +5165,7 @@ var ClinicAggregationService = class {
|
|
|
4976
5165
|
);
|
|
4977
5166
|
batch.update(doc3.ref, {
|
|
4978
5167
|
eventLocation: newLocation,
|
|
4979
|
-
updatedAt:
|
|
5168
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
4980
5169
|
});
|
|
4981
5170
|
});
|
|
4982
5171
|
await batch.commit();
|
|
@@ -5006,7 +5195,7 @@ var ClinicAggregationService = class {
|
|
|
5006
5195
|
console.log(
|
|
5007
5196
|
`[ClinicAggregationService] Querying upcoming calendar events for clinic ${clinicId} to update clinic info.`
|
|
5008
5197
|
);
|
|
5009
|
-
const now =
|
|
5198
|
+
const now = admin8.firestore.Timestamp.now();
|
|
5010
5199
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID).where("clinicBranchId", "==", clinicId).where("eventTime.start", ">", now);
|
|
5011
5200
|
try {
|
|
5012
5201
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -5023,7 +5212,7 @@ var ClinicAggregationService = class {
|
|
|
5023
5212
|
);
|
|
5024
5213
|
batch.update(doc3.ref, {
|
|
5025
5214
|
clinicInfo,
|
|
5026
|
-
updatedAt:
|
|
5215
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5027
5216
|
});
|
|
5028
5217
|
});
|
|
5029
5218
|
await batch.commit();
|
|
@@ -5072,7 +5261,7 @@ var ClinicAggregationService = class {
|
|
|
5072
5261
|
batch.update(practitionerRef, {
|
|
5073
5262
|
clinics: filteredClinicIds,
|
|
5074
5263
|
clinicsInfo: filteredClinicsInfo,
|
|
5075
|
-
updatedAt:
|
|
5264
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5076
5265
|
});
|
|
5077
5266
|
if (checkAndDeactivateDoctors) {
|
|
5078
5267
|
practitionersToCheck.push(practitionerId);
|
|
@@ -5124,7 +5313,7 @@ var ClinicAggregationService = class {
|
|
|
5124
5313
|
);
|
|
5125
5314
|
batch.update(practitionerRef, {
|
|
5126
5315
|
isActive: false,
|
|
5127
|
-
updatedAt:
|
|
5316
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5128
5317
|
});
|
|
5129
5318
|
deactivationCount++;
|
|
5130
5319
|
} else {
|
|
@@ -5146,7 +5335,7 @@ var ClinicAggregationService = class {
|
|
|
5146
5335
|
);
|
|
5147
5336
|
batch.update(practitionerRef, {
|
|
5148
5337
|
isActive: false,
|
|
5149
|
-
updatedAt:
|
|
5338
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5150
5339
|
});
|
|
5151
5340
|
deactivationCount++;
|
|
5152
5341
|
}
|
|
@@ -5203,7 +5392,7 @@ var ClinicAggregationService = class {
|
|
|
5203
5392
|
);
|
|
5204
5393
|
batch.update(practitionerRef, {
|
|
5205
5394
|
isActive: true,
|
|
5206
|
-
updatedAt:
|
|
5395
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5207
5396
|
});
|
|
5208
5397
|
reactivationCount++;
|
|
5209
5398
|
} else {
|
|
@@ -5225,7 +5414,7 @@ var ClinicAggregationService = class {
|
|
|
5225
5414
|
);
|
|
5226
5415
|
batch.update(practitionerRef, {
|
|
5227
5416
|
isActive: true,
|
|
5228
|
-
updatedAt:
|
|
5417
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5229
5418
|
});
|
|
5230
5419
|
reactivationCount++;
|
|
5231
5420
|
}
|
|
@@ -5271,7 +5460,7 @@ var ClinicAggregationService = class {
|
|
|
5271
5460
|
const procedureRef = this.db.collection(PROCEDURES_COLLECTION).doc(procedureId);
|
|
5272
5461
|
batch.update(procedureRef, {
|
|
5273
5462
|
isActive: false,
|
|
5274
|
-
updatedAt:
|
|
5463
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5275
5464
|
});
|
|
5276
5465
|
}
|
|
5277
5466
|
try {
|
|
@@ -5310,7 +5499,7 @@ var ClinicAggregationService = class {
|
|
|
5310
5499
|
if (procedureDoc.exists) {
|
|
5311
5500
|
batch.update(procedureRef, {
|
|
5312
5501
|
isActive: true,
|
|
5313
|
-
updatedAt:
|
|
5502
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5314
5503
|
});
|
|
5315
5504
|
reactivationCount++;
|
|
5316
5505
|
} else {
|
|
@@ -5369,7 +5558,7 @@ var ClinicAggregationService = class {
|
|
|
5369
5558
|
await groupRef.update({
|
|
5370
5559
|
clinics: filteredClinicIds,
|
|
5371
5560
|
clinicsInfo: filteredClinicsInfo,
|
|
5372
|
-
updatedAt:
|
|
5561
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5373
5562
|
});
|
|
5374
5563
|
console.log(
|
|
5375
5564
|
`[ClinicAggregationService] Successfully removed Clinic (ID: ${clinicId}) from Clinic Group ${clinicGroupId}.`
|
|
@@ -5406,8 +5595,8 @@ var ClinicAggregationService = class {
|
|
|
5406
5595
|
for (const patientId of patientIds) {
|
|
5407
5596
|
const patientRef = this.db.collection(PATIENTS_COLLECTION).doc(patientId);
|
|
5408
5597
|
batch.update(patientRef, {
|
|
5409
|
-
clinicIds:
|
|
5410
|
-
updatedAt:
|
|
5598
|
+
clinicIds: admin8.firestore.FieldValue.arrayRemove(clinicId),
|
|
5599
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5411
5600
|
});
|
|
5412
5601
|
}
|
|
5413
5602
|
try {
|
|
@@ -5437,7 +5626,7 @@ var ClinicAggregationService = class {
|
|
|
5437
5626
|
console.log(
|
|
5438
5627
|
`[ClinicAggregationService] Querying upcoming calendar events for clinic ${clinicId} to cancel.`
|
|
5439
5628
|
);
|
|
5440
|
-
const now =
|
|
5629
|
+
const now = admin8.firestore.Timestamp.now();
|
|
5441
5630
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID).where("clinicBranchId", "==", clinicId).where("eventTime.start", ">", now);
|
|
5442
5631
|
try {
|
|
5443
5632
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -5455,7 +5644,7 @@ var ClinicAggregationService = class {
|
|
|
5455
5644
|
batch.update(doc3.ref, {
|
|
5456
5645
|
status: "CANCELED",
|
|
5457
5646
|
cancelReason: "Clinic deleted",
|
|
5458
|
-
updatedAt:
|
|
5647
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5459
5648
|
});
|
|
5460
5649
|
});
|
|
5461
5650
|
await batch.commit();
|
|
@@ -5473,14 +5662,14 @@ var ClinicAggregationService = class {
|
|
|
5473
5662
|
};
|
|
5474
5663
|
|
|
5475
5664
|
// src/admin/aggregation/forms/filled-forms.aggregation.service.ts
|
|
5476
|
-
var
|
|
5665
|
+
var admin9 = __toESM(require("firebase-admin"));
|
|
5477
5666
|
var FilledFormsAggregationService = class {
|
|
5478
5667
|
/**
|
|
5479
5668
|
* Constructor for FilledFormsAggregationService.
|
|
5480
5669
|
* @param firestore Optional Firestore instance. If not provided, it uses the default admin SDK instance.
|
|
5481
5670
|
*/
|
|
5482
|
-
constructor(
|
|
5483
|
-
this.db =
|
|
5671
|
+
constructor(firestore20) {
|
|
5672
|
+
this.db = firestore20 || admin9.firestore();
|
|
5484
5673
|
Logger.info("[FilledFormsAggregationService] Initialized");
|
|
5485
5674
|
}
|
|
5486
5675
|
/**
|
|
@@ -5539,12 +5728,12 @@ var FilledFormsAggregationService = class {
|
|
|
5539
5728
|
path: `${APPOINTMENTS_COLLECTION}/${filledDocument.appointmentId}/${formSubcollection}/${filledDocument.id}`
|
|
5540
5729
|
};
|
|
5541
5730
|
if (filledDocument.updatedAt) {
|
|
5542
|
-
linkedFormInfo.submittedAt =
|
|
5731
|
+
linkedFormInfo.submittedAt = admin9.firestore.Timestamp.fromMillis(
|
|
5543
5732
|
filledDocument.updatedAt
|
|
5544
5733
|
);
|
|
5545
5734
|
}
|
|
5546
5735
|
if (filledDocument.status === "completed" /* COMPLETED */ || filledDocument.status === "signed" /* SIGNED */) {
|
|
5547
|
-
linkedFormInfo.completedAt =
|
|
5736
|
+
linkedFormInfo.completedAt = admin9.firestore.Timestamp.fromMillis(
|
|
5548
5737
|
filledDocument.updatedAt
|
|
5549
5738
|
);
|
|
5550
5739
|
}
|
|
@@ -5558,7 +5747,7 @@ var FilledFormsAggregationService = class {
|
|
|
5558
5747
|
updatedLinkedForms.push(linkedFormInfo);
|
|
5559
5748
|
updateData = {
|
|
5560
5749
|
linkedForms: updatedLinkedForms,
|
|
5561
|
-
updatedAt:
|
|
5750
|
+
updatedAt: admin9.firestore.FieldValue.serverTimestamp()
|
|
5562
5751
|
};
|
|
5563
5752
|
let updatedLinkedFormIds = appointment.linkedFormIds || [];
|
|
5564
5753
|
if (!updatedLinkedFormIds.includes(filledDocument.id)) {
|
|
@@ -5567,7 +5756,7 @@ var FilledFormsAggregationService = class {
|
|
|
5567
5756
|
}
|
|
5568
5757
|
if (filledDocument.isUserForm && filledDocument.isRequired && (filledDocument.status === "completed" /* COMPLETED */ || filledDocument.status === "signed" /* SIGNED */)) {
|
|
5569
5758
|
if (appointment.pendingUserFormsIds && appointment.pendingUserFormsIds.includes(filledDocument.id)) {
|
|
5570
|
-
updateData.pendingUserFormsIds =
|
|
5759
|
+
updateData.pendingUserFormsIds = admin9.firestore.FieldValue.arrayRemove(
|
|
5571
5760
|
filledDocument.id
|
|
5572
5761
|
);
|
|
5573
5762
|
Logger.info(
|
|
@@ -5613,21 +5802,21 @@ var FilledFormsAggregationService = class {
|
|
|
5613
5802
|
(form) => form.formId === filledDocument.id
|
|
5614
5803
|
);
|
|
5615
5804
|
if (formToRemove) {
|
|
5616
|
-
updateData.linkedForms =
|
|
5805
|
+
updateData.linkedForms = admin9.firestore.FieldValue.arrayRemove(formToRemove);
|
|
5617
5806
|
}
|
|
5618
5807
|
}
|
|
5619
5808
|
if (appointment.linkedFormIds && appointment.linkedFormIds.includes(filledDocument.id)) {
|
|
5620
|
-
updateData.linkedFormIds =
|
|
5809
|
+
updateData.linkedFormIds = admin9.firestore.FieldValue.arrayRemove(filledDocument.id);
|
|
5621
5810
|
}
|
|
5622
5811
|
if (filledDocument.isUserForm && filledDocument.isRequired) {
|
|
5623
5812
|
if (filledDocument.status !== "completed" /* COMPLETED */ && filledDocument.status !== "signed" /* SIGNED */) {
|
|
5624
5813
|
if (!appointment.pendingUserFormsIds || !appointment.pendingUserFormsIds.includes(filledDocument.id)) {
|
|
5625
|
-
updateData.pendingUserFormsIds = appointment.pendingUserFormsIds ?
|
|
5814
|
+
updateData.pendingUserFormsIds = appointment.pendingUserFormsIds ? admin9.firestore.FieldValue.arrayUnion(filledDocument.id) : [filledDocument.id];
|
|
5626
5815
|
}
|
|
5627
5816
|
}
|
|
5628
5817
|
}
|
|
5629
5818
|
if (Object.keys(updateData).length > 0) {
|
|
5630
|
-
updateData.updatedAt =
|
|
5819
|
+
updateData.updatedAt = admin9.firestore.FieldValue.serverTimestamp();
|
|
5631
5820
|
await appointmentRef.update(updateData);
|
|
5632
5821
|
Logger.info(
|
|
5633
5822
|
`[FilledFormsAggregationService] Successfully updated appointment ${filledDocument.appointmentId} after form deletion`
|
|
@@ -5667,8 +5856,8 @@ var FilledFormsAggregationService = class {
|
|
|
5667
5856
|
return;
|
|
5668
5857
|
}
|
|
5669
5858
|
await appointmentRef.update({
|
|
5670
|
-
pendingUserFormsIds:
|
|
5671
|
-
updatedAt:
|
|
5859
|
+
pendingUserFormsIds: admin9.firestore.FieldValue.arrayUnion(filledDocument.id),
|
|
5860
|
+
updatedAt: admin9.firestore.FieldValue.serverTimestamp()
|
|
5672
5861
|
});
|
|
5673
5862
|
Logger.info(
|
|
5674
5863
|
`[FilledFormsAggregationService] Successfully added form ${filledDocument.id} to pendingUserFormsIds for appointment ${filledDocument.appointmentId}`
|
|
@@ -5684,11 +5873,11 @@ var FilledFormsAggregationService = class {
|
|
|
5684
5873
|
};
|
|
5685
5874
|
|
|
5686
5875
|
// src/admin/aggregation/patient/patient.aggregation.service.ts
|
|
5687
|
-
var
|
|
5876
|
+
var admin10 = __toESM(require("firebase-admin"));
|
|
5688
5877
|
var CALENDAR_SUBCOLLECTION_ID2 = "calendar";
|
|
5689
5878
|
var PatientAggregationService = class {
|
|
5690
|
-
constructor(
|
|
5691
|
-
this.db =
|
|
5879
|
+
constructor(firestore20) {
|
|
5880
|
+
this.db = firestore20 || admin10.firestore();
|
|
5692
5881
|
}
|
|
5693
5882
|
// --- Methods for Patient Creation --- >
|
|
5694
5883
|
// No specific aggregations defined for patient creation in the plan.
|
|
@@ -5709,7 +5898,7 @@ var PatientAggregationService = class {
|
|
|
5709
5898
|
console.log(
|
|
5710
5899
|
`[PatientAggregationService] Querying upcoming calendar events for patient ${patientId} to update patient info.`
|
|
5711
5900
|
);
|
|
5712
|
-
const now =
|
|
5901
|
+
const now = admin10.firestore.Timestamp.now();
|
|
5713
5902
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID2).where("patientId", "==", patientId).where("eventTime.start", ">", now);
|
|
5714
5903
|
try {
|
|
5715
5904
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -5726,7 +5915,7 @@ var PatientAggregationService = class {
|
|
|
5726
5915
|
);
|
|
5727
5916
|
batch.update(doc3.ref, {
|
|
5728
5917
|
patientInfo,
|
|
5729
|
-
updatedAt:
|
|
5918
|
+
updatedAt: admin10.firestore.FieldValue.serverTimestamp()
|
|
5730
5919
|
});
|
|
5731
5920
|
});
|
|
5732
5921
|
await batch.commit();
|
|
@@ -5757,7 +5946,7 @@ var PatientAggregationService = class {
|
|
|
5757
5946
|
console.log(
|
|
5758
5947
|
`[PatientAggregationService] Querying upcoming calendar events for patient ${patientId} to cancel.`
|
|
5759
5948
|
);
|
|
5760
|
-
const now =
|
|
5949
|
+
const now = admin10.firestore.Timestamp.now();
|
|
5761
5950
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID2).where("patientId", "==", patientId).where("eventTime.start", ">", now);
|
|
5762
5951
|
try {
|
|
5763
5952
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -5775,7 +5964,7 @@ var PatientAggregationService = class {
|
|
|
5775
5964
|
batch.update(doc3.ref, {
|
|
5776
5965
|
status: "CANCELED",
|
|
5777
5966
|
cancelReason: "Patient deleted",
|
|
5778
|
-
updatedAt:
|
|
5967
|
+
updatedAt: admin10.firestore.FieldValue.serverTimestamp()
|
|
5779
5968
|
});
|
|
5780
5969
|
});
|
|
5781
5970
|
await batch.commit();
|
|
@@ -5793,11 +5982,11 @@ var PatientAggregationService = class {
|
|
|
5793
5982
|
};
|
|
5794
5983
|
|
|
5795
5984
|
// src/admin/aggregation/practitioner/practitioner.aggregation.service.ts
|
|
5796
|
-
var
|
|
5985
|
+
var admin11 = __toESM(require("firebase-admin"));
|
|
5797
5986
|
var CALENDAR_SUBCOLLECTION_ID3 = "calendar";
|
|
5798
5987
|
var PractitionerAggregationService = class {
|
|
5799
|
-
constructor(
|
|
5800
|
-
this.db =
|
|
5988
|
+
constructor(firestore20) {
|
|
5989
|
+
this.db = firestore20 || admin11.firestore();
|
|
5801
5990
|
}
|
|
5802
5991
|
/**
|
|
5803
5992
|
* Adds practitioner information to a clinic when a new practitioner is created
|
|
@@ -5819,9 +6008,9 @@ var PractitionerAggregationService = class {
|
|
|
5819
6008
|
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
5820
6009
|
try {
|
|
5821
6010
|
await clinicRef.update({
|
|
5822
|
-
doctors:
|
|
5823
|
-
doctorsInfo:
|
|
5824
|
-
updatedAt:
|
|
6011
|
+
doctors: admin11.firestore.FieldValue.arrayUnion(practitionerId),
|
|
6012
|
+
doctorsInfo: admin11.firestore.FieldValue.arrayUnion(doctorInfo),
|
|
6013
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
5825
6014
|
});
|
|
5826
6015
|
console.log(
|
|
5827
6016
|
`[PractitionerAggregationService] Successfully added practitioner ${practitionerId} to clinic ${clinicId}.`
|
|
@@ -5855,14 +6044,14 @@ var PractitionerAggregationService = class {
|
|
|
5855
6044
|
for (const clinicId of clinicIds) {
|
|
5856
6045
|
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
5857
6046
|
batch.update(clinicRef, {
|
|
5858
|
-
doctorsInfo:
|
|
6047
|
+
doctorsInfo: admin11.firestore.FieldValue.arrayRemove({
|
|
5859
6048
|
id: practitionerId
|
|
5860
6049
|
}),
|
|
5861
|
-
updatedAt:
|
|
6050
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
5862
6051
|
});
|
|
5863
6052
|
batch.update(clinicRef, {
|
|
5864
|
-
doctorsInfo:
|
|
5865
|
-
updatedAt:
|
|
6053
|
+
doctorsInfo: admin11.firestore.FieldValue.arrayUnion(doctorInfo),
|
|
6054
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
5866
6055
|
});
|
|
5867
6056
|
}
|
|
5868
6057
|
try {
|
|
@@ -5900,7 +6089,7 @@ var PractitionerAggregationService = class {
|
|
|
5900
6089
|
const procedureRef = this.db.collection(PROCEDURES_COLLECTION).doc(procedureId);
|
|
5901
6090
|
batch.update(procedureRef, {
|
|
5902
6091
|
doctorInfo,
|
|
5903
|
-
updatedAt:
|
|
6092
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
5904
6093
|
});
|
|
5905
6094
|
}
|
|
5906
6095
|
try {
|
|
@@ -5932,7 +6121,7 @@ var PractitionerAggregationService = class {
|
|
|
5932
6121
|
console.log(
|
|
5933
6122
|
`[PractitionerAggregationService] Querying upcoming calendar events for practitioner ${practitionerId} to update practitioner info.`
|
|
5934
6123
|
);
|
|
5935
|
-
const now =
|
|
6124
|
+
const now = admin11.firestore.Timestamp.now();
|
|
5936
6125
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID3).where("practitionerId", "==", practitionerId).where("eventTime.start", ">", now);
|
|
5937
6126
|
try {
|
|
5938
6127
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -5949,7 +6138,7 @@ var PractitionerAggregationService = class {
|
|
|
5949
6138
|
);
|
|
5950
6139
|
batch.update(doc3.ref, {
|
|
5951
6140
|
practitionerInfo,
|
|
5952
|
-
updatedAt:
|
|
6141
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
5953
6142
|
});
|
|
5954
6143
|
});
|
|
5955
6144
|
await batch.commit();
|
|
@@ -5984,12 +6173,12 @@ var PractitionerAggregationService = class {
|
|
|
5984
6173
|
for (const clinicId of clinicIds) {
|
|
5985
6174
|
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
5986
6175
|
batch.update(clinicRef, {
|
|
5987
|
-
doctors:
|
|
6176
|
+
doctors: admin11.firestore.FieldValue.arrayRemove(practitionerId),
|
|
5988
6177
|
// Remove all doctor info objects where id matches the practitioner ID
|
|
5989
|
-
doctorsInfo:
|
|
6178
|
+
doctorsInfo: admin11.firestore.FieldValue.arrayRemove({
|
|
5990
6179
|
id: practitionerId
|
|
5991
6180
|
}),
|
|
5992
|
-
updatedAt:
|
|
6181
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
5993
6182
|
});
|
|
5994
6183
|
}
|
|
5995
6184
|
try {
|
|
@@ -6020,7 +6209,7 @@ var PractitionerAggregationService = class {
|
|
|
6020
6209
|
console.log(
|
|
6021
6210
|
`[PractitionerAggregationService] Querying upcoming calendar events for practitioner ${practitionerId} to cancel.`
|
|
6022
6211
|
);
|
|
6023
|
-
const now =
|
|
6212
|
+
const now = admin11.firestore.Timestamp.now();
|
|
6024
6213
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID3).where("practitionerId", "==", practitionerId).where("eventTime.start", ">", now);
|
|
6025
6214
|
try {
|
|
6026
6215
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -6038,7 +6227,7 @@ var PractitionerAggregationService = class {
|
|
|
6038
6227
|
batch.update(doc3.ref, {
|
|
6039
6228
|
status: "CANCELED",
|
|
6040
6229
|
cancelReason: "Practitioner deleted",
|
|
6041
|
-
updatedAt:
|
|
6230
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
6042
6231
|
});
|
|
6043
6232
|
});
|
|
6044
6233
|
await batch.commit();
|
|
@@ -6073,8 +6262,8 @@ var PractitionerAggregationService = class {
|
|
|
6073
6262
|
for (const patientId of patientIds) {
|
|
6074
6263
|
const patientRef = this.db.collection(PATIENTS_COLLECTION).doc(patientId);
|
|
6075
6264
|
batch.update(patientRef, {
|
|
6076
|
-
doctorIds:
|
|
6077
|
-
updatedAt:
|
|
6265
|
+
doctorIds: admin11.firestore.FieldValue.arrayRemove(practitionerId),
|
|
6266
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
6078
6267
|
});
|
|
6079
6268
|
}
|
|
6080
6269
|
try {
|
|
@@ -6110,7 +6299,7 @@ var PractitionerAggregationService = class {
|
|
|
6110
6299
|
const procedureRef = this.db.collection(PROCEDURES_COLLECTION).doc(procedureId);
|
|
6111
6300
|
batch.update(procedureRef, {
|
|
6112
6301
|
isActive: false,
|
|
6113
|
-
updatedAt:
|
|
6302
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
6114
6303
|
});
|
|
6115
6304
|
}
|
|
6116
6305
|
try {
|
|
@@ -6129,15 +6318,15 @@ var PractitionerAggregationService = class {
|
|
|
6129
6318
|
};
|
|
6130
6319
|
|
|
6131
6320
|
// src/admin/aggregation/practitioner-invite/practitioner-invite.aggregation.service.ts
|
|
6132
|
-
var
|
|
6321
|
+
var admin12 = __toESM(require("firebase-admin"));
|
|
6133
6322
|
var PractitionerInviteAggregationService = class {
|
|
6134
6323
|
/**
|
|
6135
6324
|
* Constructor for PractitionerInviteAggregationService.
|
|
6136
6325
|
* @param firestore Optional Firestore instance. If not provided, it uses the default admin SDK instance.
|
|
6137
6326
|
* @param mailingService Optional mailing service for sending emails
|
|
6138
6327
|
*/
|
|
6139
|
-
constructor(
|
|
6140
|
-
this.db =
|
|
6328
|
+
constructor(firestore20, mailingService) {
|
|
6329
|
+
this.db = firestore20 || admin12.firestore();
|
|
6141
6330
|
this.mailingService = mailingService;
|
|
6142
6331
|
Logger.info("[PractitionerInviteAggregationService] Initialized.");
|
|
6143
6332
|
}
|
|
@@ -6434,9 +6623,9 @@ var PractitionerInviteAggregationService = class {
|
|
|
6434
6623
|
try {
|
|
6435
6624
|
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
6436
6625
|
await clinicRef.update({
|
|
6437
|
-
doctors:
|
|
6438
|
-
doctorsInfo:
|
|
6439
|
-
updatedAt:
|
|
6626
|
+
doctors: admin12.firestore.FieldValue.arrayUnion(doctorInfo.id),
|
|
6627
|
+
doctorsInfo: admin12.firestore.FieldValue.arrayUnion(doctorInfo),
|
|
6628
|
+
updatedAt: admin12.firestore.FieldValue.serverTimestamp()
|
|
6440
6629
|
});
|
|
6441
6630
|
Logger.info(
|
|
6442
6631
|
`[PractitionerInviteAggService] Successfully added practitioner ${doctorInfo.id} to clinic ${clinicId}`
|
|
@@ -6471,7 +6660,7 @@ var PractitionerInviteAggregationService = class {
|
|
|
6471
6660
|
const updatedDoctorsInfo = [...filteredDoctorsInfo, doctorInfo];
|
|
6472
6661
|
await clinicRef.update({
|
|
6473
6662
|
doctorsInfo: updatedDoctorsInfo,
|
|
6474
|
-
updatedAt:
|
|
6663
|
+
updatedAt: admin12.firestore.FieldValue.serverTimestamp()
|
|
6475
6664
|
});
|
|
6476
6665
|
Logger.info(
|
|
6477
6666
|
`[PractitionerInviteAggService] Successfully updated practitioner ${doctorInfo.id} info in clinic ${clinicId}`
|
|
@@ -6506,14 +6695,14 @@ var PractitionerInviteAggregationService = class {
|
|
|
6506
6695
|
clinicId: clinicInfo.id,
|
|
6507
6696
|
workingHours: invite.proposedWorkingHours,
|
|
6508
6697
|
isActive: true,
|
|
6509
|
-
createdAt:
|
|
6510
|
-
updatedAt:
|
|
6698
|
+
createdAt: admin12.firestore.Timestamp.now(),
|
|
6699
|
+
updatedAt: admin12.firestore.Timestamp.now()
|
|
6511
6700
|
};
|
|
6512
6701
|
await practitionerRef.update({
|
|
6513
|
-
clinics:
|
|
6514
|
-
clinicsInfo:
|
|
6515
|
-
clinicWorkingHours:
|
|
6516
|
-
updatedAt:
|
|
6702
|
+
clinics: admin12.firestore.FieldValue.arrayUnion(clinicInfo.id),
|
|
6703
|
+
clinicsInfo: admin12.firestore.FieldValue.arrayUnion(clinicInfo),
|
|
6704
|
+
clinicWorkingHours: admin12.firestore.FieldValue.arrayUnion(workingHours),
|
|
6705
|
+
updatedAt: admin12.firestore.FieldValue.serverTimestamp()
|
|
6517
6706
|
});
|
|
6518
6707
|
Logger.info(
|
|
6519
6708
|
`[PractitionerInviteAggService] Successfully added clinic ${clinicInfo.id} to practitioner ${practitionerId}`
|
|
@@ -6550,7 +6739,7 @@ var PractitionerInviteAggregationService = class {
|
|
|
6550
6739
|
...wh,
|
|
6551
6740
|
workingHours: invite.proposedWorkingHours,
|
|
6552
6741
|
isActive: true,
|
|
6553
|
-
updatedAt:
|
|
6742
|
+
updatedAt: admin12.firestore.Timestamp.now()
|
|
6554
6743
|
};
|
|
6555
6744
|
}
|
|
6556
6745
|
return wh;
|
|
@@ -6560,13 +6749,13 @@ var PractitionerInviteAggregationService = class {
|
|
|
6560
6749
|
clinicId: invite.clinicId,
|
|
6561
6750
|
workingHours: invite.proposedWorkingHours,
|
|
6562
6751
|
isActive: true,
|
|
6563
|
-
createdAt:
|
|
6564
|
-
updatedAt:
|
|
6752
|
+
createdAt: admin12.firestore.Timestamp.now(),
|
|
6753
|
+
updatedAt: admin12.firestore.Timestamp.now()
|
|
6565
6754
|
});
|
|
6566
6755
|
}
|
|
6567
6756
|
await practitionerRef.update({
|
|
6568
6757
|
clinicWorkingHours: updatedWorkingHours,
|
|
6569
|
-
updatedAt:
|
|
6758
|
+
updatedAt: admin12.firestore.FieldValue.serverTimestamp()
|
|
6570
6759
|
});
|
|
6571
6760
|
Logger.info(
|
|
6572
6761
|
`[PractitionerInviteAggService] Successfully updated working hours for practitioner ${practitionerId} at clinic ${invite.clinicId}`
|
|
@@ -6643,8 +6832,8 @@ var PractitionerInviteAggregationService = class {
|
|
|
6643
6832
|
var _a, _b, _c, _d, _e, _f;
|
|
6644
6833
|
if (!this.mailingService) return;
|
|
6645
6834
|
try {
|
|
6646
|
-
const
|
|
6647
|
-
if (!
|
|
6835
|
+
const admin20 = await this.fetchClinicAdminById(invite.invitedBy);
|
|
6836
|
+
if (!admin20) {
|
|
6648
6837
|
Logger.warn(
|
|
6649
6838
|
`[PractitionerInviteAggService] Admin ${invite.invitedBy} not found, using clinic contact email as fallback`
|
|
6650
6839
|
);
|
|
@@ -6682,7 +6871,7 @@ var PractitionerInviteAggregationService = class {
|
|
|
6682
6871
|
);
|
|
6683
6872
|
return;
|
|
6684
6873
|
}
|
|
6685
|
-
const adminName = `${
|
|
6874
|
+
const adminName = `${admin20.contactInfo.firstName} ${admin20.contactInfo.lastName}`;
|
|
6686
6875
|
const notificationData = {
|
|
6687
6876
|
invite,
|
|
6688
6877
|
practitioner: {
|
|
@@ -6698,7 +6887,7 @@ var PractitionerInviteAggregationService = class {
|
|
|
6698
6887
|
clinic: {
|
|
6699
6888
|
name: clinic.name,
|
|
6700
6889
|
adminName,
|
|
6701
|
-
adminEmail:
|
|
6890
|
+
adminEmail: admin20.contactInfo.email
|
|
6702
6891
|
// Use the specific admin's email
|
|
6703
6892
|
},
|
|
6704
6893
|
context: {
|
|
@@ -6734,8 +6923,8 @@ var PractitionerInviteAggregationService = class {
|
|
|
6734
6923
|
var _a, _b, _c, _d, _e, _f;
|
|
6735
6924
|
if (!this.mailingService) return;
|
|
6736
6925
|
try {
|
|
6737
|
-
const
|
|
6738
|
-
if (!
|
|
6926
|
+
const admin20 = await this.fetchClinicAdminById(invite.invitedBy);
|
|
6927
|
+
if (!admin20) {
|
|
6739
6928
|
Logger.warn(
|
|
6740
6929
|
`[PractitionerInviteAggService] Admin ${invite.invitedBy} not found, using clinic contact email as fallback`
|
|
6741
6930
|
);
|
|
@@ -6773,7 +6962,7 @@ var PractitionerInviteAggregationService = class {
|
|
|
6773
6962
|
);
|
|
6774
6963
|
return;
|
|
6775
6964
|
}
|
|
6776
|
-
const adminName = `${
|
|
6965
|
+
const adminName = `${admin20.contactInfo.firstName} ${admin20.contactInfo.lastName}`;
|
|
6777
6966
|
const notificationData = {
|
|
6778
6967
|
invite,
|
|
6779
6968
|
practitioner: {
|
|
@@ -6787,7 +6976,7 @@ var PractitionerInviteAggregationService = class {
|
|
|
6787
6976
|
clinic: {
|
|
6788
6977
|
name: clinic.name,
|
|
6789
6978
|
adminName,
|
|
6790
|
-
adminEmail:
|
|
6979
|
+
adminEmail: admin20.contactInfo.email
|
|
6791
6980
|
// Use the specific admin's email
|
|
6792
6981
|
},
|
|
6793
6982
|
context: {
|
|
@@ -6816,11 +7005,11 @@ var PractitionerInviteAggregationService = class {
|
|
|
6816
7005
|
};
|
|
6817
7006
|
|
|
6818
7007
|
// src/admin/aggregation/procedure/procedure.aggregation.service.ts
|
|
6819
|
-
var
|
|
7008
|
+
var admin13 = __toESM(require("firebase-admin"));
|
|
6820
7009
|
var CALENDAR_SUBCOLLECTION_ID4 = "calendar";
|
|
6821
7010
|
var ProcedureAggregationService = class {
|
|
6822
|
-
constructor(
|
|
6823
|
-
this.db =
|
|
7011
|
+
constructor(firestore20) {
|
|
7012
|
+
this.db = firestore20 || admin13.firestore();
|
|
6824
7013
|
}
|
|
6825
7014
|
/**
|
|
6826
7015
|
* Adds procedure information to a practitioner when a new procedure is created
|
|
@@ -6844,9 +7033,9 @@ var ProcedureAggregationService = class {
|
|
|
6844
7033
|
const practitionerRef = this.db.collection(PRACTITIONERS_COLLECTION).doc(practitionerId);
|
|
6845
7034
|
try {
|
|
6846
7035
|
const updateData = {
|
|
6847
|
-
procedureIds:
|
|
6848
|
-
proceduresInfo:
|
|
6849
|
-
updatedAt:
|
|
7036
|
+
procedureIds: admin13.firestore.FieldValue.arrayUnion(procedureId),
|
|
7037
|
+
proceduresInfo: admin13.firestore.FieldValue.arrayUnion(procedureSummary),
|
|
7038
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
6850
7039
|
};
|
|
6851
7040
|
if (isFreeConsultation) {
|
|
6852
7041
|
await this.db.runTransaction(async (transaction) => {
|
|
@@ -6909,9 +7098,9 @@ var ProcedureAggregationService = class {
|
|
|
6909
7098
|
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
6910
7099
|
try {
|
|
6911
7100
|
await clinicRef.update({
|
|
6912
|
-
procedures:
|
|
6913
|
-
proceduresInfo:
|
|
6914
|
-
updatedAt:
|
|
7101
|
+
procedures: admin13.firestore.FieldValue.arrayUnion(procedureId),
|
|
7102
|
+
proceduresInfo: admin13.firestore.FieldValue.arrayUnion(procedureSummary),
|
|
7103
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
6915
7104
|
});
|
|
6916
7105
|
console.log(
|
|
6917
7106
|
`[ProcedureAggregationService] Successfully added procedure ${procedureId} to clinic ${clinicId}.`
|
|
@@ -6963,7 +7152,7 @@ var ProcedureAggregationService = class {
|
|
|
6963
7152
|
updatedProceduresInfo.push(procedureSummary);
|
|
6964
7153
|
transaction.update(practitionerRef, {
|
|
6965
7154
|
proceduresInfo: updatedProceduresInfo,
|
|
6966
|
-
updatedAt:
|
|
7155
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
6967
7156
|
});
|
|
6968
7157
|
});
|
|
6969
7158
|
console.log(
|
|
@@ -7016,7 +7205,7 @@ var ProcedureAggregationService = class {
|
|
|
7016
7205
|
updatedProceduresInfo.push(procedureSummary);
|
|
7017
7206
|
transaction.update(clinicRef, {
|
|
7018
7207
|
proceduresInfo: updatedProceduresInfo,
|
|
7019
|
-
updatedAt:
|
|
7208
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
7020
7209
|
});
|
|
7021
7210
|
});
|
|
7022
7211
|
console.log(
|
|
@@ -7046,7 +7235,7 @@ var ProcedureAggregationService = class {
|
|
|
7046
7235
|
console.log(
|
|
7047
7236
|
`[ProcedureAggregationService] Querying upcoming calendar events for procedure ${procedureId} to update procedure info.`
|
|
7048
7237
|
);
|
|
7049
|
-
const now =
|
|
7238
|
+
const now = admin13.firestore.Timestamp.now();
|
|
7050
7239
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID4).where("procedureId", "==", procedureId).where("eventTime.start", ">", now);
|
|
7051
7240
|
try {
|
|
7052
7241
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -7063,7 +7252,7 @@ var ProcedureAggregationService = class {
|
|
|
7063
7252
|
);
|
|
7064
7253
|
batch.update(doc3.ref, {
|
|
7065
7254
|
procedureInfo,
|
|
7066
|
-
updatedAt:
|
|
7255
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
7067
7256
|
});
|
|
7068
7257
|
});
|
|
7069
7258
|
await batch.commit();
|
|
@@ -7093,7 +7282,7 @@ var ProcedureAggregationService = class {
|
|
|
7093
7282
|
console.log(
|
|
7094
7283
|
`[ProcedureAggregationService] Querying upcoming calendar events for procedure ${procedureId} to cancel.`
|
|
7095
7284
|
);
|
|
7096
|
-
const now =
|
|
7285
|
+
const now = admin13.firestore.Timestamp.now();
|
|
7097
7286
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID4).where("procedureId", "==", procedureId).where("eventTime.start", ">", now);
|
|
7098
7287
|
try {
|
|
7099
7288
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -7111,7 +7300,7 @@ var ProcedureAggregationService = class {
|
|
|
7111
7300
|
batch.update(doc3.ref, {
|
|
7112
7301
|
status: "CANCELED",
|
|
7113
7302
|
cancelReason: "Procedure deleted or inactivated",
|
|
7114
|
-
updatedAt:
|
|
7303
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
7115
7304
|
});
|
|
7116
7305
|
});
|
|
7117
7306
|
await batch.commit();
|
|
@@ -7168,9 +7357,9 @@ var ProcedureAggregationService = class {
|
|
|
7168
7357
|
(p) => p.id !== procedureId
|
|
7169
7358
|
);
|
|
7170
7359
|
const updateData = {
|
|
7171
|
-
procedureIds:
|
|
7360
|
+
procedureIds: admin13.firestore.FieldValue.arrayRemove(procedureId),
|
|
7172
7361
|
proceduresInfo: updatedProceduresInfo,
|
|
7173
|
-
updatedAt:
|
|
7362
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
7174
7363
|
};
|
|
7175
7364
|
if (isFreeConsultation && procedureClinicId) {
|
|
7176
7365
|
const currentFreeConsultations = practitionerData.freeConsultations || {};
|
|
@@ -7236,9 +7425,9 @@ var ProcedureAggregationService = class {
|
|
|
7236
7425
|
(p) => p.id !== procedureId
|
|
7237
7426
|
);
|
|
7238
7427
|
transaction.update(clinicRef, {
|
|
7239
|
-
procedures:
|
|
7428
|
+
procedures: admin13.firestore.FieldValue.arrayRemove(procedureId),
|
|
7240
7429
|
proceduresInfo: updatedProceduresInfo,
|
|
7241
|
-
updatedAt:
|
|
7430
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
7242
7431
|
});
|
|
7243
7432
|
});
|
|
7244
7433
|
console.log(
|
|
@@ -7315,7 +7504,7 @@ var ProcedureAggregationService = class {
|
|
|
7315
7504
|
}
|
|
7316
7505
|
transaction.update(practitionerRef, {
|
|
7317
7506
|
freeConsultations: updatedFreeConsultations,
|
|
7318
|
-
updatedAt:
|
|
7507
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
7319
7508
|
});
|
|
7320
7509
|
});
|
|
7321
7510
|
console.log(
|
|
@@ -7332,14 +7521,14 @@ var ProcedureAggregationService = class {
|
|
|
7332
7521
|
};
|
|
7333
7522
|
|
|
7334
7523
|
// src/admin/aggregation/reviews/reviews.aggregation.service.ts
|
|
7335
|
-
var
|
|
7524
|
+
var admin14 = __toESM(require("firebase-admin"));
|
|
7336
7525
|
var ReviewsAggregationService = class {
|
|
7337
7526
|
/**
|
|
7338
7527
|
* Constructor for ReviewsAggregationService.
|
|
7339
7528
|
* @param firestore Optional Firestore instance. If not provided, it uses the default admin SDK instance.
|
|
7340
7529
|
*/
|
|
7341
|
-
constructor(
|
|
7342
|
-
this.db =
|
|
7530
|
+
constructor(firestore20) {
|
|
7531
|
+
this.db = firestore20 || admin14.firestore();
|
|
7343
7532
|
}
|
|
7344
7533
|
/**
|
|
7345
7534
|
* Process a newly created review and update all related entities
|
|
@@ -7482,7 +7671,7 @@ var ReviewsAggregationService = class {
|
|
|
7482
7671
|
};
|
|
7483
7672
|
await this.db.collection(CLINICS_COLLECTION).doc(clinicId).update({
|
|
7484
7673
|
reviewInfo: updatedReviewInfo2,
|
|
7485
|
-
updatedAt:
|
|
7674
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7486
7675
|
});
|
|
7487
7676
|
console.log(
|
|
7488
7677
|
`[ReviewsAggregationService] Reset review info for clinic: ${clinicId}`
|
|
@@ -7521,7 +7710,7 @@ var ReviewsAggregationService = class {
|
|
|
7521
7710
|
};
|
|
7522
7711
|
await this.db.collection(CLINICS_COLLECTION).doc(clinicId).update({
|
|
7523
7712
|
reviewInfo: updatedReviewInfo,
|
|
7524
|
-
updatedAt:
|
|
7713
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7525
7714
|
});
|
|
7526
7715
|
console.log(
|
|
7527
7716
|
`[ReviewsAggregationService] Updated review info for clinic: ${clinicId}`
|
|
@@ -7571,7 +7760,7 @@ var ReviewsAggregationService = class {
|
|
|
7571
7760
|
};
|
|
7572
7761
|
await this.db.collection(PRACTITIONERS_COLLECTION).doc(practitionerId).update({
|
|
7573
7762
|
reviewInfo: updatedReviewInfo2,
|
|
7574
|
-
updatedAt:
|
|
7763
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7575
7764
|
});
|
|
7576
7765
|
await this.updateDoctorInfoInProcedures(practitionerId, 0);
|
|
7577
7766
|
console.log(
|
|
@@ -7611,7 +7800,7 @@ var ReviewsAggregationService = class {
|
|
|
7611
7800
|
};
|
|
7612
7801
|
await this.db.collection(PRACTITIONERS_COLLECTION).doc(practitionerId).update({
|
|
7613
7802
|
reviewInfo: updatedReviewInfo,
|
|
7614
|
-
updatedAt:
|
|
7803
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7615
7804
|
});
|
|
7616
7805
|
await this.updateDoctorInfoInProcedures(
|
|
7617
7806
|
practitionerId,
|
|
@@ -7678,7 +7867,7 @@ var ReviewsAggregationService = class {
|
|
|
7678
7867
|
};
|
|
7679
7868
|
await this.db.collection(PROCEDURES_COLLECTION).doc(procedureId).update({
|
|
7680
7869
|
reviewInfo: updatedReviewInfo2,
|
|
7681
|
-
updatedAt:
|
|
7870
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7682
7871
|
});
|
|
7683
7872
|
console.log(
|
|
7684
7873
|
`[ReviewsAggregationService] Reset review info for procedure: ${procedureId}`
|
|
@@ -7717,7 +7906,7 @@ var ReviewsAggregationService = class {
|
|
|
7717
7906
|
};
|
|
7718
7907
|
await this.db.collection(PROCEDURES_COLLECTION).doc(procedureId).update({
|
|
7719
7908
|
reviewInfo: updatedReviewInfo,
|
|
7720
|
-
updatedAt:
|
|
7909
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7721
7910
|
});
|
|
7722
7911
|
console.log(
|
|
7723
7912
|
`[ReviewsAggregationService] Updated review info for procedure: ${procedureId}`
|
|
@@ -7745,7 +7934,7 @@ var ReviewsAggregationService = class {
|
|
|
7745
7934
|
const procedureRef = this.db.collection(PROCEDURES_COLLECTION).doc(docSnapshot.id);
|
|
7746
7935
|
batch.update(procedureRef, {
|
|
7747
7936
|
"doctorInfo.rating": rating,
|
|
7748
|
-
updatedAt:
|
|
7937
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7749
7938
|
});
|
|
7750
7939
|
});
|
|
7751
7940
|
await batch.commit();
|
|
@@ -7788,7 +7977,7 @@ var ReviewsAggregationService = class {
|
|
|
7788
7977
|
practitionerReview: review.practitionerReview,
|
|
7789
7978
|
procedureReview: review.procedureReview,
|
|
7790
7979
|
extendedProcedureReviews: review.extendedProcedureReviews,
|
|
7791
|
-
updatedAt:
|
|
7980
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7792
7981
|
});
|
|
7793
7982
|
await batch.commit();
|
|
7794
7983
|
console.log(
|
|
@@ -7819,7 +8008,7 @@ var ReviewsAggregationService = class {
|
|
|
7819
8008
|
};
|
|
7820
8009
|
|
|
7821
8010
|
// src/admin/analytics/analytics.admin.service.ts
|
|
7822
|
-
var
|
|
8011
|
+
var admin15 = __toESM(require("firebase-admin"));
|
|
7823
8012
|
|
|
7824
8013
|
// src/services/analytics/analytics.service.ts
|
|
7825
8014
|
var import_firestore4 = require("firebase/firestore");
|
|
@@ -10882,8 +11071,8 @@ var AnalyticsAdminService = class {
|
|
|
10882
11071
|
*
|
|
10883
11072
|
* @param firestore - Admin Firestore instance (optional, defaults to admin.firestore())
|
|
10884
11073
|
*/
|
|
10885
|
-
constructor(
|
|
10886
|
-
this.db =
|
|
11074
|
+
constructor(firestore20) {
|
|
11075
|
+
this.db = firestore20 || admin15.firestore();
|
|
10887
11076
|
const mockApp = {
|
|
10888
11077
|
name: "[DEFAULT]",
|
|
10889
11078
|
options: {},
|
|
@@ -10920,12 +11109,12 @@ var AnalyticsAdminService = class {
|
|
|
10920
11109
|
}
|
|
10921
11110
|
if (params.startDate) {
|
|
10922
11111
|
const startDate = params.startDate instanceof Date ? params.startDate : params.startDate.toDate();
|
|
10923
|
-
const startTimestamp =
|
|
11112
|
+
const startTimestamp = admin15.firestore.Timestamp.fromDate(startDate);
|
|
10924
11113
|
query3 = query3.where("appointmentStartTime", ">=", startTimestamp);
|
|
10925
11114
|
}
|
|
10926
11115
|
if (params.endDate) {
|
|
10927
11116
|
const endDate = params.endDate instanceof Date ? params.endDate : params.endDate.toDate();
|
|
10928
|
-
const endTimestamp =
|
|
11117
|
+
const endTimestamp = admin15.firestore.Timestamp.fromDate(endDate);
|
|
10929
11118
|
query3 = query3.where("appointmentStartTime", "<=", endTimestamp);
|
|
10930
11119
|
}
|
|
10931
11120
|
const snapshot = await query3.get();
|
|
@@ -11076,6 +11265,13 @@ var BookingAvailabilityCalculator = class {
|
|
|
11076
11265
|
availableIntervals,
|
|
11077
11266
|
practitionerCalendarEvents
|
|
11078
11267
|
);
|
|
11268
|
+
if (request.resourceCalendarEventsMap) {
|
|
11269
|
+
availableIntervals = this.applyResourceAvailability(
|
|
11270
|
+
availableIntervals,
|
|
11271
|
+
request.resourceCalendarEventsMap,
|
|
11272
|
+
timeframe
|
|
11273
|
+
);
|
|
11274
|
+
}
|
|
11079
11275
|
console.log(
|
|
11080
11276
|
`After all filters, have ${availableIntervals.length} available intervals`
|
|
11081
11277
|
);
|
|
@@ -11481,18 +11677,98 @@ var BookingAvailabilityCalculator = class {
|
|
|
11481
11677
|
}
|
|
11482
11678
|
return result;
|
|
11483
11679
|
}
|
|
11680
|
+
/**
|
|
11681
|
+
* Apply resource availability constraints to the available intervals.
|
|
11682
|
+
* For each required resource:
|
|
11683
|
+
* - Compute each instance's availability (full timeframe minus its busy events)
|
|
11684
|
+
* - Union all instance availabilities (at least one must be free)
|
|
11685
|
+
* Then intersect all resource availabilities with the current doctor availability.
|
|
11686
|
+
*
|
|
11687
|
+
* @param intervals - Current available intervals (doctor availability)
|
|
11688
|
+
* @param resourceEventsMap - Map of resource data with per-instance calendar events
|
|
11689
|
+
* @param timeframe - Overall timeframe being considered
|
|
11690
|
+
* @returns Intervals where doctor AND all required resources are available
|
|
11691
|
+
*/
|
|
11692
|
+
static applyResourceAvailability(intervals, resourceEventsMap, timeframe) {
|
|
11693
|
+
if (!intervals.length) return [];
|
|
11694
|
+
const resourceIds = Object.keys(resourceEventsMap);
|
|
11695
|
+
if (resourceIds.length === 0) return intervals;
|
|
11696
|
+
console.log(
|
|
11697
|
+
`Applying resource availability for ${resourceIds.length} resource(s)`
|
|
11698
|
+
);
|
|
11699
|
+
let result = intervals;
|
|
11700
|
+
for (const resourceId of resourceIds) {
|
|
11701
|
+
const resourceData = resourceEventsMap[resourceId];
|
|
11702
|
+
const resourceAvailability = this.computeResourceAvailability(
|
|
11703
|
+
resourceData.instanceEvents,
|
|
11704
|
+
timeframe
|
|
11705
|
+
);
|
|
11706
|
+
console.log(
|
|
11707
|
+
`Resource "${resourceData.resourceName}" (qty=${resourceData.quantity}): ${resourceAvailability.length} available intervals`
|
|
11708
|
+
);
|
|
11709
|
+
result = this.intersectIntervals(result, resourceAvailability);
|
|
11710
|
+
if (result.length === 0) {
|
|
11711
|
+
console.log(
|
|
11712
|
+
`No availability remaining after applying resource "${resourceData.resourceName}"`
|
|
11713
|
+
);
|
|
11714
|
+
return [];
|
|
11715
|
+
}
|
|
11716
|
+
}
|
|
11717
|
+
return result;
|
|
11718
|
+
}
|
|
11719
|
+
/**
|
|
11720
|
+
* Compute combined availability for a single resource across all its instances.
|
|
11721
|
+
* For each instance, subtract its busy events from the full timeframe.
|
|
11722
|
+
* Then union all instance availabilities — if at least one instance is free, the resource is available.
|
|
11723
|
+
*
|
|
11724
|
+
* @param instanceEvents - Calendar events keyed by instanceId
|
|
11725
|
+
* @param timeframe - Overall timeframe
|
|
11726
|
+
* @returns Combined availability intervals for the resource
|
|
11727
|
+
*/
|
|
11728
|
+
static computeResourceAvailability(instanceEvents, timeframe) {
|
|
11729
|
+
const instanceIds = Object.keys(instanceEvents);
|
|
11730
|
+
if (instanceIds.length === 0) {
|
|
11731
|
+
return [{ start: timeframe.start, end: timeframe.end }];
|
|
11732
|
+
}
|
|
11733
|
+
const allInstanceAvailabilities = [];
|
|
11734
|
+
for (const instanceId of instanceIds) {
|
|
11735
|
+
const events = instanceEvents[instanceId];
|
|
11736
|
+
let instanceAvailability = [
|
|
11737
|
+
{ start: timeframe.start, end: timeframe.end }
|
|
11738
|
+
];
|
|
11739
|
+
for (const event of events) {
|
|
11740
|
+
const isBlockingEvent = event.eventType === "blocking" /* BLOCKING */ || event.eventType === "break" /* BREAK */ || event.eventType === "free_day" /* FREE_DAY */;
|
|
11741
|
+
const isActiveBooking = event.status === "pending" /* PENDING */ || event.status === "confirmed" /* CONFIRMED */;
|
|
11742
|
+
if (isBlockingEvent || isActiveBooking) {
|
|
11743
|
+
const busyInterval = {
|
|
11744
|
+
start: event.eventTime.start,
|
|
11745
|
+
end: event.eventTime.end
|
|
11746
|
+
};
|
|
11747
|
+
const newAvailability = [];
|
|
11748
|
+
for (const interval of instanceAvailability) {
|
|
11749
|
+
newAvailability.push(
|
|
11750
|
+
...this.subtractInterval(interval, busyInterval)
|
|
11751
|
+
);
|
|
11752
|
+
}
|
|
11753
|
+
instanceAvailability = newAvailability;
|
|
11754
|
+
}
|
|
11755
|
+
}
|
|
11756
|
+
allInstanceAvailabilities.push(...instanceAvailability);
|
|
11757
|
+
}
|
|
11758
|
+
return this.mergeOverlappingIntervals(allInstanceAvailabilities);
|
|
11759
|
+
}
|
|
11484
11760
|
};
|
|
11485
11761
|
/** Default scheduling interval in minutes if not specified by the clinic */
|
|
11486
11762
|
BookingAvailabilityCalculator.DEFAULT_INTERVAL_MINUTES = 15;
|
|
11487
11763
|
|
|
11488
11764
|
// src/admin/booking/booking.admin.ts
|
|
11489
|
-
var
|
|
11765
|
+
var admin17 = __toESM(require("firebase-admin"));
|
|
11490
11766
|
|
|
11491
11767
|
// src/admin/documentation-templates/document-manager.admin.ts
|
|
11492
|
-
var
|
|
11768
|
+
var admin16 = __toESM(require("firebase-admin"));
|
|
11493
11769
|
var DocumentManagerAdminService = class {
|
|
11494
|
-
constructor(
|
|
11495
|
-
this.db =
|
|
11770
|
+
constructor(firestore20) {
|
|
11771
|
+
this.db = firestore20;
|
|
11496
11772
|
}
|
|
11497
11773
|
/**
|
|
11498
11774
|
* Adds operations to a Firestore batch to initialize all linked forms for a new appointment
|
|
@@ -11595,7 +11871,7 @@ var DocumentManagerAdminService = class {
|
|
|
11595
11871
|
};
|
|
11596
11872
|
}
|
|
11597
11873
|
const templateIds = technologyTemplates.map((t) => t.templateId);
|
|
11598
|
-
const templatesSnapshot = await this.db.collection(DOCUMENTATION_TEMPLATES_COLLECTION).where(
|
|
11874
|
+
const templatesSnapshot = await this.db.collection(DOCUMENTATION_TEMPLATES_COLLECTION).where(admin16.firestore.FieldPath.documentId(), "in", templateIds).get();
|
|
11599
11875
|
const templatesMap = /* @__PURE__ */ new Map();
|
|
11600
11876
|
templatesSnapshot.forEach((doc3) => {
|
|
11601
11877
|
templatesMap.set(doc3.id, doc3.data());
|
|
@@ -11661,8 +11937,8 @@ var BookingAdmin = class {
|
|
|
11661
11937
|
* Creates a new BookingAdmin instance
|
|
11662
11938
|
* @param firestore - Firestore instance provided by the caller
|
|
11663
11939
|
*/
|
|
11664
|
-
constructor(
|
|
11665
|
-
this.db =
|
|
11940
|
+
constructor(firestore20) {
|
|
11941
|
+
this.db = firestore20 || admin17.firestore();
|
|
11666
11942
|
this.documentManagerAdmin = new DocumentManagerAdminService(this.db);
|
|
11667
11943
|
}
|
|
11668
11944
|
/**
|
|
@@ -11675,7 +11951,7 @@ var BookingAdmin = class {
|
|
|
11675
11951
|
* @returns Promise resolving to an array of available booking slots
|
|
11676
11952
|
*/
|
|
11677
11953
|
async getAvailableBookingSlots(clinicId, practitionerId, procedureId, timeframe) {
|
|
11678
|
-
var _a;
|
|
11954
|
+
var _a, _b;
|
|
11679
11955
|
try {
|
|
11680
11956
|
Logger.info("[BookingAdmin] Starting availability calculation", {
|
|
11681
11957
|
clinicId,
|
|
@@ -11684,8 +11960,8 @@ var BookingAdmin = class {
|
|
|
11684
11960
|
timeframeStart: timeframe.start instanceof Date ? timeframe.start.toISOString() : timeframe.start.toDate().toISOString(),
|
|
11685
11961
|
timeframeEnd: timeframe.end instanceof Date ? timeframe.end.toISOString() : timeframe.end.toDate().toISOString()
|
|
11686
11962
|
});
|
|
11687
|
-
const start = timeframe.start instanceof Date ?
|
|
11688
|
-
const end = timeframe.end instanceof Date ?
|
|
11963
|
+
const start = timeframe.start instanceof Date ? admin17.firestore.Timestamp.fromDate(timeframe.start) : timeframe.start;
|
|
11964
|
+
const end = timeframe.end instanceof Date ? admin17.firestore.Timestamp.fromDate(timeframe.end) : timeframe.end;
|
|
11689
11965
|
Logger.debug("[BookingAdmin] Fetching clinic data", { clinicId });
|
|
11690
11966
|
const clinicDoc = await this.db.collection("clinics").doc(clinicId).get();
|
|
11691
11967
|
if (!clinicDoc.exists) {
|
|
@@ -11745,6 +12021,74 @@ var BookingAdmin = class {
|
|
|
11745
12021
|
Logger.debug("[BookingAdmin] Retrieved practitioner calendar events", {
|
|
11746
12022
|
count: practitionerCalendarEvents.length
|
|
11747
12023
|
});
|
|
12024
|
+
let resourceCalendarEventsMap;
|
|
12025
|
+
if (procedure.resourceRequirements && procedure.resourceRequirements.length > 0) {
|
|
12026
|
+
Logger.debug(
|
|
12027
|
+
"[BookingAdmin] Procedure has resource requirements, fetching resource data",
|
|
12028
|
+
{
|
|
12029
|
+
resourceRequirementCount: procedure.resourceRequirements.length,
|
|
12030
|
+
resourceIds: procedure.resourceRequirements.map(
|
|
12031
|
+
(r) => r.resourceId
|
|
12032
|
+
)
|
|
12033
|
+
}
|
|
12034
|
+
);
|
|
12035
|
+
resourceCalendarEventsMap = {};
|
|
12036
|
+
for (const requirement of procedure.resourceRequirements) {
|
|
12037
|
+
const resourceDoc = await this.db.collection(CLINICS_COLLECTION).doc(clinicId).collection(RESOURCES_COLLECTION).doc(requirement.resourceId).get();
|
|
12038
|
+
if (!resourceDoc.exists) {
|
|
12039
|
+
Logger.warn(
|
|
12040
|
+
"[BookingAdmin] Required resource not found, skipping",
|
|
12041
|
+
{
|
|
12042
|
+
resourceId: requirement.resourceId,
|
|
12043
|
+
resourceName: requirement.resourceName
|
|
12044
|
+
}
|
|
12045
|
+
);
|
|
12046
|
+
continue;
|
|
12047
|
+
}
|
|
12048
|
+
const resource = resourceDoc.data();
|
|
12049
|
+
if (resource.status !== "active" /* ACTIVE */) {
|
|
12050
|
+
Logger.warn(
|
|
12051
|
+
"[BookingAdmin] Required resource is not active, skipping",
|
|
12052
|
+
{
|
|
12053
|
+
resourceId: requirement.resourceId,
|
|
12054
|
+
resourceStatus: resource.status
|
|
12055
|
+
}
|
|
12056
|
+
);
|
|
12057
|
+
continue;
|
|
12058
|
+
}
|
|
12059
|
+
const instancesSnapshot = await this.db.collection(CLINICS_COLLECTION).doc(clinicId).collection(RESOURCES_COLLECTION).doc(requirement.resourceId).collection(RESOURCE_INSTANCES_SUBCOLLECTION).where("status", "==", "active" /* ACTIVE */).get();
|
|
12060
|
+
const instanceEvents = {};
|
|
12061
|
+
for (const instanceDoc of instancesSnapshot.docs) {
|
|
12062
|
+
const instanceId = instanceDoc.id;
|
|
12063
|
+
const MAX_EVENT_DURATION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
12064
|
+
const queryStart = admin17.firestore.Timestamp.fromMillis(
|
|
12065
|
+
start.toMillis() - MAX_EVENT_DURATION_MS
|
|
12066
|
+
);
|
|
12067
|
+
const eventsSnapshot = await this.db.collection(CLINICS_COLLECTION).doc(clinicId).collection(RESOURCES_COLLECTION).doc(requirement.resourceId).collection(RESOURCE_INSTANCES_SUBCOLLECTION).doc(instanceId).collection(RESOURCE_CALENDAR_SUBCOLLECTION).where("eventTime.start", ">=", queryStart).where("eventTime.start", "<=", end).orderBy("eventTime.start").get();
|
|
12068
|
+
const events = eventsSnapshot.docs.map((doc3) => ({ ...doc3.data(), id: doc3.id })).filter(
|
|
12069
|
+
(event) => event.eventTime.end.toMillis() > start.toMillis()
|
|
12070
|
+
);
|
|
12071
|
+
instanceEvents[instanceId] = this.convertEventsTimestamps(
|
|
12072
|
+
events
|
|
12073
|
+
);
|
|
12074
|
+
}
|
|
12075
|
+
resourceCalendarEventsMap[requirement.resourceId] = {
|
|
12076
|
+
resourceId: requirement.resourceId,
|
|
12077
|
+
resourceName: requirement.resourceName,
|
|
12078
|
+
quantity: resource.quantity,
|
|
12079
|
+
instanceEvents
|
|
12080
|
+
};
|
|
12081
|
+
Logger.debug("[BookingAdmin] Fetched resource calendar data", {
|
|
12082
|
+
resourceId: requirement.resourceId,
|
|
12083
|
+
resourceName: requirement.resourceName,
|
|
12084
|
+
instanceCount: instancesSnapshot.size,
|
|
12085
|
+
totalEvents: Object.values(instanceEvents).reduce(
|
|
12086
|
+
(sum, events) => sum + events.length,
|
|
12087
|
+
0
|
|
12088
|
+
)
|
|
12089
|
+
});
|
|
12090
|
+
}
|
|
12091
|
+
}
|
|
11748
12092
|
const convertedTimeframe = {
|
|
11749
12093
|
start: this.adminTimestampToClientTimestamp(start),
|
|
11750
12094
|
end: this.adminTimestampToClientTimestamp(end)
|
|
@@ -11758,7 +12102,8 @@ var BookingAdmin = class {
|
|
|
11758
12102
|
practitionerCalendarEvents: this.convertEventsTimestamps(
|
|
11759
12103
|
practitionerCalendarEvents
|
|
11760
12104
|
),
|
|
11761
|
-
tz: clinic.location.tz || "UTC"
|
|
12105
|
+
tz: clinic.location.tz || "UTC",
|
|
12106
|
+
...resourceCalendarEventsMap && { resourceCalendarEventsMap }
|
|
11762
12107
|
};
|
|
11763
12108
|
Logger.info("[BookingAdmin] Calling availability calculator", {
|
|
11764
12109
|
calculatorInputReady: true,
|
|
@@ -11766,12 +12111,14 @@ var BookingAdmin = class {
|
|
|
11766
12111
|
(end.toMillis() - start.toMillis()) / (1e3 * 60 * 60)
|
|
11767
12112
|
),
|
|
11768
12113
|
clinicEventsCount: clinicCalendarEvents.length,
|
|
11769
|
-
practitionerEventsCount: practitionerCalendarEvents.length
|
|
12114
|
+
practitionerEventsCount: practitionerCalendarEvents.length,
|
|
12115
|
+
resourceRequirementCount: ((_b = procedure.resourceRequirements) == null ? void 0 : _b.length) || 0,
|
|
12116
|
+
hasResourceData: !!resourceCalendarEventsMap
|
|
11770
12117
|
});
|
|
11771
12118
|
const result = BookingAvailabilityCalculator.calculateSlots(request);
|
|
11772
12119
|
const availableSlotsResult = {
|
|
11773
12120
|
availableSlots: result.availableSlots.map((slot) => ({
|
|
11774
|
-
start:
|
|
12121
|
+
start: admin17.firestore.Timestamp.fromMillis(slot.start.toMillis())
|
|
11775
12122
|
}))
|
|
11776
12123
|
};
|
|
11777
12124
|
Logger.info(
|
|
@@ -11834,7 +12181,7 @@ var BookingAdmin = class {
|
|
|
11834
12181
|
endTime: end.toDate().toISOString()
|
|
11835
12182
|
});
|
|
11836
12183
|
const MAX_EVENT_DURATION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
11837
|
-
const queryStart =
|
|
12184
|
+
const queryStart = admin17.firestore.Timestamp.fromMillis(
|
|
11838
12185
|
start.toMillis() - MAX_EVENT_DURATION_MS
|
|
11839
12186
|
);
|
|
11840
12187
|
const eventsRef = this.db.collection(`clinics/${clinicId}/calendar`).where("eventTime.start", ">=", queryStart).where("eventTime.start", "<=", end).orderBy("eventTime.start");
|
|
@@ -11890,7 +12237,7 @@ var BookingAdmin = class {
|
|
|
11890
12237
|
endTime: end.toDate().toISOString()
|
|
11891
12238
|
});
|
|
11892
12239
|
const MAX_EVENT_DURATION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
11893
|
-
const queryStart =
|
|
12240
|
+
const queryStart = admin17.firestore.Timestamp.fromMillis(
|
|
11894
12241
|
start.toMillis() - MAX_EVENT_DURATION_MS
|
|
11895
12242
|
);
|
|
11896
12243
|
const eventsRef = this.db.collection(`practitioners/${practitionerId}/calendar`).where("eventTime.start", ">=", queryStart).where("eventTime.start", "<=", end).orderBy("eventTime.start");
|
|
@@ -11969,8 +12316,8 @@ var BookingAdmin = class {
|
|
|
11969
12316
|
`[BookingAdmin] Orchestrating appointment creation for patient ${data.patientId} by user ${authenticatedUserId}`
|
|
11970
12317
|
);
|
|
11971
12318
|
const batch = this.db.batch();
|
|
11972
|
-
const adminTsNow =
|
|
11973
|
-
const serverTimestampValue =
|
|
12319
|
+
const adminTsNow = admin17.firestore.Timestamp.now();
|
|
12320
|
+
const serverTimestampValue = admin17.firestore.FieldValue.serverTimestamp();
|
|
11974
12321
|
try {
|
|
11975
12322
|
if (!data.patientId || !data.procedureId || !data.appointmentStartTime || !data.appointmentEndTime) {
|
|
11976
12323
|
return {
|
|
@@ -12067,7 +12414,7 @@ var BookingAdmin = class {
|
|
|
12067
12414
|
fullName: `${(patientSensitiveData == null ? void 0 : patientSensitiveData.firstName) || ""} ${(patientSensitiveData == null ? void 0 : patientSensitiveData.lastName) || ""}`.trim() || patientProfileData.displayName,
|
|
12068
12415
|
email: (patientSensitiveData == null ? void 0 : patientSensitiveData.email) || "",
|
|
12069
12416
|
phone: (patientSensitiveData == null ? void 0 : patientSensitiveData.phoneNumber) || patientProfileData.phoneNumber || null,
|
|
12070
|
-
dateOfBirth: (patientSensitiveData == null ? void 0 : patientSensitiveData.dateOfBirth) || patientProfileData.dateOfBirth ||
|
|
12417
|
+
dateOfBirth: (patientSensitiveData == null ? void 0 : patientSensitiveData.dateOfBirth) || patientProfileData.dateOfBirth || admin17.firestore.Timestamp.now(),
|
|
12071
12418
|
gender: (patientSensitiveData == null ? void 0 : patientSensitiveData.gender) || "other" /* OTHER */
|
|
12072
12419
|
};
|
|
12073
12420
|
const newAppointmentId = this.db.collection(APPOINTMENTS_COLLECTION).doc().id;
|
|
@@ -12149,6 +12496,76 @@ var BookingAdmin = class {
|
|
|
12149
12496
|
this.db.collection(CLINICS_COLLECTION).doc(clinicData.id).collection(CALENDAR_COLLECTION).doc(practitionerCalendarEventId),
|
|
12150
12497
|
clinicCalendarEventData
|
|
12151
12498
|
);
|
|
12499
|
+
let resourceBookings = [];
|
|
12500
|
+
if (procedure.resourceRequirements && procedure.resourceRequirements.length > 0) {
|
|
12501
|
+
console.log(
|
|
12502
|
+
`[BookingAdmin] Allocating resources for appointment ${newAppointmentId}, ${procedure.resourceRequirements.length} resource(s) required`
|
|
12503
|
+
);
|
|
12504
|
+
for (const requirement of procedure.resourceRequirements) {
|
|
12505
|
+
const instancesSnapshot = await this.db.collection(CLINICS_COLLECTION).doc(clinicData.id).collection(RESOURCES_COLLECTION).doc(requirement.resourceId).collection(RESOURCE_INSTANCES_SUBCOLLECTION).where("status", "==", "active" /* ACTIVE */).orderBy("index").get();
|
|
12506
|
+
if (instancesSnapshot.empty) {
|
|
12507
|
+
return {
|
|
12508
|
+
success: false,
|
|
12509
|
+
error: `Resource "${requirement.resourceName}" has no active instances available.`
|
|
12510
|
+
};
|
|
12511
|
+
}
|
|
12512
|
+
let allocatedInstance = null;
|
|
12513
|
+
for (const instanceDoc of instancesSnapshot.docs) {
|
|
12514
|
+
const instance = {
|
|
12515
|
+
...instanceDoc.data(),
|
|
12516
|
+
id: instanceDoc.id
|
|
12517
|
+
};
|
|
12518
|
+
const overlappingEventsSnapshot = await this.db.collection(CLINICS_COLLECTION).doc(clinicData.id).collection(RESOURCES_COLLECTION).doc(requirement.resourceId).collection(RESOURCE_INSTANCES_SUBCOLLECTION).doc(instance.id).collection(RESOURCE_CALENDAR_SUBCOLLECTION).where("eventTime.start", "<", data.appointmentEndTime).where("status", "in", [
|
|
12519
|
+
"pending" /* PENDING */,
|
|
12520
|
+
"confirmed" /* CONFIRMED */,
|
|
12521
|
+
"checked_in" /* CHECKED_IN */,
|
|
12522
|
+
"in_progress" /* IN_PROGRESS */
|
|
12523
|
+
]).get();
|
|
12524
|
+
const hasOverlap = overlappingEventsSnapshot.docs.some((doc3) => {
|
|
12525
|
+
const event = doc3.data();
|
|
12526
|
+
return event.eventTime.end.toMillis() > data.appointmentStartTime.toMillis();
|
|
12527
|
+
});
|
|
12528
|
+
if (!hasOverlap) {
|
|
12529
|
+
allocatedInstance = instance;
|
|
12530
|
+
break;
|
|
12531
|
+
}
|
|
12532
|
+
}
|
|
12533
|
+
if (!allocatedInstance) {
|
|
12534
|
+
return {
|
|
12535
|
+
success: false,
|
|
12536
|
+
error: `Resource "${requirement.resourceName}" is not available at the selected time. All instances are booked.`
|
|
12537
|
+
};
|
|
12538
|
+
}
|
|
12539
|
+
const resourceCalendarEventRef = this.db.collection(CLINICS_COLLECTION).doc(clinicData.id).collection(RESOURCES_COLLECTION).doc(requirement.resourceId).collection(RESOURCE_INSTANCES_SUBCOLLECTION).doc(allocatedInstance.id).collection(RESOURCE_CALENDAR_SUBCOLLECTION).doc();
|
|
12540
|
+
const resourceCalendarEventData = {
|
|
12541
|
+
id: resourceCalendarEventRef.id,
|
|
12542
|
+
resourceId: requirement.resourceId,
|
|
12543
|
+
resourceInstanceId: allocatedInstance.id,
|
|
12544
|
+
clinicBranchId: clinicData.id,
|
|
12545
|
+
eventType: "resource_booking" /* RESOURCE_BOOKING */,
|
|
12546
|
+
appointmentId: newAppointmentId,
|
|
12547
|
+
procedureId: procedure.id,
|
|
12548
|
+
practitionerId: practitionerData.id,
|
|
12549
|
+
patientId: data.patientId,
|
|
12550
|
+
eventTime: eventTimeForCalendarEvents,
|
|
12551
|
+
status: initialCalendarEventStatus,
|
|
12552
|
+
eventName: `${procedure.name} - ${allocatedInstance.label}`,
|
|
12553
|
+
createdAt: serverTimestampValue,
|
|
12554
|
+
updatedAt: serverTimestampValue
|
|
12555
|
+
};
|
|
12556
|
+
batch.set(resourceCalendarEventRef, resourceCalendarEventData);
|
|
12557
|
+
resourceBookings.push({
|
|
12558
|
+
resourceId: requirement.resourceId,
|
|
12559
|
+
resourceName: requirement.resourceName,
|
|
12560
|
+
resourceInstanceId: allocatedInstance.id,
|
|
12561
|
+
resourceInstanceLabel: allocatedInstance.label,
|
|
12562
|
+
calendarEventId: resourceCalendarEventRef.id
|
|
12563
|
+
});
|
|
12564
|
+
console.log(
|
|
12565
|
+
`[BookingAdmin] Allocated resource "${requirement.resourceName}" \u2192 instance "${allocatedInstance.label}" (${allocatedInstance.id})`
|
|
12566
|
+
);
|
|
12567
|
+
}
|
|
12568
|
+
}
|
|
12152
12569
|
let initializedFormsInfo = [];
|
|
12153
12570
|
let pendingUserFormTemplateIds = [];
|
|
12154
12571
|
let allLinkedFormTemplateIds = [];
|
|
@@ -12231,6 +12648,7 @@ var BookingAdmin = class {
|
|
|
12231
12648
|
isRecurring: false,
|
|
12232
12649
|
recurringAppointmentId: null,
|
|
12233
12650
|
isArchived: false,
|
|
12651
|
+
...resourceBookings.length > 0 && { resourceBookings },
|
|
12234
12652
|
createdAt: adminTsNow,
|
|
12235
12653
|
updatedAt: adminTsNow
|
|
12236
12654
|
};
|
|
@@ -12332,7 +12750,7 @@ var BookingAdmin = class {
|
|
|
12332
12750
|
};
|
|
12333
12751
|
|
|
12334
12752
|
// src/admin/free-consultation/free-consultation-utils.admin.ts
|
|
12335
|
-
var
|
|
12753
|
+
var admin18 = __toESM(require("firebase-admin"));
|
|
12336
12754
|
|
|
12337
12755
|
// src/backoffice/types/category.types.ts
|
|
12338
12756
|
var CATEGORIES_COLLECTION = "backoffice_categories";
|
|
@@ -12345,10 +12763,10 @@ var TECHNOLOGIES_COLLECTION = "technologies";
|
|
|
12345
12763
|
|
|
12346
12764
|
// src/admin/free-consultation/free-consultation-utils.admin.ts
|
|
12347
12765
|
async function freeConsultationInfrastructure(db) {
|
|
12348
|
-
const
|
|
12766
|
+
const firestore20 = db || admin18.firestore();
|
|
12349
12767
|
try {
|
|
12350
12768
|
console.log("[freeConsultationInfrastructure] Checking free consultation infrastructure...");
|
|
12351
|
-
const technologyRef =
|
|
12769
|
+
const technologyRef = firestore20.collection(TECHNOLOGIES_COLLECTION).doc("free-consultation-tech");
|
|
12352
12770
|
const technologyDoc = await technologyRef.get();
|
|
12353
12771
|
if (technologyDoc.exists) {
|
|
12354
12772
|
console.log(
|
|
@@ -12357,7 +12775,7 @@ async function freeConsultationInfrastructure(db) {
|
|
|
12357
12775
|
return true;
|
|
12358
12776
|
}
|
|
12359
12777
|
console.log("[freeConsultationInfrastructure] Creating free consultation infrastructure...");
|
|
12360
|
-
await createFreeConsultationInfrastructure(
|
|
12778
|
+
await createFreeConsultationInfrastructure(firestore20);
|
|
12361
12779
|
console.log(
|
|
12362
12780
|
"[freeConsultationInfrastructure] Successfully created free consultation infrastructure"
|
|
12363
12781
|
);
|
|
@@ -12554,8 +12972,8 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
12554
12972
|
* @param firestore Firestore instance provided by the caller
|
|
12555
12973
|
* @param mailgunClient Mailgun client instance (mailgun.js v10+) provided by the caller
|
|
12556
12974
|
*/
|
|
12557
|
-
constructor(
|
|
12558
|
-
super(
|
|
12975
|
+
constructor(firestore20, mailgunClient) {
|
|
12976
|
+
super(firestore20, mailgunClient);
|
|
12559
12977
|
this.DEFAULT_REGISTRATION_URL = "https://metaesthetics.net/register";
|
|
12560
12978
|
this.DEFAULT_SUBJECT = "You've Been Invited to Join as a Practitioner";
|
|
12561
12979
|
this.DEFAULT_MAILGUN_DOMAIN = "mg.metaesthetics.net";
|
|
@@ -13418,8 +13836,8 @@ var ExistingPractitionerInviteMailingService = class extends BaseMailingService
|
|
|
13418
13836
|
* @param firestore Firestore instance provided by the caller
|
|
13419
13837
|
* @param mailgunClient Mailgun client instance (mailgun.js v10+) provided by the caller
|
|
13420
13838
|
*/
|
|
13421
|
-
constructor(
|
|
13422
|
-
super(
|
|
13839
|
+
constructor(firestore20, mailgunClient) {
|
|
13840
|
+
super(firestore20, mailgunClient);
|
|
13423
13841
|
this.DEFAULT_MAILGUN_DOMAIN = "mg.metaesthetics.net";
|
|
13424
13842
|
this.DEFAULT_FROM_ADDRESS = "Metaesthetics <no-reply@mg.metaesthetics.net>";
|
|
13425
13843
|
}
|
|
@@ -13901,8 +14319,8 @@ var PatientInviteMailingService = class extends BaseMailingService {
|
|
|
13901
14319
|
* @param firestore - Firestore instance provided by the caller
|
|
13902
14320
|
* @param mailgunClient - Mailgun client instance (mailgun.js v10+) provided by the caller
|
|
13903
14321
|
*/
|
|
13904
|
-
constructor(
|
|
13905
|
-
super(
|
|
14322
|
+
constructor(firestore20, mailgunClient) {
|
|
14323
|
+
super(firestore20, mailgunClient);
|
|
13906
14324
|
this.DEFAULT_REGISTRATION_URL = "https://metaesthetics.net/patient/register";
|
|
13907
14325
|
this.DEFAULT_SUBJECT = "Claim Your Patient Profile - Metaesthetics";
|
|
13908
14326
|
this.DEFAULT_MAILGUN_DOMAIN = "mg.metaesthetics.net";
|
|
@@ -14377,8 +14795,8 @@ var ClinicWelcomeMailingService = class extends BaseMailingService {
|
|
|
14377
14795
|
* @param firestore - Firestore instance provided by the caller
|
|
14378
14796
|
* @param mailgunClient - Mailgun client instance (mailgun.js v10+) provided by the caller
|
|
14379
14797
|
*/
|
|
14380
|
-
constructor(
|
|
14381
|
-
super(
|
|
14798
|
+
constructor(firestore20, mailgunClient) {
|
|
14799
|
+
super(firestore20, mailgunClient);
|
|
14382
14800
|
this.DEFAULT_DASHBOARD_URL = "https://app.metaesthetics.net/dashboard";
|
|
14383
14801
|
this.DEFAULT_SUPPORT_EMAIL = "support@metaesthetics.net";
|
|
14384
14802
|
this.DEFAULT_SUBJECT = "Welcome to Metaesthetics - Your Clinic Registration is Complete";
|
|
@@ -14548,14 +14966,14 @@ var ClinicWelcomeMailingService = class extends BaseMailingService {
|
|
|
14548
14966
|
};
|
|
14549
14967
|
|
|
14550
14968
|
// src/admin/users/user-profile.admin.ts
|
|
14551
|
-
var
|
|
14969
|
+
var admin19 = __toESM(require("firebase-admin"));
|
|
14552
14970
|
var UserProfileAdminService = class {
|
|
14553
14971
|
/**
|
|
14554
14972
|
* Constructor for UserProfileAdminService
|
|
14555
14973
|
* @param firestore Optional Firestore instance. If not provided, uses the default admin SDK instance.
|
|
14556
14974
|
*/
|
|
14557
|
-
constructor(
|
|
14558
|
-
this.db =
|
|
14975
|
+
constructor(firestore20) {
|
|
14976
|
+
this.db = firestore20 || admin19.firestore();
|
|
14559
14977
|
}
|
|
14560
14978
|
/**
|
|
14561
14979
|
* Creates a blank user profile with minimal information
|
|
@@ -14572,9 +14990,9 @@ var UserProfileAdminService = class {
|
|
|
14572
14990
|
roles: [],
|
|
14573
14991
|
// Empty roles array as requested
|
|
14574
14992
|
isAnonymous: authUserData.isAnonymous,
|
|
14575
|
-
createdAt:
|
|
14576
|
-
updatedAt:
|
|
14577
|
-
lastLoginAt:
|
|
14993
|
+
createdAt: admin19.firestore.FieldValue.serverTimestamp(),
|
|
14994
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp(),
|
|
14995
|
+
lastLoginAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
14578
14996
|
};
|
|
14579
14997
|
try {
|
|
14580
14998
|
const userRef = this.db.collection(USERS_COLLECTION).doc(authUserData.uid);
|
|
@@ -14650,8 +15068,8 @@ var UserProfileAdminService = class {
|
|
|
14650
15068
|
clinics: mergedProfileData.clinics || [],
|
|
14651
15069
|
doctorIds: mergedProfileData.doctorIds || [],
|
|
14652
15070
|
clinicIds: mergedProfileData.clinicIds || [],
|
|
14653
|
-
createdAt:
|
|
14654
|
-
updatedAt:
|
|
15071
|
+
createdAt: admin19.firestore.FieldValue.serverTimestamp(),
|
|
15072
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
14655
15073
|
};
|
|
14656
15074
|
await patientProfileRef.set(patientProfileData);
|
|
14657
15075
|
patientProfile = {
|
|
@@ -14690,8 +15108,8 @@ var UserProfileAdminService = class {
|
|
|
14690
15108
|
};
|
|
14691
15109
|
const sensitiveInfoData = {
|
|
14692
15110
|
...mergedSensitiveData,
|
|
14693
|
-
createdAt:
|
|
14694
|
-
updatedAt:
|
|
15111
|
+
createdAt: admin19.firestore.FieldValue.serverTimestamp(),
|
|
15112
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
14695
15113
|
// Leave dateOfBirth as is
|
|
14696
15114
|
};
|
|
14697
15115
|
await sensitiveInfoRef.set(sensitiveInfoData);
|
|
@@ -14717,7 +15135,7 @@ var UserProfileAdminService = class {
|
|
|
14717
15135
|
contraindications: [],
|
|
14718
15136
|
allergies: [],
|
|
14719
15137
|
currentMedications: [],
|
|
14720
|
-
lastUpdated:
|
|
15138
|
+
lastUpdated: admin19.firestore.FieldValue.serverTimestamp(),
|
|
14721
15139
|
updatedBy: userId
|
|
14722
15140
|
};
|
|
14723
15141
|
await medicalInfoRef.set(medicalInfoData);
|
|
@@ -14734,14 +15152,14 @@ var UserProfileAdminService = class {
|
|
|
14734
15152
|
const batch = this.db.batch();
|
|
14735
15153
|
if (!userData.roles.includes("patient" /* PATIENT */)) {
|
|
14736
15154
|
batch.update(userRef, {
|
|
14737
|
-
roles:
|
|
14738
|
-
updatedAt:
|
|
15155
|
+
roles: admin19.firestore.FieldValue.arrayUnion("patient" /* PATIENT */),
|
|
15156
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
14739
15157
|
});
|
|
14740
15158
|
}
|
|
14741
15159
|
if (!userData.patientProfile) {
|
|
14742
15160
|
batch.update(userRef, {
|
|
14743
15161
|
patientProfile: patientProfileId,
|
|
14744
|
-
updatedAt:
|
|
15162
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
14745
15163
|
});
|
|
14746
15164
|
}
|
|
14747
15165
|
await batch.commit();
|
|
@@ -14782,8 +15200,8 @@ var UserProfileAdminService = class {
|
|
|
14782
15200
|
const userData = userDoc.data();
|
|
14783
15201
|
if (!userData.roles.includes("clinic_admin" /* CLINIC_ADMIN */)) {
|
|
14784
15202
|
await userRef.update({
|
|
14785
|
-
roles:
|
|
14786
|
-
updatedAt:
|
|
15203
|
+
roles: admin19.firestore.FieldValue.arrayUnion("clinic_admin" /* CLINIC_ADMIN */),
|
|
15204
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
14787
15205
|
});
|
|
14788
15206
|
}
|
|
14789
15207
|
const updatedUserDoc = await userRef.get();
|
|
@@ -14814,8 +15232,8 @@ var UserProfileAdminService = class {
|
|
|
14814
15232
|
const userData = userDoc.data();
|
|
14815
15233
|
if (!userData.roles.includes("practitioner" /* PRACTITIONER */)) {
|
|
14816
15234
|
await userRef.update({
|
|
14817
|
-
roles:
|
|
14818
|
-
updatedAt:
|
|
15235
|
+
roles: admin19.firestore.FieldValue.arrayUnion("practitioner" /* PRACTITIONER */),
|
|
15236
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
14819
15237
|
});
|
|
14820
15238
|
}
|
|
14821
15239
|
const updatedUserDoc = await userRef.get();
|
|
@@ -14879,6 +15297,7 @@ TimestampUtils.enableServerMode();
|
|
|
14879
15297
|
PractitionerTokenStatus,
|
|
14880
15298
|
ProcedureAggregationService,
|
|
14881
15299
|
REVENUE_ANALYTICS_SUBCOLLECTION,
|
|
15300
|
+
ResourceCalendarAdminService,
|
|
14882
15301
|
ReviewsAggregationService,
|
|
14883
15302
|
SubscriptionStatus,
|
|
14884
15303
|
TIME_EFFICIENCY_ANALYTICS_SUBCOLLECTION,
|