@blackcode_sa/metaestetics-api 1.6.24 → 1.6.25

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.
@@ -5,11 +5,13 @@ import {
5
5
  FilledDocumentStatus,
6
6
  USER_FORMS_SUBCOLLECTION,
7
7
  DOCTOR_FORMS_SUBCOLLECTION,
8
+ DOCUMENTATION_TEMPLATES_COLLECTION,
8
9
  } from "../../types/documentation-templates";
9
10
  import {
10
11
  APPOINTMENTS_COLLECTION,
11
12
  LinkedFormInfo,
12
13
  } from "../../types/appointment";
14
+ import { TechnologyDocumentationTemplate } from "../../backoffice/types/technology.types";
13
15
 
14
16
  export interface InitializeAppointmentFormsResult {
15
17
  initializedFormsInfo: LinkedFormInfo[];
@@ -128,4 +130,130 @@ export class DocumentManagerAdminService {
128
130
  }
129
131
  return { initializedFormsInfo, pendingUserFormsIds, allLinkedTemplateIds };
130
132
  }
133
+
134
+ /**
135
+ * Adds operations to a Firestore batch to initialize all linked forms for a new appointment
136
+ * using the TechnologyDocumentationTemplate references.
137
+ *
138
+ * @param dbBatch - The Firestore batch to add operations to.
139
+ * @param appointmentId - The ID of the newly created appointment.
140
+ * @param procedureIdForForms - The ID of the procedure associated with this appointment.
141
+ * @param technologyTemplates - Array of technology documentation template references.
142
+ * @param patientId - ID of the patient.
143
+ * @param practitionerId - ID of the practitioner associated with the procedure.
144
+ * @param clinicId - ID of the clinic where the procedure is performed.
145
+ * @param nowMillis - Current timestamp in milliseconds for createdAt/updatedAt.
146
+ * @returns An object containing initializedFormsInfo, pendingUserFormsIds, and allLinkedTemplateIds.
147
+ */
148
+ async batchInitializeAppointmentFormsFromTechnologyTemplates(
149
+ dbBatch: admin.firestore.WriteBatch,
150
+ appointmentId: string,
151
+ procedureIdForForms: string,
152
+ technologyTemplates: TechnologyDocumentationTemplate[],
153
+ patientId: string,
154
+ practitionerId: string,
155
+ clinicId: string,
156
+ nowMillis: number
157
+ ): Promise<InitializeAppointmentFormsResult> {
158
+ const initializedFormsInfo: LinkedFormInfo[] = [];
159
+ const pendingUserFormsIds: string[] = [];
160
+ const allLinkedTemplateIds: string[] = [];
161
+
162
+ if (!technologyTemplates || technologyTemplates.length === 0) {
163
+ console.log(
164
+ `[DocManagerAdmin] No document templates to initialize for appointment ${appointmentId}.`
165
+ );
166
+ return {
167
+ initializedFormsInfo,
168
+ pendingUserFormsIds,
169
+ allLinkedTemplateIds,
170
+ };
171
+ }
172
+
173
+ // Fetch all template documents in one batch
174
+ const templateIds = technologyTemplates.map((t) => t.templateId);
175
+ const templatesSnapshot = await this.db
176
+ .collection(DOCUMENTATION_TEMPLATES_COLLECTION)
177
+ .where(admin.firestore.FieldPath.documentId(), "in", templateIds)
178
+ .get();
179
+
180
+ const templatesMap = new Map<string, DocumentTemplate>();
181
+ templatesSnapshot.forEach((doc) => {
182
+ templatesMap.set(doc.id, doc.data() as DocumentTemplate);
183
+ });
184
+
185
+ for (const templateRef of technologyTemplates) {
186
+ const template = templatesMap.get(templateRef.templateId);
187
+ if (!template) {
188
+ console.warn(
189
+ `[DocManagerAdmin] Template ${templateRef.templateId} not found in Firestore.`
190
+ );
191
+ continue;
192
+ }
193
+
194
+ const isUserForm = templateRef.isUserForm;
195
+ const isRequired = templateRef.isRequired;
196
+
197
+ const formSubcollectionPath = isUserForm
198
+ ? USER_FORMS_SUBCOLLECTION
199
+ : DOCTOR_FORMS_SUBCOLLECTION;
200
+
201
+ const filledDocumentId = this.db
202
+ .collection(APPOINTMENTS_COLLECTION)
203
+ .doc(appointmentId)
204
+ .collection(formSubcollectionPath)
205
+ .doc().id;
206
+
207
+ if (isUserForm && isRequired) {
208
+ pendingUserFormsIds.push(filledDocumentId);
209
+ }
210
+
211
+ allLinkedTemplateIds.push(filledDocumentId);
212
+ // Always initialize with PENDING status regardless of whether the form is required
213
+ // PENDING is the starting state, DRAFT is when a form is saved but not submitted
214
+ const initialStatus = FilledDocumentStatus.PENDING;
215
+
216
+ const filledDocumentData: FilledDocument = {
217
+ id: filledDocumentId,
218
+ templateId: templateRef.templateId,
219
+ templateVersion: template.version,
220
+ isUserForm: isUserForm,
221
+ isRequired: isRequired,
222
+ appointmentId: appointmentId,
223
+ procedureId: procedureIdForForms,
224
+ patientId: patientId,
225
+ practitionerId: practitionerId,
226
+ clinicId: clinicId,
227
+ createdAt: nowMillis,
228
+ updatedAt: nowMillis,
229
+ values: {},
230
+ status: initialStatus,
231
+ };
232
+
233
+ const docRef = this.db
234
+ .collection(APPOINTMENTS_COLLECTION)
235
+ .doc(appointmentId)
236
+ .collection(formSubcollectionPath)
237
+ .doc(filledDocumentId);
238
+
239
+ dbBatch.set(docRef, filledDocumentData);
240
+
241
+ const linkedForm: LinkedFormInfo = {
242
+ formId: filledDocumentData.id,
243
+ templateId: template.id,
244
+ templateVersion: template.version,
245
+ title: template.title,
246
+ isUserForm: filledDocumentData.isUserForm,
247
+ isRequired: filledDocumentData.isRequired,
248
+ status: filledDocumentData.status,
249
+ path: docRef.path,
250
+ };
251
+ initializedFormsInfo.push(linkedForm);
252
+
253
+ console.log(
254
+ `[DocManagerAdmin] Added FilledDocument ${filledDocumentId} (template: ${template.id}) and its LinkedFormInfo to batch for appointment ${appointmentId}.`
255
+ );
256
+ }
257
+ return { initializedFormsInfo, pendingUserFormsIds, allLinkedTemplateIds };
258
+ }
131
259
  }
