@blackcode_sa/metaestetics-api 1.12.43 → 1.12.46
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 +6 -12
- package/dist/admin/index.d.ts +6 -12
- package/dist/backoffice/index.d.mts +18 -275
- package/dist/backoffice/index.d.ts +18 -275
- package/dist/backoffice/index.js +14 -802
- package/dist/backoffice/index.mjs +38 -830
- package/dist/index.d.mts +10 -255
- package/dist/index.d.ts +10 -255
- package/dist/index.js +36 -754
- package/dist/index.mjs +44 -765
- package/package.json +1 -1
- package/src/backoffice/services/brand.service.ts +0 -86
- package/src/backoffice/services/category.service.ts +0 -84
- package/src/backoffice/services/constants.service.ts +0 -77
- package/src/backoffice/services/product.service.ts +18 -316
- package/src/backoffice/services/requirement.service.ts +0 -76
- package/src/backoffice/services/subcategory.service.ts +0 -87
- package/src/backoffice/services/technology.service.ts +0 -289
- package/src/backoffice/types/product.types.ts +6 -116
- package/src/services/appointment/utils/zone-management.utils.ts +24 -10
- package/src/backoffice/services/migrate-products.ts +0 -116
package/dist/index.js
CHANGED
|
@@ -1546,14 +1546,14 @@ function calculateItemSubtotal(item) {
|
|
|
1546
1546
|
if (item.type === "note") {
|
|
1547
1547
|
return 0;
|
|
1548
1548
|
}
|
|
1549
|
+
const quantity = item.quantity || 0;
|
|
1549
1550
|
if (item.priceOverrideAmount !== void 0 && item.priceOverrideAmount !== null) {
|
|
1550
|
-
return item.priceOverrideAmount;
|
|
1551
|
+
return item.priceOverrideAmount * quantity;
|
|
1551
1552
|
}
|
|
1552
1553
|
const price = item.price || 0;
|
|
1553
|
-
const quantity = item.quantity || 0;
|
|
1554
1554
|
return price * quantity;
|
|
1555
1555
|
}
|
|
1556
|
-
function calculateFinalBilling(zonesData, taxRate = 0.
|
|
1556
|
+
function calculateFinalBilling(zonesData, taxRate = 0.081) {
|
|
1557
1557
|
let subtotalAll = 0;
|
|
1558
1558
|
Object.values(zonesData).forEach((items) => {
|
|
1559
1559
|
items.forEach((item) => {
|
|
@@ -1617,7 +1617,7 @@ async function addItemToZoneUtil(db, appointmentId, zoneId, item) {
|
|
|
1617
1617
|
updatedAt: now
|
|
1618
1618
|
};
|
|
1619
1619
|
zonesData[zoneId].push(itemWithSubtotal);
|
|
1620
|
-
const finalbilling = calculateFinalBilling(zonesData);
|
|
1620
|
+
const finalbilling = calculateFinalBilling(zonesData, 0.081);
|
|
1621
1621
|
const appointmentRef = (0, import_firestore5.doc)(db, APPOINTMENTS_COLLECTION, appointmentId);
|
|
1622
1622
|
await (0, import_firestore4.updateDoc)(appointmentRef, {
|
|
1623
1623
|
"metadata.zonesData": zonesData,
|
|
@@ -1641,7 +1641,7 @@ async function removeItemFromZoneUtil(db, appointmentId, zoneId, itemIndex) {
|
|
|
1641
1641
|
if (items.length === 0) {
|
|
1642
1642
|
delete metadata.zonesData[zoneId];
|
|
1643
1643
|
}
|
|
1644
|
-
const finalbilling = calculateFinalBilling(metadata.zonesData);
|
|
1644
|
+
const finalbilling = calculateFinalBilling(metadata.zonesData, 0.081);
|
|
1645
1645
|
const appointmentRef = (0, import_firestore5.doc)(db, APPOINTMENTS_COLLECTION, appointmentId);
|
|
1646
1646
|
await (0, import_firestore4.updateDoc)(appointmentRef, {
|
|
1647
1647
|
"metadata.zonesData": metadata.zonesData,
|
|
@@ -1666,8 +1666,19 @@ async function updateZoneItemUtil(db, appointmentId, zoneId, itemIndex, updates)
|
|
|
1666
1666
|
...updates,
|
|
1667
1667
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1668
1668
|
};
|
|
1669
|
+
console.log(`[updateZoneItemUtil] BEFORE recalculation:`, {
|
|
1670
|
+
itemIndex,
|
|
1671
|
+
quantity: items[itemIndex].quantity,
|
|
1672
|
+
priceOverrideAmount: items[itemIndex].priceOverrideAmount,
|
|
1673
|
+
price: items[itemIndex].price,
|
|
1674
|
+
oldSubtotal: items[itemIndex].subtotal
|
|
1675
|
+
});
|
|
1669
1676
|
items[itemIndex].subtotal = calculateItemSubtotal(items[itemIndex]);
|
|
1670
|
-
|
|
1677
|
+
console.log(`[updateZoneItemUtil] AFTER recalculation:`, {
|
|
1678
|
+
itemIndex,
|
|
1679
|
+
newSubtotal: items[itemIndex].subtotal
|
|
1680
|
+
});
|
|
1681
|
+
const finalbilling = calculateFinalBilling(metadata.zonesData, 0.081);
|
|
1671
1682
|
const appointmentRef = (0, import_firestore5.doc)(db, APPOINTMENTS_COLLECTION, appointmentId);
|
|
1672
1683
|
await (0, import_firestore4.updateDoc)(appointmentRef, {
|
|
1673
1684
|
"metadata.zonesData": metadata.zonesData,
|
|
@@ -18238,73 +18249,6 @@ var BrandService = class extends BaseService {
|
|
|
18238
18249
|
...docSnap.data()
|
|
18239
18250
|
};
|
|
18240
18251
|
}
|
|
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
|
-
}
|
|
18308
18252
|
};
|
|
18309
18253
|
|
|
18310
18254
|
// src/backoffice/services/category.service.ts
|
|
@@ -18483,71 +18427,6 @@ var CategoryService = class extends BaseService {
|
|
|
18483
18427
|
...docSnap.data()
|
|
18484
18428
|
};
|
|
18485
18429
|
}
|
|
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
|
-
}
|
|
18551
18430
|
};
|
|
18552
18431
|
|
|
18553
18432
|
// src/backoffice/services/subcategory.service.ts
|
|
@@ -18775,83 +18654,10 @@ var SubcategoryService = class extends BaseService {
|
|
|
18775
18654
|
...docSnap.data()
|
|
18776
18655
|
};
|
|
18777
18656
|
}
|
|
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
|
-
}
|
|
18846
18657
|
};
|
|
18847
18658
|
|
|
18848
18659
|
// src/backoffice/services/technology.service.ts
|
|
18849
18660
|
var import_firestore61 = require("firebase/firestore");
|
|
18850
|
-
|
|
18851
|
-
// src/backoffice/types/product.types.ts
|
|
18852
|
-
var PRODUCTS_COLLECTION = "products";
|
|
18853
|
-
|
|
18854
|
-
// src/backoffice/services/technology.service.ts
|
|
18855
18661
|
var DEFAULT_CERTIFICATION_REQUIREMENT = {
|
|
18856
18662
|
minimumLevel: "aesthetician" /* AESTHETICIAN */,
|
|
18857
18663
|
requiredSpecialties: []
|
|
@@ -19013,18 +18819,7 @@ var TechnologyService = class extends BaseService {
|
|
|
19013
18819
|
});
|
|
19014
18820
|
updateData.updatedAt = /* @__PURE__ */ new Date();
|
|
19015
18821
|
const docRef = (0, import_firestore61.doc)(this.technologiesRef, id);
|
|
19016
|
-
const beforeTech = await this.getById(id);
|
|
19017
18822
|
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
|
-
}
|
|
19028
18823
|
return this.getById(id);
|
|
19029
18824
|
}
|
|
19030
18825
|
/**
|
|
@@ -19460,239 +19255,18 @@ var TechnologyService = class extends BaseService {
|
|
|
19460
19255
|
})
|
|
19461
19256
|
);
|
|
19462
19257
|
}
|
|
19463
|
-
// ==========================================
|
|
19464
|
-
// NEW METHODS: Product assignment management
|
|
19465
|
-
// ==========================================
|
|
19466
|
-
/**
|
|
19467
|
-
* Assigns multiple products to a technology
|
|
19468
|
-
* Updates each product's assignedTechnologyIds array
|
|
19469
|
-
*/
|
|
19470
|
-
async assignProducts(technologyId, productIds) {
|
|
19471
|
-
const batch = (0, import_firestore61.writeBatch)(this.db);
|
|
19472
|
-
for (const productId of productIds) {
|
|
19473
|
-
const productRef = (0, import_firestore61.doc)(this.db, PRODUCTS_COLLECTION, productId);
|
|
19474
|
-
batch.update(productRef, {
|
|
19475
|
-
assignedTechnologyIds: (0, import_firestore61.arrayUnion)(technologyId),
|
|
19476
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
19477
|
-
});
|
|
19478
|
-
}
|
|
19479
|
-
await batch.commit();
|
|
19480
|
-
}
|
|
19481
|
-
/**
|
|
19482
|
-
* Unassigns multiple products from a technology
|
|
19483
|
-
* Updates each product's assignedTechnologyIds array
|
|
19484
|
-
*/
|
|
19485
|
-
async unassignProducts(technologyId, productIds) {
|
|
19486
|
-
const batch = (0, import_firestore61.writeBatch)(this.db);
|
|
19487
|
-
for (const productId of productIds) {
|
|
19488
|
-
const productRef = (0, import_firestore61.doc)(this.db, PRODUCTS_COLLECTION, productId);
|
|
19489
|
-
batch.update(productRef, {
|
|
19490
|
-
assignedTechnologyIds: (0, import_firestore61.arrayRemove)(technologyId),
|
|
19491
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
19492
|
-
});
|
|
19493
|
-
}
|
|
19494
|
-
await batch.commit();
|
|
19495
|
-
}
|
|
19496
|
-
/**
|
|
19497
|
-
* Gets products assigned to a specific technology
|
|
19498
|
-
* Reads from top-level collection for immediate consistency (Cloud Functions may lag)
|
|
19499
|
-
*/
|
|
19500
|
-
async getAssignedProducts(technologyId) {
|
|
19501
|
-
const q = (0, import_firestore61.query)(
|
|
19502
|
-
(0, import_firestore61.collection)(this.db, PRODUCTS_COLLECTION),
|
|
19503
|
-
(0, import_firestore61.where)("assignedTechnologyIds", "array-contains", technologyId),
|
|
19504
|
-
(0, import_firestore61.where)("isActive", "==", true),
|
|
19505
|
-
(0, import_firestore61.orderBy)("name")
|
|
19506
|
-
);
|
|
19507
|
-
const snapshot = await (0, import_firestore61.getDocs)(q);
|
|
19508
|
-
return snapshot.docs.map(
|
|
19509
|
-
(doc44) => ({
|
|
19510
|
-
id: doc44.id,
|
|
19511
|
-
...doc44.data()
|
|
19512
|
-
})
|
|
19513
|
-
);
|
|
19514
|
-
}
|
|
19515
|
-
/**
|
|
19516
|
-
* Gets products NOT assigned to a specific technology
|
|
19517
|
-
*/
|
|
19518
|
-
async getUnassignedProducts(technologyId) {
|
|
19519
|
-
const q = (0, import_firestore61.query)(
|
|
19520
|
-
(0, import_firestore61.collection)(this.db, PRODUCTS_COLLECTION),
|
|
19521
|
-
(0, import_firestore61.where)("isActive", "==", true),
|
|
19522
|
-
(0, import_firestore61.orderBy)("name")
|
|
19523
|
-
);
|
|
19524
|
-
const snapshot = await (0, import_firestore61.getDocs)(q);
|
|
19525
|
-
const allProducts = snapshot.docs.map(
|
|
19526
|
-
(doc44) => ({
|
|
19527
|
-
id: doc44.id,
|
|
19528
|
-
...doc44.data()
|
|
19529
|
-
})
|
|
19530
|
-
);
|
|
19531
|
-
return allProducts.filter(
|
|
19532
|
-
(product) => {
|
|
19533
|
-
var _a;
|
|
19534
|
-
return !((_a = product.assignedTechnologyIds) == null ? void 0 : _a.includes(technologyId));
|
|
19535
|
-
}
|
|
19536
|
-
);
|
|
19537
|
-
}
|
|
19538
|
-
/**
|
|
19539
|
-
* Gets product assignment statistics for a technology
|
|
19540
|
-
*/
|
|
19541
|
-
async getProductStats(technologyId) {
|
|
19542
|
-
const products = await this.getAssignedProducts(technologyId);
|
|
19543
|
-
const byBrand = {};
|
|
19544
|
-
products.forEach((product) => {
|
|
19545
|
-
byBrand[product.brandName] = (byBrand[product.brandName] || 0) + 1;
|
|
19546
|
-
});
|
|
19547
|
-
return {
|
|
19548
|
-
totalAssigned: products.length,
|
|
19549
|
-
byBrand
|
|
19550
|
-
};
|
|
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
|
-
}
|
|
19682
19258
|
};
|
|
19683
19259
|
|
|
19684
19260
|
// src/backoffice/services/product.service.ts
|
|
19685
19261
|
var import_firestore62 = require("firebase/firestore");
|
|
19262
|
+
|
|
19263
|
+
// src/backoffice/types/product.types.ts
|
|
19264
|
+
var PRODUCTS_COLLECTION = "products";
|
|
19265
|
+
|
|
19266
|
+
// src/backoffice/services/product.service.ts
|
|
19686
19267
|
var ProductService = class extends BaseService {
|
|
19687
19268
|
/**
|
|
19688
|
-
* Gets reference to
|
|
19689
|
-
* @returns Firestore collection reference
|
|
19690
|
-
*/
|
|
19691
|
-
getTopLevelProductsRef() {
|
|
19692
|
-
return (0, import_firestore62.collection)(this.db, PRODUCTS_COLLECTION);
|
|
19693
|
-
}
|
|
19694
|
-
/**
|
|
19695
|
-
* Gets reference to products collection under a technology (backward compatibility)
|
|
19269
|
+
* Gets reference to products collection under a technology
|
|
19696
19270
|
* @param technologyId - ID of the technology
|
|
19697
19271
|
* @returns Firestore collection reference
|
|
19698
19272
|
*/
|
|
@@ -19708,7 +19282,6 @@ var ProductService = class extends BaseService {
|
|
|
19708
19282
|
...product,
|
|
19709
19283
|
brandId,
|
|
19710
19284
|
technologyId,
|
|
19711
|
-
// Required for old subcollection structure
|
|
19712
19285
|
createdAt: now,
|
|
19713
19286
|
updatedAt: now,
|
|
19714
19287
|
isActive: true
|
|
@@ -19768,26 +19341,30 @@ var ProductService = class extends BaseService {
|
|
|
19768
19341
|
}
|
|
19769
19342
|
/**
|
|
19770
19343
|
* Gets counts of active products grouped by category, subcategory, and technology.
|
|
19771
|
-
*
|
|
19344
|
+
* This uses a single collectionGroup query for efficiency.
|
|
19772
19345
|
*/
|
|
19773
19346
|
async getProductCounts() {
|
|
19347
|
+
const q = (0, import_firestore62.query)((0, import_firestore62.collectionGroup)(this.db, PRODUCTS_COLLECTION), (0, import_firestore62.where)("isActive", "==", true));
|
|
19348
|
+
const snapshot = await (0, import_firestore62.getDocs)(q);
|
|
19774
19349
|
const counts = {
|
|
19775
19350
|
byCategory: {},
|
|
19776
19351
|
bySubcategory: {},
|
|
19777
19352
|
byTechnology: {}
|
|
19778
19353
|
};
|
|
19779
|
-
|
|
19780
|
-
|
|
19354
|
+
if (snapshot.empty) {
|
|
19355
|
+
return counts;
|
|
19356
|
+
}
|
|
19781
19357
|
snapshot.docs.forEach((doc44) => {
|
|
19782
19358
|
const product = doc44.data();
|
|
19783
|
-
|
|
19784
|
-
|
|
19359
|
+
const { categoryId, subcategoryId, technologyId } = product;
|
|
19360
|
+
if (categoryId) {
|
|
19361
|
+
counts.byCategory[categoryId] = (counts.byCategory[categoryId] || 0) + 1;
|
|
19785
19362
|
}
|
|
19786
|
-
if (
|
|
19787
|
-
counts.bySubcategory[
|
|
19363
|
+
if (subcategoryId) {
|
|
19364
|
+
counts.bySubcategory[subcategoryId] = (counts.bySubcategory[subcategoryId] || 0) + 1;
|
|
19788
19365
|
}
|
|
19789
|
-
if (
|
|
19790
|
-
counts.byTechnology[
|
|
19366
|
+
if (technologyId) {
|
|
19367
|
+
counts.byTechnology[technologyId] = (counts.byTechnology[technologyId] || 0) + 1;
|
|
19791
19368
|
}
|
|
19792
19369
|
});
|
|
19793
19370
|
return counts;
|
|
@@ -19866,241 +19443,6 @@ var ProductService = class extends BaseService {
|
|
|
19866
19443
|
...docSnap.data()
|
|
19867
19444
|
};
|
|
19868
19445
|
}
|
|
19869
|
-
// ==========================================
|
|
19870
|
-
// NEW METHODS: Top-level collection (preferred)
|
|
19871
|
-
// ==========================================
|
|
19872
|
-
/**
|
|
19873
|
-
* Creates a new product in the top-level collection
|
|
19874
|
-
*/
|
|
19875
|
-
async createTopLevel(brandId, product, technologyIds = []) {
|
|
19876
|
-
const now = /* @__PURE__ */ new Date();
|
|
19877
|
-
const newProduct = {
|
|
19878
|
-
...product,
|
|
19879
|
-
brandId,
|
|
19880
|
-
assignedTechnologyIds: technologyIds,
|
|
19881
|
-
createdAt: now,
|
|
19882
|
-
updatedAt: now,
|
|
19883
|
-
isActive: true
|
|
19884
|
-
};
|
|
19885
|
-
const productRef = await (0, import_firestore62.addDoc)(this.getTopLevelProductsRef(), newProduct);
|
|
19886
|
-
return { id: productRef.id, ...newProduct };
|
|
19887
|
-
}
|
|
19888
|
-
/**
|
|
19889
|
-
* Gets all products from the top-level collection
|
|
19890
|
-
*/
|
|
19891
|
-
async getAllTopLevel(options) {
|
|
19892
|
-
const { rowsPerPage, lastVisible, brandId } = options;
|
|
19893
|
-
const constraints = [(0, import_firestore62.where)("isActive", "==", true), (0, import_firestore62.orderBy)("name")];
|
|
19894
|
-
if (brandId) {
|
|
19895
|
-
constraints.push((0, import_firestore62.where)("brandId", "==", brandId));
|
|
19896
|
-
}
|
|
19897
|
-
if (lastVisible) {
|
|
19898
|
-
constraints.push((0, import_firestore62.startAfter)(lastVisible));
|
|
19899
|
-
}
|
|
19900
|
-
constraints.push((0, import_firestore62.limit)(rowsPerPage));
|
|
19901
|
-
const q = (0, import_firestore62.query)(this.getTopLevelProductsRef(), ...constraints);
|
|
19902
|
-
const snapshot = await (0, import_firestore62.getDocs)(q);
|
|
19903
|
-
const products = snapshot.docs.map(
|
|
19904
|
-
(doc44) => ({
|
|
19905
|
-
id: doc44.id,
|
|
19906
|
-
...doc44.data()
|
|
19907
|
-
})
|
|
19908
|
-
);
|
|
19909
|
-
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
19910
|
-
return { products, lastVisible: newLastVisible };
|
|
19911
|
-
}
|
|
19912
|
-
/**
|
|
19913
|
-
* Gets a product by ID from the top-level collection
|
|
19914
|
-
*/
|
|
19915
|
-
async getByIdTopLevel(productId) {
|
|
19916
|
-
const docRef = (0, import_firestore62.doc)(this.getTopLevelProductsRef(), productId);
|
|
19917
|
-
const docSnap = await (0, import_firestore62.getDoc)(docRef);
|
|
19918
|
-
if (!docSnap.exists()) return null;
|
|
19919
|
-
return {
|
|
19920
|
-
id: docSnap.id,
|
|
19921
|
-
...docSnap.data()
|
|
19922
|
-
};
|
|
19923
|
-
}
|
|
19924
|
-
/**
|
|
19925
|
-
* Updates a product in the top-level collection
|
|
19926
|
-
*/
|
|
19927
|
-
async updateTopLevel(productId, product) {
|
|
19928
|
-
const updateData = {
|
|
19929
|
-
...product,
|
|
19930
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
19931
|
-
};
|
|
19932
|
-
const docRef = (0, import_firestore62.doc)(this.getTopLevelProductsRef(), productId);
|
|
19933
|
-
await (0, import_firestore62.updateDoc)(docRef, updateData);
|
|
19934
|
-
return this.getByIdTopLevel(productId);
|
|
19935
|
-
}
|
|
19936
|
-
/**
|
|
19937
|
-
* Deletes a product from the top-level collection (soft delete)
|
|
19938
|
-
*/
|
|
19939
|
-
async deleteTopLevel(productId) {
|
|
19940
|
-
await this.updateTopLevel(productId, {
|
|
19941
|
-
isActive: false
|
|
19942
|
-
});
|
|
19943
|
-
}
|
|
19944
|
-
/**
|
|
19945
|
-
* Assigns a product to a technology
|
|
19946
|
-
*/
|
|
19947
|
-
async assignToTechnology(productId, technologyId) {
|
|
19948
|
-
const docRef = (0, import_firestore62.doc)(this.getTopLevelProductsRef(), productId);
|
|
19949
|
-
await (0, import_firestore62.updateDoc)(docRef, {
|
|
19950
|
-
assignedTechnologyIds: (0, import_firestore62.arrayUnion)(technologyId),
|
|
19951
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
19952
|
-
});
|
|
19953
|
-
}
|
|
19954
|
-
/**
|
|
19955
|
-
* Unassigns a product from a technology
|
|
19956
|
-
*/
|
|
19957
|
-
async unassignFromTechnology(productId, technologyId) {
|
|
19958
|
-
const docRef = (0, import_firestore62.doc)(this.getTopLevelProductsRef(), productId);
|
|
19959
|
-
await (0, import_firestore62.updateDoc)(docRef, {
|
|
19960
|
-
assignedTechnologyIds: (0, import_firestore62.arrayRemove)(technologyId),
|
|
19961
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
19962
|
-
});
|
|
19963
|
-
}
|
|
19964
|
-
/**
|
|
19965
|
-
* Gets products assigned to a specific technology
|
|
19966
|
-
*/
|
|
19967
|
-
async getAssignedProducts(technologyId) {
|
|
19968
|
-
const q = (0, import_firestore62.query)(
|
|
19969
|
-
this.getTopLevelProductsRef(),
|
|
19970
|
-
(0, import_firestore62.where)("assignedTechnologyIds", "array-contains", technologyId),
|
|
19971
|
-
(0, import_firestore62.where)("isActive", "==", true),
|
|
19972
|
-
(0, import_firestore62.orderBy)("name")
|
|
19973
|
-
);
|
|
19974
|
-
const snapshot = await (0, import_firestore62.getDocs)(q);
|
|
19975
|
-
return snapshot.docs.map(
|
|
19976
|
-
(doc44) => ({
|
|
19977
|
-
id: doc44.id,
|
|
19978
|
-
...doc44.data()
|
|
19979
|
-
})
|
|
19980
|
-
);
|
|
19981
|
-
}
|
|
19982
|
-
/**
|
|
19983
|
-
* Gets products NOT assigned to a specific technology
|
|
19984
|
-
*/
|
|
19985
|
-
async getUnassignedProducts(technologyId) {
|
|
19986
|
-
const q = (0, import_firestore62.query)(
|
|
19987
|
-
this.getTopLevelProductsRef(),
|
|
19988
|
-
(0, import_firestore62.where)("isActive", "==", true),
|
|
19989
|
-
(0, import_firestore62.orderBy)("name")
|
|
19990
|
-
);
|
|
19991
|
-
const snapshot = await (0, import_firestore62.getDocs)(q);
|
|
19992
|
-
const allProducts = snapshot.docs.map(
|
|
19993
|
-
(doc44) => ({
|
|
19994
|
-
id: doc44.id,
|
|
19995
|
-
...doc44.data()
|
|
19996
|
-
})
|
|
19997
|
-
);
|
|
19998
|
-
return allProducts.filter(
|
|
19999
|
-
(product) => {
|
|
20000
|
-
var _a;
|
|
20001
|
-
return !((_a = product.assignedTechnologyIds) == null ? void 0 : _a.includes(technologyId));
|
|
20002
|
-
}
|
|
20003
|
-
);
|
|
20004
|
-
}
|
|
20005
|
-
/**
|
|
20006
|
-
* Gets all products for a brand (from top-level collection)
|
|
20007
|
-
*/
|
|
20008
|
-
async getByBrand(brandId) {
|
|
20009
|
-
const q = (0, import_firestore62.query)(
|
|
20010
|
-
this.getTopLevelProductsRef(),
|
|
20011
|
-
(0, import_firestore62.where)("brandId", "==", brandId),
|
|
20012
|
-
(0, import_firestore62.where)("isActive", "==", true),
|
|
20013
|
-
(0, import_firestore62.orderBy)("name")
|
|
20014
|
-
);
|
|
20015
|
-
const snapshot = await (0, import_firestore62.getDocs)(q);
|
|
20016
|
-
return snapshot.docs.map(
|
|
20017
|
-
(doc44) => ({
|
|
20018
|
-
id: doc44.id,
|
|
20019
|
-
...doc44.data()
|
|
20020
|
-
})
|
|
20021
|
-
);
|
|
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
|
-
}
|
|
20104
19446
|
};
|
|
20105
19447
|
|
|
20106
19448
|
// src/backoffice/services/constants.service.ts
|
|
@@ -20333,66 +19675,6 @@ var ConstantsService = class extends BaseService {
|
|
|
20333
19675
|
contraindications: (0, import_firestore63.arrayRemove)(toRemove)
|
|
20334
19676
|
});
|
|
20335
19677
|
}
|
|
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
|
-
}
|
|
20396
19678
|
};
|
|
20397
19679
|
|
|
20398
19680
|
// src/backoffice/types/static/contraindication.types.ts
|