@blackcode_sa/metaestetics-api 1.13.4 → 1.13.5
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 +15 -28
- package/dist/admin/index.d.ts +15 -28
- package/dist/index.d.mts +16 -29
- package/dist/index.d.ts +16 -29
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/package.json +121 -119
- package/src/__mocks__/firstore.ts +10 -10
- package/src/admin/aggregation/README.md +79 -79
- package/src/admin/aggregation/appointment/README.md +128 -128
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +1984 -1984
- package/src/admin/aggregation/appointment/index.ts +1 -1
- package/src/admin/aggregation/clinic/README.md +52 -52
- package/src/admin/aggregation/clinic/clinic.aggregation.service.ts +703 -703
- package/src/admin/aggregation/clinic/index.ts +1 -1
- package/src/admin/aggregation/forms/README.md +13 -13
- package/src/admin/aggregation/forms/filled-forms.aggregation.service.ts +322 -322
- package/src/admin/aggregation/forms/index.ts +1 -1
- package/src/admin/aggregation/index.ts +8 -8
- package/src/admin/aggregation/patient/README.md +27 -27
- package/src/admin/aggregation/patient/index.ts +1 -1
- package/src/admin/aggregation/patient/patient.aggregation.service.ts +141 -141
- package/src/admin/aggregation/practitioner/README.md +42 -42
- package/src/admin/aggregation/practitioner/index.ts +1 -1
- package/src/admin/aggregation/practitioner/practitioner.aggregation.service.ts +433 -433
- package/src/admin/aggregation/practitioner-invite/index.ts +1 -1
- package/src/admin/aggregation/practitioner-invite/practitioner-invite.aggregation.service.ts +961 -961
- package/src/admin/aggregation/procedure/README.md +43 -43
- package/src/admin/aggregation/procedure/index.ts +1 -1
- package/src/admin/aggregation/procedure/procedure.aggregation.service.ts +702 -702
- package/src/admin/aggregation/reviews/index.ts +1 -1
- package/src/admin/aggregation/reviews/reviews.aggregation.service.ts +689 -689
- package/src/admin/analytics/analytics.admin.service.ts +278 -278
- package/src/admin/analytics/index.ts +2 -2
- package/src/admin/booking/README.md +125 -125
- package/src/admin/booking/booking.admin.ts +1037 -1037
- package/src/admin/booking/booking.calculator.ts +712 -712
- package/src/admin/booking/booking.types.ts +59 -59
- package/src/admin/booking/index.ts +3 -3
- package/src/admin/booking/timezones-problem.md +185 -185
- package/src/admin/calendar/README.md +7 -7
- package/src/admin/calendar/calendar.admin.service.ts +345 -345
- package/src/admin/calendar/index.ts +1 -1
- package/src/admin/documentation-templates/document-manager.admin.ts +260 -260
- package/src/admin/documentation-templates/index.ts +1 -1
- package/src/admin/free-consultation/free-consultation-utils.admin.ts +148 -148
- package/src/admin/free-consultation/index.ts +1 -1
- package/src/admin/index.ts +81 -81
- package/src/admin/logger/index.ts +78 -78
- package/src/admin/mailing/README.md +95 -95
- package/src/admin/mailing/appointment/appointment.mailing.service.ts +732 -732
- package/src/admin/mailing/appointment/index.ts +1 -1
- package/src/admin/mailing/appointment/templates/patient/appointment-confirmed.html +40 -40
- package/src/admin/mailing/base.mailing.service.ts +208 -208
- package/src/admin/mailing/index.ts +3 -3
- package/src/admin/mailing/practitionerInvite/existing-practitioner-invite.mailing.ts +611 -611
- package/src/admin/mailing/practitionerInvite/index.ts +2 -2
- package/src/admin/mailing/practitionerInvite/practitionerInvite.mailing.ts +395 -395
- package/src/admin/mailing/practitionerInvite/templates/existing-practitioner-invitation.template.ts +155 -155
- package/src/admin/mailing/practitionerInvite/templates/invitation.template.ts +101 -101
- package/src/admin/mailing/practitionerInvite/templates/invite-accepted-notification.template.ts +228 -228
- package/src/admin/mailing/practitionerInvite/templates/invite-rejected-notification.template.ts +242 -242
- package/src/admin/notifications/index.ts +1 -1
- package/src/admin/notifications/notifications.admin.ts +710 -710
- package/src/admin/requirements/README.md +128 -128
- package/src/admin/requirements/index.ts +1 -1
- package/src/admin/requirements/patient-requirements.admin.service.ts +475 -475
- package/src/admin/users/index.ts +1 -1
- package/src/admin/users/user-profile.admin.ts +405 -405
- package/src/backoffice/constants/certification.constants.ts +13 -13
- package/src/backoffice/constants/index.ts +1 -1
- package/src/backoffice/errors/backoffice.errors.ts +181 -181
- package/src/backoffice/errors/index.ts +1 -1
- package/src/backoffice/expo-safe/README.md +26 -26
- package/src/backoffice/expo-safe/index.ts +41 -41
- package/src/backoffice/index.ts +5 -5
- package/src/backoffice/services/FIXES_README.md +102 -102
- package/src/backoffice/services/README.md +57 -57
- package/src/backoffice/services/analytics.service.proposal.md +863 -863
- package/src/backoffice/services/analytics.service.summary.md +143 -143
- package/src/backoffice/services/brand.service.ts +256 -256
- package/src/backoffice/services/category.service.ts +384 -384
- package/src/backoffice/services/constants.service.ts +385 -385
- package/src/backoffice/services/documentation-template.service.ts +202 -202
- package/src/backoffice/services/index.ts +10 -10
- package/src/backoffice/services/migrate-products.ts +116 -116
- package/src/backoffice/services/product.service.ts +553 -553
- package/src/backoffice/services/requirement.service.ts +235 -235
- package/src/backoffice/services/subcategory.service.ts +461 -461
- package/src/backoffice/services/technology.service.ts +1151 -1151
- package/src/backoffice/types/README.md +12 -12
- package/src/backoffice/types/admin-constants.types.ts +69 -69
- package/src/backoffice/types/brand.types.ts +29 -29
- package/src/backoffice/types/category.types.ts +67 -67
- package/src/backoffice/types/documentation-templates.types.ts +28 -28
- package/src/backoffice/types/index.ts +10 -10
- package/src/backoffice/types/procedure-product.types.ts +38 -38
- package/src/backoffice/types/product.types.ts +240 -240
- package/src/backoffice/types/requirement.types.ts +63 -63
- package/src/backoffice/types/static/README.md +18 -18
- package/src/backoffice/types/static/blocking-condition.types.ts +21 -21
- package/src/backoffice/types/static/certification.types.ts +37 -37
- package/src/backoffice/types/static/contraindication.types.ts +19 -19
- package/src/backoffice/types/static/index.ts +6 -6
- package/src/backoffice/types/static/pricing.types.ts +16 -16
- package/src/backoffice/types/static/procedure-family.types.ts +14 -14
- package/src/backoffice/types/static/treatment-benefit.types.ts +22 -22
- package/src/backoffice/types/subcategory.types.ts +34 -34
- package/src/backoffice/types/technology.types.ts +168 -168
- package/src/backoffice/validations/index.ts +1 -1
- package/src/backoffice/validations/schemas.ts +164 -164
- package/src/config/__mocks__/firebase.ts +99 -99
- package/src/config/firebase.ts +78 -78
- package/src/config/index.ts +9 -9
- package/src/errors/auth.error.ts +6 -6
- package/src/errors/auth.errors.ts +200 -200
- package/src/errors/clinic.errors.ts +32 -32
- package/src/errors/firebase.errors.ts +47 -47
- package/src/errors/user.errors.ts +99 -99
- package/src/index.backup.ts +407 -407
- package/src/index.ts +6 -6
- package/src/locales/en.ts +31 -31
- package/src/recommender/admin/index.ts +1 -1
- package/src/recommender/admin/services/recommender.service.admin.ts +5 -5
- package/src/recommender/front/index.ts +1 -1
- package/src/recommender/front/services/onboarding.service.ts +5 -5
- package/src/recommender/front/services/recommender.service.ts +3 -3
- package/src/recommender/index.ts +1 -1
- package/src/services/PATIENTAUTH.MD +197 -197
- package/src/services/README.md +106 -106
- package/src/services/__tests__/auth/auth.mock.test.ts +17 -17
- package/src/services/__tests__/auth/auth.setup.ts +293 -293
- package/src/services/__tests__/auth.service.test.ts +346 -346
- package/src/services/__tests__/base.service.test.ts +77 -77
- package/src/services/__tests__/user.service.test.ts +528 -528
- package/src/services/analytics/ARCHITECTURE.md +199 -199
- package/src/services/analytics/CLOUD_FUNCTIONS.md +225 -225
- package/src/services/analytics/GROUPED_ANALYTICS.md +501 -501
- package/src/services/analytics/QUICK_START.md +393 -393
- package/src/services/analytics/README.md +304 -304
- package/src/services/analytics/SUMMARY.md +141 -141
- package/src/services/analytics/TRENDS.md +380 -380
- package/src/services/analytics/USAGE_GUIDE.md +518 -518
- package/src/services/analytics/analytics-cloud.service.ts +222 -222
- package/src/services/analytics/analytics.service.ts +2142 -2142
- package/src/services/analytics/index.ts +4 -4
- package/src/services/analytics/review-analytics.service.ts +941 -941
- package/src/services/analytics/utils/appointment-filtering.utils.ts +138 -138
- package/src/services/analytics/utils/cost-calculation.utils.ts +182 -182
- package/src/services/analytics/utils/grouping.utils.ts +434 -434
- package/src/services/analytics/utils/stored-analytics.utils.ts +347 -347
- package/src/services/analytics/utils/time-calculation.utils.ts +186 -186
- package/src/services/analytics/utils/trend-calculation.utils.ts +200 -200
- package/src/services/appointment/README.md +17 -17
- package/src/services/appointment/appointment.service.ts +2558 -2558
- package/src/services/appointment/index.ts +1 -1
- package/src/services/appointment/utils/appointment.utils.ts +552 -552
- package/src/services/appointment/utils/extended-procedure.utils.ts +314 -314
- package/src/services/appointment/utils/form-initialization.utils.ts +225 -225
- package/src/services/appointment/utils/recommended-procedure.utils.ts +195 -195
- package/src/services/appointment/utils/zone-management.utils.ts +353 -353
- package/src/services/appointment/utils/zone-photo.utils.ts +152 -152
- package/src/services/auth/auth.service.ts +989 -989
- package/src/services/auth/auth.v2.service.ts +961 -961
- package/src/services/auth/index.ts +7 -7
- package/src/services/auth/utils/error.utils.ts +90 -90
- package/src/services/auth/utils/firebase.utils.ts +49 -49
- package/src/services/auth/utils/index.ts +21 -21
- package/src/services/auth/utils/practitioner.utils.ts +125 -125
- package/src/services/base.service.ts +41 -41
- package/src/services/calendar/calendar.service.ts +1077 -1077
- package/src/services/calendar/calendar.v2.service.ts +1683 -1683
- package/src/services/calendar/calendar.v3.service.ts +313 -313
- package/src/services/calendar/externalCalendar.service.ts +178 -178
- package/src/services/calendar/index.ts +5 -5
- package/src/services/calendar/synced-calendars.service.ts +743 -743
- package/src/services/calendar/utils/appointment.utils.ts +265 -265
- package/src/services/calendar/utils/calendar-event.utils.ts +646 -646
- package/src/services/calendar/utils/clinic.utils.ts +237 -237
- package/src/services/calendar/utils/docs.utils.ts +157 -157
- package/src/services/calendar/utils/google-calendar.utils.ts +697 -697
- package/src/services/calendar/utils/index.ts +8 -8
- package/src/services/calendar/utils/patient.utils.ts +198 -198
- package/src/services/calendar/utils/practitioner.utils.ts +221 -221
- package/src/services/calendar/utils/synced-calendar.utils.ts +472 -472
- package/src/services/clinic/README.md +204 -204
- package/src/services/clinic/__tests__/clinic-admin.service.test.ts +287 -287
- package/src/services/clinic/__tests__/clinic-group.service.test.ts +352 -352
- package/src/services/clinic/__tests__/clinic.service.test.ts +354 -354
- package/src/services/clinic/billing-transactions.service.ts +217 -217
- package/src/services/clinic/clinic-admin.service.ts +202 -202
- package/src/services/clinic/clinic-group.service.ts +310 -310
- package/src/services/clinic/clinic.service.ts +708 -708
- package/src/services/clinic/index.ts +5 -5
- package/src/services/clinic/practitioner-invite.service.ts +519 -519
- package/src/services/clinic/utils/admin.utils.ts +551 -551
- package/src/services/clinic/utils/clinic-group.utils.ts +646 -646
- package/src/services/clinic/utils/clinic.utils.ts +949 -949
- package/src/services/clinic/utils/filter.utils.d.ts +23 -23
- package/src/services/clinic/utils/filter.utils.ts +446 -446
- package/src/services/clinic/utils/index.ts +11 -11
- package/src/services/clinic/utils/photos.utils.ts +188 -188
- package/src/services/clinic/utils/search.utils.ts +84 -84
- package/src/services/clinic/utils/tag.utils.ts +124 -124
- package/src/services/documentation-templates/documentation-template.service.ts +537 -537
- package/src/services/documentation-templates/filled-document.service.ts +587 -587
- package/src/services/documentation-templates/index.ts +2 -2
- package/src/services/index.ts +14 -14
- package/src/services/media/index.ts +1 -1
- package/src/services/media/media.service.ts +418 -418
- package/src/services/notifications/__tests__/notification.service.test.ts +242 -242
- package/src/services/notifications/index.ts +1 -1
- package/src/services/notifications/notification.service.ts +215 -215
- package/src/services/patient/README.md +48 -48
- package/src/services/patient/To-Do.md +43 -43
- package/src/services/patient/__tests__/patient.service.test.ts +294 -294
- package/src/services/patient/index.ts +2 -2
- package/src/services/patient/patient.service.ts +883 -883
- package/src/services/patient/patientRequirements.service.ts +285 -285
- package/src/services/patient/utils/aesthetic-analysis.utils.ts +176 -176
- package/src/services/patient/utils/clinic.utils.ts +80 -80
- package/src/services/patient/utils/docs.utils.ts +142 -142
- package/src/services/patient/utils/index.ts +9 -9
- package/src/services/patient/utils/location.utils.ts +126 -126
- package/src/services/patient/utils/medical-stuff.utils.ts +143 -143
- package/src/services/patient/utils/medical.utils.ts +458 -458
- package/src/services/patient/utils/practitioner.utils.ts +260 -260
- package/src/services/patient/utils/profile.utils.ts +510 -510
- package/src/services/patient/utils/sensitive.utils.ts +260 -260
- package/src/services/patient/utils/token.utils.ts +211 -211
- package/src/services/practitioner/README.md +145 -145
- package/src/services/practitioner/index.ts +1 -1
- package/src/services/practitioner/practitioner.service.ts +1742 -1742
- package/src/services/procedure/README.md +163 -163
- package/src/services/procedure/index.ts +1 -1
- package/src/services/procedure/procedure.service.ts +2200 -2200
- package/src/services/reviews/index.ts +1 -1
- package/src/services/reviews/reviews.service.ts +734 -734
- package/src/services/user/index.ts +1 -1
- package/src/services/user/user.service.ts +489 -489
- package/src/services/user/user.v2.service.ts +466 -466
- package/src/types/analytics/analytics.types.ts +597 -597
- package/src/types/analytics/grouped-analytics.types.ts +173 -173
- package/src/types/analytics/index.ts +4 -4
- package/src/types/analytics/stored-analytics.types.ts +137 -137
- package/src/types/appointment/index.ts +480 -480
- package/src/types/calendar/index.ts +258 -258
- package/src/types/calendar/synced-calendar.types.ts +66 -66
- package/src/types/clinic/index.ts +498 -489
- package/src/types/clinic/practitioner-invite.types.ts +91 -91
- package/src/types/clinic/preferences.types.ts +159 -159
- package/src/types/clinic/to-do +3 -3
- package/src/types/documentation-templates/index.ts +308 -308
- package/src/types/index.ts +47 -47
- package/src/types/notifications/README.md +77 -77
- package/src/types/notifications/index.ts +286 -286
- package/src/types/patient/aesthetic-analysis.types.ts +66 -66
- package/src/types/patient/allergies.ts +58 -58
- package/src/types/patient/index.ts +275 -275
- package/src/types/patient/medical-info.types.ts +152 -152
- package/src/types/patient/patient-requirements.ts +92 -92
- package/src/types/patient/token.types.ts +61 -61
- package/src/types/practitioner/index.ts +206 -206
- package/src/types/procedure/index.ts +181 -181
- package/src/types/profile/index.ts +39 -39
- package/src/types/reviews/index.ts +132 -132
- package/src/types/tz-lookup.d.ts +4 -4
- package/src/types/user/index.ts +38 -38
- package/src/utils/TIMESTAMPS.md +176 -176
- package/src/utils/TimestampUtils.ts +241 -241
- package/src/utils/index.ts +1 -1
- package/src/validations/appointment.schema.ts +574 -574
- package/src/validations/calendar.schema.ts +225 -225
- package/src/validations/clinic.schema.ts +494 -493
- package/src/validations/common.schema.ts +25 -25
- package/src/validations/documentation-templates/index.ts +1 -1
- package/src/validations/documentation-templates/template.schema.ts +220 -220
- package/src/validations/documentation-templates.schema.ts +10 -10
- package/src/validations/index.ts +20 -20
- package/src/validations/media.schema.ts +10 -10
- package/src/validations/notification.schema.ts +90 -90
- package/src/validations/patient/aesthetic-analysis.schema.ts +55 -55
- package/src/validations/patient/medical-info.schema.ts +125 -125
- package/src/validations/patient/patient-requirements.schema.ts +84 -84
- package/src/validations/patient/token.schema.ts +29 -29
- package/src/validations/patient.schema.ts +217 -217
- package/src/validations/practitioner.schema.ts +222 -222
- package/src/validations/procedure-product.schema.ts +41 -41
- package/src/validations/procedure.schema.ts +124 -124
- package/src/validations/profile-info.schema.ts +41 -41
- package/src/validations/reviews.schema.ts +195 -195
- package/src/validations/schemas.ts +104 -104
- package/src/validations/shared.schema.ts +78 -78
|
@@ -1,285 +1,285 @@
|
|
|
1
|
-
import {
|
|
2
|
-
collection,
|
|
3
|
-
getDocs,
|
|
4
|
-
query,
|
|
5
|
-
where,
|
|
6
|
-
doc,
|
|
7
|
-
updateDoc,
|
|
8
|
-
Timestamp,
|
|
9
|
-
DocumentReference,
|
|
10
|
-
serverTimestamp,
|
|
11
|
-
orderBy,
|
|
12
|
-
limit,
|
|
13
|
-
startAfter,
|
|
14
|
-
getDoc,
|
|
15
|
-
FieldPath,
|
|
16
|
-
WhereFilterOp,
|
|
17
|
-
Firestore,
|
|
18
|
-
DocumentSnapshot,
|
|
19
|
-
} from "firebase/firestore";
|
|
20
|
-
import { FirebaseApp } from "firebase/app";
|
|
21
|
-
import { Auth } from "firebase/auth";
|
|
22
|
-
import { BaseService } from "../base.service";
|
|
23
|
-
import {
|
|
24
|
-
PatientRequirementInstance,
|
|
25
|
-
PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME,
|
|
26
|
-
PatientInstructionStatus,
|
|
27
|
-
PatientRequirementOverallStatus,
|
|
28
|
-
PatientRequirementInstruction,
|
|
29
|
-
} from "../../types/patient/patient-requirements";
|
|
30
|
-
import { UserRole } from "../../types"; // Assuming UserRole is in the root types
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Interface for filtering active patient requirements.
|
|
34
|
-
*/
|
|
35
|
-
export interface PatientRequirementsFilters {
|
|
36
|
-
appointmentId?: string | "all"; // Specific appointment, or 'all' for any appointment
|
|
37
|
-
statuses?: PatientRequirementOverallStatus[];
|
|
38
|
-
instructionStatuses?: PatientInstructionStatus[]; // Filter by status of individual instructions
|
|
39
|
-
dueBefore?: Timestamp; // Filter for instructions due before this time
|
|
40
|
-
dueAfter?: Timestamp; // Filter for instructions due after this time
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export class PatientRequirementsService extends BaseService {
|
|
44
|
-
constructor(db: Firestore, auth: Auth, app: FirebaseApp) {
|
|
45
|
-
super(db, auth, app);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
private getPatientRequirementsCollectionRef(patientId: string) {
|
|
49
|
-
return collection(
|
|
50
|
-
this.db,
|
|
51
|
-
`patients/${patientId}/${PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME}`
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
private getPatientRequirementDocRef(
|
|
56
|
-
patientId: string,
|
|
57
|
-
instanceId: string
|
|
58
|
-
): DocumentReference<PatientRequirementInstance> {
|
|
59
|
-
return doc(
|
|
60
|
-
this.getPatientRequirementsCollectionRef(patientId),
|
|
61
|
-
instanceId
|
|
62
|
-
) as DocumentReference<PatientRequirementInstance>;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Gets a specific patient requirement instance by its ID.
|
|
67
|
-
* @param patientId - The ID of the patient.
|
|
68
|
-
* @param instanceId - The ID of the requirement instance.
|
|
69
|
-
* @returns The patient requirement instance or null if not found.
|
|
70
|
-
*/
|
|
71
|
-
async getPatientRequirementInstance(
|
|
72
|
-
patientId: string,
|
|
73
|
-
instanceId: string
|
|
74
|
-
): Promise<PatientRequirementInstance | null> {
|
|
75
|
-
const docRef = this.getPatientRequirementDocRef(patientId, instanceId);
|
|
76
|
-
const docSnap = await getDoc(docRef);
|
|
77
|
-
if (!docSnap.exists()) {
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
// Explicitly type data to exclude 'id' before spreading
|
|
81
|
-
const data = docSnap.data() as Omit<PatientRequirementInstance, "id">;
|
|
82
|
-
return { id: docSnap.id, ...data } as PatientRequirementInstance;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Retrieves patient requirement instances based on specified filters.
|
|
87
|
-
* This is a flexible query method.
|
|
88
|
-
*
|
|
89
|
-
* @param patientId - The ID of the patient.
|
|
90
|
-
* @param filters - Optional filters for appointmentId, overall statuses, instruction statuses, and due timeframes.
|
|
91
|
-
* @param pageLimit - Optional limit for pagination.
|
|
92
|
-
* @param lastVisible - Optional last document snapshot for pagination.
|
|
93
|
-
* @returns A promise resolving to an array of matching patient requirement instances and the last document snapshot.
|
|
94
|
-
*/
|
|
95
|
-
async getAllPatientRequirementInstances(
|
|
96
|
-
patientId: string,
|
|
97
|
-
filters?: PatientRequirementsFilters,
|
|
98
|
-
pageLimit: number = 20,
|
|
99
|
-
lastVisible?: DocumentSnapshot
|
|
100
|
-
): Promise<{
|
|
101
|
-
requirements: PatientRequirementInstance[];
|
|
102
|
-
lastDoc: DocumentSnapshot | null;
|
|
103
|
-
}> {
|
|
104
|
-
const collRef = this.getPatientRequirementsCollectionRef(patientId);
|
|
105
|
-
let q = query(collRef, orderBy("createdAt", "desc")); // Default sort
|
|
106
|
-
|
|
107
|
-
const queryConstraints = [];
|
|
108
|
-
|
|
109
|
-
if (filters?.appointmentId && filters.appointmentId !== "all") {
|
|
110
|
-
queryConstraints.push(
|
|
111
|
-
where("appointmentId", "==", filters.appointmentId)
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (filters?.statuses && filters.statuses.length > 0) {
|
|
116
|
-
queryConstraints.push(where("overallStatus", "in", filters.statuses));
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Filtering by instruction statuses or due times requires iterating post-fetch
|
|
120
|
-
// or more complex data modeling if direct querying is essential at scale.
|
|
121
|
-
// For a "light" service, post-fetch filtering for these is acceptable for now.
|
|
122
|
-
|
|
123
|
-
if (lastVisible) {
|
|
124
|
-
queryConstraints.push(startAfter(lastVisible));
|
|
125
|
-
}
|
|
126
|
-
queryConstraints.push(limit(pageLimit));
|
|
127
|
-
|
|
128
|
-
q = query(collRef, ...queryConstraints);
|
|
129
|
-
|
|
130
|
-
const snapshot = await getDocs(q);
|
|
131
|
-
let requirements = snapshot.docs.map((docSnap: DocumentSnapshot) => {
|
|
132
|
-
// Explicitly cast data after ensuring it's not undefined (though .data() on QueryDocumentSnapshot is not undefined)
|
|
133
|
-
const data = docSnap.data() as Omit<PatientRequirementInstance, "id">;
|
|
134
|
-
return { id: docSnap.id, ...data } as PatientRequirementInstance;
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
// Post-fetch filtering for instruction statuses and due times
|
|
138
|
-
if (
|
|
139
|
-
filters?.instructionStatuses &&
|
|
140
|
-
filters.instructionStatuses.length > 0
|
|
141
|
-
) {
|
|
142
|
-
requirements = requirements.filter((req) =>
|
|
143
|
-
req.instructions.some((instr) =>
|
|
144
|
-
filters.instructionStatuses!.includes(instr.status)
|
|
145
|
-
)
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (filters?.dueBefore) {
|
|
150
|
-
const dueBeforeMillis = filters.dueBefore.toMillis();
|
|
151
|
-
requirements = requirements.filter((req) =>
|
|
152
|
-
req.instructions.some(
|
|
153
|
-
(instr) => instr.dueTime.toMillis() < dueBeforeMillis
|
|
154
|
-
)
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (filters?.dueAfter) {
|
|
159
|
-
const dueAfterMillis = filters.dueAfter.toMillis();
|
|
160
|
-
requirements = requirements.filter((req) =>
|
|
161
|
-
req.instructions.some(
|
|
162
|
-
(instr) => instr.dueTime.toMillis() > dueAfterMillis
|
|
163
|
-
)
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const newLastVisible = snapshot.docs[snapshot.docs.length - 1] || null;
|
|
168
|
-
|
|
169
|
-
return { requirements, lastDoc: newLastVisible };
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Marks a specific instruction within a PatientRequirementInstance as ACTION_TAKEN.
|
|
174
|
-
* If all instructions are actioned, updates the overallStatus of the instance.
|
|
175
|
-
*
|
|
176
|
-
* @param patientId - The ID of the patient.
|
|
177
|
-
* @param instanceId - The ID of the PatientRequirementInstance.
|
|
178
|
-
* @param instructionId - The ID of the instruction to complete.
|
|
179
|
-
* @returns The updated PatientRequirementInstance.
|
|
180
|
-
* @throws Error if the instance or instruction is not found, or if the instruction is not in a completable state.
|
|
181
|
-
*/
|
|
182
|
-
async completeInstruction(
|
|
183
|
-
patientId: string,
|
|
184
|
-
instanceId: string,
|
|
185
|
-
instructionId: string
|
|
186
|
-
): Promise<PatientRequirementInstance> {
|
|
187
|
-
const instanceRef = this.getPatientRequirementDocRef(patientId, instanceId);
|
|
188
|
-
const instanceSnap = await getDoc(instanceRef); // Simplified: getDoc without explicit generic here
|
|
189
|
-
|
|
190
|
-
if (!instanceSnap.exists()) {
|
|
191
|
-
throw new Error(
|
|
192
|
-
`PatientRequirementInstance ${instanceId} not found for patient ${patientId}.`
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Explicitly cast data after exists check
|
|
197
|
-
const instanceData = instanceSnap.data() as Omit<
|
|
198
|
-
PatientRequirementInstance,
|
|
199
|
-
"id"
|
|
200
|
-
>;
|
|
201
|
-
const instance = { id: instanceSnap.id, ...instanceData };
|
|
202
|
-
|
|
203
|
-
const instructionIndex = instance.instructions.findIndex(
|
|
204
|
-
(instr) => instr.instructionId === instructionId
|
|
205
|
-
);
|
|
206
|
-
|
|
207
|
-
if (instructionIndex === -1) {
|
|
208
|
-
throw new Error(
|
|
209
|
-
`Instruction ${instructionId} not found in instance ${instanceId}.`
|
|
210
|
-
);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const instructionToUpdate = instance.instructions[instructionIndex];
|
|
214
|
-
|
|
215
|
-
// Allow completion if it's PENDING_NOTIFICATION, ACTION_DUE, or even MISSED (if policy allows late completion)
|
|
216
|
-
if (
|
|
217
|
-
instructionToUpdate.status !==
|
|
218
|
-
PatientInstructionStatus.PENDING_NOTIFICATION &&
|
|
219
|
-
instructionToUpdate.status !== PatientInstructionStatus.ACTION_DUE &&
|
|
220
|
-
instructionToUpdate.status !== PatientInstructionStatus.MISSED
|
|
221
|
-
) {
|
|
222
|
-
// If already ACTION_TAKEN or CANCELLED, do nothing or throw specific error
|
|
223
|
-
if (
|
|
224
|
-
instructionToUpdate.status === PatientInstructionStatus.ACTION_TAKEN
|
|
225
|
-
) {
|
|
226
|
-
console.warn(
|
|
227
|
-
`Instruction ${instructionId} is already marked as ACTION_TAKEN.`
|
|
228
|
-
);
|
|
229
|
-
return instance as PatientRequirementInstance; // Ensure return type matches
|
|
230
|
-
}
|
|
231
|
-
throw new Error(
|
|
232
|
-
`Instruction ${instructionId} is in status ${instructionToUpdate.status} and cannot be marked as completed.`
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
const now = Timestamp.now();
|
|
237
|
-
const updatedInstructions = [...instance.instructions];
|
|
238
|
-
updatedInstructions[instructionIndex] = {
|
|
239
|
-
...instructionToUpdate,
|
|
240
|
-
status: PatientInstructionStatus.ACTION_TAKEN,
|
|
241
|
-
actionTakenAt: now,
|
|
242
|
-
updatedAt: now,
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
// Check if all instructions are now ACTION_TAKEN
|
|
246
|
-
const allActionTaken = updatedInstructions.every(
|
|
247
|
-
(instr) => instr.status === PatientInstructionStatus.ACTION_TAKEN
|
|
248
|
-
);
|
|
249
|
-
|
|
250
|
-
let newOverallStatus = instance.overallStatus;
|
|
251
|
-
if (allActionTaken) {
|
|
252
|
-
newOverallStatus = PatientRequirementOverallStatus.ALL_INSTRUCTIONS_MET;
|
|
253
|
-
} else if (
|
|
254
|
-
updatedInstructions.some(
|
|
255
|
-
(instr) => instr.status === PatientInstructionStatus.ACTION_TAKEN
|
|
256
|
-
)
|
|
257
|
-
) {
|
|
258
|
-
// If some are taken, but not all, and it was previously just ACTIVE
|
|
259
|
-
newOverallStatus = PatientRequirementOverallStatus.PARTIALLY_COMPLETED;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
const updatePayload: { [key: string]: any } = {
|
|
263
|
-
// Using a general type for updateDoc payload
|
|
264
|
-
instructions: updatedInstructions,
|
|
265
|
-
updatedAt: now,
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
if (newOverallStatus !== instance.overallStatus) {
|
|
269
|
-
updatePayload.overallStatus = newOverallStatus;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
await updateDoc(instanceRef, updatePayload);
|
|
273
|
-
|
|
274
|
-
// Construct the returned object accurately
|
|
275
|
-
return {
|
|
276
|
-
...instance,
|
|
277
|
-
instructions: updatedInstructions,
|
|
278
|
-
updatedAt: now,
|
|
279
|
-
overallStatus: newOverallStatus,
|
|
280
|
-
} as PatientRequirementInstance;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Note: As per the request, full CRUD (create, direct update of instance, delete) is not part of this light service,
|
|
284
|
-
// as those will be handled by Cloud Functions reacting to appointment lifecycle events.
|
|
285
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
collection,
|
|
3
|
+
getDocs,
|
|
4
|
+
query,
|
|
5
|
+
where,
|
|
6
|
+
doc,
|
|
7
|
+
updateDoc,
|
|
8
|
+
Timestamp,
|
|
9
|
+
DocumentReference,
|
|
10
|
+
serverTimestamp,
|
|
11
|
+
orderBy,
|
|
12
|
+
limit,
|
|
13
|
+
startAfter,
|
|
14
|
+
getDoc,
|
|
15
|
+
FieldPath,
|
|
16
|
+
WhereFilterOp,
|
|
17
|
+
Firestore,
|
|
18
|
+
DocumentSnapshot,
|
|
19
|
+
} from "firebase/firestore";
|
|
20
|
+
import { FirebaseApp } from "firebase/app";
|
|
21
|
+
import { Auth } from "firebase/auth";
|
|
22
|
+
import { BaseService } from "../base.service";
|
|
23
|
+
import {
|
|
24
|
+
PatientRequirementInstance,
|
|
25
|
+
PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME,
|
|
26
|
+
PatientInstructionStatus,
|
|
27
|
+
PatientRequirementOverallStatus,
|
|
28
|
+
PatientRequirementInstruction,
|
|
29
|
+
} from "../../types/patient/patient-requirements";
|
|
30
|
+
import { UserRole } from "../../types"; // Assuming UserRole is in the root types
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Interface for filtering active patient requirements.
|
|
34
|
+
*/
|
|
35
|
+
export interface PatientRequirementsFilters {
|
|
36
|
+
appointmentId?: string | "all"; // Specific appointment, or 'all' for any appointment
|
|
37
|
+
statuses?: PatientRequirementOverallStatus[];
|
|
38
|
+
instructionStatuses?: PatientInstructionStatus[]; // Filter by status of individual instructions
|
|
39
|
+
dueBefore?: Timestamp; // Filter for instructions due before this time
|
|
40
|
+
dueAfter?: Timestamp; // Filter for instructions due after this time
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class PatientRequirementsService extends BaseService {
|
|
44
|
+
constructor(db: Firestore, auth: Auth, app: FirebaseApp) {
|
|
45
|
+
super(db, auth, app);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private getPatientRequirementsCollectionRef(patientId: string) {
|
|
49
|
+
return collection(
|
|
50
|
+
this.db,
|
|
51
|
+
`patients/${patientId}/${PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME}`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private getPatientRequirementDocRef(
|
|
56
|
+
patientId: string,
|
|
57
|
+
instanceId: string
|
|
58
|
+
): DocumentReference<PatientRequirementInstance> {
|
|
59
|
+
return doc(
|
|
60
|
+
this.getPatientRequirementsCollectionRef(patientId),
|
|
61
|
+
instanceId
|
|
62
|
+
) as DocumentReference<PatientRequirementInstance>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Gets a specific patient requirement instance by its ID.
|
|
67
|
+
* @param patientId - The ID of the patient.
|
|
68
|
+
* @param instanceId - The ID of the requirement instance.
|
|
69
|
+
* @returns The patient requirement instance or null if not found.
|
|
70
|
+
*/
|
|
71
|
+
async getPatientRequirementInstance(
|
|
72
|
+
patientId: string,
|
|
73
|
+
instanceId: string
|
|
74
|
+
): Promise<PatientRequirementInstance | null> {
|
|
75
|
+
const docRef = this.getPatientRequirementDocRef(patientId, instanceId);
|
|
76
|
+
const docSnap = await getDoc(docRef);
|
|
77
|
+
if (!docSnap.exists()) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
// Explicitly type data to exclude 'id' before spreading
|
|
81
|
+
const data = docSnap.data() as Omit<PatientRequirementInstance, "id">;
|
|
82
|
+
return { id: docSnap.id, ...data } as PatientRequirementInstance;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Retrieves patient requirement instances based on specified filters.
|
|
87
|
+
* This is a flexible query method.
|
|
88
|
+
*
|
|
89
|
+
* @param patientId - The ID of the patient.
|
|
90
|
+
* @param filters - Optional filters for appointmentId, overall statuses, instruction statuses, and due timeframes.
|
|
91
|
+
* @param pageLimit - Optional limit for pagination.
|
|
92
|
+
* @param lastVisible - Optional last document snapshot for pagination.
|
|
93
|
+
* @returns A promise resolving to an array of matching patient requirement instances and the last document snapshot.
|
|
94
|
+
*/
|
|
95
|
+
async getAllPatientRequirementInstances(
|
|
96
|
+
patientId: string,
|
|
97
|
+
filters?: PatientRequirementsFilters,
|
|
98
|
+
pageLimit: number = 20,
|
|
99
|
+
lastVisible?: DocumentSnapshot
|
|
100
|
+
): Promise<{
|
|
101
|
+
requirements: PatientRequirementInstance[];
|
|
102
|
+
lastDoc: DocumentSnapshot | null;
|
|
103
|
+
}> {
|
|
104
|
+
const collRef = this.getPatientRequirementsCollectionRef(patientId);
|
|
105
|
+
let q = query(collRef, orderBy("createdAt", "desc")); // Default sort
|
|
106
|
+
|
|
107
|
+
const queryConstraints = [];
|
|
108
|
+
|
|
109
|
+
if (filters?.appointmentId && filters.appointmentId !== "all") {
|
|
110
|
+
queryConstraints.push(
|
|
111
|
+
where("appointmentId", "==", filters.appointmentId)
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (filters?.statuses && filters.statuses.length > 0) {
|
|
116
|
+
queryConstraints.push(where("overallStatus", "in", filters.statuses));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Filtering by instruction statuses or due times requires iterating post-fetch
|
|
120
|
+
// or more complex data modeling if direct querying is essential at scale.
|
|
121
|
+
// For a "light" service, post-fetch filtering for these is acceptable for now.
|
|
122
|
+
|
|
123
|
+
if (lastVisible) {
|
|
124
|
+
queryConstraints.push(startAfter(lastVisible));
|
|
125
|
+
}
|
|
126
|
+
queryConstraints.push(limit(pageLimit));
|
|
127
|
+
|
|
128
|
+
q = query(collRef, ...queryConstraints);
|
|
129
|
+
|
|
130
|
+
const snapshot = await getDocs(q);
|
|
131
|
+
let requirements = snapshot.docs.map((docSnap: DocumentSnapshot) => {
|
|
132
|
+
// Explicitly cast data after ensuring it's not undefined (though .data() on QueryDocumentSnapshot is not undefined)
|
|
133
|
+
const data = docSnap.data() as Omit<PatientRequirementInstance, "id">;
|
|
134
|
+
return { id: docSnap.id, ...data } as PatientRequirementInstance;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Post-fetch filtering for instruction statuses and due times
|
|
138
|
+
if (
|
|
139
|
+
filters?.instructionStatuses &&
|
|
140
|
+
filters.instructionStatuses.length > 0
|
|
141
|
+
) {
|
|
142
|
+
requirements = requirements.filter((req) =>
|
|
143
|
+
req.instructions.some((instr) =>
|
|
144
|
+
filters.instructionStatuses!.includes(instr.status)
|
|
145
|
+
)
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (filters?.dueBefore) {
|
|
150
|
+
const dueBeforeMillis = filters.dueBefore.toMillis();
|
|
151
|
+
requirements = requirements.filter((req) =>
|
|
152
|
+
req.instructions.some(
|
|
153
|
+
(instr) => instr.dueTime.toMillis() < dueBeforeMillis
|
|
154
|
+
)
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (filters?.dueAfter) {
|
|
159
|
+
const dueAfterMillis = filters.dueAfter.toMillis();
|
|
160
|
+
requirements = requirements.filter((req) =>
|
|
161
|
+
req.instructions.some(
|
|
162
|
+
(instr) => instr.dueTime.toMillis() > dueAfterMillis
|
|
163
|
+
)
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1] || null;
|
|
168
|
+
|
|
169
|
+
return { requirements, lastDoc: newLastVisible };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Marks a specific instruction within a PatientRequirementInstance as ACTION_TAKEN.
|
|
174
|
+
* If all instructions are actioned, updates the overallStatus of the instance.
|
|
175
|
+
*
|
|
176
|
+
* @param patientId - The ID of the patient.
|
|
177
|
+
* @param instanceId - The ID of the PatientRequirementInstance.
|
|
178
|
+
* @param instructionId - The ID of the instruction to complete.
|
|
179
|
+
* @returns The updated PatientRequirementInstance.
|
|
180
|
+
* @throws Error if the instance or instruction is not found, or if the instruction is not in a completable state.
|
|
181
|
+
*/
|
|
182
|
+
async completeInstruction(
|
|
183
|
+
patientId: string,
|
|
184
|
+
instanceId: string,
|
|
185
|
+
instructionId: string
|
|
186
|
+
): Promise<PatientRequirementInstance> {
|
|
187
|
+
const instanceRef = this.getPatientRequirementDocRef(patientId, instanceId);
|
|
188
|
+
const instanceSnap = await getDoc(instanceRef); // Simplified: getDoc without explicit generic here
|
|
189
|
+
|
|
190
|
+
if (!instanceSnap.exists()) {
|
|
191
|
+
throw new Error(
|
|
192
|
+
`PatientRequirementInstance ${instanceId} not found for patient ${patientId}.`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Explicitly cast data after exists check
|
|
197
|
+
const instanceData = instanceSnap.data() as Omit<
|
|
198
|
+
PatientRequirementInstance,
|
|
199
|
+
"id"
|
|
200
|
+
>;
|
|
201
|
+
const instance = { id: instanceSnap.id, ...instanceData };
|
|
202
|
+
|
|
203
|
+
const instructionIndex = instance.instructions.findIndex(
|
|
204
|
+
(instr) => instr.instructionId === instructionId
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
if (instructionIndex === -1) {
|
|
208
|
+
throw new Error(
|
|
209
|
+
`Instruction ${instructionId} not found in instance ${instanceId}.`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const instructionToUpdate = instance.instructions[instructionIndex];
|
|
214
|
+
|
|
215
|
+
// Allow completion if it's PENDING_NOTIFICATION, ACTION_DUE, or even MISSED (if policy allows late completion)
|
|
216
|
+
if (
|
|
217
|
+
instructionToUpdate.status !==
|
|
218
|
+
PatientInstructionStatus.PENDING_NOTIFICATION &&
|
|
219
|
+
instructionToUpdate.status !== PatientInstructionStatus.ACTION_DUE &&
|
|
220
|
+
instructionToUpdate.status !== PatientInstructionStatus.MISSED
|
|
221
|
+
) {
|
|
222
|
+
// If already ACTION_TAKEN or CANCELLED, do nothing or throw specific error
|
|
223
|
+
if (
|
|
224
|
+
instructionToUpdate.status === PatientInstructionStatus.ACTION_TAKEN
|
|
225
|
+
) {
|
|
226
|
+
console.warn(
|
|
227
|
+
`Instruction ${instructionId} is already marked as ACTION_TAKEN.`
|
|
228
|
+
);
|
|
229
|
+
return instance as PatientRequirementInstance; // Ensure return type matches
|
|
230
|
+
}
|
|
231
|
+
throw new Error(
|
|
232
|
+
`Instruction ${instructionId} is in status ${instructionToUpdate.status} and cannot be marked as completed.`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const now = Timestamp.now();
|
|
237
|
+
const updatedInstructions = [...instance.instructions];
|
|
238
|
+
updatedInstructions[instructionIndex] = {
|
|
239
|
+
...instructionToUpdate,
|
|
240
|
+
status: PatientInstructionStatus.ACTION_TAKEN,
|
|
241
|
+
actionTakenAt: now,
|
|
242
|
+
updatedAt: now,
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// Check if all instructions are now ACTION_TAKEN
|
|
246
|
+
const allActionTaken = updatedInstructions.every(
|
|
247
|
+
(instr) => instr.status === PatientInstructionStatus.ACTION_TAKEN
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
let newOverallStatus = instance.overallStatus;
|
|
251
|
+
if (allActionTaken) {
|
|
252
|
+
newOverallStatus = PatientRequirementOverallStatus.ALL_INSTRUCTIONS_MET;
|
|
253
|
+
} else if (
|
|
254
|
+
updatedInstructions.some(
|
|
255
|
+
(instr) => instr.status === PatientInstructionStatus.ACTION_TAKEN
|
|
256
|
+
)
|
|
257
|
+
) {
|
|
258
|
+
// If some are taken, but not all, and it was previously just ACTIVE
|
|
259
|
+
newOverallStatus = PatientRequirementOverallStatus.PARTIALLY_COMPLETED;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const updatePayload: { [key: string]: any } = {
|
|
263
|
+
// Using a general type for updateDoc payload
|
|
264
|
+
instructions: updatedInstructions,
|
|
265
|
+
updatedAt: now,
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
if (newOverallStatus !== instance.overallStatus) {
|
|
269
|
+
updatePayload.overallStatus = newOverallStatus;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
await updateDoc(instanceRef, updatePayload);
|
|
273
|
+
|
|
274
|
+
// Construct the returned object accurately
|
|
275
|
+
return {
|
|
276
|
+
...instance,
|
|
277
|
+
instructions: updatedInstructions,
|
|
278
|
+
updatedAt: now,
|
|
279
|
+
overallStatus: newOverallStatus,
|
|
280
|
+
} as PatientRequirementInstance;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Note: As per the request, full CRUD (create, direct update of instance, delete) is not part of this light service,
|
|
284
|
+
// as those will be handled by Cloud Functions reacting to appointment lifecycle events.
|
|
285
|
+
}
|