@blackcode_sa/metaestetics-api 1.5.32 → 1.5.33

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/index.d.ts CHANGED
@@ -850,6 +850,8 @@ interface ProcedureSummaryInfo {
850
850
  categoryName: string;
851
851
  subcategoryName: string;
852
852
  technologyName: string;
853
+ brandName?: string;
854
+ productName?: string;
853
855
  price: number;
854
856
  pricingMeasure: PricingMeasure;
855
857
  currency: Currency;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blackcode_sa/metaestetics-api",
3
3
  "private": false,
4
- "version": "1.5.32",
4
+ "version": "1.5.33",
5
5
  "description": "Firebase authentication service with anonymous upgrade support",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.mjs",
@@ -0,0 +1,234 @@
1
+ import * as admin from "firebase-admin";
2
+ import {
3
+ BookingAvailabilityCalculator,
4
+ BookingAvailabilityRequest,
5
+ BookingAvailabilityResponse,
6
+ AvailableSlot,
7
+ } from "./";
8
+ import { CalendarEventStatus, CalendarEventType } from "../../types/calendar";
9
+ import { Clinic } from "../../types/clinic";
10
+ import { Practitioner } from "../../types/practitioner";
11
+ import { Procedure } from "../../types/procedure";
12
+
13
+ /**
14
+ * Admin service for handling booking-related operations.
15
+ * This is the cloud-based implementation that will be used in Cloud Functions.
16
+ */
17
+ export class BookingAdmin {
18
+ private db: admin.firestore.Firestore;
19
+
20
+ /**
21
+ * Creates a new BookingAdmin instance
22
+ * @param firestore - Firestore instance provided by the caller
23
+ */
24
+ constructor(firestore?: admin.firestore.Firestore) {
25
+ this.db = firestore || admin.firestore();
26
+ }
27
+
28
+ /**
29
+ * Gets available booking time slots for a specific clinic, practitioner, and procedure
30
+ *
31
+ * @param clinicId - ID of the clinic
32
+ * @param practitionerId - ID of the practitioner
33
+ * @param procedureId - ID of the procedure
34
+ * @param timeframe - Time range to check for availability
35
+ * @returns Promise resolving to an array of available booking slots
36
+ */
37
+ async getAvailableBookingSlots(
38
+ clinicId: string,
39
+ practitionerId: string,
40
+ procedureId: string,
41
+ timeframe: {
42
+ start: Date | admin.firestore.Timestamp;
43
+ end: Date | admin.firestore.Timestamp;
44
+ }
45
+ ): Promise<{ availableSlots: { start: admin.firestore.Timestamp }[] }> {
46
+ try {
47
+ console.log(
48
+ `[BookingAdmin] Getting available slots for clinic ${clinicId}, practitioner ${practitionerId}, procedure ${procedureId}`
49
+ );
50
+
51
+ // Convert timeframe dates to Firestore Timestamps if needed
52
+ const start =
53
+ timeframe.start instanceof Date
54
+ ? admin.firestore.Timestamp.fromDate(timeframe.start)
55
+ : timeframe.start;
56
+
57
+ const end =
58
+ timeframe.end instanceof Date
59
+ ? admin.firestore.Timestamp.fromDate(timeframe.end)
60
+ : timeframe.end;
61
+
62
+ // 1. Fetch clinic data
63
+ const clinicDoc = await this.db.collection("clinics").doc(clinicId).get();
64
+ if (!clinicDoc.exists) {
65
+ throw new Error(`Clinic ${clinicId} not found`);
66
+ }
67
+ const clinic = clinicDoc.data() as unknown as Clinic;
68
+
69
+ // 2. Fetch practitioner data
70
+ const practitionerDoc = await this.db
71
+ .collection("practitioners")
72
+ .doc(practitionerId)
73
+ .get();
74
+ if (!practitionerDoc.exists) {
75
+ throw new Error(`Practitioner ${practitionerId} not found`);
76
+ }
77
+ const practitioner = practitionerDoc.data() as unknown as Practitioner;
78
+
79
+ // 3. Fetch procedure data
80
+ const procedureDoc = await this.db
81
+ .collection("procedures")
82
+ .doc(procedureId)
83
+ .get();
84
+ if (!procedureDoc.exists) {
85
+ throw new Error(`Procedure ${procedureId} not found`);
86
+ }
87
+ const procedure = procedureDoc.data() as unknown as Procedure;
88
+
89
+ // 4. Fetch clinic calendar events
90
+ const clinicCalendarEvents = await this.getClinicCalendarEvents(
91
+ clinicId,
92
+ start,
93
+ end
94
+ );
95
+
96
+ // 5. Fetch practitioner calendar events
97
+ const practitionerCalendarEvents =
98
+ await this.getPractitionerCalendarEvents(practitionerId, start, end);
99
+
100
+ // Since we're working with two different Timestamp implementations (admin vs client),
101
+ // we need to convert our timestamps to the client-side format expected by the calculator
102
+ // Create client Timestamp objects from admin Timestamp objects
103
+ const convertedTimeframe = {
104
+ start: this.adminTimestampToClientTimestamp(start),
105
+ end: this.adminTimestampToClientTimestamp(end),
106
+ };
107
+
108
+ // Create the request object for the calculator
109
+ const request: BookingAvailabilityRequest = {
110
+ clinic,
111
+ practitioner,
112
+ procedure,
113
+ timeframe: convertedTimeframe,
114
+ clinicCalendarEvents:
115
+ this.convertEventsTimestamps(clinicCalendarEvents),
116
+ practitionerCalendarEvents: this.convertEventsTimestamps(
117
+ practitionerCalendarEvents
118
+ ),
119
+ };
120
+
121
+ // Use the calculator to compute available slots
122
+ const result = BookingAvailabilityCalculator.calculateSlots(request);
123
+
124
+ // Convert the client Timestamps to admin Timestamps before returning
125
+ return {
126
+ availableSlots: result.availableSlots.map((slot) => ({
127
+ start: admin.firestore.Timestamp.fromMillis(slot.start.toMillis()),
128
+ })),
129
+ };
130
+ } catch (error) {
131
+ console.error("[BookingAdmin] Error getting available slots:", error);
132
+ throw error;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Converts an admin Firestore Timestamp to a client Firestore Timestamp
138
+ */
139
+ private adminTimestampToClientTimestamp(
140
+ timestamp: admin.firestore.Timestamp
141
+ ): any {
142
+ // Create a client Timestamp with the same seconds and nanoseconds
143
+ return {
144
+ seconds: timestamp.seconds,
145
+ nanoseconds: timestamp.nanoseconds,
146
+ toDate: () => timestamp.toDate(),
147
+ toMillis: () => timestamp.toMillis(),
148
+ valueOf: () => timestamp.valueOf(),
149
+ // Add any other required methods/properties
150
+ };
151
+ }
152
+
153
+ /**
154
+ * Converts timestamps in calendar events from admin Firestore Timestamps to client Firestore Timestamps
155
+ */
156
+ private convertEventsTimestamps(events: any[]): any[] {
157
+ return events.map((event) => ({
158
+ ...event,
159
+ eventTime: {
160
+ start: this.adminTimestampToClientTimestamp(event.eventTime.start),
161
+ end: this.adminTimestampToClientTimestamp(event.eventTime.end),
162
+ },
163
+ // Convert any other timestamps in the event if needed
164
+ }));
165
+ }
166
+
167
+ /**
168
+ * Fetches clinic calendar events for a specific time range
169
+ *
170
+ * @param clinicId - ID of the clinic
171
+ * @param start - Start time of the range
172
+ * @param end - End time of the range
173
+ * @returns Promise resolving to an array of calendar events
174
+ */
175
+ private async getClinicCalendarEvents(
176
+ clinicId: string,
177
+ start: admin.firestore.Timestamp,
178
+ end: admin.firestore.Timestamp
179
+ ): Promise<any[]> {
180
+ try {
181
+ const eventsRef = this.db
182
+ .collection(`clinics/${clinicId}/calendar`)
183
+ .where("eventTime.start", ">=", start)
184
+ .where("eventTime.start", "<=", end);
185
+
186
+ const snapshot = await eventsRef.get();
187
+
188
+ return snapshot.docs.map((doc) => ({
189
+ ...doc.data(),
190
+ id: doc.id,
191
+ }));
192
+ } catch (error) {
193
+ console.error(
194
+ `[BookingAdmin] Error fetching clinic calendar events:`,
195
+ error
196
+ );
197
+ return [];
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Fetches practitioner calendar events for a specific time range
203
+ *
204
+ * @param practitionerId - ID of the practitioner
205
+ * @param start - Start time of the range
206
+ * @param end - End time of the range
207
+ * @returns Promise resolving to an array of calendar events
208
+ */
209
+ private async getPractitionerCalendarEvents(
210
+ practitionerId: string,
211
+ start: admin.firestore.Timestamp,
212
+ end: admin.firestore.Timestamp
213
+ ): Promise<any[]> {
214
+ try {
215
+ const eventsRef = this.db
216
+ .collection(`practitioners/${practitionerId}/calendar`)
217
+ .where("eventTime.start", ">=", start)
218
+ .where("eventTime.start", "<=", end);
219
+
220
+ const snapshot = await eventsRef.get();
221
+
222
+ return snapshot.docs.map((doc) => ({
223
+ ...doc.data(),
224
+ id: doc.id,
225
+ }));
226
+ } catch (error) {
227
+ console.error(
228
+ `[BookingAdmin] Error fetching practitioner calendar events:`,
229
+ error
230
+ );
231
+ return [];
232
+ }
233
+ }
234
+ }