@blackcode_sa/metaestetics-api 1.7.27 → 1.7.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/index.d.mts +13 -1
- package/dist/admin/index.d.ts +13 -1
- package/dist/admin/index.js +137 -6
- package/dist/admin/index.mjs +137 -6
- package/dist/backoffice/index.d.mts +1 -0
- package/dist/backoffice/index.d.ts +1 -0
- package/dist/index.d.mts +182 -145
- package/dist/index.d.ts +182 -145
- package/dist/index.js +235 -1
- package/dist/index.mjs +235 -1
- package/package.json +1 -1
- package/src/admin/aggregation/procedure/procedure.aggregation.service.ts +202 -8
- package/src/admin/free-consultation/free-consultation-utils.admin.ts +147 -0
- package/src/services/practitioner/practitioner.service.ts +178 -1
- package/src/services/procedure/procedure.service.ts +141 -0
- package/src/types/practitioner/index.ts +3 -0
- package/src/validations/practitioner.schema.ts +3 -0
package/dist/index.js
CHANGED
|
@@ -4643,6 +4643,7 @@ var practitionerSchema = import_zod14.z.object({
|
|
|
4643
4643
|
clinicWorkingHours: import_zod14.z.array(practitionerClinicWorkingHoursSchema),
|
|
4644
4644
|
clinicsInfo: import_zod14.z.array(clinicInfoSchema),
|
|
4645
4645
|
procedures: import_zod14.z.array(import_zod14.z.string()),
|
|
4646
|
+
freeConsultations: import_zod14.z.record(import_zod14.z.string(), import_zod14.z.string()).optional().nullable(),
|
|
4646
4647
|
proceduresInfo: import_zod14.z.array(procedureSummaryInfoSchema),
|
|
4647
4648
|
reviewInfo: practitionerReviewInfoSchema,
|
|
4648
4649
|
isActive: import_zod14.z.boolean(),
|
|
@@ -4658,6 +4659,7 @@ var createPractitionerSchema = import_zod14.z.object({
|
|
|
4658
4659
|
clinics: import_zod14.z.array(import_zod14.z.string()).optional(),
|
|
4659
4660
|
clinicWorkingHours: import_zod14.z.array(practitionerClinicWorkingHoursSchema).optional(),
|
|
4660
4661
|
clinicsInfo: import_zod14.z.array(clinicInfoSchema).optional(),
|
|
4662
|
+
freeConsultations: import_zod14.z.record(import_zod14.z.string(), import_zod14.z.string()).optional().nullable(),
|
|
4661
4663
|
proceduresInfo: import_zod14.z.array(procedureSummaryInfoSchema).optional(),
|
|
4662
4664
|
isActive: import_zod14.z.boolean(),
|
|
4663
4665
|
isVerified: import_zod14.z.boolean(),
|
|
@@ -4669,6 +4671,7 @@ var createDraftPractitionerSchema = import_zod14.z.object({
|
|
|
4669
4671
|
clinics: import_zod14.z.array(import_zod14.z.string()).optional(),
|
|
4670
4672
|
clinicWorkingHours: import_zod14.z.array(practitionerClinicWorkingHoursSchema).optional(),
|
|
4671
4673
|
clinicsInfo: import_zod14.z.array(clinicInfoSchema).optional(),
|
|
4674
|
+
freeConsultations: import_zod14.z.record(import_zod14.z.string(), import_zod14.z.string()).optional().nullable(),
|
|
4672
4675
|
proceduresInfo: import_zod14.z.array(procedureSummaryInfoSchema).optional(),
|
|
4673
4676
|
isActive: import_zod14.z.boolean().optional().default(false),
|
|
4674
4677
|
isVerified: import_zod14.z.boolean().optional().default(false)
|
|
@@ -4713,9 +4716,10 @@ var practitionerSignupSchema = import_zod14.z.object({
|
|
|
4713
4716
|
var import_zod15 = require("zod");
|
|
4714
4717
|
var import_geofire_common2 = require("geofire-common");
|
|
4715
4718
|
var PractitionerService = class extends BaseService {
|
|
4716
|
-
constructor(db, auth, app, clinicService) {
|
|
4719
|
+
constructor(db, auth, app, clinicService, procedureService) {
|
|
4717
4720
|
super(db, auth, app);
|
|
4718
4721
|
this.clinicService = clinicService;
|
|
4722
|
+
this.procedureService = procedureService;
|
|
4719
4723
|
this.mediaService = new MediaService(db, auth, app);
|
|
4720
4724
|
}
|
|
4721
4725
|
getClinicService() {
|
|
@@ -4724,9 +4728,18 @@ var PractitionerService = class extends BaseService {
|
|
|
4724
4728
|
}
|
|
4725
4729
|
return this.clinicService;
|
|
4726
4730
|
}
|
|
4731
|
+
getProcedureService() {
|
|
4732
|
+
if (!this.procedureService) {
|
|
4733
|
+
throw new Error("Procedure service not initialized!");
|
|
4734
|
+
}
|
|
4735
|
+
return this.procedureService;
|
|
4736
|
+
}
|
|
4727
4737
|
setClinicService(clinicService) {
|
|
4728
4738
|
this.clinicService = clinicService;
|
|
4729
4739
|
}
|
|
4740
|
+
setProcedureService(procedureService) {
|
|
4741
|
+
this.procedureService = procedureService;
|
|
4742
|
+
}
|
|
4730
4743
|
/**
|
|
4731
4744
|
* Handles profile photo upload for practitioners
|
|
4732
4745
|
* @param profilePhoto - MediaResource (File, Blob, or URL string)
|
|
@@ -5521,6 +5534,119 @@ var PractitionerService = class extends BaseService {
|
|
|
5521
5534
|
throw error;
|
|
5522
5535
|
}
|
|
5523
5536
|
}
|
|
5537
|
+
/**
|
|
5538
|
+
* Enables free consultation for a practitioner in a specific clinic
|
|
5539
|
+
* Creates a free consultation procedure with hardcoded parameters
|
|
5540
|
+
* @param practitionerId - ID of the practitioner
|
|
5541
|
+
* @param clinicId - ID of the clinic
|
|
5542
|
+
* @returns The created consultation procedure
|
|
5543
|
+
*/
|
|
5544
|
+
async EnableFreeConsultation(practitionerId, clinicId) {
|
|
5545
|
+
try {
|
|
5546
|
+
const practitioner = await this.getPractitioner(practitionerId);
|
|
5547
|
+
if (!practitioner) {
|
|
5548
|
+
throw new Error(`Practitioner ${practitionerId} not found`);
|
|
5549
|
+
}
|
|
5550
|
+
if (!practitioner.isActive || practitioner.status !== "active" /* ACTIVE */) {
|
|
5551
|
+
throw new Error(`Practitioner ${practitionerId} is not active`);
|
|
5552
|
+
}
|
|
5553
|
+
const clinic = await this.getClinicService().getClinic(clinicId);
|
|
5554
|
+
if (!clinic) {
|
|
5555
|
+
throw new Error(`Clinic ${clinicId} not found`);
|
|
5556
|
+
}
|
|
5557
|
+
if (!practitioner.clinics.includes(clinicId)) {
|
|
5558
|
+
throw new Error(
|
|
5559
|
+
`Practitioner ${practitionerId} is not associated with clinic ${clinicId}`
|
|
5560
|
+
);
|
|
5561
|
+
}
|
|
5562
|
+
const existingProcedures = await this.getProcedureService().getProceduresByPractitioner(
|
|
5563
|
+
practitionerId
|
|
5564
|
+
);
|
|
5565
|
+
const existingConsultation = existingProcedures.find(
|
|
5566
|
+
(procedure) => procedure.name === "Free Consultation" && procedure.clinicBranchId === clinicId && procedure.isActive
|
|
5567
|
+
);
|
|
5568
|
+
if (existingConsultation) {
|
|
5569
|
+
console.log(
|
|
5570
|
+
`Free consultation already exists for practitioner ${practitionerId} in clinic ${clinicId}`
|
|
5571
|
+
);
|
|
5572
|
+
return;
|
|
5573
|
+
}
|
|
5574
|
+
const consultationData = {
|
|
5575
|
+
name: "Free Consultation",
|
|
5576
|
+
description: "Free initial consultation to discuss treatment options and assess patient needs.",
|
|
5577
|
+
family: "aesthetics" /* AESTHETICS */,
|
|
5578
|
+
categoryId: "consultation",
|
|
5579
|
+
subcategoryId: "free-consultation",
|
|
5580
|
+
technologyId: "free-consultation-tech",
|
|
5581
|
+
price: 0,
|
|
5582
|
+
currency: "EUR" /* EUR */,
|
|
5583
|
+
pricingMeasure: "per_session" /* PER_SESSION */,
|
|
5584
|
+
duration: 30,
|
|
5585
|
+
// 30 minutes consultation
|
|
5586
|
+
practitionerId,
|
|
5587
|
+
clinicBranchId: clinicId,
|
|
5588
|
+
photos: []
|
|
5589
|
+
// No photos for consultation
|
|
5590
|
+
};
|
|
5591
|
+
await this.getProcedureService().createConsultationProcedure(
|
|
5592
|
+
consultationData
|
|
5593
|
+
);
|
|
5594
|
+
console.log(
|
|
5595
|
+
`Free consultation enabled for practitioner ${practitionerId} in clinic ${clinicId}`
|
|
5596
|
+
);
|
|
5597
|
+
} catch (error) {
|
|
5598
|
+
console.error(
|
|
5599
|
+
`Error enabling free consultation for practitioner ${practitionerId} in clinic ${clinicId}:`,
|
|
5600
|
+
error
|
|
5601
|
+
);
|
|
5602
|
+
throw error;
|
|
5603
|
+
}
|
|
5604
|
+
}
|
|
5605
|
+
/**
|
|
5606
|
+
* Disables free consultation for a practitioner in a specific clinic
|
|
5607
|
+
* Finds and deactivates the existing free consultation procedure
|
|
5608
|
+
* @param practitionerId - ID of the practitioner
|
|
5609
|
+
* @param clinicId - ID of the clinic
|
|
5610
|
+
*/
|
|
5611
|
+
async DisableFreeConsultation(practitionerId, clinicId) {
|
|
5612
|
+
try {
|
|
5613
|
+
const practitioner = await this.getPractitioner(practitionerId);
|
|
5614
|
+
if (!practitioner) {
|
|
5615
|
+
throw new Error(`Practitioner ${practitionerId} not found`);
|
|
5616
|
+
}
|
|
5617
|
+
const clinic = await this.getClinicService().getClinic(clinicId);
|
|
5618
|
+
if (!clinic) {
|
|
5619
|
+
throw new Error(`Clinic ${clinicId} not found`);
|
|
5620
|
+
}
|
|
5621
|
+
if (!practitioner.clinics.includes(clinicId)) {
|
|
5622
|
+
throw new Error(
|
|
5623
|
+
`Practitioner ${practitionerId} is not associated with clinic ${clinicId}`
|
|
5624
|
+
);
|
|
5625
|
+
}
|
|
5626
|
+
const existingProcedures = await this.getProcedureService().getProceduresByPractitioner(
|
|
5627
|
+
practitionerId
|
|
5628
|
+
);
|
|
5629
|
+
const freeConsultation = existingProcedures.find(
|
|
5630
|
+
(procedure) => procedure.name === "Free Consultation" && procedure.clinicBranchId === clinicId && procedure.isActive
|
|
5631
|
+
);
|
|
5632
|
+
if (!freeConsultation) {
|
|
5633
|
+
console.log(
|
|
5634
|
+
`No active free consultation found for practitioner ${practitionerId} in clinic ${clinicId}`
|
|
5635
|
+
);
|
|
5636
|
+
return;
|
|
5637
|
+
}
|
|
5638
|
+
await this.getProcedureService().deactivateProcedure(freeConsultation.id);
|
|
5639
|
+
console.log(
|
|
5640
|
+
`Free consultation disabled for practitioner ${practitionerId} in clinic ${clinicId}`
|
|
5641
|
+
);
|
|
5642
|
+
} catch (error) {
|
|
5643
|
+
console.error(
|
|
5644
|
+
`Error disabling free consultation for practitioner ${practitionerId} in clinic ${clinicId}:`,
|
|
5645
|
+
error
|
|
5646
|
+
);
|
|
5647
|
+
throw error;
|
|
5648
|
+
}
|
|
5649
|
+
}
|
|
5524
5650
|
};
|
|
5525
5651
|
|
|
5526
5652
|
// src/services/user.service.ts
|
|
@@ -9328,6 +9454,114 @@ var ProcedureService = class extends BaseService {
|
|
|
9328
9454
|
}
|
|
9329
9455
|
return filteredProcedures;
|
|
9330
9456
|
}
|
|
9457
|
+
/**
|
|
9458
|
+
* Creates a consultation procedure without requiring a product
|
|
9459
|
+
* This is a special method for consultation procedures that don't use products
|
|
9460
|
+
* @param data - The data for creating a consultation procedure (without productId)
|
|
9461
|
+
* @returns The created procedure
|
|
9462
|
+
*/
|
|
9463
|
+
async createConsultationProcedure(data) {
|
|
9464
|
+
var _a;
|
|
9465
|
+
const procedureId = this.generateId();
|
|
9466
|
+
const [category, subcategory, technology] = await Promise.all([
|
|
9467
|
+
this.categoryService.getById(data.categoryId),
|
|
9468
|
+
this.subcategoryService.getById(data.categoryId, data.subcategoryId),
|
|
9469
|
+
this.technologyService.getById(data.technologyId)
|
|
9470
|
+
]);
|
|
9471
|
+
if (!category || !subcategory || !technology) {
|
|
9472
|
+
throw new Error("One or more required base entities not found");
|
|
9473
|
+
}
|
|
9474
|
+
const clinicRef = (0, import_firestore27.doc)(this.db, CLINICS_COLLECTION, data.clinicBranchId);
|
|
9475
|
+
const clinicSnapshot = await (0, import_firestore27.getDoc)(clinicRef);
|
|
9476
|
+
if (!clinicSnapshot.exists()) {
|
|
9477
|
+
throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
|
|
9478
|
+
}
|
|
9479
|
+
const clinic = clinicSnapshot.data();
|
|
9480
|
+
const practitionerRef = (0, import_firestore27.doc)(
|
|
9481
|
+
this.db,
|
|
9482
|
+
PRACTITIONERS_COLLECTION,
|
|
9483
|
+
data.practitionerId
|
|
9484
|
+
);
|
|
9485
|
+
const practitionerSnapshot = await (0, import_firestore27.getDoc)(practitionerRef);
|
|
9486
|
+
if (!practitionerSnapshot.exists()) {
|
|
9487
|
+
throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
|
|
9488
|
+
}
|
|
9489
|
+
const practitioner = practitionerSnapshot.data();
|
|
9490
|
+
let processedPhotos = [];
|
|
9491
|
+
if (data.photos && data.photos.length > 0) {
|
|
9492
|
+
processedPhotos = await this.processMediaArray(
|
|
9493
|
+
data.photos,
|
|
9494
|
+
procedureId,
|
|
9495
|
+
"procedure-photos"
|
|
9496
|
+
);
|
|
9497
|
+
}
|
|
9498
|
+
const clinicInfo = {
|
|
9499
|
+
id: clinicSnapshot.id,
|
|
9500
|
+
name: clinic.name,
|
|
9501
|
+
description: clinic.description || "",
|
|
9502
|
+
featuredPhoto: clinic.featuredPhotos && clinic.featuredPhotos.length > 0 ? typeof clinic.featuredPhotos[0] === "string" ? clinic.featuredPhotos[0] : "" : typeof clinic.coverPhoto === "string" ? clinic.coverPhoto : "",
|
|
9503
|
+
location: clinic.location,
|
|
9504
|
+
contactInfo: clinic.contactInfo
|
|
9505
|
+
};
|
|
9506
|
+
const doctorInfo = {
|
|
9507
|
+
id: practitionerSnapshot.id,
|
|
9508
|
+
name: `${practitioner.basicInfo.firstName} ${practitioner.basicInfo.lastName}`,
|
|
9509
|
+
description: practitioner.basicInfo.bio || "",
|
|
9510
|
+
photo: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : "",
|
|
9511
|
+
rating: ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
|
|
9512
|
+
services: practitioner.procedures || []
|
|
9513
|
+
};
|
|
9514
|
+
const consultationProduct = {
|
|
9515
|
+
id: "consultation-no-product",
|
|
9516
|
+
name: "No Product Required",
|
|
9517
|
+
description: "Consultation procedures do not require specific products",
|
|
9518
|
+
brandId: "consultation-brand",
|
|
9519
|
+
brandName: "Consultation",
|
|
9520
|
+
technologyId: data.technologyId,
|
|
9521
|
+
technologyName: technology.name,
|
|
9522
|
+
isActive: true,
|
|
9523
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
9524
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
9525
|
+
};
|
|
9526
|
+
const newProcedure = {
|
|
9527
|
+
id: procedureId,
|
|
9528
|
+
...data,
|
|
9529
|
+
photos: processedPhotos,
|
|
9530
|
+
category,
|
|
9531
|
+
subcategory,
|
|
9532
|
+
technology,
|
|
9533
|
+
product: consultationProduct,
|
|
9534
|
+
// Use placeholder product
|
|
9535
|
+
blockingConditions: technology.blockingConditions,
|
|
9536
|
+
contraindications: technology.contraindications || [],
|
|
9537
|
+
treatmentBenefits: technology.benefits,
|
|
9538
|
+
preRequirements: technology.requirements.pre,
|
|
9539
|
+
postRequirements: technology.requirements.post,
|
|
9540
|
+
certificationRequirement: technology.certificationRequirement,
|
|
9541
|
+
documentationTemplates: (technology == null ? void 0 : technology.documentationTemplates) || [],
|
|
9542
|
+
clinicInfo,
|
|
9543
|
+
doctorInfo,
|
|
9544
|
+
reviewInfo: {
|
|
9545
|
+
totalReviews: 0,
|
|
9546
|
+
averageRating: 0,
|
|
9547
|
+
effectivenessOfTreatment: 0,
|
|
9548
|
+
outcomeExplanation: 0,
|
|
9549
|
+
painManagement: 0,
|
|
9550
|
+
followUpCare: 0,
|
|
9551
|
+
valueForMoney: 0,
|
|
9552
|
+
recommendationPercentage: 0
|
|
9553
|
+
},
|
|
9554
|
+
isActive: true
|
|
9555
|
+
};
|
|
9556
|
+
const procedureRef = (0, import_firestore27.doc)(this.db, PROCEDURES_COLLECTION, procedureId);
|
|
9557
|
+
await (0, import_firestore27.setDoc)(procedureRef, {
|
|
9558
|
+
...newProcedure,
|
|
9559
|
+
createdAt: (0, import_firestore27.serverTimestamp)(),
|
|
9560
|
+
updatedAt: (0, import_firestore27.serverTimestamp)()
|
|
9561
|
+
});
|
|
9562
|
+
const savedDoc = await (0, import_firestore27.getDoc)(procedureRef);
|
|
9563
|
+
return savedDoc.data();
|
|
9564
|
+
}
|
|
9331
9565
|
};
|
|
9332
9566
|
|
|
9333
9567
|
// src/services/clinic/practitioner-invite.service.ts
|
package/dist/index.mjs
CHANGED
|
@@ -4547,6 +4547,7 @@ var practitionerSchema = z14.object({
|
|
|
4547
4547
|
clinicWorkingHours: z14.array(practitionerClinicWorkingHoursSchema),
|
|
4548
4548
|
clinicsInfo: z14.array(clinicInfoSchema),
|
|
4549
4549
|
procedures: z14.array(z14.string()),
|
|
4550
|
+
freeConsultations: z14.record(z14.string(), z14.string()).optional().nullable(),
|
|
4550
4551
|
proceduresInfo: z14.array(procedureSummaryInfoSchema),
|
|
4551
4552
|
reviewInfo: practitionerReviewInfoSchema,
|
|
4552
4553
|
isActive: z14.boolean(),
|
|
@@ -4562,6 +4563,7 @@ var createPractitionerSchema = z14.object({
|
|
|
4562
4563
|
clinics: z14.array(z14.string()).optional(),
|
|
4563
4564
|
clinicWorkingHours: z14.array(practitionerClinicWorkingHoursSchema).optional(),
|
|
4564
4565
|
clinicsInfo: z14.array(clinicInfoSchema).optional(),
|
|
4566
|
+
freeConsultations: z14.record(z14.string(), z14.string()).optional().nullable(),
|
|
4565
4567
|
proceduresInfo: z14.array(procedureSummaryInfoSchema).optional(),
|
|
4566
4568
|
isActive: z14.boolean(),
|
|
4567
4569
|
isVerified: z14.boolean(),
|
|
@@ -4573,6 +4575,7 @@ var createDraftPractitionerSchema = z14.object({
|
|
|
4573
4575
|
clinics: z14.array(z14.string()).optional(),
|
|
4574
4576
|
clinicWorkingHours: z14.array(practitionerClinicWorkingHoursSchema).optional(),
|
|
4575
4577
|
clinicsInfo: z14.array(clinicInfoSchema).optional(),
|
|
4578
|
+
freeConsultations: z14.record(z14.string(), z14.string()).optional().nullable(),
|
|
4576
4579
|
proceduresInfo: z14.array(procedureSummaryInfoSchema).optional(),
|
|
4577
4580
|
isActive: z14.boolean().optional().default(false),
|
|
4578
4581
|
isVerified: z14.boolean().optional().default(false)
|
|
@@ -4617,9 +4620,10 @@ var practitionerSignupSchema = z14.object({
|
|
|
4617
4620
|
import { z as z15 } from "zod";
|
|
4618
4621
|
import { distanceBetween } from "geofire-common";
|
|
4619
4622
|
var PractitionerService = class extends BaseService {
|
|
4620
|
-
constructor(db, auth, app, clinicService) {
|
|
4623
|
+
constructor(db, auth, app, clinicService, procedureService) {
|
|
4621
4624
|
super(db, auth, app);
|
|
4622
4625
|
this.clinicService = clinicService;
|
|
4626
|
+
this.procedureService = procedureService;
|
|
4623
4627
|
this.mediaService = new MediaService(db, auth, app);
|
|
4624
4628
|
}
|
|
4625
4629
|
getClinicService() {
|
|
@@ -4628,9 +4632,18 @@ var PractitionerService = class extends BaseService {
|
|
|
4628
4632
|
}
|
|
4629
4633
|
return this.clinicService;
|
|
4630
4634
|
}
|
|
4635
|
+
getProcedureService() {
|
|
4636
|
+
if (!this.procedureService) {
|
|
4637
|
+
throw new Error("Procedure service not initialized!");
|
|
4638
|
+
}
|
|
4639
|
+
return this.procedureService;
|
|
4640
|
+
}
|
|
4631
4641
|
setClinicService(clinicService) {
|
|
4632
4642
|
this.clinicService = clinicService;
|
|
4633
4643
|
}
|
|
4644
|
+
setProcedureService(procedureService) {
|
|
4645
|
+
this.procedureService = procedureService;
|
|
4646
|
+
}
|
|
4634
4647
|
/**
|
|
4635
4648
|
* Handles profile photo upload for practitioners
|
|
4636
4649
|
* @param profilePhoto - MediaResource (File, Blob, or URL string)
|
|
@@ -5425,6 +5438,119 @@ var PractitionerService = class extends BaseService {
|
|
|
5425
5438
|
throw error;
|
|
5426
5439
|
}
|
|
5427
5440
|
}
|
|
5441
|
+
/**
|
|
5442
|
+
* Enables free consultation for a practitioner in a specific clinic
|
|
5443
|
+
* Creates a free consultation procedure with hardcoded parameters
|
|
5444
|
+
* @param practitionerId - ID of the practitioner
|
|
5445
|
+
* @param clinicId - ID of the clinic
|
|
5446
|
+
* @returns The created consultation procedure
|
|
5447
|
+
*/
|
|
5448
|
+
async EnableFreeConsultation(practitionerId, clinicId) {
|
|
5449
|
+
try {
|
|
5450
|
+
const practitioner = await this.getPractitioner(practitionerId);
|
|
5451
|
+
if (!practitioner) {
|
|
5452
|
+
throw new Error(`Practitioner ${practitionerId} not found`);
|
|
5453
|
+
}
|
|
5454
|
+
if (!practitioner.isActive || practitioner.status !== "active" /* ACTIVE */) {
|
|
5455
|
+
throw new Error(`Practitioner ${practitionerId} is not active`);
|
|
5456
|
+
}
|
|
5457
|
+
const clinic = await this.getClinicService().getClinic(clinicId);
|
|
5458
|
+
if (!clinic) {
|
|
5459
|
+
throw new Error(`Clinic ${clinicId} not found`);
|
|
5460
|
+
}
|
|
5461
|
+
if (!practitioner.clinics.includes(clinicId)) {
|
|
5462
|
+
throw new Error(
|
|
5463
|
+
`Practitioner ${practitionerId} is not associated with clinic ${clinicId}`
|
|
5464
|
+
);
|
|
5465
|
+
}
|
|
5466
|
+
const existingProcedures = await this.getProcedureService().getProceduresByPractitioner(
|
|
5467
|
+
practitionerId
|
|
5468
|
+
);
|
|
5469
|
+
const existingConsultation = existingProcedures.find(
|
|
5470
|
+
(procedure) => procedure.name === "Free Consultation" && procedure.clinicBranchId === clinicId && procedure.isActive
|
|
5471
|
+
);
|
|
5472
|
+
if (existingConsultation) {
|
|
5473
|
+
console.log(
|
|
5474
|
+
`Free consultation already exists for practitioner ${practitionerId} in clinic ${clinicId}`
|
|
5475
|
+
);
|
|
5476
|
+
return;
|
|
5477
|
+
}
|
|
5478
|
+
const consultationData = {
|
|
5479
|
+
name: "Free Consultation",
|
|
5480
|
+
description: "Free initial consultation to discuss treatment options and assess patient needs.",
|
|
5481
|
+
family: "aesthetics" /* AESTHETICS */,
|
|
5482
|
+
categoryId: "consultation",
|
|
5483
|
+
subcategoryId: "free-consultation",
|
|
5484
|
+
technologyId: "free-consultation-tech",
|
|
5485
|
+
price: 0,
|
|
5486
|
+
currency: "EUR" /* EUR */,
|
|
5487
|
+
pricingMeasure: "per_session" /* PER_SESSION */,
|
|
5488
|
+
duration: 30,
|
|
5489
|
+
// 30 minutes consultation
|
|
5490
|
+
practitionerId,
|
|
5491
|
+
clinicBranchId: clinicId,
|
|
5492
|
+
photos: []
|
|
5493
|
+
// No photos for consultation
|
|
5494
|
+
};
|
|
5495
|
+
await this.getProcedureService().createConsultationProcedure(
|
|
5496
|
+
consultationData
|
|
5497
|
+
);
|
|
5498
|
+
console.log(
|
|
5499
|
+
`Free consultation enabled for practitioner ${practitionerId} in clinic ${clinicId}`
|
|
5500
|
+
);
|
|
5501
|
+
} catch (error) {
|
|
5502
|
+
console.error(
|
|
5503
|
+
`Error enabling free consultation for practitioner ${practitionerId} in clinic ${clinicId}:`,
|
|
5504
|
+
error
|
|
5505
|
+
);
|
|
5506
|
+
throw error;
|
|
5507
|
+
}
|
|
5508
|
+
}
|
|
5509
|
+
/**
|
|
5510
|
+
* Disables free consultation for a practitioner in a specific clinic
|
|
5511
|
+
* Finds and deactivates the existing free consultation procedure
|
|
5512
|
+
* @param practitionerId - ID of the practitioner
|
|
5513
|
+
* @param clinicId - ID of the clinic
|
|
5514
|
+
*/
|
|
5515
|
+
async DisableFreeConsultation(practitionerId, clinicId) {
|
|
5516
|
+
try {
|
|
5517
|
+
const practitioner = await this.getPractitioner(practitionerId);
|
|
5518
|
+
if (!practitioner) {
|
|
5519
|
+
throw new Error(`Practitioner ${practitionerId} not found`);
|
|
5520
|
+
}
|
|
5521
|
+
const clinic = await this.getClinicService().getClinic(clinicId);
|
|
5522
|
+
if (!clinic) {
|
|
5523
|
+
throw new Error(`Clinic ${clinicId} not found`);
|
|
5524
|
+
}
|
|
5525
|
+
if (!practitioner.clinics.includes(clinicId)) {
|
|
5526
|
+
throw new Error(
|
|
5527
|
+
`Practitioner ${practitionerId} is not associated with clinic ${clinicId}`
|
|
5528
|
+
);
|
|
5529
|
+
}
|
|
5530
|
+
const existingProcedures = await this.getProcedureService().getProceduresByPractitioner(
|
|
5531
|
+
practitionerId
|
|
5532
|
+
);
|
|
5533
|
+
const freeConsultation = existingProcedures.find(
|
|
5534
|
+
(procedure) => procedure.name === "Free Consultation" && procedure.clinicBranchId === clinicId && procedure.isActive
|
|
5535
|
+
);
|
|
5536
|
+
if (!freeConsultation) {
|
|
5537
|
+
console.log(
|
|
5538
|
+
`No active free consultation found for practitioner ${practitionerId} in clinic ${clinicId}`
|
|
5539
|
+
);
|
|
5540
|
+
return;
|
|
5541
|
+
}
|
|
5542
|
+
await this.getProcedureService().deactivateProcedure(freeConsultation.id);
|
|
5543
|
+
console.log(
|
|
5544
|
+
`Free consultation disabled for practitioner ${practitionerId} in clinic ${clinicId}`
|
|
5545
|
+
);
|
|
5546
|
+
} catch (error) {
|
|
5547
|
+
console.error(
|
|
5548
|
+
`Error disabling free consultation for practitioner ${practitionerId} in clinic ${clinicId}:`,
|
|
5549
|
+
error
|
|
5550
|
+
);
|
|
5551
|
+
throw error;
|
|
5552
|
+
}
|
|
5553
|
+
}
|
|
5428
5554
|
};
|
|
5429
5555
|
|
|
5430
5556
|
// src/services/user.service.ts
|
|
@@ -9313,6 +9439,114 @@ var ProcedureService = class extends BaseService {
|
|
|
9313
9439
|
}
|
|
9314
9440
|
return filteredProcedures;
|
|
9315
9441
|
}
|
|
9442
|
+
/**
|
|
9443
|
+
* Creates a consultation procedure without requiring a product
|
|
9444
|
+
* This is a special method for consultation procedures that don't use products
|
|
9445
|
+
* @param data - The data for creating a consultation procedure (without productId)
|
|
9446
|
+
* @returns The created procedure
|
|
9447
|
+
*/
|
|
9448
|
+
async createConsultationProcedure(data) {
|
|
9449
|
+
var _a;
|
|
9450
|
+
const procedureId = this.generateId();
|
|
9451
|
+
const [category, subcategory, technology] = await Promise.all([
|
|
9452
|
+
this.categoryService.getById(data.categoryId),
|
|
9453
|
+
this.subcategoryService.getById(data.categoryId, data.subcategoryId),
|
|
9454
|
+
this.technologyService.getById(data.technologyId)
|
|
9455
|
+
]);
|
|
9456
|
+
if (!category || !subcategory || !technology) {
|
|
9457
|
+
throw new Error("One or more required base entities not found");
|
|
9458
|
+
}
|
|
9459
|
+
const clinicRef = doc16(this.db, CLINICS_COLLECTION, data.clinicBranchId);
|
|
9460
|
+
const clinicSnapshot = await getDoc19(clinicRef);
|
|
9461
|
+
if (!clinicSnapshot.exists()) {
|
|
9462
|
+
throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
|
|
9463
|
+
}
|
|
9464
|
+
const clinic = clinicSnapshot.data();
|
|
9465
|
+
const practitionerRef = doc16(
|
|
9466
|
+
this.db,
|
|
9467
|
+
PRACTITIONERS_COLLECTION,
|
|
9468
|
+
data.practitionerId
|
|
9469
|
+
);
|
|
9470
|
+
const practitionerSnapshot = await getDoc19(practitionerRef);
|
|
9471
|
+
if (!practitionerSnapshot.exists()) {
|
|
9472
|
+
throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
|
|
9473
|
+
}
|
|
9474
|
+
const practitioner = practitionerSnapshot.data();
|
|
9475
|
+
let processedPhotos = [];
|
|
9476
|
+
if (data.photos && data.photos.length > 0) {
|
|
9477
|
+
processedPhotos = await this.processMediaArray(
|
|
9478
|
+
data.photos,
|
|
9479
|
+
procedureId,
|
|
9480
|
+
"procedure-photos"
|
|
9481
|
+
);
|
|
9482
|
+
}
|
|
9483
|
+
const clinicInfo = {
|
|
9484
|
+
id: clinicSnapshot.id,
|
|
9485
|
+
name: clinic.name,
|
|
9486
|
+
description: clinic.description || "",
|
|
9487
|
+
featuredPhoto: clinic.featuredPhotos && clinic.featuredPhotos.length > 0 ? typeof clinic.featuredPhotos[0] === "string" ? clinic.featuredPhotos[0] : "" : typeof clinic.coverPhoto === "string" ? clinic.coverPhoto : "",
|
|
9488
|
+
location: clinic.location,
|
|
9489
|
+
contactInfo: clinic.contactInfo
|
|
9490
|
+
};
|
|
9491
|
+
const doctorInfo = {
|
|
9492
|
+
id: practitionerSnapshot.id,
|
|
9493
|
+
name: `${practitioner.basicInfo.firstName} ${practitioner.basicInfo.lastName}`,
|
|
9494
|
+
description: practitioner.basicInfo.bio || "",
|
|
9495
|
+
photo: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : "",
|
|
9496
|
+
rating: ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
|
|
9497
|
+
services: practitioner.procedures || []
|
|
9498
|
+
};
|
|
9499
|
+
const consultationProduct = {
|
|
9500
|
+
id: "consultation-no-product",
|
|
9501
|
+
name: "No Product Required",
|
|
9502
|
+
description: "Consultation procedures do not require specific products",
|
|
9503
|
+
brandId: "consultation-brand",
|
|
9504
|
+
brandName: "Consultation",
|
|
9505
|
+
technologyId: data.technologyId,
|
|
9506
|
+
technologyName: technology.name,
|
|
9507
|
+
isActive: true,
|
|
9508
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
9509
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
9510
|
+
};
|
|
9511
|
+
const newProcedure = {
|
|
9512
|
+
id: procedureId,
|
|
9513
|
+
...data,
|
|
9514
|
+
photos: processedPhotos,
|
|
9515
|
+
category,
|
|
9516
|
+
subcategory,
|
|
9517
|
+
technology,
|
|
9518
|
+
product: consultationProduct,
|
|
9519
|
+
// Use placeholder product
|
|
9520
|
+
blockingConditions: technology.blockingConditions,
|
|
9521
|
+
contraindications: technology.contraindications || [],
|
|
9522
|
+
treatmentBenefits: technology.benefits,
|
|
9523
|
+
preRequirements: technology.requirements.pre,
|
|
9524
|
+
postRequirements: technology.requirements.post,
|
|
9525
|
+
certificationRequirement: technology.certificationRequirement,
|
|
9526
|
+
documentationTemplates: (technology == null ? void 0 : technology.documentationTemplates) || [],
|
|
9527
|
+
clinicInfo,
|
|
9528
|
+
doctorInfo,
|
|
9529
|
+
reviewInfo: {
|
|
9530
|
+
totalReviews: 0,
|
|
9531
|
+
averageRating: 0,
|
|
9532
|
+
effectivenessOfTreatment: 0,
|
|
9533
|
+
outcomeExplanation: 0,
|
|
9534
|
+
painManagement: 0,
|
|
9535
|
+
followUpCare: 0,
|
|
9536
|
+
valueForMoney: 0,
|
|
9537
|
+
recommendationPercentage: 0
|
|
9538
|
+
},
|
|
9539
|
+
isActive: true
|
|
9540
|
+
};
|
|
9541
|
+
const procedureRef = doc16(this.db, PROCEDURES_COLLECTION, procedureId);
|
|
9542
|
+
await setDoc14(procedureRef, {
|
|
9543
|
+
...newProcedure,
|
|
9544
|
+
createdAt: serverTimestamp14(),
|
|
9545
|
+
updatedAt: serverTimestamp14()
|
|
9546
|
+
});
|
|
9547
|
+
const savedDoc = await getDoc19(procedureRef);
|
|
9548
|
+
return savedDoc.data();
|
|
9549
|
+
}
|
|
9316
9550
|
};
|
|
9317
9551
|
|
|
9318
9552
|
// src/services/clinic/practitioner-invite.service.ts
|
package/package.json
CHANGED