@blackcode_sa/metaestetics-api 1.5.25 → 1.5.28

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.
@@ -768,3 +768,233 @@ export async function getActiveClinicsByAdmin(
768
768
  clinicGroupService
769
769
  );
770
770
  }
771
+
772
+ /**
773
+ * Retrieves a clinic by its ID
774
+ *
775
+ * @param db - Firestore database instance
776
+ * @param clinicId - ID of the clinic to retrieve
777
+ * @returns The clinic if found, null otherwise
778
+ */
779
+ export async function getClinicById(
780
+ db: Firestore,
781
+ clinicId: string
782
+ ): Promise<Clinic | null> {
783
+ try {
784
+ const clinicRef = doc(db, CLINICS_COLLECTION, clinicId);
785
+ const clinicSnapshot = await getDoc(clinicRef);
786
+
787
+ if (!clinicSnapshot.exists()) {
788
+ return null;
789
+ }
790
+
791
+ const clinicData = clinicSnapshot.data() as Clinic;
792
+ return {
793
+ ...clinicData,
794
+ id: clinicSnapshot.id,
795
+ };
796
+ } catch (error) {
797
+ console.error("[CLINIC_UTILS] Error getting clinic by ID:", error);
798
+ throw error;
799
+ }
800
+ }
801
+
802
+ /**
803
+ * Retrieves all clinics with optional pagination
804
+ *
805
+ * @param db - Firestore database instance
806
+ * @param pagination - Optional number of clinics per page (0 or undefined returns all)
807
+ * @param lastDoc - Optional last document for pagination (if continuing from a previous page)
808
+ * @returns Array of clinics and the last document for pagination
809
+ */
810
+ export async function getAllClinics(
811
+ db: Firestore,
812
+ pagination?: number,
813
+ lastDoc?: any
814
+ ): Promise<{ clinics: Clinic[]; lastDoc: any }> {
815
+ try {
816
+ const clinicsCollection = collection(db, CLINICS_COLLECTION);
817
+ let clinicsQuery = query(clinicsCollection);
818
+
819
+ // If pagination is specified and greater than 0, limit the query
820
+ if (pagination && pagination > 0) {
821
+ const { limit, startAfter } = require("firebase/firestore");
822
+
823
+ if (lastDoc) {
824
+ clinicsQuery = query(
825
+ clinicsCollection,
826
+ startAfter(lastDoc),
827
+ limit(pagination)
828
+ );
829
+ } else {
830
+ clinicsQuery = query(clinicsCollection, limit(pagination));
831
+ }
832
+ }
833
+
834
+ const clinicsSnapshot = await getDocs(clinicsQuery);
835
+ const lastVisible = clinicsSnapshot.docs[clinicsSnapshot.docs.length - 1];
836
+
837
+ const clinics = clinicsSnapshot.docs.map((doc) => {
838
+ const data = doc.data() as Clinic;
839
+ return {
840
+ ...data,
841
+ id: doc.id,
842
+ };
843
+ });
844
+
845
+ return {
846
+ clinics,
847
+ lastDoc: lastVisible,
848
+ };
849
+ } catch (error) {
850
+ console.error("[CLINIC_UTILS] Error getting all clinics:", error);
851
+ throw error;
852
+ }
853
+ }
854
+
855
+ /**
856
+ * Retrieves all clinics within a specified range from a location with optional pagination
857
+ *
858
+ * @param db - Firestore database instance
859
+ * @param center - The center location coordinates {latitude, longitude}
860
+ * @param rangeInKm - The range in kilometers to search within
861
+ * @param pagination - Optional number of clinics per page (0 or undefined returns all)
862
+ * @param lastDoc - Optional last document for pagination (if continuing from a previous page)
863
+ * @param filters - Optional filters to apply to the search (isActive, tags, etc.)
864
+ * @returns Array of clinics within range and the last document for pagination
865
+ */
866
+ export async function getAllClinicsInRange(
867
+ db: Firestore,
868
+ center: { latitude: number; longitude: number },
869
+ rangeInKm: number,
870
+ pagination?: number,
871
+ lastDoc?: any,
872
+ filters?: {
873
+ isActive?: boolean;
874
+ tags?: ClinicTag[];
875
+ }
876
+ ): Promise<{ clinics: (Clinic & { distance: number })[]; lastDoc: any }> {
877
+ try {
878
+ const { distanceBetween } = require("geofire-common");
879
+ const centerLat = center.latitude;
880
+ const centerLng = center.longitude;
881
+
882
+ // We'll need to get all clinics and filter them by distance
883
+ const clinicsCollection = collection(db, CLINICS_COLLECTION);
884
+ let clinicsQuery = query(clinicsCollection);
885
+
886
+ // Add active filter if specified
887
+ if (filters?.isActive !== undefined) {
888
+ clinicsQuery = query(
889
+ clinicsCollection,
890
+ where("isActive", "==", filters.isActive)
891
+ );
892
+ }
893
+
894
+ const querySnapshot = await getDocs(clinicsQuery);
895
+ console.log(
896
+ `[CLINIC_UTILS] Found ${querySnapshot.docs.length} total clinics to filter by distance`
897
+ );
898
+
899
+ // Filter the results by distance
900
+ const filteredDocs = [];
901
+ for (const doc of querySnapshot.docs) {
902
+ const clinic = doc.data() as Clinic;
903
+
904
+ // Skip clinics without proper location data
905
+ if (
906
+ !clinic.location ||
907
+ !clinic.location.latitude ||
908
+ !clinic.location.longitude
909
+ ) {
910
+ continue;
911
+ }
912
+
913
+ // Calculate distance
914
+ const distanceInM = distanceBetween(
915
+ [centerLat, centerLng],
916
+ [clinic.location.latitude, clinic.location.longitude]
917
+ );
918
+
919
+ // Convert to km and check if within range
920
+ const distanceInKm = distanceInM / 1000;
921
+ if (distanceInKm <= rangeInKm) {
922
+ // If tags filter exists, apply it
923
+ if (filters?.tags && filters.tags.length > 0) {
924
+ const hasAllTags = filters.tags.every((filterTag) =>
925
+ clinic.tags.some(
926
+ (clinicTag) =>
927
+ (filterTag as any).id === (clinicTag as any).id ||
928
+ (filterTag as any).name === (clinicTag as any).name
929
+ )
930
+ );
931
+
932
+ if (hasAllTags) {
933
+ // Add distance to clinic object for reference
934
+ filteredDocs.push({
935
+ doc,
936
+ distance: distanceInKm,
937
+ });
938
+ }
939
+ } else {
940
+ // Add distance to clinic object for reference
941
+ filteredDocs.push({
942
+ doc,
943
+ distance: distanceInKm,
944
+ });
945
+ }
946
+ }
947
+ }
948
+
949
+ console.log(
950
+ `[CLINIC_UTILS] Filtered to ${filteredDocs.length} clinics within ${rangeInKm}km`
951
+ );
952
+
953
+ // Sort results by distance
954
+ filteredDocs.sort((a, b) => a.distance - b.distance);
955
+
956
+ // Apply pagination if needed
957
+ let paginatedDocs = filteredDocs;
958
+ let lastVisible = null;
959
+
960
+ if (pagination && pagination > 0) {
961
+ // If we have a lastDoc, find its index in our sorted results
962
+ let startIndex = 0;
963
+ if (lastDoc) {
964
+ const lastDocIndex = filteredDocs.findIndex(
965
+ (item) => item.doc.id === lastDoc.id
966
+ );
967
+ if (lastDocIndex !== -1) {
968
+ startIndex = lastDocIndex + 1;
969
+ }
970
+ }
971
+
972
+ // Get the paginated subset
973
+ paginatedDocs = filteredDocs.slice(startIndex, startIndex + pagination);
974
+
975
+ // Set the last document for the next pagination
976
+ lastVisible =
977
+ paginatedDocs.length > 0
978
+ ? paginatedDocs[paginatedDocs.length - 1].doc
979
+ : null;
980
+ }
981
+
982
+ // Map to Clinic objects with distance information
983
+ const clinics = paginatedDocs.map((item) => {
984
+ const data = item.doc.data() as Clinic;
985
+ return {
986
+ ...data,
987
+ id: item.doc.id,
988
+ distance: item.distance, // Include distance in response
989
+ } as Clinic & { distance: number };
990
+ });
991
+
992
+ return {
993
+ clinics,
994
+ lastDoc: lastVisible,
995
+ };
996
+ } catch (error) {
997
+ console.error("[CLINIC_UTILS] Error getting clinics in range:", error);
998
+ throw error;
999
+ }
1000
+ }
@@ -11,6 +11,7 @@ import {
11
11
  Timestamp,
12
12
  serverTimestamp,
13
13
  DocumentData,
14
+ writeBatch,
14
15
  } from "firebase/firestore";
