@blackcode_sa/metaestetics-api 1.12.41 → 1.12.43
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 +4 -4
- package/dist/admin/index.d.ts +4 -4
- package/dist/backoffice/index.d.mts +105 -7
- package/dist/backoffice/index.d.ts +105 -7
- package/dist/backoffice/index.js +552 -8
- package/dist/backoffice/index.mjs +566 -21
- package/dist/index.d.mts +93 -7
- package/dist/index.d.ts +93 -7
- package/dist/index.js +493 -8
- package/dist/index.mjs +493 -8
- package/package.json +1 -1
- package/src/backoffice/services/brand.service.ts +86 -0
- package/src/backoffice/services/category.service.ts +84 -0
- package/src/backoffice/services/constants.service.ts +77 -0
- package/src/backoffice/services/product.service.ts +113 -10
- package/src/backoffice/services/requirement.service.ts +76 -0
- package/src/backoffice/services/subcategory.service.ts +87 -0
- package/src/backoffice/services/technology.service.ts +178 -0
- package/src/backoffice/types/product.types.ts +7 -6
package/dist/index.js
CHANGED
|
@@ -18238,6 +18238,73 @@ var BrandService = class extends BaseService {
|
|
|
18238
18238
|
...docSnap.data()
|
|
18239
18239
|
};
|
|
18240
18240
|
}
|
|
18241
|
+
/**
|
|
18242
|
+
* Exports brands to CSV string, suitable for Excel/Sheets.
|
|
18243
|
+
* Includes headers and optional UTF-8 BOM.
|
|
18244
|
+
* By default exports only active brands (set includeInactive to true to export all).
|
|
18245
|
+
*/
|
|
18246
|
+
async exportToCsv(options) {
|
|
18247
|
+
var _a, _b;
|
|
18248
|
+
const includeInactive = (_a = options == null ? void 0 : options.includeInactive) != null ? _a : false;
|
|
18249
|
+
const includeBom = (_b = options == null ? void 0 : options.includeBom) != null ? _b : true;
|
|
18250
|
+
const headers = [
|
|
18251
|
+
"id",
|
|
18252
|
+
"name",
|
|
18253
|
+
"manufacturer",
|
|
18254
|
+
"website",
|
|
18255
|
+
"description",
|
|
18256
|
+
"isActive"
|
|
18257
|
+
];
|
|
18258
|
+
const rows = [];
|
|
18259
|
+
rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
|
|
18260
|
+
const PAGE_SIZE = 1e3;
|
|
18261
|
+
let cursor;
|
|
18262
|
+
const baseConstraints = [];
|
|
18263
|
+
if (!includeInactive) {
|
|
18264
|
+
baseConstraints.push((0, import_firestore58.where)("isActive", "==", true));
|
|
18265
|
+
}
|
|
18266
|
+
baseConstraints.push((0, import_firestore58.orderBy)("name_lowercase"));
|
|
18267
|
+
while (true) {
|
|
18268
|
+
const constraints = [...baseConstraints, (0, import_firestore58.limit)(PAGE_SIZE)];
|
|
18269
|
+
if (cursor) constraints.push((0, import_firestore58.startAfter)(cursor));
|
|
18270
|
+
const q = (0, import_firestore58.query)(this.getBrandsRef(), ...constraints);
|
|
18271
|
+
const snapshot = await (0, import_firestore58.getDocs)(q);
|
|
18272
|
+
if (snapshot.empty) break;
|
|
18273
|
+
for (const d of snapshot.docs) {
|
|
18274
|
+
const brand = { id: d.id, ...d.data() };
|
|
18275
|
+
rows.push(this.brandToCsvRow(brand));
|
|
18276
|
+
}
|
|
18277
|
+
cursor = snapshot.docs[snapshot.docs.length - 1];
|
|
18278
|
+
if (snapshot.size < PAGE_SIZE) break;
|
|
18279
|
+
}
|
|
18280
|
+
const csvBody = rows.join("\r\n");
|
|
18281
|
+
return includeBom ? "\uFEFF" + csvBody : csvBody;
|
|
18282
|
+
}
|
|
18283
|
+
brandToCsvRow(brand) {
|
|
18284
|
+
var _a, _b, _c, _d, _e, _f;
|
|
18285
|
+
const values = [
|
|
18286
|
+
(_a = brand.id) != null ? _a : "",
|
|
18287
|
+
(_b = brand.name) != null ? _b : "",
|
|
18288
|
+
(_c = brand.manufacturer) != null ? _c : "",
|
|
18289
|
+
(_d = brand.website) != null ? _d : "",
|
|
18290
|
+
(_e = brand.description) != null ? _e : "",
|
|
18291
|
+
String((_f = brand.isActive) != null ? _f : "")
|
|
18292
|
+
];
|
|
18293
|
+
return values.map((v) => this.formatCsvValue(v)).join(",");
|
|
18294
|
+
}
|
|
18295
|
+
formatDateIso(value) {
|
|
18296
|
+
if (value instanceof Date) return value.toISOString();
|
|
18297
|
+
if (value && typeof value.toDate === "function") {
|
|
18298
|
+
const d = value.toDate();
|
|
18299
|
+
return d instanceof Date ? d.toISOString() : String(value);
|
|
18300
|
+
}
|
|
18301
|
+
return String(value != null ? value : "");
|
|
18302
|
+
}
|
|
18303
|
+
formatCsvValue(value) {
|
|
18304
|
+
const str = value === null || value === void 0 ? "" : String(value);
|
|
18305
|
+
const escaped = str.replace(/"/g, '""');
|
|
18306
|
+
return `"${escaped}"`;
|
|
18307
|
+
}
|
|
18241
18308
|
};
|
|
18242
18309
|
|
|
18243
18310
|
// src/backoffice/services/category.service.ts
|
|
@@ -18416,6 +18483,71 @@ var CategoryService = class extends BaseService {
|
|
|
18416
18483
|
...docSnap.data()
|
|
18417
18484
|
};
|
|
18418
18485
|
}
|
|
18486
|
+
/**
|
|
18487
|
+
* Exports categories to CSV string, suitable for Excel/Sheets.
|
|
18488
|
+
* Includes headers and optional UTF-8 BOM.
|
|
18489
|
+
* By default exports only active categories (set includeInactive to true to export all).
|
|
18490
|
+
*/
|
|
18491
|
+
async exportToCsv(options) {
|
|
18492
|
+
var _a, _b;
|
|
18493
|
+
const includeInactive = (_a = options == null ? void 0 : options.includeInactive) != null ? _a : false;
|
|
18494
|
+
const includeBom = (_b = options == null ? void 0 : options.includeBom) != null ? _b : true;
|
|
18495
|
+
const headers = [
|
|
18496
|
+
"id",
|
|
18497
|
+
"name",
|
|
18498
|
+
"description",
|
|
18499
|
+
"family",
|
|
18500
|
+
"isActive"
|
|
18501
|
+
];
|
|
18502
|
+
const rows = [];
|
|
18503
|
+
rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
|
|
18504
|
+
const PAGE_SIZE = 1e3;
|
|
18505
|
+
let cursor;
|
|
18506
|
+
const constraints = [];
|
|
18507
|
+
if (!includeInactive) {
|
|
18508
|
+
constraints.push((0, import_firestore59.where)("isActive", "==", true));
|
|
18509
|
+
}
|
|
18510
|
+
constraints.push((0, import_firestore59.orderBy)("name"));
|
|
18511
|
+
while (true) {
|
|
18512
|
+
const queryConstraints = [...constraints, (0, import_firestore59.limit)(PAGE_SIZE)];
|
|
18513
|
+
if (cursor) queryConstraints.push((0, import_firestore59.startAfter)(cursor));
|
|
18514
|
+
const q = (0, import_firestore59.query)(this.categoriesRef, ...queryConstraints);
|
|
18515
|
+
const snapshot = await (0, import_firestore59.getDocs)(q);
|
|
18516
|
+
if (snapshot.empty) break;
|
|
18517
|
+
for (const d of snapshot.docs) {
|
|
18518
|
+
const category = { id: d.id, ...d.data() };
|
|
18519
|
+
rows.push(this.categoryToCsvRow(category));
|
|
18520
|
+
}
|
|
18521
|
+
cursor = snapshot.docs[snapshot.docs.length - 1];
|
|
18522
|
+
if (snapshot.size < PAGE_SIZE) break;
|
|
18523
|
+
}
|
|
18524
|
+
const csvBody = rows.join("\r\n");
|
|
18525
|
+
return includeBom ? "\uFEFF" + csvBody : csvBody;
|
|
18526
|
+
}
|
|
18527
|
+
categoryToCsvRow(category) {
|
|
18528
|
+
var _a, _b, _c, _d, _e;
|
|
18529
|
+
const values = [
|
|
18530
|
+
(_a = category.id) != null ? _a : "",
|
|
18531
|
+
(_b = category.name) != null ? _b : "",
|
|
18532
|
+
(_c = category.description) != null ? _c : "",
|
|
18533
|
+
(_d = category.family) != null ? _d : "",
|
|
18534
|
+
String((_e = category.isActive) != null ? _e : "")
|
|
18535
|
+
];
|
|
18536
|
+
return values.map((v) => this.formatCsvValue(v)).join(",");
|
|
18537
|
+
}
|
|
18538
|
+
formatDateIso(value) {
|
|
18539
|
+
if (value instanceof Date) return value.toISOString();
|
|
18540
|
+
if (value && typeof value.toDate === "function") {
|
|
18541
|
+
const d = value.toDate();
|
|
18542
|
+
return d instanceof Date ? d.toISOString() : String(value);
|
|
18543
|
+
}
|
|
18544
|
+
return String(value != null ? value : "");
|
|
18545
|
+
}
|
|
18546
|
+
formatCsvValue(value) {
|
|
18547
|
+
const str = value === null || value === void 0 ? "" : String(value);
|
|
18548
|
+
const escaped = str.replace(/"/g, '""');
|
|
18549
|
+
return `"${escaped}"`;
|
|
18550
|
+
}
|
|
18419
18551
|
};
|
|
18420
18552
|
|
|
18421
18553
|
// src/backoffice/services/subcategory.service.ts
|
|
@@ -18643,6 +18775,74 @@ var SubcategoryService = class extends BaseService {
|
|
|
18643
18775
|
...docSnap.data()
|
|
18644
18776
|
};
|
|
18645
18777
|
}
|
|
18778
|
+
/**
|
|
18779
|
+
* Exports subcategories to CSV string, suitable for Excel/Sheets.
|
|
18780
|
+
* Includes headers and optional UTF-8 BOM.
|
|
18781
|
+
* By default exports only active subcategories (set includeInactive to true to export all).
|
|
18782
|
+
*/
|
|
18783
|
+
async exportToCsv(options) {
|
|
18784
|
+
var _a, _b;
|
|
18785
|
+
const includeInactive = (_a = options == null ? void 0 : options.includeInactive) != null ? _a : false;
|
|
18786
|
+
const includeBom = (_b = options == null ? void 0 : options.includeBom) != null ? _b : true;
|
|
18787
|
+
const headers = [
|
|
18788
|
+
"id",
|
|
18789
|
+
"name",
|
|
18790
|
+
"categoryId",
|
|
18791
|
+
"description",
|
|
18792
|
+
"isActive"
|
|
18793
|
+
];
|
|
18794
|
+
const rows = [];
|
|
18795
|
+
rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
|
|
18796
|
+
const PAGE_SIZE = 1e3;
|
|
18797
|
+
let cursor;
|
|
18798
|
+
const constraints = [];
|
|
18799
|
+
if (!includeInactive) {
|
|
18800
|
+
constraints.push((0, import_firestore60.where)("isActive", "==", true));
|
|
18801
|
+
}
|
|
18802
|
+
constraints.push((0, import_firestore60.orderBy)("name"));
|
|
18803
|
+
while (true) {
|
|
18804
|
+
const queryConstraints = [...constraints, (0, import_firestore60.limit)(PAGE_SIZE)];
|
|
18805
|
+
if (cursor) queryConstraints.push((0, import_firestore60.startAfter)(cursor));
|
|
18806
|
+
const q = (0, import_firestore60.query)(
|
|
18807
|
+
(0, import_firestore60.collectionGroup)(this.db, SUBCATEGORIES_COLLECTION),
|
|
18808
|
+
...queryConstraints
|
|
18809
|
+
);
|
|
18810
|
+
const snapshot = await (0, import_firestore60.getDocs)(q);
|
|
18811
|
+
if (snapshot.empty) break;
|
|
18812
|
+
for (const d of snapshot.docs) {
|
|
18813
|
+
const subcategory = { id: d.id, ...d.data() };
|
|
18814
|
+
rows.push(this.subcategoryToCsvRow(subcategory));
|
|
18815
|
+
}
|
|
18816
|
+
cursor = snapshot.docs[snapshot.docs.length - 1];
|
|
18817
|
+
if (snapshot.size < PAGE_SIZE) break;
|
|
18818
|
+
}
|
|
18819
|
+
const csvBody = rows.join("\r\n");
|
|
18820
|
+
return includeBom ? "\uFEFF" + csvBody : csvBody;
|
|
18821
|
+
}
|
|
18822
|
+
subcategoryToCsvRow(subcategory) {
|
|
18823
|
+
var _a, _b, _c, _d, _e;
|
|
18824
|
+
const values = [
|
|
18825
|
+
(_a = subcategory.id) != null ? _a : "",
|
|
18826
|
+
(_b = subcategory.name) != null ? _b : "",
|
|
18827
|
+
(_c = subcategory.categoryId) != null ? _c : "",
|
|
18828
|
+
(_d = subcategory.description) != null ? _d : "",
|
|
18829
|
+
String((_e = subcategory.isActive) != null ? _e : "")
|
|
18830
|
+
];
|
|
18831
|
+
return values.map((v) => this.formatCsvValue(v)).join(",");
|
|
18832
|
+
}
|
|
18833
|
+
formatDateIso(value) {
|
|
18834
|
+
if (value instanceof Date) return value.toISOString();
|
|
18835
|
+
if (value && typeof value.toDate === "function") {
|
|
18836
|
+
const d = value.toDate();
|
|
18837
|
+
return d instanceof Date ? d.toISOString() : String(value);
|
|
18838
|
+
}
|
|
18839
|
+
return String(value != null ? value : "");
|
|
18840
|
+
}
|
|
18841
|
+
formatCsvValue(value) {
|
|
18842
|
+
const str = value === null || value === void 0 ? "" : String(value);
|
|
18843
|
+
const escaped = str.replace(/"/g, '""');
|
|
18844
|
+
return `"${escaped}"`;
|
|
18845
|
+
}
|
|
18646
18846
|
};
|
|
18647
18847
|
|
|
18648
18848
|
// src/backoffice/services/technology.service.ts
|
|
@@ -18813,7 +19013,18 @@ var TechnologyService = class extends BaseService {
|
|
|
18813
19013
|
});
|
|
18814
19014
|
updateData.updatedAt = /* @__PURE__ */ new Date();
|
|
18815
19015
|
const docRef = (0, import_firestore61.doc)(this.technologiesRef, id);
|
|
19016
|
+
const beforeTech = await this.getById(id);
|
|
18816
19017
|
await (0, import_firestore61.updateDoc)(docRef, updateData);
|
|
19018
|
+
const categoryChanged = beforeTech && updateData.categoryId && beforeTech.categoryId !== updateData.categoryId;
|
|
19019
|
+
const subcategoryChanged = beforeTech && updateData.subcategoryId && beforeTech.subcategoryId !== updateData.subcategoryId;
|
|
19020
|
+
const nameChanged = beforeTech && updateData.name && beforeTech.name !== updateData.name;
|
|
19021
|
+
if (categoryChanged || subcategoryChanged || nameChanged) {
|
|
19022
|
+
await this.updateProductsInSubcollection(id, {
|
|
19023
|
+
categoryId: updateData.categoryId,
|
|
19024
|
+
subcategoryId: updateData.subcategoryId,
|
|
19025
|
+
technologyName: updateData.name
|
|
19026
|
+
});
|
|
19027
|
+
}
|
|
18817
19028
|
return this.getById(id);
|
|
18818
19029
|
}
|
|
18819
19030
|
/**
|
|
@@ -19338,6 +19549,136 @@ var TechnologyService = class extends BaseService {
|
|
|
19338
19549
|
byBrand
|
|
19339
19550
|
};
|
|
19340
19551
|
}
|
|
19552
|
+
/**
|
|
19553
|
+
* Updates products in technology subcollection when technology metadata changes
|
|
19554
|
+
* @param technologyId - ID of the technology
|
|
19555
|
+
* @param updates - Fields to update (categoryId, subcategoryId, technologyName)
|
|
19556
|
+
*/
|
|
19557
|
+
async updateProductsInSubcollection(technologyId, updates) {
|
|
19558
|
+
const productsRef = (0, import_firestore61.collection)(this.db, TECHNOLOGIES_COLLECTION, technologyId, PRODUCTS_COLLECTION);
|
|
19559
|
+
const productsSnapshot = await (0, import_firestore61.getDocs)(productsRef);
|
|
19560
|
+
if (productsSnapshot.empty) {
|
|
19561
|
+
return;
|
|
19562
|
+
}
|
|
19563
|
+
const batch = (0, import_firestore61.writeBatch)(this.db);
|
|
19564
|
+
for (const productDoc of productsSnapshot.docs) {
|
|
19565
|
+
const productRef = productDoc.ref;
|
|
19566
|
+
const updateFields = {};
|
|
19567
|
+
if (updates.categoryId !== void 0) {
|
|
19568
|
+
updateFields.categoryId = updates.categoryId;
|
|
19569
|
+
}
|
|
19570
|
+
if (updates.subcategoryId !== void 0) {
|
|
19571
|
+
updateFields.subcategoryId = updates.subcategoryId;
|
|
19572
|
+
}
|
|
19573
|
+
if (updates.technologyName !== void 0) {
|
|
19574
|
+
updateFields.technologyName = updates.technologyName;
|
|
19575
|
+
}
|
|
19576
|
+
if (Object.keys(updateFields).length > 0) {
|
|
19577
|
+
batch.update(productRef, updateFields);
|
|
19578
|
+
}
|
|
19579
|
+
}
|
|
19580
|
+
await batch.commit();
|
|
19581
|
+
}
|
|
19582
|
+
/**
|
|
19583
|
+
* Exports technologies to CSV string, suitable for Excel/Sheets.
|
|
19584
|
+
* Includes headers and optional UTF-8 BOM.
|
|
19585
|
+
* By default exports only active technologies (set includeInactive to true to export all).
|
|
19586
|
+
* Includes product names from subcollections.
|
|
19587
|
+
*/
|
|
19588
|
+
async exportToCsv(options) {
|
|
19589
|
+
var _a, _b;
|
|
19590
|
+
const includeInactive = (_a = options == null ? void 0 : options.includeInactive) != null ? _a : false;
|
|
19591
|
+
const includeBom = (_b = options == null ? void 0 : options.includeBom) != null ? _b : true;
|
|
19592
|
+
const headers = [
|
|
19593
|
+
"id",
|
|
19594
|
+
"name",
|
|
19595
|
+
"description",
|
|
19596
|
+
"family",
|
|
19597
|
+
"categoryId",
|
|
19598
|
+
"subcategoryId",
|
|
19599
|
+
"technicalDetails",
|
|
19600
|
+
"requirements_pre",
|
|
19601
|
+
"requirements_post",
|
|
19602
|
+
"blockingConditions",
|
|
19603
|
+
"contraindications",
|
|
19604
|
+
"benefits",
|
|
19605
|
+
"certificationMinimumLevel",
|
|
19606
|
+
"certificationRequiredSpecialties",
|
|
19607
|
+
"documentationTemplateIds",
|
|
19608
|
+
"productNames",
|
|
19609
|
+
"isActive"
|
|
19610
|
+
];
|
|
19611
|
+
const rows = [];
|
|
19612
|
+
rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
|
|
19613
|
+
const PAGE_SIZE = 1e3;
|
|
19614
|
+
let cursor;
|
|
19615
|
+
const constraints = [];
|
|
19616
|
+
if (!includeInactive) {
|
|
19617
|
+
constraints.push((0, import_firestore61.where)("isActive", "==", true));
|
|
19618
|
+
}
|
|
19619
|
+
constraints.push((0, import_firestore61.orderBy)("name"));
|
|
19620
|
+
while (true) {
|
|
19621
|
+
const queryConstraints = [...constraints, (0, import_firestore61.limit)(PAGE_SIZE)];
|
|
19622
|
+
if (cursor) queryConstraints.push((0, import_firestore61.startAfter)(cursor));
|
|
19623
|
+
const q = (0, import_firestore61.query)(this.technologiesRef, ...queryConstraints);
|
|
19624
|
+
const snapshot = await (0, import_firestore61.getDocs)(q);
|
|
19625
|
+
if (snapshot.empty) break;
|
|
19626
|
+
for (const d of snapshot.docs) {
|
|
19627
|
+
const technology = { id: d.id, ...d.data() };
|
|
19628
|
+
const productNames = await this.getProductNamesForTechnology(technology.id);
|
|
19629
|
+
rows.push(this.technologyToCsvRow(technology, productNames));
|
|
19630
|
+
}
|
|
19631
|
+
cursor = snapshot.docs[snapshot.docs.length - 1];
|
|
19632
|
+
if (snapshot.size < PAGE_SIZE) break;
|
|
19633
|
+
}
|
|
19634
|
+
const csvBody = rows.join("\r\n");
|
|
19635
|
+
return includeBom ? "\uFEFF" + csvBody : csvBody;
|
|
19636
|
+
}
|
|
19637
|
+
/**
|
|
19638
|
+
* Gets product names from the technology's product subcollection
|
|
19639
|
+
*/
|
|
19640
|
+
async getProductNamesForTechnology(technologyId) {
|
|
19641
|
+
try {
|
|
19642
|
+
const productsRef = (0, import_firestore61.collection)(this.db, TECHNOLOGIES_COLLECTION, technologyId, PRODUCTS_COLLECTION);
|
|
19643
|
+
const q = (0, import_firestore61.query)(productsRef, (0, import_firestore61.where)("isActive", "==", true));
|
|
19644
|
+
const snapshot = await (0, import_firestore61.getDocs)(q);
|
|
19645
|
+
return snapshot.docs.map((doc44) => {
|
|
19646
|
+
const product = doc44.data();
|
|
19647
|
+
return product.name || "";
|
|
19648
|
+
}).filter((name) => name);
|
|
19649
|
+
} catch (error) {
|
|
19650
|
+
console.error(`Error fetching products for technology ${technologyId}:`, error);
|
|
19651
|
+
return [];
|
|
19652
|
+
}
|
|
19653
|
+
}
|
|
19654
|
+
technologyToCsvRow(technology, productNames = []) {
|
|
19655
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A;
|
|
19656
|
+
const values = [
|
|
19657
|
+
(_a = technology.id) != null ? _a : "",
|
|
19658
|
+
(_b = technology.name) != null ? _b : "",
|
|
19659
|
+
(_c = technology.description) != null ? _c : "",
|
|
19660
|
+
(_d = technology.family) != null ? _d : "",
|
|
19661
|
+
(_e = technology.categoryId) != null ? _e : "",
|
|
19662
|
+
(_f = technology.subcategoryId) != null ? _f : "",
|
|
19663
|
+
(_g = technology.technicalDetails) != null ? _g : "",
|
|
19664
|
+
(_j = (_i = (_h = technology.requirements) == null ? void 0 : _h.pre) == null ? void 0 : _i.map((r) => r.name).join(";")) != null ? _j : "",
|
|
19665
|
+
(_m = (_l = (_k = technology.requirements) == null ? void 0 : _k.post) == null ? void 0 : _l.map((r) => r.name).join(";")) != null ? _m : "",
|
|
19666
|
+
(_o = (_n = technology.blockingConditions) == null ? void 0 : _n.join(";")) != null ? _o : "",
|
|
19667
|
+
(_q = (_p = technology.contraindications) == null ? void 0 : _p.map((c) => c.name).join(";")) != null ? _q : "",
|
|
19668
|
+
(_s = (_r = technology.benefits) == null ? void 0 : _r.map((b) => b.name).join(";")) != null ? _s : "",
|
|
19669
|
+
(_u = (_t = technology.certificationRequirement) == null ? void 0 : _t.minimumLevel) != null ? _u : "",
|
|
19670
|
+
(_x = (_w = (_v = technology.certificationRequirement) == null ? void 0 : _v.requiredSpecialties) == null ? void 0 : _w.join(";")) != null ? _x : "",
|
|
19671
|
+
(_z = (_y = technology.documentationTemplates) == null ? void 0 : _y.map((t) => t.templateId).join(";")) != null ? _z : "",
|
|
19672
|
+
productNames.join(";"),
|
|
19673
|
+
String((_A = technology.isActive) != null ? _A : "")
|
|
19674
|
+
];
|
|
19675
|
+
return values.map((v) => this.formatCsvValue(v)).join(",");
|
|
19676
|
+
}
|
|
19677
|
+
formatCsvValue(value) {
|
|
19678
|
+
const str = value === null || value === void 0 ? "" : String(value);
|
|
19679
|
+
const escaped = str.replace(/"/g, '""');
|
|
19680
|
+
return `"${escaped}"`;
|
|
19681
|
+
}
|
|
19341
19682
|
};
|
|
19342
19683
|
|
|
19343
19684
|
// src/backoffice/services/product.service.ts
|
|
@@ -19426,9 +19767,8 @@ var ProductService = class extends BaseService {
|
|
|
19426
19767
|
return snapshot.data().count;
|
|
19427
19768
|
}
|
|
19428
19769
|
/**
|
|
19429
|
-
* Gets counts of active products grouped by technology.
|
|
19430
|
-
*
|
|
19431
|
-
* Categories/subcategories not available in top-level structure.
|
|
19770
|
+
* Gets counts of active products grouped by category, subcategory, and technology.
|
|
19771
|
+
* Queries technology subcollections which have the legacy fields synced by Cloud Functions.
|
|
19432
19772
|
*/
|
|
19433
19773
|
async getProductCounts() {
|
|
19434
19774
|
const counts = {
|
|
@@ -19436,14 +19776,18 @@ var ProductService = class extends BaseService {
|
|
|
19436
19776
|
bySubcategory: {},
|
|
19437
19777
|
byTechnology: {}
|
|
19438
19778
|
};
|
|
19439
|
-
const q = (0, import_firestore62.query)(this.
|
|
19779
|
+
const q = (0, import_firestore62.query)((0, import_firestore62.collectionGroup)(this.db, PRODUCTS_COLLECTION), (0, import_firestore62.where)("isActive", "==", true));
|
|
19440
19780
|
const snapshot = await (0, import_firestore62.getDocs)(q);
|
|
19441
19781
|
snapshot.docs.forEach((doc44) => {
|
|
19442
19782
|
const product = doc44.data();
|
|
19443
|
-
if (product.
|
|
19444
|
-
product.
|
|
19445
|
-
|
|
19446
|
-
|
|
19783
|
+
if (product.categoryId) {
|
|
19784
|
+
counts.byCategory[product.categoryId] = (counts.byCategory[product.categoryId] || 0) + 1;
|
|
19785
|
+
}
|
|
19786
|
+
if (product.subcategoryId) {
|
|
19787
|
+
counts.bySubcategory[product.subcategoryId] = (counts.bySubcategory[product.subcategoryId] || 0) + 1;
|
|
19788
|
+
}
|
|
19789
|
+
if (product.technologyId) {
|
|
19790
|
+
counts.byTechnology[product.technologyId] = (counts.byTechnology[product.technologyId] || 0) + 1;
|
|
19447
19791
|
}
|
|
19448
19792
|
});
|
|
19449
19793
|
return counts;
|
|
@@ -19676,6 +20020,87 @@ var ProductService = class extends BaseService {
|
|
|
19676
20020
|
})
|
|
19677
20021
|
);
|
|
19678
20022
|
}
|
|
20023
|
+
/**
|
|
20024
|
+
* Exports products to CSV string, suitable for Excel/Sheets.
|
|
20025
|
+
* Includes headers and optional UTF-8 BOM.
|
|
20026
|
+
* By default exports only active products (set includeInactive to true to export all).
|
|
20027
|
+
*/
|
|
20028
|
+
async exportToCsv(options) {
|
|
20029
|
+
var _a, _b;
|
|
20030
|
+
const includeInactive = (_a = options == null ? void 0 : options.includeInactive) != null ? _a : false;
|
|
20031
|
+
const includeBom = (_b = options == null ? void 0 : options.includeBom) != null ? _b : true;
|
|
20032
|
+
const headers = [
|
|
20033
|
+
"id",
|
|
20034
|
+
"name",
|
|
20035
|
+
"brandId",
|
|
20036
|
+
"brandName",
|
|
20037
|
+
"assignedTechnologyIds",
|
|
20038
|
+
"description",
|
|
20039
|
+
"technicalDetails",
|
|
20040
|
+
"dosage",
|
|
20041
|
+
"composition",
|
|
20042
|
+
"indications",
|
|
20043
|
+
"contraindications",
|
|
20044
|
+
"warnings",
|
|
20045
|
+
"isActive"
|
|
20046
|
+
];
|
|
20047
|
+
const rows = [];
|
|
20048
|
+
rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
|
|
20049
|
+
const PAGE_SIZE = 1e3;
|
|
20050
|
+
let cursor;
|
|
20051
|
+
const constraints = [];
|
|
20052
|
+
if (!includeInactive) {
|
|
20053
|
+
constraints.push((0, import_firestore62.where)("isActive", "==", true));
|
|
20054
|
+
}
|
|
20055
|
+
constraints.push((0, import_firestore62.orderBy)("name"));
|
|
20056
|
+
while (true) {
|
|
20057
|
+
const queryConstraints = [...constraints, (0, import_firestore62.limit)(PAGE_SIZE)];
|
|
20058
|
+
if (cursor) queryConstraints.push((0, import_firestore62.startAfter)(cursor));
|
|
20059
|
+
const q = (0, import_firestore62.query)(this.getTopLevelProductsRef(), ...queryConstraints);
|
|
20060
|
+
const snapshot = await (0, import_firestore62.getDocs)(q);
|
|
20061
|
+
if (snapshot.empty) break;
|
|
20062
|
+
for (const d of snapshot.docs) {
|
|
20063
|
+
const product = { id: d.id, ...d.data() };
|
|
20064
|
+
rows.push(this.productToCsvRow(product));
|
|
20065
|
+
}
|
|
20066
|
+
cursor = snapshot.docs[snapshot.docs.length - 1];
|
|
20067
|
+
if (snapshot.size < PAGE_SIZE) break;
|
|
20068
|
+
}
|
|
20069
|
+
const csvBody = rows.join("\r\n");
|
|
20070
|
+
return includeBom ? "\uFEFF" + csvBody : csvBody;
|
|
20071
|
+
}
|
|
20072
|
+
productToCsvRow(product) {
|
|
20073
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
|
|
20074
|
+
const values = [
|
|
20075
|
+
(_a = product.id) != null ? _a : "",
|
|
20076
|
+
(_b = product.name) != null ? _b : "",
|
|
20077
|
+
(_c = product.brandId) != null ? _c : "",
|
|
20078
|
+
(_d = product.brandName) != null ? _d : "",
|
|
20079
|
+
(_f = (_e = product.assignedTechnologyIds) == null ? void 0 : _e.join(";")) != null ? _f : "",
|
|
20080
|
+
(_g = product.description) != null ? _g : "",
|
|
20081
|
+
(_h = product.technicalDetails) != null ? _h : "",
|
|
20082
|
+
(_i = product.dosage) != null ? _i : "",
|
|
20083
|
+
(_j = product.composition) != null ? _j : "",
|
|
20084
|
+
(_l = (_k = product.indications) == null ? void 0 : _k.join(";")) != null ? _l : "",
|
|
20085
|
+
(_n = (_m = product.contraindications) == null ? void 0 : _m.map((c) => c.name).join(";")) != null ? _n : "",
|
|
20086
|
+
(_p = (_o = product.warnings) == null ? void 0 : _o.join(";")) != null ? _p : "",
|
|
20087
|
+
String((_q = product.isActive) != null ? _q : "")
|
|
20088
|
+
];
|
|
20089
|
+
return values.map((v) => this.formatCsvValue(v)).join(",");
|
|
20090
|
+
}
|
|
20091
|
+
formatDateIso(value) {
|
|
20092
|
+
if (value instanceof Date) return value.toISOString();
|
|
20093
|
+
if (value && typeof value.toDate === "function") {
|
|
20094
|
+
const d = value.toDate();
|
|
20095
|
+
return d instanceof Date ? d.toISOString() : String(value);
|
|
20096
|
+
}
|
|
20097
|
+
return String(value != null ? value : "");
|
|
20098
|
+
}
|
|
20099
|
+
formatCsvValue(value) {
|
|
20100
|
+
const str = value === null || value === void 0 ? "" : String(value);
|
|
20101
|
+
const escaped = str.replace(/"/g, '""');
|
|
20102
|
+
return `"${escaped}"`;
|
|
20103
|
+
}
|
|
19679
20104
|
};
|
|
19680
20105
|
|
|
19681
20106
|
// src/backoffice/services/constants.service.ts
|
|
@@ -19908,6 +20333,66 @@ var ConstantsService = class extends BaseService {
|
|
|
19908
20333
|
contraindications: (0, import_firestore63.arrayRemove)(toRemove)
|
|
19909
20334
|
});
|
|
19910
20335
|
}
|
|
20336
|
+
// =================================================================
|
|
20337
|
+
// CSV Export Methods
|
|
20338
|
+
// =================================================================
|
|
20339
|
+
/**
|
|
20340
|
+
* Exports treatment benefits to CSV string, suitable for Excel/Sheets.
|
|
20341
|
+
* Includes headers and optional UTF-8 BOM.
|
|
20342
|
+
*/
|
|
20343
|
+
async exportBenefitsToCsv(options) {
|
|
20344
|
+
var _a;
|
|
20345
|
+
const includeBom = (_a = options == null ? void 0 : options.includeBom) != null ? _a : true;
|
|
20346
|
+
const headers = ["id", "name", "description"];
|
|
20347
|
+
const rows = [];
|
|
20348
|
+
rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
|
|
20349
|
+
const benefits = await this.getAllBenefitsForFilter();
|
|
20350
|
+
for (const benefit of benefits) {
|
|
20351
|
+
rows.push(this.benefitToCsvRow(benefit));
|
|
20352
|
+
}
|
|
20353
|
+
const csvBody = rows.join("\r\n");
|
|
20354
|
+
return includeBom ? "\uFEFF" + csvBody : csvBody;
|
|
20355
|
+
}
|
|
20356
|
+
/**
|
|
20357
|
+
* Exports contraindications to CSV string, suitable for Excel/Sheets.
|
|
20358
|
+
* Includes headers and optional UTF-8 BOM.
|
|
20359
|
+
*/
|
|
20360
|
+
async exportContraindicationsToCsv(options) {
|
|
20361
|
+
var _a;
|
|
20362
|
+
const includeBom = (_a = options == null ? void 0 : options.includeBom) != null ? _a : true;
|
|
20363
|
+
const headers = ["id", "name", "description"];
|
|
20364
|
+
const rows = [];
|
|
20365
|
+
rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
|
|
20366
|
+
const contraindications = await this.getAllContraindicationsForFilter();
|
|
20367
|
+
for (const contraindication of contraindications) {
|
|
20368
|
+
rows.push(this.contraindicationToCsvRow(contraindication));
|
|
20369
|
+
}
|
|
20370
|
+
const csvBody = rows.join("\r\n");
|
|
20371
|
+
return includeBom ? "\uFEFF" + csvBody : csvBody;
|
|
20372
|
+
}
|
|
20373
|
+
benefitToCsvRow(benefit) {
|
|
20374
|
+
var _a, _b, _c;
|
|
20375
|
+
const values = [
|
|
20376
|
+
(_a = benefit.id) != null ? _a : "",
|
|
20377
|
+
(_b = benefit.name) != null ? _b : "",
|
|
20378
|
+
(_c = benefit.description) != null ? _c : ""
|
|
20379
|
+
];
|
|
20380
|
+
return values.map((v) => this.formatCsvValue(v)).join(",");
|
|
20381
|
+
}
|
|
20382
|
+
contraindicationToCsvRow(contraindication) {
|
|
20383
|
+
var _a, _b, _c;
|
|
20384
|
+
const values = [
|
|
20385
|
+
(_a = contraindication.id) != null ? _a : "",
|
|
20386
|
+
(_b = contraindication.name) != null ? _b : "",
|
|
20387
|
+
(_c = contraindication.description) != null ? _c : ""
|
|
20388
|
+
];
|
|
20389
|
+
return values.map((v) => this.formatCsvValue(v)).join(",");
|
|
20390
|
+
}
|
|
20391
|
+
formatCsvValue(value) {
|
|
20392
|
+
const str = value === null || value === void 0 ? "" : String(value);
|
|
20393
|
+
const escaped = str.replace(/"/g, '""');
|
|
20394
|
+
return `"${escaped}"`;
|
|
20395
|
+
}
|
|
19911
20396
|
};
|
|
19912
20397
|
|
|
19913
20398
|
// src/backoffice/types/static/contraindication.types.ts
|