@blackcode_sa/metaestetics-api 1.12.19 → 1.12.21
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 +13 -0
- package/dist/admin/index.d.ts +13 -0
- package/dist/admin/index.js +194 -180
- package/dist/admin/index.mjs +194 -180
- package/dist/index.d.mts +48 -1
- package/dist/index.d.ts +48 -1
- package/dist/index.js +2080 -1847
- package/dist/index.mjs +2146 -1913
- package/package.json +1 -1
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +459 -457
- package/src/services/appointment/appointment.service.ts +297 -0
- package/src/types/appointment/index.ts +11 -0
- package/src/validations/appointment.schema.ts +38 -18
package/dist/admin/index.d.mts
CHANGED
|
@@ -2557,6 +2557,19 @@ declare class AppointmentAggregationService {
|
|
|
2557
2557
|
* @returns {Promise<Clinic | null>} The clinic information or null if not found or an error occurs.
|
|
2558
2558
|
*/
|
|
2559
2559
|
private fetchClinicInfo;
|
|
2560
|
+
/**
|
|
2561
|
+
* Checks if zone photos have changed between two appointment states
|
|
2562
|
+
* @param before - The appointment state before update
|
|
2563
|
+
* @param after - The appointment state after update
|
|
2564
|
+
* @returns True if zone photos have changed, false otherwise
|
|
2565
|
+
*/
|
|
2566
|
+
private hasZonePhotosChanged;
|
|
2567
|
+
/**
|
|
2568
|
+
* Handles zone photos update notifications and logging
|
|
2569
|
+
* @param before - The appointment state before update
|
|
2570
|
+
* @param after - The appointment state after update
|
|
2571
|
+
*/
|
|
2572
|
+
private handleZonePhotosUpdate;
|
|
2560
2573
|
}
|
|
2561
2574
|
|
|
2562
2575
|
/**
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -2557,6 +2557,19 @@ declare class AppointmentAggregationService {
|
|
|
2557
2557
|
* @returns {Promise<Clinic | null>} The clinic information or null if not found or an error occurs.
|
|
2558
2558
|
*/
|
|
2559
2559
|
private fetchClinicInfo;
|
|
2560
|
+
/**
|
|
2561
|
+
* Checks if zone photos have changed between two appointment states
|
|
2562
|
+
* @param before - The appointment state before update
|
|
2563
|
+
* @param after - The appointment state after update
|
|
2564
|
+
* @returns True if zone photos have changed, false otherwise
|
|
2565
|
+
*/
|
|
2566
|
+
private hasZonePhotosChanged;
|
|
2567
|
+
/**
|
|
2568
|
+
* Handles zone photos update notifications and logging
|
|
2569
|
+
* @param before - The appointment state before update
|
|
2570
|
+
* @param after - The appointment state after update
|
|
2571
|
+
*/
|
|
2572
|
+
private handleZonePhotosUpdate;
|
|
2560
2573
|
}
|
|
2561
2574
|
|
|
2562
2575
|
/**
|
package/dist/admin/index.js
CHANGED
|
@@ -2079,9 +2079,7 @@ var AppointmentAggregationService = class {
|
|
|
2079
2079
|
);
|
|
2080
2080
|
this.notificationsAdmin = new NotificationsAdmin(this.db);
|
|
2081
2081
|
this.calendarAdminService = new CalendarAdminService(this.db);
|
|
2082
|
-
this.patientRequirementsAdminService = new PatientRequirementsAdminService(
|
|
2083
|
-
this.db
|
|
2084
|
-
);
|
|
2082
|
+
this.patientRequirementsAdminService = new PatientRequirementsAdminService(this.db);
|
|
2085
2083
|
Logger.info("[AppointmentAggregationService] Initialized.");
|
|
2086
2084
|
}
|
|
2087
2085
|
/**
|
|
@@ -2096,12 +2094,7 @@ var AppointmentAggregationService = class {
|
|
|
2096
2094
|
`[AggService] Handling CREATE for appointment: ${appointment.id}, patient: ${appointment.patientId}, status: ${appointment.status}`
|
|
2097
2095
|
);
|
|
2098
2096
|
try {
|
|
2099
|
-
const [
|
|
2100
|
-
patientProfile,
|
|
2101
|
-
patientSensitiveInfo,
|
|
2102
|
-
practitionerProfile,
|
|
2103
|
-
clinicInfo
|
|
2104
|
-
] = await Promise.all([
|
|
2097
|
+
const [patientProfile, patientSensitiveInfo, practitionerProfile, clinicInfo] = await Promise.all([
|
|
2105
2098
|
this.fetchPatientProfile(appointment.patientId),
|
|
2106
2099
|
this.fetchPatientSensitiveInfo(appointment.patientId),
|
|
2107
2100
|
this.fetchPractitionerProfile(appointment.practitionerId),
|
|
@@ -2118,9 +2111,7 @@ var AppointmentAggregationService = class {
|
|
|
2118
2111
|
);
|
|
2119
2112
|
}
|
|
2120
2113
|
if (appointment.status === "confirmed" /* CONFIRMED */) {
|
|
2121
|
-
Logger.info(
|
|
2122
|
-
`[AggService] Appt ${appointment.id} created as CONFIRMED.`
|
|
2123
|
-
);
|
|
2114
|
+
Logger.info(`[AggService] Appt ${appointment.id} created as CONFIRMED.`);
|
|
2124
2115
|
await this.createPreAppointmentRequirementInstances(appointment);
|
|
2125
2116
|
if ((patientSensitiveInfo == null ? void 0 : patientSensitiveInfo.email) && patientProfile) {
|
|
2126
2117
|
Logger.info(
|
|
@@ -2188,9 +2179,7 @@ var AppointmentAggregationService = class {
|
|
|
2188
2179
|
);
|
|
2189
2180
|
}
|
|
2190
2181
|
}
|
|
2191
|
-
Logger.info(
|
|
2192
|
-
`[AggService] Successfully processed CREATE for appointment: ${appointment.id}`
|
|
2193
|
-
);
|
|
2182
|
+
Logger.info(`[AggService] Successfully processed CREATE for appointment: ${appointment.id}`);
|
|
2194
2183
|
} catch (error) {
|
|
2195
2184
|
Logger.error(
|
|
2196
2185
|
`[AggService] Critical error in handleAppointmentCreate for appointment ${appointment.id}:`,
|
|
@@ -2213,12 +2202,8 @@ var AppointmentAggregationService = class {
|
|
|
2213
2202
|
try {
|
|
2214
2203
|
const statusChanged = before.status !== after.status;
|
|
2215
2204
|
const timeChanged = before.appointmentStartTime.toMillis() !== after.appointmentStartTime.toMillis() || before.appointmentEndTime.toMillis() !== after.appointmentEndTime.toMillis();
|
|
2216
|
-
const
|
|
2217
|
-
|
|
2218
|
-
patientSensitiveInfo,
|
|
2219
|
-
practitionerProfile,
|
|
2220
|
-
clinicInfo
|
|
2221
|
-
] = await Promise.all([
|
|
2205
|
+
const zonePhotosChanged = this.hasZonePhotosChanged(before, after);
|
|
2206
|
+
const [patientProfile, patientSensitiveInfo, practitionerProfile, clinicInfo] = await Promise.all([
|
|
2222
2207
|
this.fetchPatientProfile(after.patientId),
|
|
2223
2208
|
this.fetchPatientSensitiveInfo(after.patientId),
|
|
2224
2209
|
this.fetchPractitionerProfile(after.practitionerId),
|
|
@@ -2244,9 +2229,7 @@ var AppointmentAggregationService = class {
|
|
|
2244
2229
|
recipientProfile: after.patientInfo,
|
|
2245
2230
|
recipientRole: "patient"
|
|
2246
2231
|
};
|
|
2247
|
-
await this.appointmentMailingService.sendAppointmentConfirmedEmail(
|
|
2248
|
-
emailData
|
|
2249
|
-
);
|
|
2232
|
+
await this.appointmentMailingService.sendAppointmentConfirmedEmail(emailData);
|
|
2250
2233
|
} else {
|
|
2251
2234
|
Logger.warn(
|
|
2252
2235
|
`[AggService] Cannot send confirmation email to patient ${after.patientId}: email missing.`
|
|
@@ -2277,9 +2260,7 @@ var AppointmentAggregationService = class {
|
|
|
2277
2260
|
);
|
|
2278
2261
|
}
|
|
2279
2262
|
} else if (before.status === "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */ && after.status === "confirmed" /* CONFIRMED */) {
|
|
2280
|
-
Logger.info(
|
|
2281
|
-
`[AggService] Appt ${after.id} RESCHEDULED_BY_CLINIC -> CONFIRMED.`
|
|
2282
|
-
);
|
|
2263
|
+
Logger.info(`[AggService] Appt ${after.id} RESCHEDULED_BY_CLINIC -> CONFIRMED.`);
|
|
2283
2264
|
await this.updateRelatedPatientRequirementInstances(
|
|
2284
2265
|
before,
|
|
2285
2266
|
"supersededReschedule" /* SUPERSEDED_RESCHEDULE */
|
|
@@ -2298,9 +2279,7 @@ var AppointmentAggregationService = class {
|
|
|
2298
2279
|
recipientProfile: after.patientInfo,
|
|
2299
2280
|
recipientRole: "patient"
|
|
2300
2281
|
};
|
|
2301
|
-
await this.appointmentMailingService.sendAppointmentConfirmedEmail(
|
|
2302
|
-
emailData
|
|
2303
|
-
);
|
|
2282
|
+
await this.appointmentMailingService.sendAppointmentConfirmedEmail(emailData);
|
|
2304
2283
|
}
|
|
2305
2284
|
if ((patientProfile == null ? void 0 : patientProfile.expoTokens) && patientProfile.expoTokens.length > 0) {
|
|
2306
2285
|
await this.notificationsAdmin.sendAppointmentConfirmedPush(
|
|
@@ -2411,21 +2390,16 @@ var AppointmentAggregationService = class {
|
|
|
2411
2390
|
);
|
|
2412
2391
|
}
|
|
2413
2392
|
} else if (after.status === "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
2414
|
-
Logger.info(
|
|
2415
|
-
`[AggService] Appt ${after.id} status -> RESCHEDULED_BY_CLINIC.`
|
|
2416
|
-
);
|
|
2393
|
+
Logger.info(`[AggService] Appt ${after.id} status -> RESCHEDULED_BY_CLINIC.`);
|
|
2417
2394
|
await this.updateRelatedPatientRequirementInstances(
|
|
2418
2395
|
before,
|
|
2419
2396
|
// Pass the 'before' state for old requirements
|
|
2420
2397
|
"supersededReschedule" /* SUPERSEDED_RESCHEDULE */
|
|
2421
2398
|
);
|
|
2422
|
-
await this.calendarAdminService.updateAppointmentCalendarEventsTime(
|
|
2423
|
-
after,
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
end: after.appointmentEndTime
|
|
2427
|
-
}
|
|
2428
|
-
);
|
|
2399
|
+
await this.calendarAdminService.updateAppointmentCalendarEventsTime(after, {
|
|
2400
|
+
start: after.appointmentStartTime,
|
|
2401
|
+
end: after.appointmentEndTime
|
|
2402
|
+
});
|
|
2429
2403
|
await this.calendarAdminService.updateAppointmentCalendarEventsStatus(
|
|
2430
2404
|
after,
|
|
2431
2405
|
"pending" /* PENDING */
|
|
@@ -2459,22 +2433,21 @@ var AppointmentAggregationService = class {
|
|
|
2459
2433
|
"supersededReschedule" /* SUPERSEDED_RESCHEDULE */
|
|
2460
2434
|
);
|
|
2461
2435
|
await this.createPreAppointmentRequirementInstances(after);
|
|
2462
|
-
await this.calendarAdminService.updateAppointmentCalendarEventsTime(
|
|
2463
|
-
after,
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
end: after.appointmentEndTime
|
|
2467
|
-
}
|
|
2468
|
-
);
|
|
2436
|
+
await this.calendarAdminService.updateAppointmentCalendarEventsTime(after, {
|
|
2437
|
+
start: after.appointmentStartTime,
|
|
2438
|
+
end: after.appointmentEndTime
|
|
2439
|
+
});
|
|
2469
2440
|
} else {
|
|
2470
2441
|
Logger.warn(
|
|
2471
2442
|
`[AggService] Independent time change detected for ${after.id} with status ${after.status}. Review implications for requirements and calendar.`
|
|
2472
2443
|
);
|
|
2473
2444
|
}
|
|
2474
2445
|
}
|
|
2475
|
-
|
|
2476
|
-
`[AggService]
|
|
2477
|
-
|
|
2446
|
+
if (zonePhotosChanged) {
|
|
2447
|
+
Logger.info(`[AggService] Zone photos changed for appointment ${after.id}`);
|
|
2448
|
+
await this.handleZonePhotosUpdate(before, after);
|
|
2449
|
+
}
|
|
2450
|
+
Logger.info(`[AggService] Successfully processed UPDATE for appointment: ${after.id}`);
|
|
2478
2451
|
} catch (error) {
|
|
2479
2452
|
Logger.error(
|
|
2480
2453
|
`[AggService] Critical error in handleAppointmentUpdate for appointment ${after.id}:`,
|
|
@@ -2488,16 +2461,12 @@ var AppointmentAggregationService = class {
|
|
|
2488
2461
|
* @returns {Promise<void>}
|
|
2489
2462
|
*/
|
|
2490
2463
|
async handleAppointmentDelete(deletedAppointment) {
|
|
2491
|
-
Logger.info(
|
|
2492
|
-
`[AggService] Handling DELETE for appointment: ${deletedAppointment.id}`
|
|
2493
|
-
);
|
|
2464
|
+
Logger.info(`[AggService] Handling DELETE for appointment: ${deletedAppointment.id}`);
|
|
2494
2465
|
await this.updateRelatedPatientRequirementInstances(
|
|
2495
2466
|
deletedAppointment,
|
|
2496
2467
|
"cancelledAppointment" /* CANCELLED_APPOINTMENT */
|
|
2497
2468
|
);
|
|
2498
|
-
const patientProfile = await this.fetchPatientProfile(
|
|
2499
|
-
deletedAppointment.patientId
|
|
2500
|
-
);
|
|
2469
|
+
const patientProfile = await this.fetchPatientProfile(deletedAppointment.patientId);
|
|
2501
2470
|
if (patientProfile) {
|
|
2502
2471
|
await this.managePatientClinicPractitionerLinks(
|
|
2503
2472
|
patientProfile,
|
|
@@ -2506,9 +2475,7 @@ var AppointmentAggregationService = class {
|
|
|
2506
2475
|
"cancel"
|
|
2507
2476
|
);
|
|
2508
2477
|
}
|
|
2509
|
-
await this.calendarAdminService.deleteAppointmentCalendarEvents(
|
|
2510
|
-
deletedAppointment
|
|
2511
|
-
);
|
|
2478
|
+
await this.calendarAdminService.deleteAppointmentCalendarEvents(deletedAppointment);
|
|
2512
2479
|
}
|
|
2513
2480
|
// --- Helper Methods for Aggregation Logic ---
|
|
2514
2481
|
/**
|
|
@@ -2578,15 +2545,11 @@ var AppointmentAggregationService = class {
|
|
|
2578
2545
|
`[AggService] Processing template ${template.id} (${template.name}) for appt ${appointment.id}`
|
|
2579
2546
|
);
|
|
2580
2547
|
const newInstanceRef = this.db.collection(PATIENTS_COLLECTION).doc(appointment.patientId).collection(PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME).doc();
|
|
2581
|
-
Logger.debug(
|
|
2582
|
-
`[AggService] Created doc reference: ${newInstanceRef.path}`
|
|
2583
|
-
);
|
|
2548
|
+
Logger.debug(`[AggService] Created doc reference: ${newInstanceRef.path}`);
|
|
2584
2549
|
const instructions = (((_a = template.timeframe) == null ? void 0 : _a.notifyAt) || []).map((notifyAtValue) => {
|
|
2585
2550
|
let dueTime = appointment.appointmentStartTime;
|
|
2586
2551
|
if (template.timeframe && typeof notifyAtValue === "number") {
|
|
2587
|
-
const dueDateTime = new Date(
|
|
2588
|
-
appointment.appointmentStartTime.toMillis()
|
|
2589
|
-
);
|
|
2552
|
+
const dueDateTime = new Date(appointment.appointmentStartTime.toMillis());
|
|
2590
2553
|
if (template.timeframe.unit === "days" /* DAYS */) {
|
|
2591
2554
|
dueDateTime.setDate(dueDateTime.getDate() - notifyAtValue);
|
|
2592
2555
|
} else if (template.timeframe.unit === "hours" /* HOURS */) {
|
|
@@ -2660,26 +2623,20 @@ var AppointmentAggregationService = class {
|
|
|
2660
2623
|
Logger.warn(
|
|
2661
2624
|
`[AggService] Batch commit reported success but documents not found! Attempting direct creation as fallback...`
|
|
2662
2625
|
);
|
|
2663
|
-
const fallbackPromises = createdInstances.map(
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
fallbackError
|
|
2675
|
-
);
|
|
2676
|
-
return false;
|
|
2677
|
-
}
|
|
2626
|
+
const fallbackPromises = createdInstances.map(async ({ ref, data }) => {
|
|
2627
|
+
try {
|
|
2628
|
+
await ref.set(data);
|
|
2629
|
+
Logger.info(`[AggService] Fallback direct creation success for ${ref.id}`);
|
|
2630
|
+
return true;
|
|
2631
|
+
} catch (fallbackError) {
|
|
2632
|
+
Logger.error(
|
|
2633
|
+
`[AggService] Fallback direct creation failed for ${ref.id}:`,
|
|
2634
|
+
fallbackError
|
|
2635
|
+
);
|
|
2636
|
+
return false;
|
|
2678
2637
|
}
|
|
2679
|
-
);
|
|
2680
|
-
const fallbackResults = await Promise.allSettled(
|
|
2681
|
-
fallbackPromises
|
|
2682
|
-
);
|
|
2638
|
+
});
|
|
2639
|
+
const fallbackResults = await Promise.allSettled(fallbackPromises);
|
|
2683
2640
|
const successCount = fallbackResults.filter(
|
|
2684
2641
|
(r) => r.status === "fulfilled" && r.value === true
|
|
2685
2642
|
).length;
|
|
@@ -2712,23 +2669,19 @@ var AppointmentAggregationService = class {
|
|
|
2712
2669
|
commitError
|
|
2713
2670
|
);
|
|
2714
2671
|
Logger.info(`[AggService] Attempting direct creation as fallback...`);
|
|
2715
|
-
const fallbackPromises = createdInstances.map(
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
fallbackError
|
|
2727
|
-
);
|
|
2728
|
-
return false;
|
|
2729
|
-
}
|
|
2672
|
+
const fallbackPromises = createdInstances.map(async ({ ref, data }) => {
|
|
2673
|
+
try {
|
|
2674
|
+
await ref.set(data);
|
|
2675
|
+
Logger.info(`[AggService] Fallback direct creation success for ${ref.id}`);
|
|
2676
|
+
return true;
|
|
2677
|
+
} catch (fallbackError) {
|
|
2678
|
+
Logger.error(
|
|
2679
|
+
`[AggService] Fallback direct creation failed for ${ref.id}:`,
|
|
2680
|
+
fallbackError
|
|
2681
|
+
);
|
|
2682
|
+
return false;
|
|
2730
2683
|
}
|
|
2731
|
-
);
|
|
2684
|
+
});
|
|
2732
2685
|
const fallbackResults = await Promise.allSettled(fallbackPromises);
|
|
2733
2686
|
const successCount = fallbackResults.filter(
|
|
2734
2687
|
(r) => r.status === "fulfilled" && r.value === true
|
|
@@ -2826,15 +2779,11 @@ var AppointmentAggregationService = class {
|
|
|
2826
2779
|
`[AggService] Processing template ${template.id} (${template.name}) for appt ${appointment.id}`
|
|
2827
2780
|
);
|
|
2828
2781
|
const newInstanceRef = this.db.collection(PATIENTS_COLLECTION).doc(appointment.patientId).collection(PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME).doc();
|
|
2829
|
-
Logger.debug(
|
|
2830
|
-
`[AggService] Created doc reference: ${newInstanceRef.path}`
|
|
2831
|
-
);
|
|
2782
|
+
Logger.debug(`[AggService] Created doc reference: ${newInstanceRef.path}`);
|
|
2832
2783
|
const instructions = (((_a = template.timeframe) == null ? void 0 : _a.notifyAt) || []).map((notifyAtValue) => {
|
|
2833
2784
|
let dueTime = appointment.appointmentEndTime;
|
|
2834
2785
|
if (template.timeframe && typeof notifyAtValue === "number") {
|
|
2835
|
-
const dueDateTime = new Date(
|
|
2836
|
-
appointment.appointmentEndTime.toMillis()
|
|
2837
|
-
);
|
|
2786
|
+
const dueDateTime = new Date(appointment.appointmentEndTime.toMillis());
|
|
2838
2787
|
if (template.timeframe.unit === "days" /* DAYS */) {
|
|
2839
2788
|
dueDateTime.setDate(dueDateTime.getDate() + notifyAtValue);
|
|
2840
2789
|
} else if (template.timeframe.unit === "hours" /* HOURS */) {
|
|
@@ -2905,26 +2854,20 @@ var AppointmentAggregationService = class {
|
|
|
2905
2854
|
Logger.warn(
|
|
2906
2855
|
`[AggService] Batch commit reported success but documents not found! Attempting direct creation as fallback...`
|
|
2907
2856
|
);
|
|
2908
|
-
const fallbackPromises = createdInstances.map(
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
fallbackError
|
|
2920
|
-
);
|
|
2921
|
-
return false;
|
|
2922
|
-
}
|
|
2857
|
+
const fallbackPromises = createdInstances.map(async ({ ref, data }) => {
|
|
2858
|
+
try {
|
|
2859
|
+
await ref.set(data);
|
|
2860
|
+
Logger.info(`[AggService] Fallback direct creation success for ${ref.id}`);
|
|
2861
|
+
return true;
|
|
2862
|
+
} catch (fallbackError) {
|
|
2863
|
+
Logger.error(
|
|
2864
|
+
`[AggService] Fallback direct creation failed for ${ref.id}:`,
|
|
2865
|
+
fallbackError
|
|
2866
|
+
);
|
|
2867
|
+
return false;
|
|
2923
2868
|
}
|
|
2924
|
-
);
|
|
2925
|
-
const fallbackResults = await Promise.allSettled(
|
|
2926
|
-
fallbackPromises
|
|
2927
|
-
);
|
|
2869
|
+
});
|
|
2870
|
+
const fallbackResults = await Promise.allSettled(fallbackPromises);
|
|
2928
2871
|
const successCount = fallbackResults.filter(
|
|
2929
2872
|
(r) => r.status === "fulfilled" && r.value === true
|
|
2930
2873
|
).length;
|
|
@@ -2957,23 +2900,19 @@ var AppointmentAggregationService = class {
|
|
|
2957
2900
|
commitError
|
|
2958
2901
|
);
|
|
2959
2902
|
Logger.info(`[AggService] Attempting direct creation as fallback...`);
|
|
2960
|
-
const fallbackPromises = createdInstances.map(
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
fallbackError
|
|
2972
|
-
);
|
|
2973
|
-
return false;
|
|
2974
|
-
}
|
|
2903
|
+
const fallbackPromises = createdInstances.map(async ({ ref, data }) => {
|
|
2904
|
+
try {
|
|
2905
|
+
await ref.set(data);
|
|
2906
|
+
Logger.info(`[AggService] Fallback direct creation success for ${ref.id}`);
|
|
2907
|
+
return true;
|
|
2908
|
+
} catch (fallbackError) {
|
|
2909
|
+
Logger.error(
|
|
2910
|
+
`[AggService] Fallback direct creation failed for ${ref.id}:`,
|
|
2911
|
+
fallbackError
|
|
2912
|
+
);
|
|
2913
|
+
return false;
|
|
2975
2914
|
}
|
|
2976
|
-
);
|
|
2915
|
+
});
|
|
2977
2916
|
const fallbackResults = await Promise.allSettled(fallbackPromises);
|
|
2978
2917
|
const successCount = fallbackResults.filter(
|
|
2979
2918
|
(r) => r.status === "fulfilled" && r.value === true
|
|
@@ -3123,9 +3062,7 @@ var AppointmentAggregationService = class {
|
|
|
3123
3062
|
updateData.doctorIds = admin6.firestore.FieldValue.arrayUnion(practitionerId);
|
|
3124
3063
|
}
|
|
3125
3064
|
if (!hasClinic) {
|
|
3126
|
-
Logger.debug(
|
|
3127
|
-
`[AggService] Adding clinic ${clinicId} to patient ${patientProfile.id}`
|
|
3128
|
-
);
|
|
3065
|
+
Logger.debug(`[AggService] Adding clinic ${clinicId} to patient ${patientProfile.id}`);
|
|
3129
3066
|
updateData.clinicIds = admin6.firestore.FieldValue.arrayUnion(clinicId);
|
|
3130
3067
|
}
|
|
3131
3068
|
await patientRef.update(updateData);
|
|
@@ -3180,28 +3117,19 @@ var AppointmentAggregationService = class {
|
|
|
3180
3117
|
updateNeeded = true;
|
|
3181
3118
|
}
|
|
3182
3119
|
if (activeClinicAppointments === 0 && ((_b = patientProfile.clinicIds) == null ? void 0 : _b.includes(clinicId))) {
|
|
3183
|
-
Logger.debug(
|
|
3184
|
-
`[AggService] Removing clinic ${clinicId} from patient ${patientProfile.id}`
|
|
3185
|
-
);
|
|
3120
|
+
Logger.debug(`[AggService] Removing clinic ${clinicId} from patient ${patientProfile.id}`);
|
|
3186
3121
|
updateData.clinicIds = admin6.firestore.FieldValue.arrayRemove(clinicId);
|
|
3187
3122
|
updateNeeded = true;
|
|
3188
3123
|
}
|
|
3189
3124
|
if (updateNeeded) {
|
|
3190
3125
|
updateData.updatedAt = admin6.firestore.FieldValue.serverTimestamp();
|
|
3191
3126
|
await patientRef.update(updateData);
|
|
3192
|
-
Logger.info(
|
|
3193
|
-
`[AggService] Successfully removed links from patient ${patientProfile.id}`
|
|
3194
|
-
);
|
|
3127
|
+
Logger.info(`[AggService] Successfully removed links from patient ${patientProfile.id}`);
|
|
3195
3128
|
} else {
|
|
3196
|
-
Logger.info(
|
|
3197
|
-
`[AggService] No links need to be removed from patient ${patientProfile.id}`
|
|
3198
|
-
);
|
|
3129
|
+
Logger.info(`[AggService] No links need to be removed from patient ${patientProfile.id}`);
|
|
3199
3130
|
}
|
|
3200
3131
|
} catch (error) {
|
|
3201
|
-
Logger.error(
|
|
3202
|
-
`[AggService] Error removing links from patient profile:`,
|
|
3203
|
-
error
|
|
3204
|
-
);
|
|
3132
|
+
Logger.error(`[AggService] Error removing links from patient profile:`, error);
|
|
3205
3133
|
throw error;
|
|
3206
3134
|
}
|
|
3207
3135
|
}
|
|
@@ -3234,10 +3162,7 @@ var AppointmentAggregationService = class {
|
|
|
3234
3162
|
const doc = await this.db.collection(PATIENTS_COLLECTION).doc(patientId).get();
|
|
3235
3163
|
return doc.exists ? doc.data() : null;
|
|
3236
3164
|
} catch (error) {
|
|
3237
|
-
Logger.error(
|
|
3238
|
-
`[AggService] Error fetching patient profile ${patientId}:`,
|
|
3239
|
-
error
|
|
3240
|
-
);
|
|
3165
|
+
Logger.error(`[AggService] Error fetching patient profile ${patientId}:`, error);
|
|
3241
3166
|
return null;
|
|
3242
3167
|
}
|
|
3243
3168
|
}
|
|
@@ -3250,17 +3175,12 @@ var AppointmentAggregationService = class {
|
|
|
3250
3175
|
try {
|
|
3251
3176
|
const doc = await this.db.collection(PATIENTS_COLLECTION).doc(patientId).collection(PATIENT_SENSITIVE_INFO_COLLECTION).doc(patientId).get();
|
|
3252
3177
|
if (!doc.exists) {
|
|
3253
|
-
Logger.warn(
|
|
3254
|
-
`[AggService] No sensitive info found for patient ${patientId}`
|
|
3255
|
-
);
|
|
3178
|
+
Logger.warn(`[AggService] No sensitive info found for patient ${patientId}`);
|
|
3256
3179
|
return null;
|
|
3257
3180
|
}
|
|
3258
3181
|
return doc.data();
|
|
3259
3182
|
} catch (error) {
|
|
3260
|
-
Logger.error(
|
|
3261
|
-
`[AggService] Error fetching patient sensitive info ${patientId}:`,
|
|
3262
|
-
error
|
|
3263
|
-
);
|
|
3183
|
+
Logger.error(`[AggService] Error fetching patient sensitive info ${patientId}:`, error);
|
|
3264
3184
|
return null;
|
|
3265
3185
|
}
|
|
3266
3186
|
}
|
|
@@ -3271,25 +3191,18 @@ var AppointmentAggregationService = class {
|
|
|
3271
3191
|
*/
|
|
3272
3192
|
async fetchPractitionerProfile(practitionerId) {
|
|
3273
3193
|
if (!practitionerId) {
|
|
3274
|
-
Logger.warn(
|
|
3275
|
-
"[AggService] fetchPractitionerProfile called with no practitionerId."
|
|
3276
|
-
);
|
|
3194
|
+
Logger.warn("[AggService] fetchPractitionerProfile called with no practitionerId.");
|
|
3277
3195
|
return null;
|
|
3278
3196
|
}
|
|
3279
3197
|
try {
|
|
3280
3198
|
const doc = await this.db.collection(PRACTITIONERS_COLLECTION).doc(practitionerId).get();
|
|
3281
3199
|
if (!doc.exists) {
|
|
3282
|
-
Logger.warn(
|
|
3283
|
-
`[AggService] No practitioner profile found for ID ${practitionerId}`
|
|
3284
|
-
);
|
|
3200
|
+
Logger.warn(`[AggService] No practitioner profile found for ID ${practitionerId}`);
|
|
3285
3201
|
return null;
|
|
3286
3202
|
}
|
|
3287
3203
|
return doc.data();
|
|
3288
3204
|
} catch (error) {
|
|
3289
|
-
Logger.error(
|
|
3290
|
-
`[AggService] Error fetching practitioner profile ${practitionerId}:`,
|
|
3291
|
-
error
|
|
3292
|
-
);
|
|
3205
|
+
Logger.error(`[AggService] Error fetching practitioner profile ${practitionerId}:`, error);
|
|
3293
3206
|
return null;
|
|
3294
3207
|
}
|
|
3295
3208
|
}
|
|
@@ -3310,12 +3223,113 @@ var AppointmentAggregationService = class {
|
|
|
3310
3223
|
return null;
|
|
3311
3224
|
}
|
|
3312
3225
|
return doc.data();
|
|
3226
|
+
} catch (error) {
|
|
3227
|
+
Logger.error(`[AggService] Error fetching clinic info ${clinicId}:`, error);
|
|
3228
|
+
return null;
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
/**
|
|
3232
|
+
* Checks if zone photos have changed between two appointment states
|
|
3233
|
+
* @param before - The appointment state before update
|
|
3234
|
+
* @param after - The appointment state after update
|
|
3235
|
+
* @returns True if zone photos have changed, false otherwise
|
|
3236
|
+
*/
|
|
3237
|
+
hasZonePhotosChanged(before, after) {
|
|
3238
|
+
var _a, _b;
|
|
3239
|
+
const beforePhotos = (_a = before.metadata) == null ? void 0 : _a.zonePhotos;
|
|
3240
|
+
const afterPhotos = (_b = after.metadata) == null ? void 0 : _b.zonePhotos;
|
|
3241
|
+
if (!beforePhotos && !afterPhotos) {
|
|
3242
|
+
return false;
|
|
3243
|
+
}
|
|
3244
|
+
if (!beforePhotos || !afterPhotos) {
|
|
3245
|
+
return true;
|
|
3246
|
+
}
|
|
3247
|
+
const beforeZones = Object.keys(beforePhotos);
|
|
3248
|
+
const afterZones = Object.keys(afterPhotos);
|
|
3249
|
+
if (beforeZones.length !== afterZones.length) {
|
|
3250
|
+
return true;
|
|
3251
|
+
}
|
|
3252
|
+
for (const zoneId of afterZones) {
|
|
3253
|
+
const beforeZonePhotos = beforePhotos[zoneId];
|
|
3254
|
+
const afterZonePhotos = afterPhotos[zoneId];
|
|
3255
|
+
if (!beforeZonePhotos && !afterZonePhotos) {
|
|
3256
|
+
continue;
|
|
3257
|
+
}
|
|
3258
|
+
if (!beforeZonePhotos || !afterZonePhotos) {
|
|
3259
|
+
return true;
|
|
3260
|
+
}
|
|
3261
|
+
if (beforeZonePhotos.before !== afterZonePhotos.before || beforeZonePhotos.after !== afterZonePhotos.after || beforeZonePhotos.beforeNote !== afterZonePhotos.beforeNote || beforeZonePhotos.afterNote !== afterZonePhotos.afterNote) {
|
|
3262
|
+
return true;
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
return false;
|
|
3266
|
+
}
|
|
3267
|
+
/**
|
|
3268
|
+
* Handles zone photos update notifications and logging
|
|
3269
|
+
* @param before - The appointment state before update
|
|
3270
|
+
* @param after - The appointment state after update
|
|
3271
|
+
*/
|
|
3272
|
+
async handleZonePhotosUpdate(before, after) {
|
|
3273
|
+
var _a, _b, _c;
|
|
3274
|
+
try {
|
|
3275
|
+
Logger.info(`[AggService] Processing zone photos update for appointment ${after.id}`);
|
|
3276
|
+
const beforePhotos = ((_a = before.metadata) == null ? void 0 : _a.zonePhotos) || {};
|
|
3277
|
+
const afterPhotos = ((_b = after.metadata) == null ? void 0 : _b.zonePhotos) || {};
|
|
3278
|
+
const updatedZones = [];
|
|
3279
|
+
const newPhotoTypes = [];
|
|
3280
|
+
for (const zoneId of Object.keys(afterPhotos)) {
|
|
3281
|
+
const beforeZonePhotos = beforePhotos[zoneId];
|
|
3282
|
+
const afterZonePhotos = afterPhotos[zoneId];
|
|
3283
|
+
if (!beforeZonePhotos) {
|
|
3284
|
+
updatedZones.push(zoneId);
|
|
3285
|
+
if (afterZonePhotos.before) {
|
|
3286
|
+
newPhotoTypes.push({ zoneId, photoType: "before" });
|
|
3287
|
+
}
|
|
3288
|
+
if (afterZonePhotos.after) {
|
|
3289
|
+
newPhotoTypes.push({ zoneId, photoType: "after" });
|
|
3290
|
+
}
|
|
3291
|
+
} else {
|
|
3292
|
+
if (beforeZonePhotos.before !== afterZonePhotos.before && afterZonePhotos.before) {
|
|
3293
|
+
updatedZones.push(zoneId);
|
|
3294
|
+
newPhotoTypes.push({ zoneId, photoType: "before" });
|
|
3295
|
+
}
|
|
3296
|
+
if (beforeZonePhotos.after !== afterZonePhotos.after && afterZonePhotos.after) {
|
|
3297
|
+
updatedZones.push(zoneId);
|
|
3298
|
+
newPhotoTypes.push({ zoneId, photoType: "after" });
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
if (updatedZones.length > 0) {
|
|
3303
|
+
Logger.info(
|
|
3304
|
+
`[AggService] Zone photos updated for appointment ${after.id}: ${updatedZones.join(
|
|
3305
|
+
", "
|
|
3306
|
+
)}`
|
|
3307
|
+
);
|
|
3308
|
+
for (const { zoneId, photoType } of newPhotoTypes) {
|
|
3309
|
+
Logger.info(
|
|
3310
|
+
`[AggService] New ${photoType} photo added for zone ${zoneId} in appointment ${after.id}`
|
|
3311
|
+
);
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
const selectedZones = ((_c = after.metadata) == null ? void 0 : _c.selectedZones) || [];
|
|
3315
|
+
if (selectedZones.length > 0) {
|
|
3316
|
+
const completedZones = selectedZones.filter((zoneId) => {
|
|
3317
|
+
const zonePhotos = afterPhotos[zoneId];
|
|
3318
|
+
return zonePhotos && (zonePhotos.before || zonePhotos.after);
|
|
3319
|
+
});
|
|
3320
|
+
const completionPercentage = completedZones.length / selectedZones.length * 100;
|
|
3321
|
+
Logger.info(
|
|
3322
|
+
`[AggService] Photo completion for appointment ${after.id}: ${completionPercentage.toFixed(1)}% (${completedZones.length}/${selectedZones.length} zones)`
|
|
3323
|
+
);
|
|
3324
|
+
if (completionPercentage === 100) {
|
|
3325
|
+
Logger.info(`[AggService] All zone photos completed for appointment ${after.id}`);
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3313
3328
|
} catch (error) {
|
|
3314
3329
|
Logger.error(
|
|
3315
|
-
`[AggService] Error
|
|
3330
|
+
`[AggService] Error handling zone photos update for appointment ${after.id}:`,
|
|
3316
3331
|
error
|
|
3317
3332
|
);
|
|
3318
|
-
return null;
|
|
3319
3333
|
}
|
|
3320
3334
|
}
|
|
3321
3335
|
};
|