@blackcode_sa/metaestetics-api 1.11.1 → 1.11.3

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.
Files changed (36) hide show
  1. package/dist/admin/index.d.mts +326 -330
  2. package/dist/admin/index.d.ts +326 -330
  3. package/dist/backoffice/index.d.mts +67 -283
  4. package/dist/backoffice/index.d.ts +67 -283
  5. package/dist/backoffice/index.js +6 -114
  6. package/dist/backoffice/index.mjs +6 -112
  7. package/dist/index.d.mts +3039 -3100
  8. package/dist/index.d.ts +3039 -3100
  9. package/dist/index.js +131 -380
  10. package/dist/index.mjs +132 -380
  11. package/package.json +1 -1
  12. package/src/backoffice/expo-safe/index.ts +0 -2
  13. package/src/backoffice/services/__tests__/brand.service.test.ts +196 -0
  14. package/src/backoffice/services/__tests__/category.service.test.ts +201 -0
  15. package/src/backoffice/services/__tests__/product.service.test.ts +358 -0
  16. package/src/backoffice/services/__tests__/requirement.service.test.ts +226 -0
  17. package/src/backoffice/services/__tests__/subcategory.service.test.ts +181 -0
  18. package/src/backoffice/services/__tests__/technology.service.test.ts +1097 -0
  19. package/src/backoffice/services/technology.service.ts +10 -122
  20. package/src/backoffice/types/index.ts +0 -1
  21. package/src/backoffice/types/product.types.ts +1 -3
  22. package/src/backoffice/types/technology.types.ts +4 -4
  23. package/src/backoffice/validations/schemas.ts +9 -35
  24. package/src/services/appointment/appointment.service.ts +5 -0
  25. package/src/services/appointment/utils/appointment.utils.ts +113 -124
  26. package/src/services/procedure/procedure.service.ts +234 -434
  27. package/src/types/appointment/index.ts +39 -43
  28. package/src/types/clinic/index.ts +6 -1
  29. package/src/types/patient/medical-info.types.ts +3 -3
  30. package/src/types/procedure/index.ts +17 -20
  31. package/src/validations/appointment.schema.ts +119 -170
  32. package/src/validations/clinic.schema.ts +6 -1
  33. package/src/validations/patient/medical-info.schema.ts +2 -7
  34. package/src/backoffice/services/README.md +0 -40
  35. package/src/backoffice/services/constants.service.ts +0 -268
  36. package/src/backoffice/types/admin-constants.types.ts +0 -69
@@ -1,15 +1,8 @@
1
- import { z } from "zod";
2
- import {
3
- AppointmentStatus,
4
- PaymentStatus,
5
- MediaType,
6
- } from "../types/appointment";
7
- import { filledDocumentStatusSchema } from "./documentation-templates.schema";
8
- import {
9
- Currency,
10
- PricingMeasure,
11
- } from "../backoffice/types/static/pricing.types";
12
- import { mediaResourceSchema } from "./media.schema";
1
+ import { z } from 'zod';
2
+ import { AppointmentStatus, PaymentStatus, MediaType } from '../types/appointment';
3
+ import { filledDocumentStatusSchema } from './documentation-templates.schema';
4
+ import { Currency, PricingMeasure } from '../backoffice/types/static/pricing.types';
5
+ import { mediaResourceSchema } from './media.schema';
13
6
 
14
7
  // Define common constants locally if not available from common.schema.ts
15
8
  const MIN_STRING_LENGTH = 1;
@@ -25,9 +18,9 @@ export const mediaTypeSchema = z.nativeEnum(MediaType);
25
18
  // --- Schemas for Nested Objects from types/appointment/index.ts ---
26
19
 