@@ -6,6 +6,20 @@ import { CertificationRequirement } from "./static/certification.types";
6
6
  import { DocumentTemplate } from "../../types/documentation-templates";
7
7
  import { ProcedureFamily } from "./static/procedure-family.types";
8
8
 
9
+ /**
10
+ * Reference to a documentation template with metadata
11
+ * @property templateId - ID of the documentation template
12
+ * @property isUserForm - Whether this template is filled by users
13
+ * @property isRequired - Whether this template is required
14
+ * @property sortingOrder - The display order of this template
15
+ */
16
+ export interface TechnologyDocumentationTemplate {
17
+ templateId: string;
18
+ isUserForm: boolean;
19
+ isRequired: boolean;
20
+ sortingOrder: number;
21
+ }
22
+
9
23
  /**
10
24
  * Zahtevi koji su povezani sa tehnologijom
11
25
  * @property pre - Lista zahteva koji se moraju ispuniti pre procedure
@@ -33,7 +47,7 @@ export interface TechnologyRequirements {
33
47
  * @property contraindications - List of conditions requiring special attention
34
48
  * @property benefits - List of expected benefits from the procedure
35
49
  * @property certificationRequirement - Required certification level and specialties
36
- * @property documentationTemplates - List of documentation templates required for this technology
50
+ * @property documentationTemplates - List of documentation template references
37
51
  * @property isActive - Whether the technology is active in the system
38
52
  * @property createdAt - Creation date
39
53
  * @property updatedAt - Last update date
@@ -54,7 +68,7 @@ export interface Technology {
54
68
  contraindications: Contraindication[];
55
69
  benefits: TreatmentBenefit[];
56
70
  certificationRequirement: CertificationRequirement;
57
- documentationTemplates?: DocumentTemplate[];
71
+ documentationTemplates?: TechnologyDocumentationTemplate[];
58
72
  isActive: boolean;
59
73
  createdAt: Date;
60
74
  updatedAt: Date;
@@ -95,33 +95,49 @@ export class DocumentationTemplateService extends BaseService {
95
95
  templateId: string,
96
96
  version?: number
97
97
  ): Promise<DocumentTemplate | null> {
98
- // If version is specified, try to get that specific version
99
- if (version !== undefined) {
100
- try {
101
- const versionTemplate = await this.getTemplateVersion(
102
- templateId,
103
- version
104
- );
105
- // If the version exists, return it
106
- if (versionTemplate) {
107
- return versionTemplate;
108
- }
109
- // If version doesn't exist, fall back to latest version (continue with code below)
110
- } catch (error) {
111
- console.error(`Error getting template version ${version}:`, error);
112
- // Fall back to latest version if error occurs
113
- }
114
- }
115
-
116
- // Get the latest version (default behavior)
98
+ // First, check if the template exists at all
117
99
  const docRef = doc(this.collectionRef, templateId);
118
100
  const docSnap = await getDoc(docRef);
119
101
 
120
102
  if (!docSnap.exists()) {
121
- return null;
103
+ return null; // Template doesn't exist
104
+ }
105
+
106
+ const currentTemplate = docSnap.data() as DocumentTemplate;
107
+
108
+ // If no specific version is requested, simply return the current template
109
+ if (version === undefined) {
110
+ return currentTemplate;
122
111
  }
123
112
 
124
- return docSnap.data() as DocumentTemplate;
113
+ // If the requested version matches the current version, return it
114
+ if (currentTemplate.version === version) {
115
+ return currentTemplate;
116
+ }
117
+
118
+ // Otherwise, try to find the requested version in the versions subcollection
119
+ try {
120
+ const versionTemplate = await this.getTemplateVersion(
121
+ templateId,
122
+ version
123
+ );
124
+ if (versionTemplate) {
125
+ return versionTemplate;
126
+ }
127
+ } catch (error) {
128
+ console.error(`Error getting template version ${version}:`, error);
129
+ }
130
+
131
+ // If we get here, the requested version doesn't exist
132
+ // Option 1: Return null (strict approach)
133
+ return null;
134
+
135
+ // Option 2: Return current version but indicate it's not the requested version (uncomment to use)
136
+ // return {
137
+ // ...currentTemplate,
138
+ // _versionRequested: version,
139
+ // _versionNotFound: true
140
+ // } as DocumentTemplate;
125
141
  }
126
142
 
127
143
  /**
@@ -1,7 +1,10 @@
1
1
  import { ProcedureFamily } from "../../backoffice/types/static/procedure-family.types";
2
2
  import { Category } from "../../backoffice/types/category.types";
3
3
  import { Subcategory } from "../../backoffice/types/subcategory.types";
4
- import { Technology } from "../../backoffice/types/technology.types";
4
+ import {
5
+ Technology,
6
+ type TechnologyDocumentationTemplate,
7
+ } from "../../backoffice/types/technology.types";
5
8
  import { Product } from "../../backoffice/types/product.types";
6
9
  import {
7
10
  PricingMeasure,
@@ -62,7 +65,7 @@ export interface Procedure {
62
65
  /** Certification requirements for performing this procedure */
63
66
  certificationRequirement: CertificationRequirement;
64
67
  /** Documentation templates required for this procedure */
65
- documentationTemplates: DocumentTemplate[];
68
+ documentationTemplates: TechnologyDocumentationTemplate[];
66
69
  /** ID of the practitioner who performs this procedure */
67
70
  practitionerId: string;
68
71
  /** ID of the clinic branch where this procedure is performed */