15
16
  import { BaseService } from "../base.service";
16
17
  import {
@@ -47,12 +48,16 @@ import { CategoryService } from "../../backoffice/services/category.service";
47
48
  import { SubcategoryService } from "../../backoffice/services/subcategory.service";
48
49
  import { TechnologyService } from "../../backoffice/services/technology.service";
49
50
  import { ProductService } from "../../backoffice/services/product.service";
50
- import { Practitioner } from "../../types/practitioner";
51
+ import {
52
+ Practitioner,
53
+ PRACTITIONERS_COLLECTION,
54
+ } from "../../types/practitioner";
51
55
  import {
52
56
  CertificationLevel,
53
57
  CertificationSpecialty,
54
58
  ProcedureFamily,
55
59
  } from "../../backoffice/types";
60
+ import { CLINICS_COLLECTION } from "../../types/clinic";
56
61
 
57
62
  export class ProcedureService extends BaseService {
58
63
  private categoryService: CategoryService;
@@ -103,6 +108,68 @@ export class ProcedureService extends BaseService {
103
108
  throw new Error("One or more required entities not found");
104
109
  }
105
110
 
111
+ // Get clinic and practitioner information
112
+ const clinicRef = doc(
113
+ this.db,
114
+ CLINICS_COLLECTION,
115
+ validatedData.clinicBranchId
116
+ );
117
+ const clinicSnapshot = await getDoc(clinicRef);
118
+
119
+ if (!clinicSnapshot.exists()) {
120
+ throw new Error(
121
+ `Clinic with ID ${validatedData.clinicBranchId} not found`
122
+ );
123
+ }
124
+
125
+ const clinic = clinicSnapshot.data();
126
+
127
+ // Create clinic info
128
+ const clinicInfo = {
129
+ id: clinicSnapshot.id,
130
+ name: clinic.name,
131
+ description: clinic.description || "",
132
+ featuredPhoto:
133
+ clinic.featuredPhotos && clinic.featuredPhotos.length > 0
134
+ ? clinic.featuredPhotos[0]
135
+ : clinic.coverPhoto || "",
136
+ location: clinic.location,
137
+ contactInfo: clinic.contactInfo,
138
+ };
139
+
140
+ // Get practitioner information
141
+ const practitionerRef = doc(
142
+ this.db,
143
+ PRACTITIONERS_COLLECTION,
144
+ validatedData.practitionerId
145
+ );
146
+ const practitionerSnapshot = await getDoc(practitionerRef);
147
+
148
+ if (!practitionerSnapshot.exists()) {
149
+ throw new Error(
150
+ `Practitioner with ID ${validatedData.practitionerId} not found`
151
+ );
152
+ }
153
+
154
+ const practitioner = practitionerSnapshot.data();
155
+
156
+ // Find doctor info in clinic's doctorsInfo array
157
+ let doctorInfo = clinic.doctorsInfo?.find(
158
+ (doctor: any) => doctor.id === validatedData.practitionerId
159
+ );
160
+
161
+ // If not found, create basic doctor info
162
+ if (!doctorInfo) {
163
+ doctorInfo = {
164
+ id: practitionerSnapshot.id,
165
+ name: `${practitioner.basicInfo.firstName} ${practitioner.basicInfo.lastName}`,
166
+ description: practitioner.basicInfo.bio || "",
167
+ photo: practitioner.basicInfo.profileImageUrl || "",
168
+ rating: 0,
169
+ services: [],
170
+ };
171
+ }
172
+
106
173
  // Create the procedure object
107
174
  const procedure: Omit<Procedure, "id"> = {
108
175
  ...validatedData,
@@ -116,6 +183,8 @@ export class ProcedureService extends BaseService {
116
183
  postRequirements: technology.requirements.post,
117
184
  certificationRequirement: technology.certificationRequirement,
118
185
  documentationTemplates: technology.documentationTemplates || [],
186
+ clinicInfo,
187
+ doctorInfo,
119
188
  isActive: true,
120
189
  createdAt: new Date(),
121
190
  updatedAt: new Date(),
@@ -210,6 +279,9 @@ export class ProcedureService extends BaseService {
210
279
  updatedAt: serverTimestamp(),
211
280
  });
212
281
 
282
+ // Return the updated procedure with combined data
283
+ // Note: Since we're not changing the clinicInfo or doctorInfo in this update,
284
+ // we just keep the existing values from the procedure
213
285
  return {
214
286
  ...existingProcedure,
215
287
  ...validatedData,
@@ -267,4 +339,311 @@ export class ProcedureService extends BaseService {
267
339
  subcategories,
268
340
  };
269
341
  }
342
+
343
+ /**
344
+ * Gets all procedures with optional pagination
345
+ *
346
+ * @param pagination - Optional number of procedures per page (0 or undefined returns all)
347
+ * @param lastDoc - Optional last document for pagination (if continuing from a previous page)
348
+ * @returns Object containing procedures array and the last document for pagination
349
+ */
350
+ async getAllProcedures(
351
+ pagination?: number,
352
+ lastDoc?: any
353
+ ): Promise<{ procedures: Procedure[]; lastDoc: any }> {
354
+ try {
355
+ const proceduresCollection = collection(this.db, PROCEDURES_COLLECTION);
356
+ let proceduresQuery = query(proceduresCollection);
357
+
358
+ // If pagination is specified and greater than 0, limit the query
359
+ if (pagination && pagination > 0) {
360
+ const { limit, startAfter } = require("firebase/firestore");
361
+
362
+ if (lastDoc) {
363
+ proceduresQuery = query(
364
+ proceduresCollection,
365
+ startAfter(lastDoc),
366
+ limit(pagination)
367
+ );
368
+ } else {
369
+ proceduresQuery = query(proceduresCollection, limit(pagination));
370
+ }
371
+ }
372
+
373
+ const proceduresSnapshot = await getDocs(proceduresQuery);
374
+ const lastVisible =
375
+ proceduresSnapshot.docs[proceduresSnapshot.docs.length - 1];
376
+
377
+ const procedures = proceduresSnapshot.docs.map((doc) => {
378
+ const data = doc.data() as Procedure;
379
+
380
+ // Ensure clinicInfo and doctorInfo are present
381
+ if (!data.clinicInfo || !data.doctorInfo) {
382
+ console.warn(
383
+ `Procedure ${data.id} is missing clinicInfo or doctorInfo fields. These should be updated.`
384
+ );
385
+ }
386
+
387
+ return {
388
+ ...data,
389
+ id: doc.id,
390
+ };
391
+ });
392
+
393
+ return {
394
+ procedures,
395
+ lastDoc: lastVisible,
396
+ };
397
+ } catch (error) {
398
+ console.error("[PROCEDURE_SERVICE] Error getting all procedures:", error);
399
+ throw error;
400
+ }
401
+ }
402
+
403
+ /**
404
+ * Updates the clinicInfo and doctorInfo fields in procedures when the source data changes
405
+ *
406
+ * @param entityType - The type of entity that changed ("clinic" or "doctor")
407
+ * @param entityId - The ID of the entity that changed
408
+ * @param updatedData - The updated data for the entity
409
+ * @returns Number of procedures updated
410
+ */
411
+ async updateProcedureAggregateData(
412
+ entityType: "clinic" | "doctor",
413
+ entityId: string,
414
+ updatedData: any
415
+ ): Promise<number> {
416
+ let proceduresQuery;
417
+ const updatedField = entityType === "clinic" ? "clinicInfo" : "doctorInfo";
418
+
419
+ // Find all procedures related to this entity
420
+ if (entityType === "clinic") {
421
+ proceduresQuery = query(
422
+ collection(this.db, PROCEDURES_COLLECTION),
423
+ where("clinicBranchId", "==", entityId)
424
+ );
425
+ } else {
426
+ proceduresQuery = query(
427
+ collection(this.db, PROCEDURES_COLLECTION),
428
+ where("practitionerId", "==", entityId)
429
+ );
430
+ }
431
+
432
+ const snapshot = await getDocs(proceduresQuery);
433
+
434
+ if (snapshot.empty) {
435
+ return 0;
436
+ }
437
+
438
+ // Create the updated data object
439
+ let updatedFieldData;
440
+
441
+ if (entityType === "clinic") {
442
+ // Clinic info format
443
+ updatedFieldData = {
444
+ id: entityId,
445
+ name: updatedData.name,
446
+ description: updatedData.description || "",
447
+ featuredPhoto:
448
+ updatedData.featuredPhotos && updatedData.featuredPhotos.length > 0
449
+ ? updatedData.featuredPhotos[0]
450
+ : updatedData.coverPhoto || "",
451
+ location: updatedData.location,
452
+ contactInfo: updatedData.contactInfo,
453
+ };
454
+ } else {
455
+ // Doctor info format
456
+ if (updatedData.basicInfo) {
457
+ // If it's a practitioner object
458
+ updatedFieldData = {
459
+ id: entityId,
460
+ name: `${updatedData.basicInfo.firstName} ${updatedData.basicInfo.lastName}`,
461
+ description: updatedData.basicInfo.bio || "",
462
+ photo: updatedData.basicInfo.profileImageUrl || "",
463
+ rating: 0, // This would need to be calculated or passed in
464
+ services: [], // This would need to be determined or passed in
465
+ };
466
+ } else {
467
+ // If it's already a doctorInfo object
468
+ updatedFieldData = {
469
+ id: entityId,
470
+ name: updatedData.name,
471
+ description: updatedData.description || "",
472
+ photo: updatedData.photo || "",
473
+ rating: updatedData.rating || 0,
474
+ services: updatedData.services || [],
475
+ };
476
+ }
477
+ }
478
+
479
+ // Update all found procedures
480
+ const batch = writeBatch(this.db);
481
+
482
+ snapshot.docs.forEach((doc) => {
483
+ batch.update(doc.ref, {
484
+ [updatedField]: updatedFieldData,
485
+ updatedAt: serverTimestamp(),
486
+ });
487
+ });
488
+
489
+ await batch.commit();
490
+
491
+ return snapshot.size;
492
+ }
493
+
494
+ /**
495
+ * Updates the clinicInfo for all procedures associated with a specific clinic
496
+ *
497
+ * @param clinicId - The ID of the clinic that was updated
498
+ * @param clinicData - The updated clinic data
499
+ * @returns Number of procedures updated
500
+ */
501
+ async updateClinicInfoInProcedures(
502
+ clinicId: string,
503
+ clinicData: any
504
+ ): Promise<number> {
505
+ return this.updateProcedureAggregateData("clinic", clinicId, clinicData);
506
+ }
507
+
508
+ /**
509
+ * Updates the doctorInfo for all procedures associated with a specific practitioner
510
+ *
511
+ * @param practitionerId - The ID of the practitioner that was updated
512
+ * @param practitionerData - The updated practitioner data
513
+ * @returns Number of procedures updated
514
+ */
515
+ async updateDoctorInfoInProcedures(
516
+ practitionerId: string,
517
+ practitionerData: any
518
+ ): Promise<number> {
519
+ return this.updateProcedureAggregateData(
520
+ "doctor",
521
+ practitionerId,
522
+ practitionerData
523
+ );
524
+ }
525
+
526
+ /**
527
+ * Updates all existing procedures to include clinicInfo and doctorInfo
528
+ * This is a migration helper method that can be used to update existing procedures
529
+ *
530
+ * @returns Number of procedures updated
531
+ */
532
+ async migrateAllProceduresWithAggregateData(): Promise<number> {
533
+ // Get all procedures
534
+ const proceduresQuery = query(collection(this.db, PROCEDURES_COLLECTION));
535
+ const proceduresSnapshot = await getDocs(proceduresQuery);
536
+
537
+ if (proceduresSnapshot.empty) {
538
+ return 0;
539
+ }
540
+
541
+ let updatedCount = 0;
542
+ const batch = writeBatch(this.db);
543
+ const batchLimit = 500; // Firestore batch limit
544
+ let batchCount = 0;
545
+
546
+ // Process each procedure
547
+ for (const procedureDoc of proceduresSnapshot.docs) {
548
+ const procedure = procedureDoc.data() as Procedure;
549
+
550
+ // Skip if already has both required fields
551
+ if (procedure.clinicInfo && procedure.doctorInfo) {
552
+ continue;
553
+ }
554
+
555
+ try {
556
+ // Get clinic data
557
+ const clinicRef = doc(
558
+ this.db,
559
+ CLINICS_COLLECTION,
560
+ procedure.clinicBranchId
561
+ );
562
+ const clinicSnapshot = await getDoc(clinicRef);
563
+
564
+ if (!clinicSnapshot.exists()) {
565
+ console.warn(
566
+ `Clinic ${procedure.clinicBranchId} not found for procedure ${procedure.id}`
567
+ );
568
+ continue;
569
+ }
570
+
571
+ const clinic = clinicSnapshot.data();
572
+
573
+ // Create clinic info
574
+ const clinicInfo = {
575
+ id: clinicSnapshot.id,
576
+ name: clinic.name,
577
+ description: clinic.description || "",
578
+ featuredPhoto:
579
+ clinic.featuredPhotos && clinic.featuredPhotos.length > 0
580
+ ? clinic.featuredPhotos[0]
581
+ : clinic.coverPhoto || "",
582
+ location: clinic.location,
583
+ contactInfo: clinic.contactInfo,
584
+ };
585
+
586
+ // Get practitioner data
587
+ const practitionerRef = doc(
588
+ this.db,
589
+ PRACTITIONERS_COLLECTION,
590
+ procedure.practitionerId
591
+ );
592
+ const practitionerSnapshot = await getDoc(practitionerRef);
593
+
594
+ if (!practitionerSnapshot.exists()) {
595
+ console.warn(
596
+ `Practitioner ${procedure.practitionerId} not found for procedure ${procedure.id}`
597
+ );
598
+ continue;
599
+ }
600
+
601
+ const practitioner = practitionerSnapshot.data();
602
+
603
+ // Find doctor info in clinic's doctorsInfo array
604
+ let doctorInfo = clinic.doctorsInfo?.find(
605
+ (doctor: any) => doctor.id === procedure.practitionerId
606
+ );
607
+
608
+ // If not found, create basic doctor info
609
+ if (!doctorInfo) {
610
+ doctorInfo = {
611
+ id: practitionerSnapshot.id,
612
+ name: `${practitioner.basicInfo.firstName} ${practitioner.basicInfo.lastName}`,
613
+ description: practitioner.basicInfo.bio || "",
614
+ photo: practitioner.basicInfo.profileImageUrl || "",
615
+ rating: 0,
616
+ services: [],
617
+ };
618
+ }
619
+
620
+ // Add to batch
621
+ batch.update(procedureDoc.ref, {
622
+ clinicInfo,
623
+ doctorInfo,
624
+ updatedAt: serverTimestamp(),
625
+ });
626
+
627
+ batchCount++;
628
+ updatedCount++;
629
+
630
+ // Commit batch if we've reached the limit
631
+ if (batchCount >= batchLimit) {
632
+ await batch.commit();
633
+ console.log(`Committed batch of ${batchCount} procedure updates`);
634
+ batchCount = 0;
635
+ }
636
+ } catch (error) {
637
+ console.error(`Error updating procedure ${procedure.id}:`, error);
638
+ }
639
+ }
640
+
641
+ // Commit any remaining updates
642
+ if (batchCount > 0) {
643
+ await batch.commit();
644
+ console.log(`Committed final batch of ${batchCount} procedure updates`);
645
+ }
646
+
647
+ return updatedCount;
648
+ }
270
649
  }
@@ -12,6 +12,9 @@ import { BlockingCondition } from "../../backoffice/types/static/blocking-condit
12
12
  import { TreatmentBenefit } from "../../backoffice/types/static/treatment-benefit.types";
13
13
  import { CertificationRequirement } from "../../backoffice/types/static/certification.types";
14
14
  import { DocumentTemplate } from "../documentation-templates";
15
+ import { ClinicInfo } from "../profile";
16
+ import { DoctorInfo } from "../clinic";
17
+ import { PRACTITIONERS_COLLECTION } from "../practitioner";
15
18
 
16
19
  /**
17
20
  * Procedure represents a specific medical procedure that can be performed by a practitioner in a clinic
@@ -58,6 +61,10 @@ export interface Procedure {
58
61
  practitionerId: string;
59
62
  /** ID of the clinic branch where this procedure is performed */
60
63
  clinicBranchId: string;
64
+ /** Aggregated clinic information */
65
+ clinicInfo: ClinicInfo;
66
+ /** Aggregated doctor information */
67
+ doctorInfo: DoctorInfo;
61
68
  /** Whether this procedure is active */
62
69
  isActive: boolean;
63
70
  /** When this procedure was created */
@@ -4,6 +4,7 @@ import {
4
4
  Currency,
5
5
  PricingMeasure,
6
6
  } from "../backoffice/types/static/pricing.types";
7
+ import { clinicInfoSchema, doctorInfoSchema } from "./clinic.schema";
7
8
 
8
9
  /**
9
10
  * Schema for creating a new procedure
@@ -52,6 +53,8 @@ export const procedureSchema = createProcedureSchema.extend({
52
53
  postRequirements: z.array(z.any()), // We'll validate requirements separately
53
54
  certificationRequirement: z.any(), // We'll validate certification requirement separately
54
55
  documentationTemplates: z.array(z.any()), // We'll validate documentation templates separately
56
+ clinicInfo: clinicInfoSchema, // Clinic info validation
57
+ doctorInfo: doctorInfoSchema, // Doctor info validation
55
58
  isActive: z.boolean(),
56
59
  createdAt: z.date(),
57
60
  updatedAt: z.date(),