27
20
  export const appointmentMediaItemSchema = z.object({
28
- id: z.string().min(MIN_STRING_LENGTH, "Media item ID is required"),
21
+ id: z.string().min(MIN_STRING_LENGTH, 'Media item ID is required'),
29
22
  type: mediaTypeSchema,
30
- url: z.string().url("Media URL must be a valid URL"),
23
+ url: z.string().url('Media URL must be a valid URL'),
31
24
  fileName: z.string().optional(),
32
25
  uploadedAt: z
33
26
  .any()
@@ -36,18 +29,13 @@ export const appointmentMediaItemSchema = z.object({
36
29
  val instanceof Date ||
37
30
  val?._seconds !== undefined ||
38
31
  val?.seconds !== undefined ||
39
- typeof val === "number" ||
40
- typeof val === "string" ||
41
- (val && typeof val.toMillis === "function"),
42
- "uploadedAt must be a valid timestamp or Date object"
32
+ typeof val === 'number' ||
33
+ typeof val === 'string' ||
34
+ (val && typeof val.toMillis === 'function'),
35
+ 'uploadedAt must be a valid timestamp or Date object',
43
36
  ),
44
- uploadedBy: z
45
- .string()
46
- .min(MIN_STRING_LENGTH, "Uploaded by user ID is required"),
47
- description: z
48
- .string()
49
- .max(MAX_STRING_LENGTH, "Description too long")
50
- .optional(),
37
+ uploadedBy: z.string().min(MIN_STRING_LENGTH, 'Uploaded by user ID is required'),
38
+ description: z.string().max(MAX_STRING_LENGTH, 'Description too long').optional(),
51
39
  });
52
40
 
53
41
  export const procedureExtendedInfoSchema = z.object({
@@ -70,17 +58,14 @@ export const procedureExtendedInfoSchema = z.object({
70
58
  });
71
59
 
72
60
  export const linkedFormInfoSchema = z.object({
73
- formId: z.string().min(MIN_STRING_LENGTH, "Form ID is required"),
74
- templateId: z.string().min(MIN_STRING_LENGTH, "Template ID is required"),
75
- templateVersion: z
76
- .number()
77
- .int()
78
- .positive("Template version must be a positive integer"),
79
- title: z.string().min(MIN_STRING_LENGTH, "Form title is required"),
61
+ formId: z.string().min(MIN_STRING_LENGTH, 'Form ID is required'),
62
+ templateId: z.string().min(MIN_STRING_LENGTH, 'Template ID is required'),
63
+ templateVersion: z.number().int().positive('Template version must be a positive integer'),
64
+ title: z.string().min(MIN_STRING_LENGTH, 'Form title is required'),
80
65
  isUserForm: z.boolean(),
81
66
  isRequired: z.boolean().optional(),
82
67
  status: filledDocumentStatusSchema,
83
- path: z.string().min(MIN_STRING_LENGTH, "Form path is required"),
68
+ path: z.string().min(MIN_STRING_LENGTH, 'Form path is required'),
84
69
  submittedAt: z
85
70
  .any()
86
71
  .refine(
@@ -89,10 +74,10 @@ export const linkedFormInfoSchema = z.object({
89
74
  val instanceof Date ||
90
75
  val?._seconds !== undefined ||
91
76
  val?.seconds !== undefined ||
92
- typeof val === "number" ||
93
- typeof val === "string" ||
94
- (val && typeof val.toMillis === "function"),
95
- "submittedAt must be a valid timestamp or Date object"
77
+ typeof val === 'number' ||
78
+ typeof val === 'string' ||
79
+ (val && typeof val.toMillis === 'function'),
80
+ 'submittedAt must be a valid timestamp or Date object',
96
81
  )
97
82
  .optional(),
98
83
  completedAt: z
@@ -103,21 +88,18 @@ export const linkedFormInfoSchema = z.object({
103
88
  val instanceof Date ||
104
89
  val?._seconds !== undefined ||
105
90
  val?.seconds !== undefined ||
106
- typeof val === "number" ||
107
- typeof val === "string" ||
108
- (val && typeof val.toMillis === "function"),
109
- "completedAt must be a valid timestamp or Date object"
91
+ typeof val === 'number' ||
92
+ typeof val === 'string' ||
93
+ (val && typeof val.toMillis === 'function'),
94
+ 'completedAt must be a valid timestamp or Date object',
110
95
  )
111
96
  .optional(),
112
97
  });
113
98
 
114
99
  export const patientReviewInfoSchema = z.object({
115
- reviewId: z.string().min(MIN_STRING_LENGTH, "Review ID is required"),
116
- rating: z.number().min(1).max(5, "Rating must be between 1 and 5"),
117
- comment: z
118
- .string()
119
- .max(MAX_STRING_LENGTH_LONG, "Comment too long")
120
- .optional(),
100
+ reviewId: z.string().min(MIN_STRING_LENGTH, 'Review ID is required'),
101
+ rating: z.number().min(1).max(5, 'Rating must be between 1 and 5'),
102
+ comment: z.string().max(MAX_STRING_LENGTH_LONG, 'Comment too long').optional(),
121
103
  reviewedAt: z
122
104
  .any()
123
105
  .refine(
@@ -125,15 +107,15 @@ export const patientReviewInfoSchema = z.object({
125
107
  val instanceof Date ||
126
108
  val?._seconds !== undefined ||
127
109
  val?.seconds !== undefined ||
128
- typeof val === "number" ||
129
- typeof val === "string" ||
130
- (val && typeof val.toMillis === "function"),
131
- "reviewedAt must be a valid timestamp or Date object"
110
+ typeof val === 'number' ||
111
+ typeof val === 'string' ||
112
+ (val && typeof val.toMillis === 'function'),
113
+ 'reviewedAt must be a valid timestamp or Date object',
132
114
  ),
133
115
  });
134
116
 
135
117
  export const finalizedDetailsSchema = z.object({
136
- by: z.string().min(MIN_STRING_LENGTH, "Finalized by user ID is required"),
118
+ by: z.string().min(MIN_STRING_LENGTH, 'Finalized by user ID is required'),
137
119
  at: z
138
120
  .any()
139
121
  .refine(
@@ -141,15 +123,12 @@ export const finalizedDetailsSchema = z.object({
141
123
  val instanceof Date ||
142
124
  val?._seconds !== undefined ||
143
125
  val?.seconds !== undefined ||
144
- typeof val === "number" ||
145
- typeof val === "string" ||
146
- (val && typeof val.toMillis === "function"),
147
- "Finalized at must be a valid timestamp or Date object"
126
+ typeof val === 'number' ||
127
+ typeof val === 'string' ||
128
+ (val && typeof val.toMillis === 'function'),
129
+ 'Finalized at must be a valid timestamp or Date object',
148
130
  ),
149
- notes: z
150
- .string()
151
- .max(MAX_STRING_LENGTH_LONG, "Finalization notes too long")
152
- .optional(),
131
+ notes: z.string().max(MAX_STRING_LENGTH_LONG, 'Finalization notes too long').optional(),
153
132
  });
154
133
 
155
134
  /**
@@ -158,32 +137,34 @@ export const finalizedDetailsSchema = z.object({
158
137
  export const beforeAfterPerZoneSchema = z.object({
159
138
  before: mediaResourceSchema.nullable(),
160
139
  after: mediaResourceSchema.nullable(),
161
- note: z.string().nullable(),
140
+ afterNote: z.string().nullable().optional(),
141
+ beforeNote: z.string().nullable().optional(),
162
142
  });
163
143
 
164
144
  /**
165
145
  * Schema for billing information per zone
166
146
  */
167
147
  export const billingPerZoneSchema = z.object({
168
- Product: z.string().min(MIN_STRING_LENGTH, "Product name is required"),
148
+ Product: z.string().min(MIN_STRING_LENGTH, 'Product name is required'),
169
149
  ProductId: z.string().nullable(),
170
- Quantity: z.number().min(0, "Quantity must be non-negative"),
150
+ Quantity: z.number().min(0, 'Quantity must be non-negative'),
171
151
  UnitOfMeasurement: z.nativeEnum(PricingMeasure),
172
- UnitPrice: z.number().min(0, "Unit price must be non-negative"),
152
+ UnitPrice: z.number().min(0, 'Unit price must be non-negative'),
173
153
  UnitCurency: z.nativeEnum(Currency),
174
- Subtotal: z.number().min(0, "Subtotal must be non-negative"),
154
+ Subtotal: z.number().min(0, 'Subtotal must be non-negative'),
175
155
  Note: z.string().nullable(),
156
+ IonNumber: z.string().nullable(),
176
157
  });
177
158
 
178
159
  /**
179
160
  * Schema for final billing calculations of the appointment
180
161
  */
181
162
  export const finalBillingSchema = z.object({
182
- subtotalAll: z.number().min(0, "Subtotal all must be non-negative"),
183
- taxRate: z.number().min(0).max(1, "Tax rate must be between 0 and 1"),
184
- taxPrice: z.number().min(0, "Tax price must be non-negative"),
185
- finalPrice: z.number().min(0, "Final price must be non-negative"),
186
- finalQuantity: z.number().min(0, "Final quantity must be non-negative"),
163
+ subtotalAll: z.number().min(0, 'Subtotal all must be non-negative'),
164
+ taxRate: z.number().min(0).max(1, 'Tax rate must be between 0 and 1'),
165
+ taxPrice: z.number().min(0, 'Tax price must be non-negative'),
166
+ finalPrice: z.number().min(0, 'Final price must be non-negative'),
167
+ finalQuantity: z.number().min(0, 'Final quantity must be non-negative'),
187
168
  currency: z.nativeEnum(Currency),
188
169
  unitOfMeasurement: z.nativeEnum(PricingMeasure),
189
170
  });
@@ -196,6 +177,7 @@ export const appointmentMetadataSchema = z.object({
196
177
  zonePhotos: z.record(z.string(), beforeAfterPerZoneSchema).nullable(),
197
178
  zoneBilling: z.record(z.string(), billingPerZoneSchema).nullable(),
198
179
  finalbilling: finalBillingSchema.nullable(),
180
+ finalizationNotes: z.string().nullable(),
199
181
  });
200
182
 
201
183
  // --- Main Appointment Schemas ---
@@ -205,14 +187,10 @@ export const appointmentMetadataSchema = z.object({
205
187
  */
206
188
  export const createAppointmentSchema = z
207
189
  .object({
208
- clinicBranchId: z
209
- .string()
210
- .min(MIN_STRING_LENGTH, "Clinic branch ID is required"),
211
- practitionerId: z
212
- .string()
213
- .min(MIN_STRING_LENGTH, "Practitioner ID is required"),
214
- patientId: z.string().min(MIN_STRING_LENGTH, "Patient ID is required"),
215
- procedureId: z.string().min(MIN_STRING_LENGTH, "Procedure ID is required"),
190
+ clinicBranchId: z.string().min(MIN_STRING_LENGTH, 'Clinic branch ID is required'),
191
+ practitionerId: z.string().min(MIN_STRING_LENGTH, 'Practitioner ID is required'),
192
+ patientId: z.string().min(MIN_STRING_LENGTH, 'Patient ID is required'),
193
+ procedureId: z.string().min(MIN_STRING_LENGTH, 'Procedure ID is required'),
216
194
  appointmentStartTime: z
217
195
  .any()
218
196
  .refine(
@@ -220,10 +198,10 @@ export const createAppointmentSchema = z
220
198
  val instanceof Date ||
221
199
  val?._seconds !== undefined ||
222
200
  val?.seconds !== undefined ||
223
- typeof val === "number" ||
224
- typeof val === "string" ||
225
- (val && typeof val.toMillis === "function"),
226
- "Appointment start time must be a valid timestamp or Date object"
201
+ typeof val === 'number' ||
202
+ typeof val === 'string' ||
203
+ (val && typeof val.toMillis === 'function'),
204
+ 'Appointment start time must be a valid timestamp or Date object',
227
205
  ),
228
206
  appointmentEndTime: z
229
207
  .any()
@@ -232,27 +210,21 @@ export const createAppointmentSchema = z
232
210
  val instanceof Date ||
233
211
  val?._seconds !== undefined ||
234
212
  val?.seconds !== undefined ||
235
- typeof val === "number" ||
236
- typeof val === "string" ||
237
- (val && typeof val.toMillis === "function"),
238
- "Appointment end time must be a valid timestamp or Date object"
213
+ typeof val === 'number' ||
214
+ typeof val === 'string' ||
215
+ (val && typeof val.toMillis === 'function'),
216
+ 'Appointment end time must be a valid timestamp or Date object',
239
217
  ),
240
- cost: z.number().min(0, "Cost must be a non-negative number"),
241
- currency: z.string().min(1, "Currency is required"),
242
- patientNotes: z
243
- .string()
244
- .max(MAX_STRING_LENGTH, "Patient notes too long")
245
- .nullable()
246
- .optional(),
218
+ cost: z.number().min(0, 'Cost must be a non-negative number'),
219
+ currency: z.string().min(1, 'Currency is required'),
220
+ patientNotes: z.string().max(MAX_STRING_LENGTH, 'Patient notes too long').nullable().optional(),
247
221
  initialStatus: appointmentStatusSchema,
248
- initialPaymentStatus: paymentStatusSchema
249
- .optional()
250
- .default(PaymentStatus.UNPAID),
251
- clinic_tz: z.string().min(1, "Timezone is required"),
222
+ initialPaymentStatus: paymentStatusSchema.optional().default(PaymentStatus.UNPAID),
223
+ clinic_tz: z.string().min(1, 'Timezone is required'),
252
224
  })
253
225
  .refine((data) => data.appointmentEndTime > data.appointmentStartTime, {
254
- message: "Appointment end time must be after start time",
255
- path: ["appointmentEndTime"],
226
+ message: 'Appointment end time must be after start time',
227
+ path: ['appointmentEndTime'],
256
228
  });
257
229
 
258
230
  /**
@@ -268,30 +240,24 @@ export const updateAppointmentSchema = z
268
240
  actualDurationMinutes: z
269
241
  .number()
270
242
  .int()
271
- .positive("Duration must be a positive integer")
243
+ .positive('Duration must be a positive integer')
272
244
  .optional(),
273
245
  cancellationReason: z
274
246
  .string()
275
- .max(MAX_STRING_LENGTH, "Cancellation reason too long")
247
+ .max(MAX_STRING_LENGTH, 'Cancellation reason too long')
276
248
  .nullable()
277
249
  .optional(),
278
- canceledBy: z
279
- .enum(["patient", "clinic", "practitioner", "system"])
280
- .optional(),
250
+ canceledBy: z.enum(['patient', 'clinic', 'practitioner', 'system']).optional(),
281
251
  internalNotes: z
282
252
  .string()
283
- .max(MAX_STRING_LENGTH_LONG, "Internal notes too long")
253
+ .max(MAX_STRING_LENGTH_LONG, 'Internal notes too long')
284
254
  .nullable()
285
255
  .optional(),
286
256
  patientNotes: z.any().optional().nullable(),
287
257
  paymentStatus: paymentStatusSchema.optional(),
288
258
  paymentTransactionId: z.any().optional().nullable(),
289
- completedPreRequirements: z
290
- .union([z.array(z.string()), z.any()])
291
- .optional(),
292
- completedPostRequirements: z
293
- .union([z.array(z.string()), z.any()])
294
- .optional(),
259
+ completedPreRequirements: z.union([z.array(z.string()), z.any()]).optional(),
260
+ completedPostRequirements: z.union([z.array(z.string()), z.any()]).optional(),
295
261
  linkedFormIds: z.union([z.array(z.string()), z.any()]).optional(),
296
262
  pendingUserFormsIds: z.union([z.array(z.string()), z.any()]).optional(),
297
263
  appointmentStartTime: z
@@ -302,10 +268,10 @@ export const updateAppointmentSchema = z
302
268
  val instanceof Date ||
303
269
  val?._seconds !== undefined ||
304
270
  val?.seconds !== undefined ||
305
- typeof val === "number" ||
306
- typeof val === "string" ||
307
- (val && typeof val.toMillis === "function"),
308
- "Appointment start time must be a valid timestamp or Date object"
271
+ typeof val === 'number' ||
272
+ typeof val === 'string' ||
273
+ (val && typeof val.toMillis === 'function'),
274
+ 'Appointment start time must be a valid timestamp or Date object',
309
275
  )
310
276
  .optional(),
311
277
  appointmentEndTime: z
@@ -316,10 +282,10 @@ export const updateAppointmentSchema = z
316
282
  val instanceof Date ||
317
283
  val?._seconds !== undefined ||
318
284
  val?.seconds !== undefined ||
319
- typeof val === "number" ||
320
- typeof val === "string" ||
321
- (val && typeof val.toMillis === "function"),
322
- "Appointment end time must be a valid timestamp or Date object"
285
+ typeof val === 'number' ||
286
+ typeof val === 'string' ||
287
+ (val && typeof val.toMillis === 'function'),
288
+ 'Appointment end time must be a valid timestamp or Date object',
323
289
  )
324
290
  .optional(),
325
291
  calendarEventId: z.string().min(MIN_STRING_LENGTH).optional(),
@@ -327,21 +293,10 @@ export const updateAppointmentSchema = z
327
293
  clinicBranchId: z.string().min(MIN_STRING_LENGTH).optional(),
328
294
  practitionerId: z.string().min(MIN_STRING_LENGTH).optional(),
329
295
  clinic_tz: z.string().min(MIN_STRING_LENGTH).optional(),
330
- linkedForms: z
331
- .union([z.array(linkedFormInfoSchema).max(MAX_ARRAY_LENGTH), z.any()])
332
- .optional(),
333
- media: z
334
- .union([
335
- z.array(appointmentMediaItemSchema).max(MAX_ARRAY_LENGTH),
336
- z.any(),
337
- ])
338
- .optional(),
339
- reviewInfo: z
340
- .union([patientReviewInfoSchema.nullable(), z.any()])
341
- .optional(),
342
- finalizedDetails: z
343
- .union([finalizedDetailsSchema.nullable(), z.any()])
344
- .optional(),
296
+ linkedForms: z.union([z.array(linkedFormInfoSchema).max(MAX_ARRAY_LENGTH), z.any()]).optional(),
297
+ media: z.union([z.array(appointmentMediaItemSchema).max(MAX_ARRAY_LENGTH), z.any()]).optional(),
298
+ reviewInfo: z.union([patientReviewInfoSchema.nullable(), z.any()]).optional(),
299
+ finalizedDetails: z.union([finalizedDetailsSchema.nullable(), z.any()]).optional(),
345
300
  isArchived: z.boolean().optional(),
346
301
  updatedAt: z.any().optional(),
347
302
  metadata: appointmentMetadataSchema.optional(),
@@ -359,9 +314,9 @@ export const updateAppointmentSchema = z
359
314
  },
360
315
  {
361
316
  message:
362
- "Cancellation reason and canceled by must be provided when canceling an appointment with patient or clinic origin.",
363
- path: ["status"],
364
- }
317
+ 'Cancellation reason and canceled by must be provided when canceling an appointment with patient or clinic origin.',
318
+ path: ['status'],
319
+ },
365
320
  )
366
321
  .refine(
367
322
  (data) => {
@@ -371,10 +326,9 @@ export const updateAppointmentSchema = z
371
326
  return true;
372
327
  },
373
328
  {
374
- message:
375
- "Appointment end time must be after start time if both are provided",
376
- path: ["appointmentEndTime"],
377
- }
329
+ message: 'Appointment end time must be after start time if both are provided',
330
+ path: ['appointmentEndTime'],
331
+ },
378
332
  );
379
333
 
380
334
  /**
@@ -393,10 +347,10 @@ export const searchAppointmentsSchema = z
393
347
  val instanceof Date ||
394
348
  val?._seconds !== undefined ||
395
349
  val?.seconds !== undefined ||
396
- typeof val === "number" ||
397
- typeof val === "string" ||
398
- (val && typeof val.toMillis === "function"),
399
- "Start date must be a valid timestamp or Date object"
350
+ typeof val === 'number' ||
351
+ typeof val === 'string' ||
352
+ (val && typeof val.toMillis === 'function'),
353
+ 'Start date must be a valid timestamp or Date object',
400
354
  )
401
355
  .optional(),
402
356
  endDate: z
@@ -407,17 +361,14 @@ export const searchAppointmentsSchema = z
407
361
  val instanceof Date ||
408
362
  val?._seconds !== undefined ||
409
363
  val?.seconds !== undefined ||
410
- typeof val === "number" ||
411
- typeof val === "string" ||
412
- (val && typeof val.toMillis === "function"),
413
- "End date must be a valid timestamp or Date object"
364
+ typeof val === 'number' ||
365
+ typeof val === 'string' ||
366
+ (val && typeof val.toMillis === 'function'),
367
+ 'End date must be a valid timestamp or Date object',
414
368
  )
415
369
  .optional(),
416
370
  status: z
417
- .union([
418
- appointmentStatusSchema,
419
- z.array(appointmentStatusSchema).nonempty(),
420
- ])
371
+ .union([appointmentStatusSchema, z.array(appointmentStatusSchema).nonempty()])
421
372
  .optional(),
422
373
  limit: z.number().positive().int().optional().default(20),
423
374
  startAfter: z.any().optional(),
@@ -431,9 +382,9 @@ export const searchAppointmentsSchema = z
431
382
  },
432
383
  {
433
384
  message:
434
- "At least one of patientId, practitionerId, or clinicBranchId must be provided if no date or status filters are set.",
435
- path: ["patientId"],
436
- }
385
+ 'At least one of patientId, practitionerId, or clinicBranchId must be provided if no date or status filters are set.',
386
+ path: ['patientId'],
387
+ },
437
388
  )
438
389
  .refine(
439
390
  (data) => {
@@ -443,18 +394,16 @@ export const searchAppointmentsSchema = z
443
394
  return true;
444
395
  },
445
396
  {
446
- message: "End date must be after or the same as start date",
447
- path: ["endDate"],
448
- }
397
+ message: 'End date must be after or the same as start date',
398
+ path: ['endDate'],
399
+ },
449
400
  );
450
401
 
451
402
  /**
452
403
  * Schema for validating appointment reschedule data
453
404
  */
454
405
  export const rescheduleAppointmentSchema = z.object({
455
- appointmentId: z
456
- .string()
457
- .min(MIN_STRING_LENGTH, "Appointment ID is required"),
406
+ appointmentId: z.string().min(MIN_STRING_LENGTH, 'Appointment ID is required'),
458
407
  newStartTime: z
459
408
  .any()
460
409
  .refine(
@@ -462,10 +411,10 @@ export const rescheduleAppointmentSchema = z.object({
462
411
  val instanceof Date ||
463
412
  val?._seconds !== undefined ||
464
413
  val?.seconds !== undefined ||
465
- typeof val === "number" ||
466
- typeof val === "string" ||
467
- (val && typeof val.toMillis === "function"),
468
- "New start time must be a valid timestamp, Date object, number, or string"
414
+ typeof val === 'number' ||
415
+ typeof val === 'string' ||
416
+ (val && typeof val.toMillis === 'function'),
417
+ 'New start time must be a valid timestamp, Date object, number, or string',
469
418
  ),
470
419
  newEndTime: z
471
420
  .any()
@@ -474,9 +423,9 @@ export const rescheduleAppointmentSchema = z.object({
474
423
  val instanceof Date ||
475
424
  val?._seconds !== undefined ||
476
425
  val?.seconds !== undefined ||
477
- typeof val === "number" ||
478
- typeof val === "string" ||
479
- (val && typeof val.toMillis === "function"),
480
- "New end time must be a valid timestamp, Date object, number, or string"
426
+ typeof val === 'number' ||
427
+ typeof val === 'string' ||
428
+ (val && typeof val.toMillis === 'function'),
429
+ 'New end time must be a valid timestamp, Date object, number, or string',
481
430
  ),
482
431
  });
@@ -7,7 +7,12 @@ import {
7
7
  PracticeType,
8
8
  Language,
9
9
  } from "../types/clinic";
10
-
10
+ import { ProcedureFamily } from "../backoffice/types/static/procedure-family.types";
11
+ import { TreatmentBenefit } from "../backoffice/types/static/treatment-benefit.types";
12
+ import {
13
+ Currency,
14
+ PricingMeasure,
15
+ } from "../backoffice/types/static/pricing.types";
11
16
  import { clinicReviewInfoSchema } from "./reviews.schema";
12
17
  import {
13
18
  procedureSummaryInfoSchema,
@@ -7,6 +7,7 @@ import {
7
7
  CosmeticAllergySubtype,
8
8
  } from "../../types/patient/allergies";
9
9
  import { BlockingCondition } from "../../backoffice/types/static/blocking-condition.types";
10
+ import { Contraindication } from "../../backoffice/types/static/contraindication.types";
10
11
  import { timestampSchema } from "../common.schema";
11
12
 
12
13
  export const allergySubtypeSchema = z.union([
@@ -49,14 +50,8 @@ export const blockingConditionSchema = z.object({
49
50
  isActive: z.boolean(),
50
51
  });
51
52
 
52
- export const contraindicationDynamicSchema = z.object({
53
- id: z.string(),
54
- name: z.string(),
55
- description: z.string().optional(),
56
- });
57
-
58
53
  export const contraindicationSchema = z.object({
59
- condition: contraindicationDynamicSchema,
54
+ condition: z.nativeEnum(Contraindication),
60
55
  lastOccurrence: timestampSchema,
61
56
  frequency: z.enum(["rare", "occasional", "frequent"]),
62
57
  notes: z.string().optional().nullable(),
@@ -1,40 +0,0 @@
1
- # Backoffice Services
2
-
3
- This directory contains services used by the backoffice application.
4
-
5
- ## Services
6
-
7
- ### `CategoryService`
8
-
9
- Manages procedure categories. Categories are the first level of organization after procedure family (aesthetics/surgery).
10
-
11
- - **`create(category)`**: Creates a new category.
12
- - **`getAll()`**: Retrieves all active categories.
13
- - **`getAllByFamily(family)`**: Retrieves all active categories for a specific procedure family.
14
- - **`update(id, category)`**: Updates an existing category.
15
- - **`delete(id)`**: Soft deletes a category.
16
- - **`getById(id)`**: Retrieves a category by its ID.
17
-
18
- ### `ProductService`
19
-
20
- Manages products, which are sub-items of a `Technology`.
21
-
22
- - **`create(technologyId, brandId, product)`**: Creates a new product under a technology.
23
- - **`getAllByTechnology(technologyId)`**: Retrieves all products for a technology.
24
- - **`getAllByBrand(brandId)`**: Retrieves all products for a brand.
25
- - **`update(technologyId, productId, product)`**: Updates a product.
26
- - **`delete(technologyId, productId)`**: Soft deletes a product.
27
- - **`getById(technologyId, productId)`**: Retrieves a product by its ID.
28
-
29
- ### `ConstantsService`
30
-
31
- Manages administrative constants like treatment benefits and contraindications.
32
-
33
- - **`getTreatmentBenefits()`**: Retrieves all treatment benefits.
34
- - **`addTreatmentBenefit(benefit)`**: Adds a new treatment benefit.
35
- - **`updateTreatmentBenefit(benefit)`**: Updates an existing treatment benefit.
36
- - **`deleteTreatmentBenefit(benefitId)`**: Deletes a treatment benefit.
37
- - **`getContraindications()`**: Retrieves all contraindications.
38
- - **`addContraindication(contraindication)`**: Adds a new contraindication.
39
- - **`updateContraindication(contraindication)`**: Updates an existing contraindication.
40
- - **`deleteContraindication(contraindicationId)`**: Deletes a contraindication.