@blackcode_sa/metaestetics-api 1.15.16 → 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 +371 -4
- package/dist/index.d.ts +371 -4
- package/dist/index.js +2227 -1580
- package/dist/index.mjs +1543 -891
- 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 +116 -0
- 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 +15 -10
- 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.mjs
CHANGED
|
@@ -421,6 +421,7 @@ var BillingTransactionType = /* @__PURE__ */ ((BillingTransactionType2) => {
|
|
|
421
421
|
BillingTransactionType2["SUBSCRIPTION_CANCELED"] = "subscription_canceled";
|
|
422
422
|
BillingTransactionType2["SUBSCRIPTION_REACTIVATED"] = "subscription_reactivated";
|
|
423
423
|
BillingTransactionType2["SUBSCRIPTION_DELETED"] = "subscription_deleted";
|
|
424
|
+
BillingTransactionType2["ADDON_PURCHASED"] = "addon_purchased";
|
|
424
425
|
return BillingTransactionType2;
|
|
425
426
|
})(BillingTransactionType || {});
|
|
426
427
|
|
|
@@ -524,7 +525,7 @@ var PatientRequirementOverallStatus = /* @__PURE__ */ ((PatientRequirementOveral
|
|
|
524
525
|
var PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME = "patientRequirements";
|
|
525
526
|
|
|
526
527
|
// src/admin/aggregation/appointment/appointment.aggregation.service.ts
|
|
527
|
-
import * as
|
|
528
|
+
import * as admin7 from "firebase-admin";
|
|
528
529
|
|
|
529
530
|
// src/backoffice/types/requirement.types.ts
|
|
530
531
|
var REQUIREMENTS_COLLECTION = "backoffice_requirements";
|
|
@@ -543,6 +544,11 @@ var DOCUMENTATION_TEMPLATES_COLLECTION = "documentation-templates";
|
|
|
543
544
|
var USER_FORMS_SUBCOLLECTION = "user-forms";
|
|
544
545
|
var DOCTOR_FORMS_SUBCOLLECTION = "doctor-forms";
|
|
545
546
|
|
|
547
|
+
// src/types/resource/index.ts
|
|
548
|
+
var RESOURCES_COLLECTION = "resources";
|
|
549
|
+
var RESOURCE_INSTANCES_SUBCOLLECTION = "instances";
|
|
550
|
+
var RESOURCE_CALENDAR_SUBCOLLECTION = "calendar";
|
|
551
|
+
|
|
546
552
|
// src/types/reviews/index.ts
|
|
547
553
|
var REVIEWS_COLLECTION = "reviews";
|
|
548
554
|
|
|
@@ -621,9 +627,9 @@ var Logger = class {
|
|
|
621
627
|
|
|
622
628
|
// src/admin/notifications/notifications.admin.ts
|
|
623
629
|
var NotificationsAdmin = class {
|
|
624
|
-
constructor(
|
|
630
|
+
constructor(firestore20) {
|
|
625
631
|
this.expo = new Expo();
|
|
626
|
-
this.db =
|
|
632
|
+
this.db = firestore20 || admin2.firestore();
|
|
627
633
|
}
|
|
628
634
|
/**
|
|
629
635
|
* Dohvata notifikaciju po ID-u
|
|
@@ -1215,8 +1221,8 @@ var NotificationsAdmin = class {
|
|
|
1215
1221
|
|
|
1216
1222
|
// src/admin/requirements/patient-requirements.admin.service.ts
|
|
1217
1223
|
var PatientRequirementsAdminService = class {
|
|
1218
|
-
constructor(
|
|
1219
|
-
this.db =
|
|
1224
|
+
constructor(firestore20) {
|
|
1225
|
+
this.db = firestore20 || admin3.firestore();
|
|
1220
1226
|
this.notificationsAdmin = new NotificationsAdmin(this.db);
|
|
1221
1227
|
}
|
|
1222
1228
|
/**
|
|
@@ -1544,8 +1550,8 @@ var PatientRequirementsAdminService = class {
|
|
|
1544
1550
|
// src/admin/calendar/calendar.admin.service.ts
|
|
1545
1551
|
import * as admin4 from "firebase-admin";
|
|
1546
1552
|
var CalendarAdminService = class {
|
|
1547
|
-
constructor(
|
|
1548
|
-
this.db =
|
|
1553
|
+
constructor(firestore20) {
|
|
1554
|
+
this.db = firestore20 || admin4.firestore();
|
|
1549
1555
|
Logger.info("[CalendarAdminService] Initialized.");
|
|
1550
1556
|
}
|
|
1551
1557
|
/**
|
|
@@ -1819,11 +1825,163 @@ var CalendarAdminService = class {
|
|
|
1819
1825
|
}
|
|
1820
1826
|
};
|
|
1821
1827
|
|
|
1828
|
+
// src/admin/calendar/resource-calendar.admin.ts
|
|
1829
|
+
import * as admin5 from "firebase-admin";
|
|
1830
|
+
var ResourceCalendarAdminService = class {
|
|
1831
|
+
constructor(firestore20) {
|
|
1832
|
+
this.db = firestore20 || admin5.firestore();
|
|
1833
|
+
Logger.info("[ResourceCalendarAdminService] Initialized.");
|
|
1834
|
+
}
|
|
1835
|
+
/**
|
|
1836
|
+
* Builds the Firestore document path for a resource calendar event.
|
|
1837
|
+
*/
|
|
1838
|
+
getResourceCalendarEventPath(clinicBranchId, booking) {
|
|
1839
|
+
return `${CLINICS_COLLECTION}/${clinicBranchId}/${RESOURCES_COLLECTION}/${booking.resourceId}/${RESOURCE_INSTANCES_SUBCOLLECTION}/${booking.resourceInstanceId}/${RESOURCE_CALENDAR_SUBCOLLECTION}/${booking.calendarEventId}`;
|
|
1840
|
+
}
|
|
1841
|
+
/**
|
|
1842
|
+
* Updates the status of all resource calendar events associated with a given appointment.
|
|
1843
|
+
*
|
|
1844
|
+
* @param appointment - The appointment object containing resourceBookings.
|
|
1845
|
+
* @param newStatus - The new CalendarEventStatus to set.
|
|
1846
|
+
*/
|
|
1847
|
+
async updateResourceBookingEventsStatus(appointment, newStatus) {
|
|
1848
|
+
const resourceBookings = appointment.resourceBookings;
|
|
1849
|
+
if (!resourceBookings || resourceBookings.length === 0) {
|
|
1850
|
+
Logger.debug(
|
|
1851
|
+
`[ResourceCalendarAdminService] No resource bookings on appointment ${appointment.id}, skipping status update.`
|
|
1852
|
+
);
|
|
1853
|
+
return;
|
|
1854
|
+
}
|
|
1855
|
+
Logger.info(
|
|
1856
|
+
`[ResourceCalendarAdminService] Updating ${resourceBookings.length} resource calendar event(s) to ${newStatus} for appointment ${appointment.id}`
|
|
1857
|
+
);
|
|
1858
|
+
const batch = this.db.batch();
|
|
1859
|
+
const serverTimestamp = admin5.firestore.FieldValue.serverTimestamp();
|
|
1860
|
+
for (const booking of resourceBookings) {
|
|
1861
|
+
const eventPath = this.getResourceCalendarEventPath(
|
|
1862
|
+
appointment.clinicBranchId,
|
|
1863
|
+
booking
|
|
1864
|
+
);
|
|
1865
|
+
const eventRef = this.db.doc(eventPath);
|
|
1866
|
+
batch.update(eventRef, {
|
|
1867
|
+
status: newStatus,
|
|
1868
|
+
updatedAt: serverTimestamp
|
|
1869
|
+
});
|
|
1870
|
+
Logger.debug(
|
|
1871
|
+
`[ResourceCalendarAdminService] Added status update for resource event ${booking.calendarEventId} (${booking.resourceName} / ${booking.resourceInstanceLabel})`
|
|
1872
|
+
);
|
|
1873
|
+
}
|
|
1874
|
+
try {
|
|
1875
|
+
await batch.commit();
|
|
1876
|
+
Logger.info(
|
|
1877
|
+
`[ResourceCalendarAdminService] Successfully updated ${resourceBookings.length} resource calendar event statuses for appointment ${appointment.id}.`
|
|
1878
|
+
);
|
|
1879
|
+
} catch (error) {
|
|
1880
|
+
Logger.error(
|
|
1881
|
+
`[ResourceCalendarAdminService] Error updating resource calendar event statuses for appointment ${appointment.id}:`,
|
|
1882
|
+
error
|
|
1883
|
+
);
|
|
1884
|
+
throw error;
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
/**
|
|
1888
|
+
* Updates the eventTime (start and end) of all resource calendar events
|
|
1889
|
+
* associated with a given appointment.
|
|
1890
|
+
*
|
|
1891
|
+
* @param appointment - The appointment object containing resourceBookings.
|
|
1892
|
+
* @param newEventTime - The new event time with admin Timestamps.
|
|
1893
|
+
*/
|
|
1894
|
+
async updateResourceBookingEventsTime(appointment, newEventTime) {
|
|
1895
|
+
const resourceBookings = appointment.resourceBookings;
|
|
1896
|
+
if (!resourceBookings || resourceBookings.length === 0) {
|
|
1897
|
+
Logger.debug(
|
|
1898
|
+
`[ResourceCalendarAdminService] No resource bookings on appointment ${appointment.id}, skipping time update.`
|
|
1899
|
+
);
|
|
1900
|
+
return;
|
|
1901
|
+
}
|
|
1902
|
+
Logger.info(
|
|
1903
|
+
`[ResourceCalendarAdminService] Updating ${resourceBookings.length} resource calendar event time(s) for appointment ${appointment.id}`
|
|
1904
|
+
);
|
|
1905
|
+
const batch = this.db.batch();
|
|
1906
|
+
const serverTimestamp = admin5.firestore.FieldValue.serverTimestamp();
|
|
1907
|
+
for (const booking of resourceBookings) {
|
|
1908
|
+
const eventPath = this.getResourceCalendarEventPath(
|
|
1909
|
+
appointment.clinicBranchId,
|
|
1910
|
+
booking
|
|
1911
|
+
);
|
|
1912
|
+
const eventRef = this.db.doc(eventPath);
|
|
1913
|
+
batch.update(eventRef, {
|
|
1914
|
+
eventTime: {
|
|
1915
|
+
start: newEventTime.start,
|
|
1916
|
+
end: newEventTime.end
|
|
1917
|
+
},
|
|
1918
|
+
updatedAt: serverTimestamp
|
|
1919
|
+
});
|
|
1920
|
+
Logger.debug(
|
|
1921
|
+
`[ResourceCalendarAdminService] Added time update for resource event ${booking.calendarEventId} (${booking.resourceName} / ${booking.resourceInstanceLabel})`
|
|
1922
|
+
);
|
|
1923
|
+
}
|
|
1924
|
+
try {
|
|
1925
|
+
await batch.commit();
|
|
1926
|
+
Logger.info(
|
|
1927
|
+
`[ResourceCalendarAdminService] Successfully updated ${resourceBookings.length} resource calendar event times for appointment ${appointment.id}.`
|
|
1928
|
+
);
|
|
1929
|
+
} catch (error) {
|
|
1930
|
+
Logger.error(
|
|
1931
|
+
`[ResourceCalendarAdminService] Error updating resource calendar event times for appointment ${appointment.id}:`,
|
|
1932
|
+
error
|
|
1933
|
+
);
|
|
1934
|
+
throw error;
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
/**
|
|
1938
|
+
* Deletes all resource calendar events associated with a given appointment.
|
|
1939
|
+
*
|
|
1940
|
+
* @param appointment - The appointment object containing resourceBookings.
|
|
1941
|
+
*/
|
|
1942
|
+
async deleteResourceBookingEvents(appointment) {
|
|
1943
|
+
const resourceBookings = appointment.resourceBookings;
|
|
1944
|
+
if (!resourceBookings || resourceBookings.length === 0) {
|
|
1945
|
+
Logger.debug(
|
|
1946
|
+
`[ResourceCalendarAdminService] No resource bookings on appointment ${appointment.id}, skipping deletion.`
|
|
1947
|
+
);
|
|
1948
|
+
return;
|
|
1949
|
+
}
|
|
1950
|
+
Logger.info(
|
|
1951
|
+
`[ResourceCalendarAdminService] Deleting ${resourceBookings.length} resource calendar event(s) for appointment ${appointment.id}`
|
|
1952
|
+
);
|
|
1953
|
+
const batch = this.db.batch();
|
|
1954
|
+
for (const booking of resourceBookings) {
|
|
1955
|
+
const eventPath = this.getResourceCalendarEventPath(
|
|
1956
|
+
appointment.clinicBranchId,
|
|
1957
|
+
booking
|
|
1958
|
+
);
|
|
1959
|
+
const eventRef = this.db.doc(eventPath);
|
|
1960
|
+
batch.delete(eventRef);
|
|
1961
|
+
Logger.debug(
|
|
1962
|
+
`[ResourceCalendarAdminService] Added deletion for resource event ${booking.calendarEventId} (${booking.resourceName} / ${booking.resourceInstanceLabel})`
|
|
1963
|
+
);
|
|
1964
|
+
}
|
|
1965
|
+
try {
|
|
1966
|
+
await batch.commit();
|
|
1967
|
+
Logger.info(
|
|
1968
|
+
`[ResourceCalendarAdminService] Successfully deleted ${resourceBookings.length} resource calendar events for appointment ${appointment.id}.`
|
|
1969
|
+
);
|
|
1970
|
+
} catch (error) {
|
|
1971
|
+
Logger.error(
|
|
1972
|
+
`[ResourceCalendarAdminService] Error deleting resource calendar events for appointment ${appointment.id}:`,
|
|
1973
|
+
error
|
|
1974
|
+
);
|
|
1975
|
+
throw error;
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
};
|
|
1979
|
+
|
|
1822
1980
|
// src/admin/mailing/appointment/appointment.mailing.service.ts
|
|
1823
1981
|
import { DateTime } from "luxon";
|
|
1824
1982
|
|
|
1825
1983
|
// src/admin/mailing/base.mailing.service.ts
|
|
1826
|
-
import * as
|
|
1984
|
+
import * as admin6 from "firebase-admin";
|
|
1827
1985
|
var BaseMailingService = class {
|
|
1828
1986
|
// Expecting the new mailgun.js client
|
|
1829
1987
|
/**
|
|
@@ -1831,9 +1989,9 @@ var BaseMailingService = class {
|
|
|
1831
1989
|
* @param firestore Firestore instance provided by the caller
|
|
1832
1990
|
* @param mailgunClient Mailgun client instance (mailgun.js v10+) provided by the caller
|
|
1833
1991
|
*/
|
|
1834
|
-
constructor(
|
|
1992
|
+
constructor(firestore20, mailgunClient) {
|
|
1835
1993
|
var _a;
|
|
1836
|
-
this.db =
|
|
1994
|
+
this.db = firestore20;
|
|
1837
1995
|
this.mailgunClient = mailgunClient;
|
|
1838
1996
|
if (!this.db) {
|
|
1839
1997
|
Logger.error("[BaseMailingService] No Firestore instance provided");
|
|
@@ -1933,7 +2091,7 @@ var BaseMailingService = class {
|
|
|
1933
2091
|
status: error.status,
|
|
1934
2092
|
stack: error.stack
|
|
1935
2093
|
} : null,
|
|
1936
|
-
sentAt:
|
|
2094
|
+
sentAt: admin6.firestore.FieldValue.serverTimestamp()
|
|
1937
2095
|
});
|
|
1938
2096
|
Logger.info(
|
|
1939
2097
|
`[BaseMailingService] Email log recorded. Success: ${success}`
|
|
@@ -2640,8 +2798,8 @@ var appointmentRescheduledProposalTemplate = `
|
|
|
2640
2798
|
</html>
|
|
2641
2799
|
`;
|
|
2642
2800
|
var AppointmentMailingService = class extends BaseMailingService {
|
|
2643
|
-
constructor(
|
|
2644
|
-
super(
|
|
2801
|
+
constructor(firestore20, mailgunClient) {
|
|
2802
|
+
super(firestore20, mailgunClient);
|
|
2645
2803
|
this.DEFAULT_MAILGUN_DOMAIN = "mg.metaesthetics.net";
|
|
2646
2804
|
Logger.info("[AppointmentMailingService] Initialized.");
|
|
2647
2805
|
}
|
|
@@ -3081,8 +3239,8 @@ var AppointmentAggregationService = class {
|
|
|
3081
3239
|
* @param mailgunClient - An initialized Mailgun client instance.
|
|
3082
3240
|
* @param firestore Optional Firestore instance. If not provided, it uses the default admin SDK instance.
|
|
3083
3241
|
*/
|
|
3084
|
-
constructor(mailgunClient,
|
|
3085
|
-
this.db =
|
|
3242
|
+
constructor(mailgunClient, firestore20) {
|
|
3243
|
+
this.db = firestore20 || admin7.firestore();
|
|
3086
3244
|
this.appointmentMailingService = new AppointmentMailingService(
|
|
3087
3245
|
this.db,
|
|
3088
3246
|
mailgunClient
|
|
@@ -3090,6 +3248,7 @@ var AppointmentAggregationService = class {
|
|
|
3090
3248
|
);
|
|
3091
3249
|
this.notificationsAdmin = new NotificationsAdmin(this.db);
|
|
3092
3250
|
this.calendarAdminService = new CalendarAdminService(this.db);
|
|
3251
|
+
this.resourceCalendarAdminService = new ResourceCalendarAdminService(this.db);
|
|
3093
3252
|
this.patientRequirementsAdminService = new PatientRequirementsAdminService(this.db);
|
|
3094
3253
|
Logger.info("[AppointmentAggregationService] Initialized.");
|
|
3095
3254
|
}
|
|
@@ -3231,6 +3390,10 @@ var AppointmentAggregationService = class {
|
|
|
3231
3390
|
after,
|
|
3232
3391
|
"confirmed" /* CONFIRMED */
|
|
3233
3392
|
);
|
|
3393
|
+
await this.resourceCalendarAdminService.updateResourceBookingEventsStatus(
|
|
3394
|
+
after,
|
|
3395
|
+
"confirmed" /* CONFIRMED */
|
|
3396
|
+
);
|
|
3234
3397
|
if ((patientSensitiveInfo == null ? void 0 : patientSensitiveInfo.email) && patientProfile) {
|
|
3235
3398
|
Logger.info(
|
|
3236
3399
|
`[AggService] Sending appointment confirmed email to patient ${patientSensitiveInfo.email}`
|
|
@@ -3281,6 +3444,10 @@ var AppointmentAggregationService = class {
|
|
|
3281
3444
|
after,
|
|
3282
3445
|
"confirmed" /* CONFIRMED */
|
|
3283
3446
|
);
|
|
3447
|
+
await this.resourceCalendarAdminService.updateResourceBookingEventsStatus(
|
|
3448
|
+
after,
|
|
3449
|
+
"confirmed" /* CONFIRMED */
|
|
3450
|
+
);
|
|
3284
3451
|
if ((patientSensitiveInfo == null ? void 0 : patientSensitiveInfo.email) && patientProfile) {
|
|
3285
3452
|
Logger.info(
|
|
3286
3453
|
`[AggService] Sending appointment confirmed email to patient ${patientSensitiveInfo.email}`
|
|
@@ -3348,6 +3515,10 @@ var AppointmentAggregationService = class {
|
|
|
3348
3515
|
after,
|
|
3349
3516
|
calendarStatus(after.status)
|
|
3350
3517
|
);
|
|
3518
|
+
await this.resourceCalendarAdminService.updateResourceBookingEventsStatus(
|
|
3519
|
+
after,
|
|
3520
|
+
calendarStatus(after.status)
|
|
3521
|
+
);
|
|
3351
3522
|
if ((patientSensitiveInfo == null ? void 0 : patientSensitiveInfo.email) && patientProfile) {
|
|
3352
3523
|
Logger.info(
|
|
3353
3524
|
`[AggService] Sending appointment cancellation email to patient ${patientSensitiveInfo.email}`
|
|
@@ -3394,6 +3565,10 @@ var AppointmentAggregationService = class {
|
|
|
3394
3565
|
after,
|
|
3395
3566
|
"completed" /* COMPLETED */
|
|
3396
3567
|
);
|
|
3568
|
+
await this.resourceCalendarAdminService.updateResourceBookingEventsStatus(
|
|
3569
|
+
after,
|
|
3570
|
+
"completed" /* COMPLETED */
|
|
3571
|
+
);
|
|
3397
3572
|
if ((patientSensitiveInfo == null ? void 0 : patientSensitiveInfo.email) && patientProfile) {
|
|
3398
3573
|
Logger.info(
|
|
3399
3574
|
`[AggService] Sending review request email to patient ${patientSensitiveInfo.email}`
|
|
@@ -3424,6 +3599,14 @@ var AppointmentAggregationService = class {
|
|
|
3424
3599
|
after,
|
|
3425
3600
|
"pending" /* PENDING */
|
|
3426
3601
|
);
|
|
3602
|
+
await this.resourceCalendarAdminService.updateResourceBookingEventsTime(after, {
|
|
3603
|
+
start: after.appointmentStartTime,
|
|
3604
|
+
end: after.appointmentEndTime
|
|
3605
|
+
});
|
|
3606
|
+
await this.resourceCalendarAdminService.updateResourceBookingEventsStatus(
|
|
3607
|
+
after,
|
|
3608
|
+
"pending" /* PENDING */
|
|
3609
|
+
);
|
|
3427
3610
|
if ((patientSensitiveInfo == null ? void 0 : patientSensitiveInfo.email) && patientProfile) {
|
|
3428
3611
|
Logger.info(
|
|
3429
3612
|
`[AggService] Sending reschedule proposal email to patient ${patientSensitiveInfo.email}`
|
|
@@ -3467,6 +3650,10 @@ var AppointmentAggregationService = class {
|
|
|
3467
3650
|
start: after.appointmentStartTime,
|
|
3468
3651
|
end: after.appointmentEndTime
|
|
3469
3652
|
});
|
|
3653
|
+
await this.resourceCalendarAdminService.updateResourceBookingEventsTime(after, {
|
|
3654
|
+
start: after.appointmentStartTime,
|
|
3655
|
+
end: after.appointmentEndTime
|
|
3656
|
+
});
|
|
3470
3657
|
} else {
|
|
3471
3658
|
Logger.warn(
|
|
3472
3659
|
`[AggService] Independent time change detected for ${after.id} with status ${after.status}. Review implications for requirements and calendar.`
|
|
@@ -3511,6 +3698,7 @@ var AppointmentAggregationService = class {
|
|
|
3511
3698
|
);
|
|
3512
3699
|
}
|
|
3513
3700
|
await this.calendarAdminService.deleteAppointmentCalendarEvents(deletedAppointment);
|
|
3701
|
+
await this.resourceCalendarAdminService.deleteResourceBookingEvents(deletedAppointment);
|
|
3514
3702
|
}
|
|
3515
3703
|
// --- Helper Methods for Aggregation Logic ---
|
|
3516
3704
|
/**
|
|
@@ -3602,7 +3790,7 @@ var AppointmentAggregationService = class {
|
|
|
3602
3790
|
} else if (template.timeframe.unit === "hours" /* HOURS */) {
|
|
3603
3791
|
dueDateTime.setHours(dueDateTime.getHours() - notifyAtValue);
|
|
3604
3792
|
}
|
|
3605
|
-
dueTime =
|
|
3793
|
+
dueTime = admin7.firestore.Timestamp.fromDate(dueDateTime);
|
|
3606
3794
|
}
|
|
3607
3795
|
const actionableWindowHours = template.importance === "high" ? 1 : template.importance === "medium" ? 4 : 15;
|
|
3608
3796
|
const instructionObject = {
|
|
@@ -3617,7 +3805,7 @@ var AppointmentAggregationService = class {
|
|
|
3617
3805
|
status: "pendingNotification" /* PENDING_NOTIFICATION */,
|
|
3618
3806
|
originalNotifyAtValue: notifyAtValue,
|
|
3619
3807
|
originalTimeframeUnit: template.timeframe.unit,
|
|
3620
|
-
updatedAt:
|
|
3808
|
+
updatedAt: admin7.firestore.Timestamp.now()
|
|
3621
3809
|
// Use current server timestamp
|
|
3622
3810
|
};
|
|
3623
3811
|
return instructionObject;
|
|
@@ -3636,8 +3824,8 @@ var AppointmentAggregationService = class {
|
|
|
3636
3824
|
overallStatus: "active" /* ACTIVE */,
|
|
3637
3825
|
instructions,
|
|
3638
3826
|
// Timestamps - cast to any to satisfy client-side Timestamp type for now
|
|
3639
|
-
createdAt:
|
|
3640
|
-
updatedAt:
|
|
3827
|
+
createdAt: admin7.firestore.FieldValue.serverTimestamp(),
|
|
3828
|
+
updatedAt: admin7.firestore.FieldValue.serverTimestamp()
|
|
3641
3829
|
};
|
|
3642
3830
|
Logger.debug(
|
|
3643
3831
|
`[AggService] Setting data for requirement: ${JSON.stringify({
|
|
@@ -3987,7 +4175,7 @@ var AppointmentAggregationService = class {
|
|
|
3987
4175
|
} else if (template.timeframe.unit === "hours" /* HOURS */) {
|
|
3988
4176
|
dueDateTime.setHours(dueDateTime.getHours() + notifyAtValue);
|
|
3989
4177
|
}
|
|
3990
|
-
dueTime =
|
|
4178
|
+
dueTime = admin7.firestore.Timestamp.fromDate(dueDateTime);
|
|
3991
4179
|
}
|
|
3992
4180
|
const actionableWindowHours = template.importance === "high" ? 1 : template.importance === "medium" ? 4 : 15;
|
|
3993
4181
|
const instructionObject = {
|
|
@@ -4001,7 +4189,7 @@ var AppointmentAggregationService = class {
|
|
|
4001
4189
|
status: "pendingNotification" /* PENDING_NOTIFICATION */,
|
|
4002
4190
|
originalNotifyAtValue: notifyAtValue,
|
|
4003
4191
|
originalTimeframeUnit: template.timeframe.unit,
|
|
4004
|
-
updatedAt:
|
|
4192
|
+
updatedAt: admin7.firestore.Timestamp.now(),
|
|
4005
4193
|
notificationId: void 0,
|
|
4006
4194
|
actionTakenAt: void 0
|
|
4007
4195
|
};
|
|
@@ -4020,8 +4208,8 @@ var AppointmentAggregationService = class {
|
|
|
4020
4208
|
instructions,
|
|
4021
4209
|
sourceProcedures: reqWithSource.sourceProcedures,
|
|
4022
4210
|
// Track which procedures this requirement comes from
|
|
4023
|
-
createdAt:
|
|
4024
|
-
updatedAt:
|
|
4211
|
+
createdAt: admin7.firestore.FieldValue.serverTimestamp(),
|
|
4212
|
+
updatedAt: admin7.firestore.FieldValue.serverTimestamp()
|
|
4025
4213
|
};
|
|
4026
4214
|
Logger.debug(
|
|
4027
4215
|
`[AggService] Setting data for requirement: ${JSON.stringify({
|
|
@@ -4181,7 +4369,7 @@ var AppointmentAggregationService = class {
|
|
|
4181
4369
|
if (instance.overallStatus !== newOverallStatus && instance.overallStatus !== "failedToProcess" /* FAILED_TO_PROCESS */) {
|
|
4182
4370
|
batch.update(doc3.ref, {
|
|
4183
4371
|
overallStatus: newOverallStatus,
|
|
4184
|
-
updatedAt:
|
|
4372
|
+
updatedAt: admin7.firestore.FieldValue.serverTimestamp()
|
|
4185
4373
|
// Cast for now
|
|
4186
4374
|
// Potentially also cancel individual instructions if not handled by another trigger
|
|
4187
4375
|
// instructions: instance.instructions.map(instr => ({ ...instr, status: PatientInstructionStatus.CANCELLED, updatedAt: admin.firestore.FieldValue.serverTimestamp() as any }))
|
|
@@ -4257,17 +4445,17 @@ var AppointmentAggregationService = class {
|
|
|
4257
4445
|
if (!hasDoctor || !hasClinic) {
|
|
4258
4446
|
const patientRef = this.db.collection(PATIENTS_COLLECTION).doc(patientProfile.id);
|
|
4259
4447
|
const updateData = {
|
|
4260
|
-
updatedAt:
|
|
4448
|
+
updatedAt: admin7.firestore.FieldValue.serverTimestamp()
|
|
4261
4449
|
};
|
|
4262
4450
|
if (!hasDoctor) {
|
|
4263
4451
|
Logger.debug(
|
|
4264
4452
|
`[AggService] Adding practitioner ${practitionerId} to patient ${patientProfile.id}`
|
|
4265
4453
|
);
|
|
4266
|
-
updateData.doctorIds =
|
|
4454
|
+
updateData.doctorIds = admin7.firestore.FieldValue.arrayUnion(practitionerId);
|
|
4267
4455
|
}
|
|
4268
4456
|
if (!hasClinic) {
|
|
4269
4457
|
Logger.debug(`[AggService] Adding clinic ${clinicId} to patient ${patientProfile.id}`);
|
|
4270
|
-
updateData.clinicIds =
|
|
4458
|
+
updateData.clinicIds = admin7.firestore.FieldValue.arrayUnion(clinicId);
|
|
4271
4459
|
}
|
|
4272
4460
|
await patientRef.update(updateData);
|
|
4273
4461
|
Logger.info(
|
|
@@ -4317,16 +4505,16 @@ var AppointmentAggregationService = class {
|
|
|
4317
4505
|
Logger.debug(
|
|
4318
4506
|
`[AggService] Removing practitioner ${practitionerId} from patient ${patientProfile.id}`
|
|
4319
4507
|
);
|
|
4320
|
-
updateData.doctorIds =
|
|
4508
|
+
updateData.doctorIds = admin7.firestore.FieldValue.arrayRemove(practitionerId);
|
|
4321
4509
|
updateNeeded = true;
|
|
4322
4510
|
}
|
|
4323
4511
|
if (activeClinicAppointments === 0 && ((_b = patientProfile.clinicIds) == null ? void 0 : _b.includes(clinicId))) {
|
|
4324
4512
|
Logger.debug(`[AggService] Removing clinic ${clinicId} from patient ${patientProfile.id}`);
|
|
4325
|
-
updateData.clinicIds =
|
|
4513
|
+
updateData.clinicIds = admin7.firestore.FieldValue.arrayRemove(clinicId);
|
|
4326
4514
|
updateNeeded = true;
|
|
4327
4515
|
}
|
|
4328
4516
|
if (updateNeeded) {
|
|
4329
|
-
updateData.updatedAt =
|
|
4517
|
+
updateData.updatedAt = admin7.firestore.FieldValue.serverTimestamp();
|
|
4330
4518
|
await patientRef.update(updateData);
|
|
4331
4519
|
Logger.info(`[AggService] Successfully removed links from patient ${patientProfile.id}`);
|
|
4332
4520
|
} else {
|
|
@@ -4617,7 +4805,7 @@ var AppointmentAggregationService = class {
|
|
|
4617
4805
|
userId: after.patientId,
|
|
4618
4806
|
userRole: "patient" /* PATIENT */,
|
|
4619
4807
|
notificationType: "procedureRecommendation" /* PROCEDURE_RECOMMENDATION */,
|
|
4620
|
-
notificationTime:
|
|
4808
|
+
notificationTime: admin7.firestore.Timestamp.now(),
|
|
4621
4809
|
notificationTokens: (patientProfile == null ? void 0 : patientProfile.expoTokens) || [],
|
|
4622
4810
|
title: "New Procedure Recommendation",
|
|
4623
4811
|
body: `${((_c = after.practitionerInfo) == null ? void 0 : _c.name) || "Your doctor"} recommended "${recommendation.procedure.procedureName}" for you. Suggested timeframe: in ${timeframeText}`,
|
|
@@ -4663,15 +4851,15 @@ var AppointmentAggregationService = class {
|
|
|
4663
4851
|
};
|
|
4664
4852
|
|
|
4665
4853
|
// src/admin/aggregation/clinic/clinic.aggregation.service.ts
|
|
4666
|
-
import * as
|
|
4854
|
+
import * as admin8 from "firebase-admin";
|
|
4667
4855
|
var CALENDAR_SUBCOLLECTION_ID = "calendar";
|
|
4668
4856
|
var ClinicAggregationService = class {
|
|
4669
4857
|
/**
|
|
4670
4858
|
* Constructor for ClinicAggregationService.
|
|
4671
4859
|
* @param firestore Optional Firestore instance. If not provided, it uses the default admin SDK instance.
|
|
4672
4860
|
*/
|
|
4673
|
-
constructor(
|
|
4674
|
-
this.db =
|
|
4861
|
+
constructor(firestore20) {
|
|
4862
|
+
this.db = firestore20 || admin8.firestore();
|
|
4675
4863
|
}
|
|
4676
4864
|
/**
|
|
4677
4865
|
* Adds clinic information to a clinic group when a new clinic is created
|
|
@@ -4694,9 +4882,9 @@ var ClinicAggregationService = class {
|
|
|
4694
4882
|
);
|
|
4695
4883
|
try {
|
|
4696
4884
|
await groupRef.update({
|
|
4697
|
-
clinicsInfo:
|
|
4698
|
-
clinicIds:
|
|
4699
|
-
updatedAt:
|
|
4885
|
+
clinicsInfo: admin8.firestore.FieldValue.arrayUnion(clinicInfo),
|
|
4886
|
+
clinicIds: admin8.firestore.FieldValue.arrayUnion(clinicId),
|
|
4887
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
4700
4888
|
});
|
|
4701
4889
|
console.log(
|
|
4702
4890
|
`[ClinicAggregationService] Successfully added ClinicInfo (ID: ${clinicId}) to Clinic Group ${clinicGroupId}.`
|
|
@@ -4741,7 +4929,7 @@ var ClinicAggregationService = class {
|
|
|
4741
4929
|
const updatedClinicsInfo = [...filteredClinicsInfo, clinicInfo];
|
|
4742
4930
|
batch.update(practitionerRef, {
|
|
4743
4931
|
clinicsInfo: updatedClinicsInfo,
|
|
4744
|
-
updatedAt:
|
|
4932
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
4745
4933
|
});
|
|
4746
4934
|
}
|
|
4747
4935
|
}
|
|
@@ -4779,7 +4967,7 @@ var ClinicAggregationService = class {
|
|
|
4779
4967
|
const procedureRef = this.db.collection(PROCEDURES_COLLECTION).doc(procedureId);
|
|
4780
4968
|
batch.update(procedureRef, {
|
|
4781
4969
|
clinicInfo,
|
|
4782
|
-
updatedAt:
|
|
4970
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
4783
4971
|
});
|
|
4784
4972
|
}
|
|
4785
4973
|
try {
|
|
@@ -4823,7 +5011,7 @@ var ClinicAggregationService = class {
|
|
|
4823
5011
|
const updatedClinicsInfo = [...filteredClinicsInfo, clinicInfo];
|
|
4824
5012
|
await groupRef.update({
|
|
4825
5013
|
clinicsInfo: updatedClinicsInfo,
|
|
4826
|
-
updatedAt:
|
|
5014
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
4827
5015
|
});
|
|
4828
5016
|
console.log(
|
|
4829
5017
|
`[ClinicAggregationService] Successfully updated ClinicInfo (ID: ${clinicId}) in Clinic Group ${clinicGroupId}.`
|
|
@@ -4882,7 +5070,7 @@ var ClinicAggregationService = class {
|
|
|
4882
5070
|
console.log(
|
|
4883
5071
|
`[ClinicAggregationService] Querying upcoming calendar events via collection group '${CALENDAR_SUBCOLLECTION_ID}' for clinic ${clinicId} to update location.`
|
|
4884
5072
|
);
|
|
4885
|
-
const now =
|
|
5073
|
+
const now = admin8.firestore.Timestamp.now();
|
|
4886
5074
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID).where("clinicBranchId", "==", clinicId).where("eventTime.start", ">", now);
|
|
4887
5075
|
try {
|
|
4888
5076
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -4899,7 +5087,7 @@ var ClinicAggregationService = class {
|
|
|
4899
5087
|
);
|
|
4900
5088
|
batch.update(doc3.ref, {
|
|
4901
5089
|
eventLocation: newLocation,
|
|
4902
|
-
updatedAt:
|
|
5090
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
4903
5091
|
});
|
|
4904
5092
|
});
|
|
4905
5093
|
await batch.commit();
|
|
@@ -4929,7 +5117,7 @@ var ClinicAggregationService = class {
|
|
|
4929
5117
|
console.log(
|
|
4930
5118
|
`[ClinicAggregationService] Querying upcoming calendar events for clinic ${clinicId} to update clinic info.`
|
|
4931
5119
|
);
|
|
4932
|
-
const now =
|
|
5120
|
+
const now = admin8.firestore.Timestamp.now();
|
|
4933
5121
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID).where("clinicBranchId", "==", clinicId).where("eventTime.start", ">", now);
|
|
4934
5122
|
try {
|
|
4935
5123
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -4946,7 +5134,7 @@ var ClinicAggregationService = class {
|
|
|
4946
5134
|
);
|
|
4947
5135
|
batch.update(doc3.ref, {
|
|
4948
5136
|
clinicInfo,
|
|
4949
|
-
updatedAt:
|
|
5137
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
4950
5138
|
});
|
|
4951
5139
|
});
|
|
4952
5140
|
await batch.commit();
|
|
@@ -4995,7 +5183,7 @@ var ClinicAggregationService = class {
|
|
|
4995
5183
|
batch.update(practitionerRef, {
|
|
4996
5184
|
clinics: filteredClinicIds,
|
|
4997
5185
|
clinicsInfo: filteredClinicsInfo,
|
|
4998
|
-
updatedAt:
|
|
5186
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
4999
5187
|
});
|
|
5000
5188
|
if (checkAndDeactivateDoctors) {
|
|
5001
5189
|
practitionersToCheck.push(practitionerId);
|
|
@@ -5047,7 +5235,7 @@ var ClinicAggregationService = class {
|
|
|
5047
5235
|
);
|
|
5048
5236
|
batch.update(practitionerRef, {
|
|
5049
5237
|
isActive: false,
|
|
5050
|
-
updatedAt:
|
|
5238
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5051
5239
|
});
|
|
5052
5240
|
deactivationCount++;
|
|
5053
5241
|
} else {
|
|
@@ -5069,7 +5257,7 @@ var ClinicAggregationService = class {
|
|
|
5069
5257
|
);
|
|
5070
5258
|
batch.update(practitionerRef, {
|
|
5071
5259
|
isActive: false,
|
|
5072
|
-
updatedAt:
|
|
5260
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5073
5261
|
});
|
|
5074
5262
|
deactivationCount++;
|
|
5075
5263
|
}
|
|
@@ -5126,7 +5314,7 @@ var ClinicAggregationService = class {
|
|
|
5126
5314
|
);
|
|
5127
5315
|
batch.update(practitionerRef, {
|
|
5128
5316
|
isActive: true,
|
|
5129
|
-
updatedAt:
|
|
5317
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5130
5318
|
});
|
|
5131
5319
|
reactivationCount++;
|
|
5132
5320
|
} else {
|
|
@@ -5148,7 +5336,7 @@ var ClinicAggregationService = class {
|
|
|
5148
5336
|
);
|
|
5149
5337
|
batch.update(practitionerRef, {
|
|
5150
5338
|
isActive: true,
|
|
5151
|
-
updatedAt:
|
|
5339
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5152
5340
|
});
|
|
5153
5341
|
reactivationCount++;
|
|
5154
5342
|
}
|
|
@@ -5194,7 +5382,7 @@ var ClinicAggregationService = class {
|
|
|
5194
5382
|
const procedureRef = this.db.collection(PROCEDURES_COLLECTION).doc(procedureId);
|
|
5195
5383
|
batch.update(procedureRef, {
|
|
5196
5384
|
isActive: false,
|
|
5197
|
-
updatedAt:
|
|
5385
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5198
5386
|
});
|
|
5199
5387
|
}
|
|
5200
5388
|
try {
|
|
@@ -5233,7 +5421,7 @@ var ClinicAggregationService = class {
|
|
|
5233
5421
|
if (procedureDoc.exists) {
|
|
5234
5422
|
batch.update(procedureRef, {
|
|
5235
5423
|
isActive: true,
|
|
5236
|
-
updatedAt:
|
|
5424
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5237
5425
|
});
|
|
5238
5426
|
reactivationCount++;
|
|
5239
5427
|
} else {
|
|
@@ -5292,7 +5480,7 @@ var ClinicAggregationService = class {
|
|
|
5292
5480
|
await groupRef.update({
|
|
5293
5481
|
clinics: filteredClinicIds,
|
|
5294
5482
|
clinicsInfo: filteredClinicsInfo,
|
|
5295
|
-
updatedAt:
|
|
5483
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5296
5484
|
});
|
|
5297
5485
|
console.log(
|
|
5298
5486
|
`[ClinicAggregationService] Successfully removed Clinic (ID: ${clinicId}) from Clinic Group ${clinicGroupId}.`
|
|
@@ -5329,8 +5517,8 @@ var ClinicAggregationService = class {
|
|
|
5329
5517
|
for (const patientId of patientIds) {
|
|
5330
5518
|
const patientRef = this.db.collection(PATIENTS_COLLECTION).doc(patientId);
|
|
5331
5519
|
batch.update(patientRef, {
|
|
5332
|
-
clinicIds:
|
|
5333
|
-
updatedAt:
|
|
5520
|
+
clinicIds: admin8.firestore.FieldValue.arrayRemove(clinicId),
|
|
5521
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5334
5522
|
});
|
|
5335
5523
|
}
|
|
5336
5524
|
try {
|
|
@@ -5360,7 +5548,7 @@ var ClinicAggregationService = class {
|
|
|
5360
5548
|
console.log(
|
|
5361
5549
|
`[ClinicAggregationService] Querying upcoming calendar events for clinic ${clinicId} to cancel.`
|
|
5362
5550
|
);
|
|
5363
|
-
const now =
|
|
5551
|
+
const now = admin8.firestore.Timestamp.now();
|
|
5364
5552
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID).where("clinicBranchId", "==", clinicId).where("eventTime.start", ">", now);
|
|
5365
5553
|
try {
|
|
5366
5554
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -5378,7 +5566,7 @@ var ClinicAggregationService = class {
|
|
|
5378
5566
|
batch.update(doc3.ref, {
|
|
5379
5567
|
status: "CANCELED",
|
|
5380
5568
|
cancelReason: "Clinic deleted",
|
|
5381
|
-
updatedAt:
|
|
5569
|
+
updatedAt: admin8.firestore.FieldValue.serverTimestamp()
|
|
5382
5570
|
});
|
|
5383
5571
|
});
|
|
5384
5572
|
await batch.commit();
|
|
@@ -5396,14 +5584,14 @@ var ClinicAggregationService = class {
|
|
|
5396
5584
|
};
|
|
5397
5585
|
|
|
5398
5586
|
// src/admin/aggregation/forms/filled-forms.aggregation.service.ts
|
|
5399
|
-
import * as
|
|
5587
|
+
import * as admin9 from "firebase-admin";
|
|
5400
5588
|
var FilledFormsAggregationService = class {
|
|
5401
5589
|
/**
|
|
5402
5590
|
* Constructor for FilledFormsAggregationService.
|
|
5403
5591
|
* @param firestore Optional Firestore instance. If not provided, it uses the default admin SDK instance.
|
|
5404
5592
|
*/
|
|
5405
|
-
constructor(
|
|
5406
|
-
this.db =
|
|
5593
|
+
constructor(firestore20) {
|
|
5594
|
+
this.db = firestore20 || admin9.firestore();
|
|
5407
5595
|
Logger.info("[FilledFormsAggregationService] Initialized");
|
|
5408
5596
|
}
|
|
5409
5597
|
/**
|
|
@@ -5462,12 +5650,12 @@ var FilledFormsAggregationService = class {
|
|
|
5462
5650
|
path: `${APPOINTMENTS_COLLECTION}/${filledDocument.appointmentId}/${formSubcollection}/${filledDocument.id}`
|
|
5463
5651
|
};
|
|
5464
5652
|
if (filledDocument.updatedAt) {
|
|
5465
|
-
linkedFormInfo.submittedAt =
|
|
5653
|
+
linkedFormInfo.submittedAt = admin9.firestore.Timestamp.fromMillis(
|
|
5466
5654
|
filledDocument.updatedAt
|
|
5467
5655
|
);
|
|
5468
5656
|
}
|
|
5469
5657
|
if (filledDocument.status === "completed" /* COMPLETED */ || filledDocument.status === "signed" /* SIGNED */) {
|
|
5470
|
-
linkedFormInfo.completedAt =
|
|
5658
|
+
linkedFormInfo.completedAt = admin9.firestore.Timestamp.fromMillis(
|
|
5471
5659
|
filledDocument.updatedAt
|
|
5472
5660
|
);
|
|
5473
5661
|
}
|
|
@@ -5481,7 +5669,7 @@ var FilledFormsAggregationService = class {
|
|
|
5481
5669
|
updatedLinkedForms.push(linkedFormInfo);
|
|
5482
5670
|
updateData = {
|
|
5483
5671
|
linkedForms: updatedLinkedForms,
|
|
5484
|
-
updatedAt:
|
|
5672
|
+
updatedAt: admin9.firestore.FieldValue.serverTimestamp()
|
|
5485
5673
|
};
|
|
5486
5674
|
let updatedLinkedFormIds = appointment.linkedFormIds || [];
|
|
5487
5675
|
if (!updatedLinkedFormIds.includes(filledDocument.id)) {
|
|
@@ -5490,7 +5678,7 @@ var FilledFormsAggregationService = class {
|
|
|
5490
5678
|
}
|
|
5491
5679
|
if (filledDocument.isUserForm && filledDocument.isRequired && (filledDocument.status === "completed" /* COMPLETED */ || filledDocument.status === "signed" /* SIGNED */)) {
|
|
5492
5680
|
if (appointment.pendingUserFormsIds && appointment.pendingUserFormsIds.includes(filledDocument.id)) {
|
|
5493
|
-
updateData.pendingUserFormsIds =
|
|
5681
|
+
updateData.pendingUserFormsIds = admin9.firestore.FieldValue.arrayRemove(
|
|
5494
5682
|
filledDocument.id
|
|
5495
5683
|
);
|
|
5496
5684
|
Logger.info(
|
|
@@ -5536,21 +5724,21 @@ var FilledFormsAggregationService = class {
|
|
|
5536
5724
|
(form) => form.formId === filledDocument.id
|
|
5537
5725
|
);
|
|
5538
5726
|
if (formToRemove) {
|
|
5539
|
-
updateData.linkedForms =
|
|
5727
|
+
updateData.linkedForms = admin9.firestore.FieldValue.arrayRemove(formToRemove);
|
|
5540
5728
|
}
|
|
5541
5729
|
}
|
|
5542
5730
|
if (appointment.linkedFormIds && appointment.linkedFormIds.includes(filledDocument.id)) {
|
|
5543
|
-
updateData.linkedFormIds =
|
|
5731
|
+
updateData.linkedFormIds = admin9.firestore.FieldValue.arrayRemove(filledDocument.id);
|
|
5544
5732
|
}
|
|
5545
5733
|
if (filledDocument.isUserForm && filledDocument.isRequired) {
|
|
5546
5734
|
if (filledDocument.status !== "completed" /* COMPLETED */ && filledDocument.status !== "signed" /* SIGNED */) {
|
|
5547
5735
|
if (!appointment.pendingUserFormsIds || !appointment.pendingUserFormsIds.includes(filledDocument.id)) {
|
|
5548
|
-
updateData.pendingUserFormsIds = appointment.pendingUserFormsIds ?
|
|
5736
|
+
updateData.pendingUserFormsIds = appointment.pendingUserFormsIds ? admin9.firestore.FieldValue.arrayUnion(filledDocument.id) : [filledDocument.id];
|
|
5549
5737
|
}
|
|
5550
5738
|
}
|
|
5551
5739
|
}
|
|
5552
5740
|
if (Object.keys(updateData).length > 0) {
|
|
5553
|
-
updateData.updatedAt =
|
|
5741
|
+
updateData.updatedAt = admin9.firestore.FieldValue.serverTimestamp();
|
|
5554
5742
|
await appointmentRef.update(updateData);
|
|
5555
5743
|
Logger.info(
|
|
5556
5744
|
`[FilledFormsAggregationService] Successfully updated appointment ${filledDocument.appointmentId} after form deletion`
|
|
@@ -5590,8 +5778,8 @@ var FilledFormsAggregationService = class {
|
|
|
5590
5778
|
return;
|
|
5591
5779
|
}
|
|
5592
5780
|
await appointmentRef.update({
|
|
5593
|
-
pendingUserFormsIds:
|
|
5594
|
-
updatedAt:
|
|
5781
|
+
pendingUserFormsIds: admin9.firestore.FieldValue.arrayUnion(filledDocument.id),
|
|
5782
|
+
updatedAt: admin9.firestore.FieldValue.serverTimestamp()
|
|
5595
5783
|
});
|
|
5596
5784
|
Logger.info(
|
|
5597
5785
|
`[FilledFormsAggregationService] Successfully added form ${filledDocument.id} to pendingUserFormsIds for appointment ${filledDocument.appointmentId}`
|
|
@@ -5607,11 +5795,11 @@ var FilledFormsAggregationService = class {
|
|
|
5607
5795
|
};
|
|
5608
5796
|
|
|
5609
5797
|
// src/admin/aggregation/patient/patient.aggregation.service.ts
|
|
5610
|
-
import * as
|
|
5798
|
+
import * as admin10 from "firebase-admin";
|
|
5611
5799
|
var CALENDAR_SUBCOLLECTION_ID2 = "calendar";
|
|
5612
5800
|
var PatientAggregationService = class {
|
|
5613
|
-
constructor(
|
|
5614
|
-
this.db =
|
|
5801
|
+
constructor(firestore20) {
|
|
5802
|
+
this.db = firestore20 || admin10.firestore();
|
|
5615
5803
|
}
|
|
5616
5804
|
// --- Methods for Patient Creation --- >
|
|
5617
5805
|
// No specific aggregations defined for patient creation in the plan.
|
|
@@ -5632,7 +5820,7 @@ var PatientAggregationService = class {
|
|
|
5632
5820
|
console.log(
|
|
5633
5821
|
`[PatientAggregationService] Querying upcoming calendar events for patient ${patientId} to update patient info.`
|
|
5634
5822
|
);
|
|
5635
|
-
const now =
|
|
5823
|
+
const now = admin10.firestore.Timestamp.now();
|
|
5636
5824
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID2).where("patientId", "==", patientId).where("eventTime.start", ">", now);
|
|
5637
5825
|
try {
|
|
5638
5826
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -5649,7 +5837,7 @@ var PatientAggregationService = class {
|
|
|
5649
5837
|
);
|
|
5650
5838
|
batch.update(doc3.ref, {
|
|
5651
5839
|
patientInfo,
|
|
5652
|
-
updatedAt:
|
|
5840
|
+
updatedAt: admin10.firestore.FieldValue.serverTimestamp()
|
|
5653
5841
|
});
|
|
5654
5842
|
});
|
|
5655
5843
|
await batch.commit();
|
|
@@ -5680,7 +5868,7 @@ var PatientAggregationService = class {
|
|
|
5680
5868
|
console.log(
|
|
5681
5869
|
`[PatientAggregationService] Querying upcoming calendar events for patient ${patientId} to cancel.`
|
|
5682
5870
|
);
|
|
5683
|
-
const now =
|
|
5871
|
+
const now = admin10.firestore.Timestamp.now();
|
|
5684
5872
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID2).where("patientId", "==", patientId).where("eventTime.start", ">", now);
|
|
5685
5873
|
try {
|
|
5686
5874
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -5698,7 +5886,7 @@ var PatientAggregationService = class {
|
|
|
5698
5886
|
batch.update(doc3.ref, {
|
|
5699
5887
|
status: "CANCELED",
|
|
5700
5888
|
cancelReason: "Patient deleted",
|
|
5701
|
-
updatedAt:
|
|
5889
|
+
updatedAt: admin10.firestore.FieldValue.serverTimestamp()
|
|
5702
5890
|
});
|
|
5703
5891
|
});
|
|
5704
5892
|
await batch.commit();
|
|
@@ -5716,11 +5904,11 @@ var PatientAggregationService = class {
|
|
|
5716
5904
|
};
|
|
5717
5905
|
|
|
5718
5906
|
// src/admin/aggregation/practitioner/practitioner.aggregation.service.ts
|
|
5719
|
-
import * as
|
|
5907
|
+
import * as admin11 from "firebase-admin";
|
|
5720
5908
|
var CALENDAR_SUBCOLLECTION_ID3 = "calendar";
|
|
5721
5909
|
var PractitionerAggregationService = class {
|
|
5722
|
-
constructor(
|
|
5723
|
-
this.db =
|
|
5910
|
+
constructor(firestore20) {
|
|
5911
|
+
this.db = firestore20 || admin11.firestore();
|
|
5724
5912
|
}
|
|
5725
5913
|
/**
|
|
5726
5914
|
* Adds practitioner information to a clinic when a new practitioner is created
|
|
@@ -5742,9 +5930,9 @@ var PractitionerAggregationService = class {
|
|
|
5742
5930
|
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
5743
5931
|
try {
|
|
5744
5932
|
await clinicRef.update({
|
|
5745
|
-
doctors:
|
|
5746
|
-
doctorsInfo:
|
|
5747
|
-
updatedAt:
|
|
5933
|
+
doctors: admin11.firestore.FieldValue.arrayUnion(practitionerId),
|
|
5934
|
+
doctorsInfo: admin11.firestore.FieldValue.arrayUnion(doctorInfo),
|
|
5935
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
5748
5936
|
});
|
|
5749
5937
|
console.log(
|
|
5750
5938
|
`[PractitionerAggregationService] Successfully added practitioner ${practitionerId} to clinic ${clinicId}.`
|
|
@@ -5778,14 +5966,14 @@ var PractitionerAggregationService = class {
|
|
|
5778
5966
|
for (const clinicId of clinicIds) {
|
|
5779
5967
|
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
5780
5968
|
batch.update(clinicRef, {
|
|
5781
|
-
doctorsInfo:
|
|
5969
|
+
doctorsInfo: admin11.firestore.FieldValue.arrayRemove({
|
|
5782
5970
|
id: practitionerId
|
|
5783
5971
|
}),
|
|
5784
|
-
updatedAt:
|
|
5972
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
5785
5973
|
});
|
|
5786
5974
|
batch.update(clinicRef, {
|
|
5787
|
-
doctorsInfo:
|
|
5788
|
-
updatedAt:
|
|
5975
|
+
doctorsInfo: admin11.firestore.FieldValue.arrayUnion(doctorInfo),
|
|
5976
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
5789
5977
|
});
|
|
5790
5978
|
}
|
|
5791
5979
|
try {
|
|
@@ -5823,7 +6011,7 @@ var PractitionerAggregationService = class {
|
|
|
5823
6011
|
const procedureRef = this.db.collection(PROCEDURES_COLLECTION).doc(procedureId);
|
|
5824
6012
|
batch.update(procedureRef, {
|
|
5825
6013
|
doctorInfo,
|
|
5826
|
-
updatedAt:
|
|
6014
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
5827
6015
|
});
|
|
5828
6016
|
}
|
|
5829
6017
|
try {
|
|
@@ -5855,7 +6043,7 @@ var PractitionerAggregationService = class {
|
|
|
5855
6043
|
console.log(
|
|
5856
6044
|
`[PractitionerAggregationService] Querying upcoming calendar events for practitioner ${practitionerId} to update practitioner info.`
|
|
5857
6045
|
);
|
|
5858
|
-
const now =
|
|
6046
|
+
const now = admin11.firestore.Timestamp.now();
|
|
5859
6047
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID3).where("practitionerId", "==", practitionerId).where("eventTime.start", ">", now);
|
|
5860
6048
|
try {
|
|
5861
6049
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -5872,7 +6060,7 @@ var PractitionerAggregationService = class {
|
|
|
5872
6060
|
);
|
|
5873
6061
|
batch.update(doc3.ref, {
|
|
5874
6062
|
practitionerInfo,
|
|
5875
|
-
updatedAt:
|
|
6063
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
5876
6064
|
});
|
|
5877
6065
|
});
|
|
5878
6066
|
await batch.commit();
|
|
@@ -5907,12 +6095,12 @@ var PractitionerAggregationService = class {
|
|
|
5907
6095
|
for (const clinicId of clinicIds) {
|
|
5908
6096
|
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
5909
6097
|
batch.update(clinicRef, {
|
|
5910
|
-
doctors:
|
|
6098
|
+
doctors: admin11.firestore.FieldValue.arrayRemove(practitionerId),
|
|
5911
6099
|
// Remove all doctor info objects where id matches the practitioner ID
|
|
5912
|
-
doctorsInfo:
|
|
6100
|
+
doctorsInfo: admin11.firestore.FieldValue.arrayRemove({
|
|
5913
6101
|
id: practitionerId
|
|
5914
6102
|
}),
|
|
5915
|
-
updatedAt:
|
|
6103
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
5916
6104
|
});
|
|
5917
6105
|
}
|
|
5918
6106
|
try {
|
|
@@ -5943,7 +6131,7 @@ var PractitionerAggregationService = class {
|
|
|
5943
6131
|
console.log(
|
|
5944
6132
|
`[PractitionerAggregationService] Querying upcoming calendar events for practitioner ${practitionerId} to cancel.`
|
|
5945
6133
|
);
|
|
5946
|
-
const now =
|
|
6134
|
+
const now = admin11.firestore.Timestamp.now();
|
|
5947
6135
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID3).where("practitionerId", "==", practitionerId).where("eventTime.start", ">", now);
|
|
5948
6136
|
try {
|
|
5949
6137
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -5961,7 +6149,7 @@ var PractitionerAggregationService = class {
|
|
|
5961
6149
|
batch.update(doc3.ref, {
|
|
5962
6150
|
status: "CANCELED",
|
|
5963
6151
|
cancelReason: "Practitioner deleted",
|
|
5964
|
-
updatedAt:
|
|
6152
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
5965
6153
|
});
|
|
5966
6154
|
});
|
|
5967
6155
|
await batch.commit();
|
|
@@ -5996,8 +6184,8 @@ var PractitionerAggregationService = class {
|
|
|
5996
6184
|
for (const patientId of patientIds) {
|
|
5997
6185
|
const patientRef = this.db.collection(PATIENTS_COLLECTION).doc(patientId);
|
|
5998
6186
|
batch.update(patientRef, {
|
|
5999
|
-
doctorIds:
|
|
6000
|
-
updatedAt:
|
|
6187
|
+
doctorIds: admin11.firestore.FieldValue.arrayRemove(practitionerId),
|
|
6188
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
6001
6189
|
});
|
|
6002
6190
|
}
|
|
6003
6191
|
try {
|
|
@@ -6033,7 +6221,7 @@ var PractitionerAggregationService = class {
|
|
|
6033
6221
|
const procedureRef = this.db.collection(PROCEDURES_COLLECTION).doc(procedureId);
|
|
6034
6222
|
batch.update(procedureRef, {
|
|
6035
6223
|
isActive: false,
|
|
6036
|
-
updatedAt:
|
|
6224
|
+
updatedAt: admin11.firestore.FieldValue.serverTimestamp()
|
|
6037
6225
|
});
|
|
6038
6226
|
}
|
|
6039
6227
|
try {
|
|
@@ -6052,15 +6240,15 @@ var PractitionerAggregationService = class {
|
|
|
6052
6240
|
};
|
|
6053
6241
|
|
|
6054
6242
|
// src/admin/aggregation/practitioner-invite/practitioner-invite.aggregation.service.ts
|
|
6055
|
-
import * as
|
|
6243
|
+
import * as admin12 from "firebase-admin";
|
|
6056
6244
|
var PractitionerInviteAggregationService = class {
|
|
6057
6245
|
/**
|
|
6058
6246
|
* Constructor for PractitionerInviteAggregationService.
|
|
6059
6247
|
* @param firestore Optional Firestore instance. If not provided, it uses the default admin SDK instance.
|
|
6060
6248
|
* @param mailingService Optional mailing service for sending emails
|
|
6061
6249
|
*/
|
|
6062
|
-
constructor(
|
|
6063
|
-
this.db =
|
|
6250
|
+
constructor(firestore20, mailingService) {
|
|
6251
|
+
this.db = firestore20 || admin12.firestore();
|
|
6064
6252
|
this.mailingService = mailingService;
|
|
6065
6253
|
Logger.info("[PractitionerInviteAggregationService] Initialized.");
|
|
6066
6254
|
}
|
|
@@ -6357,9 +6545,9 @@ var PractitionerInviteAggregationService = class {
|
|
|
6357
6545
|
try {
|
|
6358
6546
|
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
6359
6547
|
await clinicRef.update({
|
|
6360
|
-
doctors:
|
|
6361
|
-
doctorsInfo:
|
|
6362
|
-
updatedAt:
|
|
6548
|
+
doctors: admin12.firestore.FieldValue.arrayUnion(doctorInfo.id),
|
|
6549
|
+
doctorsInfo: admin12.firestore.FieldValue.arrayUnion(doctorInfo),
|
|
6550
|
+
updatedAt: admin12.firestore.FieldValue.serverTimestamp()
|
|
6363
6551
|
});
|
|
6364
6552
|
Logger.info(
|
|
6365
6553
|
`[PractitionerInviteAggService] Successfully added practitioner ${doctorInfo.id} to clinic ${clinicId}`
|
|
@@ -6394,7 +6582,7 @@ var PractitionerInviteAggregationService = class {
|
|
|
6394
6582
|
const updatedDoctorsInfo = [...filteredDoctorsInfo, doctorInfo];
|
|
6395
6583
|
await clinicRef.update({
|
|
6396
6584
|
doctorsInfo: updatedDoctorsInfo,
|
|
6397
|
-
updatedAt:
|
|
6585
|
+
updatedAt: admin12.firestore.FieldValue.serverTimestamp()
|
|
6398
6586
|
});
|
|
6399
6587
|
Logger.info(
|
|
6400
6588
|
`[PractitionerInviteAggService] Successfully updated practitioner ${doctorInfo.id} info in clinic ${clinicId}`
|
|
@@ -6429,14 +6617,14 @@ var PractitionerInviteAggregationService = class {
|
|
|
6429
6617
|
clinicId: clinicInfo.id,
|
|
6430
6618
|
workingHours: invite.proposedWorkingHours,
|
|
6431
6619
|
isActive: true,
|
|
6432
|
-
createdAt:
|
|
6433
|
-
updatedAt:
|
|
6620
|
+
createdAt: admin12.firestore.Timestamp.now(),
|
|
6621
|
+
updatedAt: admin12.firestore.Timestamp.now()
|
|
6434
6622
|
};
|
|
6435
6623
|
await practitionerRef.update({
|
|
6436
|
-
clinics:
|
|
6437
|
-
clinicsInfo:
|
|
6438
|
-
clinicWorkingHours:
|
|
6439
|
-
updatedAt:
|
|
6624
|
+
clinics: admin12.firestore.FieldValue.arrayUnion(clinicInfo.id),
|
|
6625
|
+
clinicsInfo: admin12.firestore.FieldValue.arrayUnion(clinicInfo),
|
|
6626
|
+
clinicWorkingHours: admin12.firestore.FieldValue.arrayUnion(workingHours),
|
|
6627
|
+
updatedAt: admin12.firestore.FieldValue.serverTimestamp()
|
|
6440
6628
|
});
|
|
6441
6629
|
Logger.info(
|
|
6442
6630
|
`[PractitionerInviteAggService] Successfully added clinic ${clinicInfo.id} to practitioner ${practitionerId}`
|
|
@@ -6473,7 +6661,7 @@ var PractitionerInviteAggregationService = class {
|
|
|
6473
6661
|
...wh,
|
|
6474
6662
|
workingHours: invite.proposedWorkingHours,
|
|
6475
6663
|
isActive: true,
|
|
6476
|
-
updatedAt:
|
|
6664
|
+
updatedAt: admin12.firestore.Timestamp.now()
|
|
6477
6665
|
};
|
|
6478
6666
|
}
|
|
6479
6667
|
return wh;
|
|
@@ -6483,13 +6671,13 @@ var PractitionerInviteAggregationService = class {
|
|
|
6483
6671
|
clinicId: invite.clinicId,
|
|
6484
6672
|
workingHours: invite.proposedWorkingHours,
|
|
6485
6673
|
isActive: true,
|
|
6486
|
-
createdAt:
|
|
6487
|
-
updatedAt:
|
|
6674
|
+
createdAt: admin12.firestore.Timestamp.now(),
|
|
6675
|
+
updatedAt: admin12.firestore.Timestamp.now()
|
|
6488
6676
|
});
|
|
6489
6677
|
}
|
|
6490
6678
|
await practitionerRef.update({
|
|
6491
6679
|
clinicWorkingHours: updatedWorkingHours,
|
|
6492
|
-
updatedAt:
|
|
6680
|
+
updatedAt: admin12.firestore.FieldValue.serverTimestamp()
|
|
6493
6681
|
});
|
|
6494
6682
|
Logger.info(
|
|
6495
6683
|
`[PractitionerInviteAggService] Successfully updated working hours for practitioner ${practitionerId} at clinic ${invite.clinicId}`
|
|
@@ -6566,8 +6754,8 @@ var PractitionerInviteAggregationService = class {
|
|
|
6566
6754
|
var _a, _b, _c, _d, _e, _f;
|
|
6567
6755
|
if (!this.mailingService) return;
|
|
6568
6756
|
try {
|
|
6569
|
-
const
|
|
6570
|
-
if (!
|
|
6757
|
+
const admin20 = await this.fetchClinicAdminById(invite.invitedBy);
|
|
6758
|
+
if (!admin20) {
|
|
6571
6759
|
Logger.warn(
|
|
6572
6760
|
`[PractitionerInviteAggService] Admin ${invite.invitedBy} not found, using clinic contact email as fallback`
|
|
6573
6761
|
);
|
|
@@ -6605,7 +6793,7 @@ var PractitionerInviteAggregationService = class {
|
|
|
6605
6793
|
);
|
|
6606
6794
|
return;
|
|
6607
6795
|
}
|
|
6608
|
-
const adminName = `${
|
|
6796
|
+
const adminName = `${admin20.contactInfo.firstName} ${admin20.contactInfo.lastName}`;
|
|
6609
6797
|
const notificationData = {
|
|
6610
6798
|
invite,
|
|
6611
6799
|
practitioner: {
|
|
@@ -6621,7 +6809,7 @@ var PractitionerInviteAggregationService = class {
|
|
|
6621
6809
|
clinic: {
|
|
6622
6810
|
name: clinic.name,
|
|
6623
6811
|
adminName,
|
|
6624
|
-
adminEmail:
|
|
6812
|
+
adminEmail: admin20.contactInfo.email
|
|
6625
6813
|
// Use the specific admin's email
|
|
6626
6814
|
},
|
|
6627
6815
|
context: {
|
|
@@ -6657,8 +6845,8 @@ var PractitionerInviteAggregationService = class {
|
|
|
6657
6845
|
var _a, _b, _c, _d, _e, _f;
|
|
6658
6846
|
if (!this.mailingService) return;
|
|
6659
6847
|
try {
|
|
6660
|
-
const
|
|
6661
|
-
if (!
|
|
6848
|
+
const admin20 = await this.fetchClinicAdminById(invite.invitedBy);
|
|
6849
|
+
if (!admin20) {
|
|
6662
6850
|
Logger.warn(
|
|
6663
6851
|
`[PractitionerInviteAggService] Admin ${invite.invitedBy} not found, using clinic contact email as fallback`
|
|
6664
6852
|
);
|
|
@@ -6696,7 +6884,7 @@ var PractitionerInviteAggregationService = class {
|
|
|
6696
6884
|
);
|
|
6697
6885
|
return;
|
|
6698
6886
|
}
|
|
6699
|
-
const adminName = `${
|
|
6887
|
+
const adminName = `${admin20.contactInfo.firstName} ${admin20.contactInfo.lastName}`;
|
|
6700
6888
|
const notificationData = {
|
|
6701
6889
|
invite,
|
|
6702
6890
|
practitioner: {
|
|
@@ -6710,7 +6898,7 @@ var PractitionerInviteAggregationService = class {
|
|
|
6710
6898
|
clinic: {
|
|
6711
6899
|
name: clinic.name,
|
|
6712
6900
|
adminName,
|
|
6713
|
-
adminEmail:
|
|
6901
|
+
adminEmail: admin20.contactInfo.email
|
|
6714
6902
|
// Use the specific admin's email
|
|
6715
6903
|
},
|
|
6716
6904
|
context: {
|
|
@@ -6739,11 +6927,11 @@ var PractitionerInviteAggregationService = class {
|
|
|
6739
6927
|
};
|
|
6740
6928
|
|
|
6741
6929
|
// src/admin/aggregation/procedure/procedure.aggregation.service.ts
|
|
6742
|
-
import * as
|
|
6930
|
+
import * as admin13 from "firebase-admin";
|
|
6743
6931
|
var CALENDAR_SUBCOLLECTION_ID4 = "calendar";
|
|
6744
6932
|
var ProcedureAggregationService = class {
|
|
6745
|
-
constructor(
|
|
6746
|
-
this.db =
|
|
6933
|
+
constructor(firestore20) {
|
|
6934
|
+
this.db = firestore20 || admin13.firestore();
|
|
6747
6935
|
}
|
|
6748
6936
|
/**
|
|
6749
6937
|
* Adds procedure information to a practitioner when a new procedure is created
|
|
@@ -6767,9 +6955,9 @@ var ProcedureAggregationService = class {
|
|
|
6767
6955
|
const practitionerRef = this.db.collection(PRACTITIONERS_COLLECTION).doc(practitionerId);
|
|
6768
6956
|
try {
|
|
6769
6957
|
const updateData = {
|
|
6770
|
-
procedureIds:
|
|
6771
|
-
proceduresInfo:
|
|
6772
|
-
updatedAt:
|
|
6958
|
+
procedureIds: admin13.firestore.FieldValue.arrayUnion(procedureId),
|
|
6959
|
+
proceduresInfo: admin13.firestore.FieldValue.arrayUnion(procedureSummary),
|
|
6960
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
6773
6961
|
};
|
|
6774
6962
|
if (isFreeConsultation) {
|
|
6775
6963
|
await this.db.runTransaction(async (transaction) => {
|
|
@@ -6832,9 +7020,9 @@ var ProcedureAggregationService = class {
|
|
|
6832
7020
|
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(clinicId);
|
|
6833
7021
|
try {
|
|
6834
7022
|
await clinicRef.update({
|
|
6835
|
-
procedures:
|
|
6836
|
-
proceduresInfo:
|
|
6837
|
-
updatedAt:
|
|
7023
|
+
procedures: admin13.firestore.FieldValue.arrayUnion(procedureId),
|
|
7024
|
+
proceduresInfo: admin13.firestore.FieldValue.arrayUnion(procedureSummary),
|
|
7025
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
6838
7026
|
});
|
|
6839
7027
|
console.log(
|
|
6840
7028
|
`[ProcedureAggregationService] Successfully added procedure ${procedureId} to clinic ${clinicId}.`
|
|
@@ -6886,7 +7074,7 @@ var ProcedureAggregationService = class {
|
|
|
6886
7074
|
updatedProceduresInfo.push(procedureSummary);
|
|
6887
7075
|
transaction.update(practitionerRef, {
|
|
6888
7076
|
proceduresInfo: updatedProceduresInfo,
|
|
6889
|
-
updatedAt:
|
|
7077
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
6890
7078
|
});
|
|
6891
7079
|
});
|
|
6892
7080
|
console.log(
|
|
@@ -6939,7 +7127,7 @@ var ProcedureAggregationService = class {
|
|
|
6939
7127
|
updatedProceduresInfo.push(procedureSummary);
|
|
6940
7128
|
transaction.update(clinicRef, {
|
|
6941
7129
|
proceduresInfo: updatedProceduresInfo,
|
|
6942
|
-
updatedAt:
|
|
7130
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
6943
7131
|
});
|
|
6944
7132
|
});
|
|
6945
7133
|
console.log(
|
|
@@ -6969,7 +7157,7 @@ var ProcedureAggregationService = class {
|
|
|
6969
7157
|
console.log(
|
|
6970
7158
|
`[ProcedureAggregationService] Querying upcoming calendar events for procedure ${procedureId} to update procedure info.`
|
|
6971
7159
|
);
|
|
6972
|
-
const now =
|
|
7160
|
+
const now = admin13.firestore.Timestamp.now();
|
|
6973
7161
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID4).where("procedureId", "==", procedureId).where("eventTime.start", ">", now);
|
|
6974
7162
|
try {
|
|
6975
7163
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -6986,7 +7174,7 @@ var ProcedureAggregationService = class {
|
|
|
6986
7174
|
);
|
|
6987
7175
|
batch.update(doc3.ref, {
|
|
6988
7176
|
procedureInfo,
|
|
6989
|
-
updatedAt:
|
|
7177
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
6990
7178
|
});
|
|
6991
7179
|
});
|
|
6992
7180
|
await batch.commit();
|
|
@@ -7016,7 +7204,7 @@ var ProcedureAggregationService = class {
|
|
|
7016
7204
|
console.log(
|
|
7017
7205
|
`[ProcedureAggregationService] Querying upcoming calendar events for procedure ${procedureId} to cancel.`
|
|
7018
7206
|
);
|
|
7019
|
-
const now =
|
|
7207
|
+
const now = admin13.firestore.Timestamp.now();
|
|
7020
7208
|
const calendarEventsQuery = this.db.collectionGroup(CALENDAR_SUBCOLLECTION_ID4).where("procedureId", "==", procedureId).where("eventTime.start", ">", now);
|
|
7021
7209
|
try {
|
|
7022
7210
|
const snapshot = await calendarEventsQuery.get();
|
|
@@ -7034,7 +7222,7 @@ var ProcedureAggregationService = class {
|
|
|
7034
7222
|
batch.update(doc3.ref, {
|
|
7035
7223
|
status: "CANCELED",
|
|
7036
7224
|
cancelReason: "Procedure deleted or inactivated",
|
|
7037
|
-
updatedAt:
|
|
7225
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
7038
7226
|
});
|
|
7039
7227
|
});
|
|
7040
7228
|
await batch.commit();
|
|
@@ -7091,9 +7279,9 @@ var ProcedureAggregationService = class {
|
|
|
7091
7279
|
(p) => p.id !== procedureId
|
|
7092
7280
|
);
|
|
7093
7281
|
const updateData = {
|
|
7094
|
-
procedureIds:
|
|
7282
|
+
procedureIds: admin13.firestore.FieldValue.arrayRemove(procedureId),
|
|
7095
7283
|
proceduresInfo: updatedProceduresInfo,
|
|
7096
|
-
updatedAt:
|
|
7284
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
7097
7285
|
};
|
|
7098
7286
|
if (isFreeConsultation && procedureClinicId) {
|
|
7099
7287
|
const currentFreeConsultations = practitionerData.freeConsultations || {};
|
|
@@ -7159,9 +7347,9 @@ var ProcedureAggregationService = class {
|
|
|
7159
7347
|
(p) => p.id !== procedureId
|
|
7160
7348
|
);
|
|
7161
7349
|
transaction.update(clinicRef, {
|
|
7162
|
-
procedures:
|
|
7350
|
+
procedures: admin13.firestore.FieldValue.arrayRemove(procedureId),
|
|
7163
7351
|
proceduresInfo: updatedProceduresInfo,
|
|
7164
|
-
updatedAt:
|
|
7352
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
7165
7353
|
});
|
|
7166
7354
|
});
|
|
7167
7355
|
console.log(
|
|
@@ -7238,7 +7426,7 @@ var ProcedureAggregationService = class {
|
|
|
7238
7426
|
}
|
|
7239
7427
|
transaction.update(practitionerRef, {
|
|
7240
7428
|
freeConsultations: updatedFreeConsultations,
|
|
7241
|
-
updatedAt:
|
|
7429
|
+
updatedAt: admin13.firestore.FieldValue.serverTimestamp()
|
|
7242
7430
|
});
|
|
7243
7431
|
});
|
|
7244
7432
|
console.log(
|
|
@@ -7255,14 +7443,14 @@ var ProcedureAggregationService = class {
|
|
|
7255
7443
|
};
|
|
7256
7444
|
|
|
7257
7445
|
// src/admin/aggregation/reviews/reviews.aggregation.service.ts
|
|
7258
|
-
import * as
|
|
7446
|
+
import * as admin14 from "firebase-admin";
|
|
7259
7447
|
var ReviewsAggregationService = class {
|
|
7260
7448
|
/**
|
|
7261
7449
|
* Constructor for ReviewsAggregationService.
|
|
7262
7450
|
* @param firestore Optional Firestore instance. If not provided, it uses the default admin SDK instance.
|
|
7263
7451
|
*/
|
|
7264
|
-
constructor(
|
|
7265
|
-
this.db =
|
|
7452
|
+
constructor(firestore20) {
|
|
7453
|
+
this.db = firestore20 || admin14.firestore();
|
|
7266
7454
|
}
|
|
7267
7455
|
/**
|
|
7268
7456
|
* Process a newly created review and update all related entities
|
|
@@ -7405,7 +7593,7 @@ var ReviewsAggregationService = class {
|
|
|
7405
7593
|
};
|
|
7406
7594
|
await this.db.collection(CLINICS_COLLECTION).doc(clinicId).update({
|
|
7407
7595
|
reviewInfo: updatedReviewInfo2,
|
|
7408
|
-
updatedAt:
|
|
7596
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7409
7597
|
});
|
|
7410
7598
|
console.log(
|
|
7411
7599
|
`[ReviewsAggregationService] Reset review info for clinic: ${clinicId}`
|
|
@@ -7444,7 +7632,7 @@ var ReviewsAggregationService = class {
|
|
|
7444
7632
|
};
|
|
7445
7633
|
await this.db.collection(CLINICS_COLLECTION).doc(clinicId).update({
|
|
7446
7634
|
reviewInfo: updatedReviewInfo,
|
|
7447
|
-
updatedAt:
|
|
7635
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7448
7636
|
});
|
|
7449
7637
|
console.log(
|
|
7450
7638
|
`[ReviewsAggregationService] Updated review info for clinic: ${clinicId}`
|
|
@@ -7494,7 +7682,7 @@ var ReviewsAggregationService = class {
|
|
|
7494
7682
|
};
|
|
7495
7683
|
await this.db.collection(PRACTITIONERS_COLLECTION).doc(practitionerId).update({
|
|
7496
7684
|
reviewInfo: updatedReviewInfo2,
|
|
7497
|
-
updatedAt:
|
|
7685
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7498
7686
|
});
|
|
7499
7687
|
await this.updateDoctorInfoInProcedures(practitionerId, 0);
|
|
7500
7688
|
console.log(
|
|
@@ -7534,7 +7722,7 @@ var ReviewsAggregationService = class {
|
|
|
7534
7722
|
};
|
|
7535
7723
|
await this.db.collection(PRACTITIONERS_COLLECTION).doc(practitionerId).update({
|
|
7536
7724
|
reviewInfo: updatedReviewInfo,
|
|
7537
|
-
updatedAt:
|
|
7725
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7538
7726
|
});
|
|
7539
7727
|
await this.updateDoctorInfoInProcedures(
|
|
7540
7728
|
practitionerId,
|
|
@@ -7601,7 +7789,7 @@ var ReviewsAggregationService = class {
|
|
|
7601
7789
|
};
|
|
7602
7790
|
await this.db.collection(PROCEDURES_COLLECTION).doc(procedureId).update({
|
|
7603
7791
|
reviewInfo: updatedReviewInfo2,
|
|
7604
|
-
updatedAt:
|
|
7792
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7605
7793
|
});
|
|
7606
7794
|
console.log(
|
|
7607
7795
|
`[ReviewsAggregationService] Reset review info for procedure: ${procedureId}`
|
|
@@ -7640,7 +7828,7 @@ var ReviewsAggregationService = class {
|
|
|
7640
7828
|
};
|
|
7641
7829
|
await this.db.collection(PROCEDURES_COLLECTION).doc(procedureId).update({
|
|
7642
7830
|
reviewInfo: updatedReviewInfo,
|
|
7643
|
-
updatedAt:
|
|
7831
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7644
7832
|
});
|
|
7645
7833
|
console.log(
|
|
7646
7834
|
`[ReviewsAggregationService] Updated review info for procedure: ${procedureId}`
|
|
@@ -7668,7 +7856,7 @@ var ReviewsAggregationService = class {
|
|
|
7668
7856
|
const procedureRef = this.db.collection(PROCEDURES_COLLECTION).doc(docSnapshot.id);
|
|
7669
7857
|
batch.update(procedureRef, {
|
|
7670
7858
|
"doctorInfo.rating": rating,
|
|
7671
|
-
updatedAt:
|
|
7859
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7672
7860
|
});
|
|
7673
7861
|
});
|
|
7674
7862
|
await batch.commit();
|
|
@@ -7711,7 +7899,7 @@ var ReviewsAggregationService = class {
|
|
|
7711
7899
|
practitionerReview: review.practitionerReview,
|
|
7712
7900
|
procedureReview: review.procedureReview,
|
|
7713
7901
|
extendedProcedureReviews: review.extendedProcedureReviews,
|
|
7714
|
-
updatedAt:
|
|
7902
|
+
updatedAt: admin14.firestore.FieldValue.serverTimestamp()
|
|
7715
7903
|
});
|
|
7716
7904
|
await batch.commit();
|
|
7717
7905
|
console.log(
|
|
@@ -7742,7 +7930,7 @@ var ReviewsAggregationService = class {
|
|
|
7742
7930
|
};
|
|
7743
7931
|
|
|
7744
7932
|
// src/admin/analytics/analytics.admin.service.ts
|
|
7745
|
-
import * as
|
|
7933
|
+
import * as admin15 from "firebase-admin";
|
|
7746
7934
|
|
|
7747
7935
|
// src/services/analytics/analytics.service.ts
|
|
7748
7936
|
import { where as where2, Timestamp as Timestamp3 } from "firebase/firestore";
|
|
@@ -10805,8 +10993,8 @@ var AnalyticsAdminService = class {
|
|
|
10805
10993
|
*
|
|
10806
10994
|
* @param firestore - Admin Firestore instance (optional, defaults to admin.firestore())
|
|
10807
10995
|
*/
|
|
10808
|
-
constructor(
|
|
10809
|
-
this.db =
|
|
10996
|
+
constructor(firestore20) {
|
|
10997
|
+
this.db = firestore20 || admin15.firestore();
|
|
10810
10998
|
const mockApp = {
|
|
10811
10999
|
name: "[DEFAULT]",
|
|
10812
11000
|
options: {},
|
|
@@ -10843,12 +11031,12 @@ var AnalyticsAdminService = class {
|
|
|
10843
11031
|
}
|
|
10844
11032
|
if (params.startDate) {
|
|
10845
11033
|
const startDate = params.startDate instanceof Date ? params.startDate : params.startDate.toDate();
|
|
10846
|
-
const startTimestamp =
|
|
11034
|
+
const startTimestamp = admin15.firestore.Timestamp.fromDate(startDate);
|
|
10847
11035
|
query3 = query3.where("appointmentStartTime", ">=", startTimestamp);
|
|
10848
11036
|
}
|
|
10849
11037
|
if (params.endDate) {
|
|
10850
11038
|
const endDate = params.endDate instanceof Date ? params.endDate : params.endDate.toDate();
|
|
10851
|
-
const endTimestamp =
|
|
11039
|
+
const endTimestamp = admin15.firestore.Timestamp.fromDate(endDate);
|
|
10852
11040
|
query3 = query3.where("appointmentStartTime", "<=", endTimestamp);
|
|
10853
11041
|
}
|
|
10854
11042
|
const snapshot = await query3.get();
|
|
@@ -10999,6 +11187,13 @@ var BookingAvailabilityCalculator = class {
|
|
|
10999
11187
|
availableIntervals,
|
|
11000
11188
|
practitionerCalendarEvents
|
|
11001
11189
|
);
|
|
11190
|
+
if (request.resourceCalendarEventsMap) {
|
|
11191
|
+
availableIntervals = this.applyResourceAvailability(
|
|
11192
|
+
availableIntervals,
|
|
11193
|
+
request.resourceCalendarEventsMap,
|
|
11194
|
+
timeframe
|
|
11195
|
+
);
|
|
11196
|
+
}
|
|
11002
11197
|
console.log(
|
|
11003
11198
|
`After all filters, have ${availableIntervals.length} available intervals`
|
|
11004
11199
|
);
|
|
@@ -11404,18 +11599,98 @@ var BookingAvailabilityCalculator = class {
|
|
|
11404
11599
|
}
|
|
11405
11600
|
return result;
|
|
11406
11601
|
}
|
|
11602
|
+
/**
|
|
11603
|
+
* Apply resource availability constraints to the available intervals.
|
|
11604
|
+
* For each required resource:
|
|
11605
|
+
* - Compute each instance's availability (full timeframe minus its busy events)
|
|
11606
|
+
* - Union all instance availabilities (at least one must be free)
|
|
11607
|
+
* Then intersect all resource availabilities with the current doctor availability.
|
|
11608
|
+
*
|
|
11609
|
+
* @param intervals - Current available intervals (doctor availability)
|
|
11610
|
+
* @param resourceEventsMap - Map of resource data with per-instance calendar events
|
|
11611
|
+
* @param timeframe - Overall timeframe being considered
|
|
11612
|
+
* @returns Intervals where doctor AND all required resources are available
|
|
11613
|
+
*/
|
|
11614
|
+
static applyResourceAvailability(intervals, resourceEventsMap, timeframe) {
|
|
11615
|
+
if (!intervals.length) return [];
|
|
11616
|
+
const resourceIds = Object.keys(resourceEventsMap);
|
|
11617
|
+
if (resourceIds.length === 0) return intervals;
|
|
11618
|
+
console.log(
|
|
11619
|
+
`Applying resource availability for ${resourceIds.length} resource(s)`
|
|
11620
|
+
);
|
|
11621
|
+
let result = intervals;
|
|
11622
|
+
for (const resourceId of resourceIds) {
|
|
11623
|
+
const resourceData = resourceEventsMap[resourceId];
|
|
11624
|
+
const resourceAvailability = this.computeResourceAvailability(
|
|
11625
|
+
resourceData.instanceEvents,
|
|
11626
|
+
timeframe
|
|
11627
|
+
);
|
|
11628
|
+
console.log(
|
|
11629
|
+
`Resource "${resourceData.resourceName}" (qty=${resourceData.quantity}): ${resourceAvailability.length} available intervals`
|
|
11630
|
+
);
|
|
11631
|
+
result = this.intersectIntervals(result, resourceAvailability);
|
|
11632
|
+
if (result.length === 0) {
|
|
11633
|
+
console.log(
|
|
11634
|
+
`No availability remaining after applying resource "${resourceData.resourceName}"`
|
|
11635
|
+
);
|
|
11636
|
+
return [];
|
|
11637
|
+
}
|
|
11638
|
+
}
|
|
11639
|
+
return result;
|
|
11640
|
+
}
|
|
11641
|
+
/**
|
|
11642
|
+
* Compute combined availability for a single resource across all its instances.
|
|
11643
|
+
* For each instance, subtract its busy events from the full timeframe.
|
|
11644
|
+
* Then union all instance availabilities — if at least one instance is free, the resource is available.
|
|
11645
|
+
*
|
|
11646
|
+
* @param instanceEvents - Calendar events keyed by instanceId
|
|
11647
|
+
* @param timeframe - Overall timeframe
|
|
11648
|
+
* @returns Combined availability intervals for the resource
|
|
11649
|
+
*/
|
|
11650
|
+
static computeResourceAvailability(instanceEvents, timeframe) {
|
|
11651
|
+
const instanceIds = Object.keys(instanceEvents);
|
|
11652
|
+
if (instanceIds.length === 0) {
|
|
11653
|
+
return [{ start: timeframe.start, end: timeframe.end }];
|
|
11654
|
+
}
|
|
11655
|
+
const allInstanceAvailabilities = [];
|
|
11656
|
+
for (const instanceId of instanceIds) {
|
|
11657
|
+
const events = instanceEvents[instanceId];
|
|
11658
|
+
let instanceAvailability = [
|
|
11659
|
+
{ start: timeframe.start, end: timeframe.end }
|
|
11660
|
+
];
|
|
11661
|
+
for (const event of events) {
|
|
11662
|
+
const isBlockingEvent = event.eventType === "blocking" /* BLOCKING */ || event.eventType === "break" /* BREAK */ || event.eventType === "free_day" /* FREE_DAY */;
|
|
11663
|
+
const isActiveBooking = event.status === "pending" /* PENDING */ || event.status === "confirmed" /* CONFIRMED */;
|
|
11664
|
+
if (isBlockingEvent || isActiveBooking) {
|
|
11665
|
+
const busyInterval = {
|
|
11666
|
+
start: event.eventTime.start,
|
|
11667
|
+
end: event.eventTime.end
|
|
11668
|
+
};
|
|
11669
|
+
const newAvailability = [];
|
|
11670
|
+
for (const interval of instanceAvailability) {
|
|
11671
|
+
newAvailability.push(
|
|
11672
|
+
...this.subtractInterval(interval, busyInterval)
|
|
11673
|
+
);
|
|
11674
|
+
}
|
|
11675
|
+
instanceAvailability = newAvailability;
|
|
11676
|
+
}
|
|
11677
|
+
}
|
|
11678
|
+
allInstanceAvailabilities.push(...instanceAvailability);
|
|
11679
|
+
}
|
|
11680
|
+
return this.mergeOverlappingIntervals(allInstanceAvailabilities);
|
|
11681
|
+
}
|
|
11407
11682
|
};
|
|
11408
11683
|
/** Default scheduling interval in minutes if not specified by the clinic */
|
|
11409
11684
|
BookingAvailabilityCalculator.DEFAULT_INTERVAL_MINUTES = 15;
|
|
11410
11685
|
|
|
11411
11686
|
// src/admin/booking/booking.admin.ts
|
|
11412
|
-
import * as
|
|
11687
|
+
import * as admin17 from "firebase-admin";
|
|
11413
11688
|
|
|
11414
11689
|
// src/admin/documentation-templates/document-manager.admin.ts
|
|
11415
|
-
import * as
|
|
11690
|
+
import * as admin16 from "firebase-admin";
|
|
11416
11691
|
var DocumentManagerAdminService = class {
|
|
11417
|
-
constructor(
|
|
11418
|
-
this.db =
|
|
11692
|
+
constructor(firestore20) {
|
|
11693
|
+
this.db = firestore20;
|
|
11419
11694
|
}
|
|
11420
11695
|
/**
|
|
11421
11696
|
* Adds operations to a Firestore batch to initialize all linked forms for a new appointment
|
|
@@ -11518,7 +11793,7 @@ var DocumentManagerAdminService = class {
|
|
|
11518
11793
|
};
|
|
11519
11794
|
}
|
|
11520
11795
|
const templateIds = technologyTemplates.map((t) => t.templateId);
|
|
11521
|
-
const templatesSnapshot = await this.db.collection(DOCUMENTATION_TEMPLATES_COLLECTION).where(
|
|
11796
|
+
const templatesSnapshot = await this.db.collection(DOCUMENTATION_TEMPLATES_COLLECTION).where(admin16.firestore.FieldPath.documentId(), "in", templateIds).get();
|
|
11522
11797
|
const templatesMap = /* @__PURE__ */ new Map();
|
|
11523
11798
|
templatesSnapshot.forEach((doc3) => {
|
|
11524
11799
|
templatesMap.set(doc3.id, doc3.data());
|
|
@@ -11584,8 +11859,8 @@ var BookingAdmin = class {
|
|
|
11584
11859
|
* Creates a new BookingAdmin instance
|
|
11585
11860
|
* @param firestore - Firestore instance provided by the caller
|
|
11586
11861
|
*/
|
|
11587
|
-
constructor(
|
|
11588
|
-
this.db =
|
|
11862
|
+
constructor(firestore20) {
|
|
11863
|
+
this.db = firestore20 || admin17.firestore();
|
|
11589
11864
|
this.documentManagerAdmin = new DocumentManagerAdminService(this.db);
|
|
11590
11865
|
}
|
|
11591
11866
|
/**
|
|
@@ -11598,7 +11873,7 @@ var BookingAdmin = class {
|
|
|
11598
11873
|
* @returns Promise resolving to an array of available booking slots
|
|
11599
11874
|
*/
|
|
11600
11875
|
async getAvailableBookingSlots(clinicId, practitionerId, procedureId, timeframe) {
|
|
11601
|
-
var _a;
|
|
11876
|
+
var _a, _b;
|
|
11602
11877
|
try {
|
|
11603
11878
|
Logger.info("[BookingAdmin] Starting availability calculation", {
|
|
11604
11879
|
clinicId,
|
|
@@ -11607,8 +11882,8 @@ var BookingAdmin = class {
|
|
|
11607
11882
|
timeframeStart: timeframe.start instanceof Date ? timeframe.start.toISOString() : timeframe.start.toDate().toISOString(),
|
|
11608
11883
|
timeframeEnd: timeframe.end instanceof Date ? timeframe.end.toISOString() : timeframe.end.toDate().toISOString()
|
|
11609
11884
|
});
|
|
11610
|
-
const start = timeframe.start instanceof Date ?
|
|
11611
|
-
const end = timeframe.end instanceof Date ?
|
|
11885
|
+
const start = timeframe.start instanceof Date ? admin17.firestore.Timestamp.fromDate(timeframe.start) : timeframe.start;
|
|
11886
|
+
const end = timeframe.end instanceof Date ? admin17.firestore.Timestamp.fromDate(timeframe.end) : timeframe.end;
|
|
11612
11887
|
Logger.debug("[BookingAdmin] Fetching clinic data", { clinicId });
|
|
11613
11888
|
const clinicDoc = await this.db.collection("clinics").doc(clinicId).get();
|
|
11614
11889
|
if (!clinicDoc.exists) {
|
|
@@ -11668,6 +11943,74 @@ var BookingAdmin = class {
|
|
|
11668
11943
|
Logger.debug("[BookingAdmin] Retrieved practitioner calendar events", {
|
|
11669
11944
|
count: practitionerCalendarEvents.length
|
|
11670
11945
|
});
|
|
11946
|
+
let resourceCalendarEventsMap;
|
|
11947
|
+
if (procedure.resourceRequirements && procedure.resourceRequirements.length > 0) {
|
|
11948
|
+
Logger.debug(
|
|
11949
|
+
"[BookingAdmin] Procedure has resource requirements, fetching resource data",
|
|
11950
|
+
{
|
|
11951
|
+
resourceRequirementCount: procedure.resourceRequirements.length,
|
|
11952
|
+
resourceIds: procedure.resourceRequirements.map(
|
|
11953
|
+
(r) => r.resourceId
|
|
11954
|
+
)
|
|
11955
|
+
}
|
|
11956
|
+
);
|
|
11957
|
+
resourceCalendarEventsMap = {};
|
|
11958
|
+
for (const requirement of procedure.resourceRequirements) {
|
|
11959
|
+
const resourceDoc = await this.db.collection(CLINICS_COLLECTION).doc(clinicId).collection(RESOURCES_COLLECTION).doc(requirement.resourceId).get();
|
|
11960
|
+
if (!resourceDoc.exists) {
|
|
11961
|
+
Logger.warn(
|
|
11962
|
+
"[BookingAdmin] Required resource not found, skipping",
|
|
11963
|
+
{
|
|
11964
|
+
resourceId: requirement.resourceId,
|
|
11965
|
+
resourceName: requirement.resourceName
|
|
11966
|
+
}
|
|
11967
|
+
);
|
|
11968
|
+
continue;
|
|
11969
|
+
}
|
|
11970
|
+
const resource = resourceDoc.data();
|
|
11971
|
+
if (resource.status !== "active" /* ACTIVE */) {
|
|
11972
|
+
Logger.warn(
|
|
11973
|
+
"[BookingAdmin] Required resource is not active, skipping",
|
|
11974
|
+
{
|
|
11975
|
+
resourceId: requirement.resourceId,
|
|
11976
|
+
resourceStatus: resource.status
|
|
11977
|
+
}
|
|
11978
|
+
);
|
|
11979
|
+
continue;
|
|
11980
|
+
}
|
|
11981
|
+
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();
|
|
11982
|
+
const instanceEvents = {};
|
|
11983
|
+
for (const instanceDoc of instancesSnapshot.docs) {
|
|
11984
|
+
const instanceId = instanceDoc.id;
|
|
11985
|
+
const MAX_EVENT_DURATION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
11986
|
+
const queryStart = admin17.firestore.Timestamp.fromMillis(
|
|
11987
|
+
start.toMillis() - MAX_EVENT_DURATION_MS
|
|
11988
|
+
);
|
|
11989
|
+
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();
|
|
11990
|
+
const events = eventsSnapshot.docs.map((doc3) => ({ ...doc3.data(), id: doc3.id })).filter(
|
|
11991
|
+
(event) => event.eventTime.end.toMillis() > start.toMillis()
|
|
11992
|
+
);
|
|
11993
|
+
instanceEvents[instanceId] = this.convertEventsTimestamps(
|
|
11994
|
+
events
|
|
11995
|
+
);
|
|
11996
|
+
}
|
|
11997
|
+
resourceCalendarEventsMap[requirement.resourceId] = {
|
|
11998
|
+
resourceId: requirement.resourceId,
|
|
11999
|
+
resourceName: requirement.resourceName,
|
|
12000
|
+
quantity: resource.quantity,
|
|
12001
|
+
instanceEvents
|
|
12002
|
+
};
|
|
12003
|
+
Logger.debug("[BookingAdmin] Fetched resource calendar data", {
|
|
12004
|
+
resourceId: requirement.resourceId,
|
|
12005
|
+
resourceName: requirement.resourceName,
|
|
12006
|
+
instanceCount: instancesSnapshot.size,
|
|
12007
|
+
totalEvents: Object.values(instanceEvents).reduce(
|
|
12008
|
+
(sum, events) => sum + events.length,
|
|
12009
|
+
0
|
|
12010
|
+
)
|
|
12011
|
+
});
|
|
12012
|
+
}
|
|
12013
|
+
}
|
|
11671
12014
|
const convertedTimeframe = {
|
|
11672
12015
|
start: this.adminTimestampToClientTimestamp(start),
|
|
11673
12016
|
end: this.adminTimestampToClientTimestamp(end)
|
|
@@ -11681,7 +12024,8 @@ var BookingAdmin = class {
|
|
|
11681
12024
|
practitionerCalendarEvents: this.convertEventsTimestamps(
|
|
11682
12025
|
practitionerCalendarEvents
|
|
11683
12026
|
),
|
|
11684
|
-
tz: clinic.location.tz || "UTC"
|
|
12027
|
+
tz: clinic.location.tz || "UTC",
|
|
12028
|
+
...resourceCalendarEventsMap && { resourceCalendarEventsMap }
|
|
11685
12029
|
};
|
|
11686
12030
|
Logger.info("[BookingAdmin] Calling availability calculator", {
|
|
11687
12031
|
calculatorInputReady: true,
|
|
@@ -11689,12 +12033,14 @@ var BookingAdmin = class {
|
|
|
11689
12033
|
(end.toMillis() - start.toMillis()) / (1e3 * 60 * 60)
|
|
11690
12034
|
),
|
|
11691
12035
|
clinicEventsCount: clinicCalendarEvents.length,
|
|
11692
|
-
practitionerEventsCount: practitionerCalendarEvents.length
|
|
12036
|
+
practitionerEventsCount: practitionerCalendarEvents.length,
|
|
12037
|
+
resourceRequirementCount: ((_b = procedure.resourceRequirements) == null ? void 0 : _b.length) || 0,
|
|
12038
|
+
hasResourceData: !!resourceCalendarEventsMap
|
|
11693
12039
|
});
|
|
11694
12040
|
const result = BookingAvailabilityCalculator.calculateSlots(request);
|
|
11695
12041
|
const availableSlotsResult = {
|
|
11696
12042
|
availableSlots: result.availableSlots.map((slot) => ({
|
|
11697
|
-
start:
|
|
12043
|
+
start: admin17.firestore.Timestamp.fromMillis(slot.start.toMillis())
|
|
11698
12044
|
}))
|
|
11699
12045
|
};
|
|
11700
12046
|
Logger.info(
|
|
@@ -11757,7 +12103,7 @@ var BookingAdmin = class {
|
|
|
11757
12103
|
endTime: end.toDate().toISOString()
|
|
11758
12104
|
});
|
|
11759
12105
|
const MAX_EVENT_DURATION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
11760
|
-
const queryStart =
|
|
12106
|
+
const queryStart = admin17.firestore.Timestamp.fromMillis(
|
|
11761
12107
|
start.toMillis() - MAX_EVENT_DURATION_MS
|
|
11762
12108
|
);
|
|
11763
12109
|
const eventsRef = this.db.collection(`clinics/${clinicId}/calendar`).where("eventTime.start", ">=", queryStart).where("eventTime.start", "<=", end).orderBy("eventTime.start");
|
|
@@ -11813,7 +12159,7 @@ var BookingAdmin = class {
|
|
|
11813
12159
|
endTime: end.toDate().toISOString()
|
|
11814
12160
|
});
|
|
11815
12161
|
const MAX_EVENT_DURATION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
11816
|
-
const queryStart =
|
|
12162
|
+
const queryStart = admin17.firestore.Timestamp.fromMillis(
|
|
11817
12163
|
start.toMillis() - MAX_EVENT_DURATION_MS
|
|
11818
12164
|
);
|
|
11819
12165
|
const eventsRef = this.db.collection(`practitioners/${practitionerId}/calendar`).where("eventTime.start", ">=", queryStart).where("eventTime.start", "<=", end).orderBy("eventTime.start");
|
|
@@ -11892,8 +12238,8 @@ var BookingAdmin = class {
|
|
|
11892
12238
|
`[BookingAdmin] Orchestrating appointment creation for patient ${data.patientId} by user ${authenticatedUserId}`
|
|
11893
12239
|
);
|
|
11894
12240
|
const batch = this.db.batch();
|
|
11895
|
-
const adminTsNow =
|
|
11896
|
-
const serverTimestampValue =
|
|
12241
|
+
const adminTsNow = admin17.firestore.Timestamp.now();
|
|
12242
|
+
const serverTimestampValue = admin17.firestore.FieldValue.serverTimestamp();
|
|
11897
12243
|
try {
|
|
11898
12244
|
if (!data.patientId || !data.procedureId || !data.appointmentStartTime || !data.appointmentEndTime) {
|
|
11899
12245
|
return {
|
|
@@ -11990,7 +12336,7 @@ var BookingAdmin = class {
|
|
|
11990
12336
|
fullName: `${(patientSensitiveData == null ? void 0 : patientSensitiveData.firstName) || ""} ${(patientSensitiveData == null ? void 0 : patientSensitiveData.lastName) || ""}`.trim() || patientProfileData.displayName,
|
|
11991
12337
|
email: (patientSensitiveData == null ? void 0 : patientSensitiveData.email) || "",
|
|
11992
12338
|
phone: (patientSensitiveData == null ? void 0 : patientSensitiveData.phoneNumber) || patientProfileData.phoneNumber || null,
|
|
11993
|
-
dateOfBirth: (patientSensitiveData == null ? void 0 : patientSensitiveData.dateOfBirth) || patientProfileData.dateOfBirth ||
|
|
12339
|
+
dateOfBirth: (patientSensitiveData == null ? void 0 : patientSensitiveData.dateOfBirth) || patientProfileData.dateOfBirth || admin17.firestore.Timestamp.now(),
|
|
11994
12340
|
gender: (patientSensitiveData == null ? void 0 : patientSensitiveData.gender) || "other" /* OTHER */
|
|
11995
12341
|
};
|
|
11996
12342
|
const newAppointmentId = this.db.collection(APPOINTMENTS_COLLECTION).doc().id;
|
|
@@ -12072,6 +12418,76 @@ var BookingAdmin = class {
|
|
|
12072
12418
|
this.db.collection(CLINICS_COLLECTION).doc(clinicData.id).collection(CALENDAR_COLLECTION).doc(practitionerCalendarEventId),
|
|
12073
12419
|
clinicCalendarEventData
|
|
12074
12420
|
);
|
|
12421
|
+
let resourceBookings = [];
|
|
12422
|
+
if (procedure.resourceRequirements && procedure.resourceRequirements.length > 0) {
|
|
12423
|
+
console.log(
|
|
12424
|
+
`[BookingAdmin] Allocating resources for appointment ${newAppointmentId}, ${procedure.resourceRequirements.length} resource(s) required`
|
|
12425
|
+
);
|
|
12426
|
+
for (const requirement of procedure.resourceRequirements) {
|
|
12427
|
+
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();
|
|
12428
|
+
if (instancesSnapshot.empty) {
|
|
12429
|
+
return {
|
|
12430
|
+
success: false,
|
|
12431
|
+
error: `Resource "${requirement.resourceName}" has no active instances available.`
|
|
12432
|
+
};
|
|
12433
|
+
}
|
|
12434
|
+
let allocatedInstance = null;
|
|
12435
|
+
for (const instanceDoc of instancesSnapshot.docs) {
|
|
12436
|
+
const instance = {
|
|
12437
|
+
...instanceDoc.data(),
|
|
12438
|
+
id: instanceDoc.id
|
|
12439
|
+
};
|
|
12440
|
+
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", [
|
|
12441
|
+
"pending" /* PENDING */,
|
|
12442
|
+
"confirmed" /* CONFIRMED */,
|
|
12443
|
+
"checked_in" /* CHECKED_IN */,
|
|
12444
|
+
"in_progress" /* IN_PROGRESS */
|
|
12445
|
+
]).get();
|
|
12446
|
+
const hasOverlap = overlappingEventsSnapshot.docs.some((doc3) => {
|
|
12447
|
+
const event = doc3.data();
|
|
12448
|
+
return event.eventTime.end.toMillis() > data.appointmentStartTime.toMillis();
|
|
12449
|
+
});
|
|
12450
|
+
if (!hasOverlap) {
|
|
12451
|
+
allocatedInstance = instance;
|
|
12452
|
+
break;
|
|
12453
|
+
}
|
|
12454
|
+
}
|
|
12455
|
+
if (!allocatedInstance) {
|
|
12456
|
+
return {
|
|
12457
|
+
success: false,
|
|
12458
|
+
error: `Resource "${requirement.resourceName}" is not available at the selected time. All instances are booked.`
|
|
12459
|
+
};
|
|
12460
|
+
}
|
|
12461
|
+
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();
|
|
12462
|
+
const resourceCalendarEventData = {
|
|
12463
|
+
id: resourceCalendarEventRef.id,
|
|
12464
|
+
resourceId: requirement.resourceId,
|
|
12465
|
+
resourceInstanceId: allocatedInstance.id,
|
|
12466
|
+
clinicBranchId: clinicData.id,
|
|
12467
|
+
eventType: "resource_booking" /* RESOURCE_BOOKING */,
|
|
12468
|
+
appointmentId: newAppointmentId,
|
|
12469
|
+
procedureId: procedure.id,
|
|
12470
|
+
practitionerId: practitionerData.id,
|
|
12471
|
+
patientId: data.patientId,
|
|
12472
|
+
eventTime: eventTimeForCalendarEvents,
|
|
12473
|
+
status: initialCalendarEventStatus,
|
|
12474
|
+
eventName: `${procedure.name} - ${allocatedInstance.label}`,
|
|
12475
|
+
createdAt: serverTimestampValue,
|
|
12476
|
+
updatedAt: serverTimestampValue
|
|
12477
|
+
};
|
|
12478
|
+
batch.set(resourceCalendarEventRef, resourceCalendarEventData);
|
|
12479
|
+
resourceBookings.push({
|
|
12480
|
+
resourceId: requirement.resourceId,
|
|
12481
|
+
resourceName: requirement.resourceName,
|
|
12482
|
+
resourceInstanceId: allocatedInstance.id,
|
|
12483
|
+
resourceInstanceLabel: allocatedInstance.label,
|
|
12484
|
+
calendarEventId: resourceCalendarEventRef.id
|
|
12485
|
+
});
|
|
12486
|
+
console.log(
|
|
12487
|
+
`[BookingAdmin] Allocated resource "${requirement.resourceName}" \u2192 instance "${allocatedInstance.label}" (${allocatedInstance.id})`
|
|
12488
|
+
);
|
|
12489
|
+
}
|
|
12490
|
+
}
|
|
12075
12491
|
let initializedFormsInfo = [];
|
|
12076
12492
|
let pendingUserFormTemplateIds = [];
|
|
12077
12493
|
let allLinkedFormTemplateIds = [];
|
|
@@ -12154,6 +12570,7 @@ var BookingAdmin = class {
|
|
|
12154
12570
|
isRecurring: false,
|
|
12155
12571
|
recurringAppointmentId: null,
|
|
12156
12572
|
isArchived: false,
|
|
12573
|
+
...resourceBookings.length > 0 && { resourceBookings },
|
|
12157
12574
|
createdAt: adminTsNow,
|
|
12158
12575
|
updatedAt: adminTsNow
|
|
12159
12576
|
};
|
|
@@ -12255,7 +12672,7 @@ var BookingAdmin = class {
|
|
|
12255
12672
|
};
|
|
12256
12673
|
|
|
12257
12674
|
// src/admin/free-consultation/free-consultation-utils.admin.ts
|
|
12258
|
-
import * as
|
|
12675
|
+
import * as admin18 from "firebase-admin";
|
|
12259
12676
|
|
|
12260
12677
|
// src/backoffice/types/category.types.ts
|
|
12261
12678
|
var CATEGORIES_COLLECTION = "backoffice_categories";
|
|
@@ -12268,10 +12685,10 @@ var TECHNOLOGIES_COLLECTION = "technologies";
|
|
|
12268
12685
|
|
|
12269
12686
|
// src/admin/free-consultation/free-consultation-utils.admin.ts
|
|
12270
12687
|
async function freeConsultationInfrastructure(db) {
|
|
12271
|
-
const
|
|
12688
|
+
const firestore20 = db || admin18.firestore();
|
|
12272
12689
|
try {
|
|
12273
12690
|
console.log("[freeConsultationInfrastructure] Checking free consultation infrastructure...");
|
|
12274
|
-
const technologyRef =
|
|
12691
|
+
const technologyRef = firestore20.collection(TECHNOLOGIES_COLLECTION).doc("free-consultation-tech");
|
|
12275
12692
|
const technologyDoc = await technologyRef.get();
|
|
12276
12693
|
if (technologyDoc.exists) {
|
|
12277
12694
|
console.log(
|
|
@@ -12280,7 +12697,7 @@ async function freeConsultationInfrastructure(db) {
|
|
|
12280
12697
|
return true;
|
|
12281
12698
|
}
|
|
12282
12699
|
console.log("[freeConsultationInfrastructure] Creating free consultation infrastructure...");
|
|
12283
|
-
await createFreeConsultationInfrastructure(
|
|
12700
|
+
await createFreeConsultationInfrastructure(firestore20);
|
|
12284
12701
|
console.log(
|
|
12285
12702
|
"[freeConsultationInfrastructure] Successfully created free consultation infrastructure"
|
|
12286
12703
|
);
|
|
@@ -12477,8 +12894,8 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
12477
12894
|
* @param firestore Firestore instance provided by the caller
|
|
12478
12895
|
* @param mailgunClient Mailgun client instance (mailgun.js v10+) provided by the caller
|
|
12479
12896
|
*/
|
|
12480
|
-
constructor(
|
|
12481
|
-
super(
|
|
12897
|
+
constructor(firestore20, mailgunClient) {
|
|
12898
|
+
super(firestore20, mailgunClient);
|
|
12482
12899
|
this.DEFAULT_REGISTRATION_URL = "https://metaesthetics.net/register";
|
|
12483
12900
|
this.DEFAULT_SUBJECT = "You've Been Invited to Join as a Practitioner";
|
|
12484
12901
|
this.DEFAULT_MAILGUN_DOMAIN = "mg.metaesthetics.net";
|
|
@@ -13341,8 +13758,8 @@ var ExistingPractitionerInviteMailingService = class extends BaseMailingService
|
|
|
13341
13758
|
* @param firestore Firestore instance provided by the caller
|
|
13342
13759
|
* @param mailgunClient Mailgun client instance (mailgun.js v10+) provided by the caller
|
|
13343
13760
|
*/
|
|
13344
|
-
constructor(
|
|
13345
|
-
super(
|
|
13761
|
+
constructor(firestore20, mailgunClient) {
|
|
13762
|
+
super(firestore20, mailgunClient);
|
|
13346
13763
|
this.DEFAULT_MAILGUN_DOMAIN = "mg.metaesthetics.net";
|
|
13347
13764
|
this.DEFAULT_FROM_ADDRESS = "Metaesthetics <no-reply@mg.metaesthetics.net>";
|
|
13348
13765
|
}
|
|
@@ -13824,8 +14241,8 @@ var PatientInviteMailingService = class extends BaseMailingService {
|
|
|
13824
14241
|
* @param firestore - Firestore instance provided by the caller
|
|
13825
14242
|
* @param mailgunClient - Mailgun client instance (mailgun.js v10+) provided by the caller
|
|
13826
14243
|
*/
|
|
13827
|
-
constructor(
|
|
13828
|
-
super(
|
|
14244
|
+
constructor(firestore20, mailgunClient) {
|
|
14245
|
+
super(firestore20, mailgunClient);
|
|
13829
14246
|
this.DEFAULT_REGISTRATION_URL = "https://metaesthetics.net/patient/register";
|
|
13830
14247
|
this.DEFAULT_SUBJECT = "Claim Your Patient Profile - Metaesthetics";
|
|
13831
14248
|
this.DEFAULT_MAILGUN_DOMAIN = "mg.metaesthetics.net";
|
|
@@ -14300,8 +14717,8 @@ var ClinicWelcomeMailingService = class extends BaseMailingService {
|
|
|
14300
14717
|
* @param firestore - Firestore instance provided by the caller
|
|
14301
14718
|
* @param mailgunClient - Mailgun client instance (mailgun.js v10+) provided by the caller
|
|
14302
14719
|
*/
|
|
14303
|
-
constructor(
|
|
14304
|
-
super(
|
|
14720
|
+
constructor(firestore20, mailgunClient) {
|
|
14721
|
+
super(firestore20, mailgunClient);
|
|
14305
14722
|
this.DEFAULT_DASHBOARD_URL = "https://app.metaesthetics.net/dashboard";
|
|
14306
14723
|
this.DEFAULT_SUPPORT_EMAIL = "support@metaesthetics.net";
|
|
14307
14724
|
this.DEFAULT_SUBJECT = "Welcome to Metaesthetics - Your Clinic Registration is Complete";
|
|
@@ -14471,14 +14888,14 @@ var ClinicWelcomeMailingService = class extends BaseMailingService {
|
|
|
14471
14888
|
};
|
|
14472
14889
|
|
|
14473
14890
|
// src/admin/users/user-profile.admin.ts
|
|
14474
|
-
import * as
|
|
14891
|
+
import * as admin19 from "firebase-admin";
|
|
14475
14892
|
var UserProfileAdminService = class {
|
|
14476
14893
|
/**
|
|
14477
14894
|
* Constructor for UserProfileAdminService
|
|
14478
14895
|
* @param firestore Optional Firestore instance. If not provided, uses the default admin SDK instance.
|
|
14479
14896
|
*/
|
|
14480
|
-
constructor(
|
|
14481
|
-
this.db =
|
|
14897
|
+
constructor(firestore20) {
|
|
14898
|
+
this.db = firestore20 || admin19.firestore();
|
|
14482
14899
|
}
|
|
14483
14900
|
/**
|
|
14484
14901
|
* Creates a blank user profile with minimal information
|
|
@@ -14495,9 +14912,9 @@ var UserProfileAdminService = class {
|
|
|
14495
14912
|
roles: [],
|
|
14496
14913
|
// Empty roles array as requested
|
|
14497
14914
|
isAnonymous: authUserData.isAnonymous,
|
|
14498
|
-
createdAt:
|
|
14499
|
-
updatedAt:
|
|
14500
|
-
lastLoginAt:
|
|
14915
|
+
createdAt: admin19.firestore.FieldValue.serverTimestamp(),
|
|
14916
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp(),
|
|
14917
|
+
lastLoginAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
14501
14918
|
};
|
|
14502
14919
|
try {
|
|
14503
14920
|
const userRef = this.db.collection(USERS_COLLECTION).doc(authUserData.uid);
|
|
@@ -14573,8 +14990,8 @@ var UserProfileAdminService = class {
|
|
|
14573
14990
|
clinics: mergedProfileData.clinics || [],
|
|
14574
14991
|
doctorIds: mergedProfileData.doctorIds || [],
|
|
14575
14992
|
clinicIds: mergedProfileData.clinicIds || [],
|
|
14576
|
-
createdAt:
|
|
14577
|
-
updatedAt:
|
|
14993
|
+
createdAt: admin19.firestore.FieldValue.serverTimestamp(),
|
|
14994
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
14578
14995
|
};
|
|
14579
14996
|
await patientProfileRef.set(patientProfileData);
|
|
14580
14997
|
patientProfile = {
|
|
@@ -14613,8 +15030,8 @@ var UserProfileAdminService = class {
|
|
|
14613
15030
|
};
|
|
14614
15031
|
const sensitiveInfoData = {
|
|
14615
15032
|
...mergedSensitiveData,
|
|
14616
|
-
createdAt:
|
|
14617
|
-
updatedAt:
|
|
15033
|
+
createdAt: admin19.firestore.FieldValue.serverTimestamp(),
|
|
15034
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
14618
15035
|
// Leave dateOfBirth as is
|
|
14619
15036
|
};
|
|
14620
15037
|
await sensitiveInfoRef.set(sensitiveInfoData);
|
|
@@ -14640,7 +15057,7 @@ var UserProfileAdminService = class {
|
|
|
14640
15057
|
contraindications: [],
|
|
14641
15058
|
allergies: [],
|
|
14642
15059
|
currentMedications: [],
|
|
14643
|
-
lastUpdated:
|
|
15060
|
+
lastUpdated: admin19.firestore.FieldValue.serverTimestamp(),
|
|
14644
15061
|
updatedBy: userId
|
|
14645
15062
|
};
|
|
14646
15063
|
await medicalInfoRef.set(medicalInfoData);
|
|
@@ -14657,14 +15074,14 @@ var UserProfileAdminService = class {
|
|
|
14657
15074
|
const batch = this.db.batch();
|
|
14658
15075
|
if (!userData.roles.includes("patient" /* PATIENT */)) {
|
|
14659
15076
|
batch.update(userRef, {
|
|
14660
|
-
roles:
|
|
14661
|
-
updatedAt:
|
|
15077
|
+
roles: admin19.firestore.FieldValue.arrayUnion("patient" /* PATIENT */),
|
|
15078
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
14662
15079
|
});
|
|
14663
15080
|
}
|
|
14664
15081
|
if (!userData.patientProfile) {
|
|
14665
15082
|
batch.update(userRef, {
|
|
14666
15083
|
patientProfile: patientProfileId,
|
|
14667
|
-
updatedAt:
|
|
15084
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
14668
15085
|
});
|
|
14669
15086
|
}
|
|
14670
15087
|
await batch.commit();
|
|
@@ -14705,8 +15122,8 @@ var UserProfileAdminService = class {
|
|
|
14705
15122
|
const userData = userDoc.data();
|
|
14706
15123
|
if (!userData.roles.includes("clinic_admin" /* CLINIC_ADMIN */)) {
|
|
14707
15124
|
await userRef.update({
|
|
14708
|
-
roles:
|
|
14709
|
-
updatedAt:
|
|
15125
|
+
roles: admin19.firestore.FieldValue.arrayUnion("clinic_admin" /* CLINIC_ADMIN */),
|
|
15126
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
14710
15127
|
});
|
|
14711
15128
|
}
|
|
14712
15129
|
const updatedUserDoc = await userRef.get();
|
|
@@ -14737,8 +15154,8 @@ var UserProfileAdminService = class {
|
|
|
14737
15154
|
const userData = userDoc.data();
|
|
14738
15155
|
if (!userData.roles.includes("practitioner" /* PRACTITIONER */)) {
|
|
14739
15156
|
await userRef.update({
|
|
14740
|
-
roles:
|
|
14741
|
-
updatedAt:
|
|
15157
|
+
roles: admin19.firestore.FieldValue.arrayUnion("practitioner" /* PRACTITIONER */),
|
|
15158
|
+
updatedAt: admin19.firestore.FieldValue.serverTimestamp()
|
|
14742
15159
|
});
|
|
14743
15160
|
}
|
|
14744
15161
|
const updatedUserDoc = await userRef.get();
|
|
@@ -14801,6 +15218,7 @@ export {
|
|
|
14801
15218
|
PractitionerTokenStatus,
|
|
14802
15219
|
ProcedureAggregationService,
|
|
14803
15220
|
REVENUE_ANALYTICS_SUBCOLLECTION,
|
|
15221
|
+
ResourceCalendarAdminService,
|
|
14804
15222
|
ReviewsAggregationService,
|
|
14805
15223
|
SubscriptionStatus,
|
|
14806
15224
|
TIME_EFFICIENCY_ANALYTICS_SUBCOLLECTION,
|