@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.
@@ -169,73 +169,6 @@ var BrandService = class extends BaseService {
169
169
  ...docSnap.data()
170
170
  };
171
171
  }
172
- /**
173
- * Exports brands to CSV string, suitable for Excel/Sheets.
174
- * Includes headers and optional UTF-8 BOM.
175
- * By default exports only active brands (set includeInactive to true to export all).
176
- */
177
- async exportToCsv(options) {
178
- var _a, _b;
179
- const includeInactive = (_a = options == null ? void 0 : options.includeInactive) != null ? _a : false;
180
- const includeBom = (_b = options == null ? void 0 : options.includeBom) != null ? _b : true;
181
- const headers = [
182
- "id",
183
- "name",
184
- "manufacturer",
185
- "website",
186
- "description",
187
- "isActive"
188
- ];
189
- const rows = [];
190
- rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
191
- const PAGE_SIZE = 1e3;
192
- let cursor;
193
- const baseConstraints = [];
194
- if (!includeInactive) {
195
- baseConstraints.push(where("isActive", "==", true));
196
- }
197
- baseConstraints.push(orderBy("name_lowercase"));
198
- while (true) {
199
- const constraints = [...baseConstraints, limit(PAGE_SIZE)];
200
- if (cursor) constraints.push(startAfter(cursor));
201
- const q = query(this.getBrandsRef(), ...constraints);
202
- const snapshot = await getDocs(q);
203
- if (snapshot.empty) break;
204
- for (const d of snapshot.docs) {
205
- const brand = { id: d.id, ...d.data() };
206
- rows.push(this.brandToCsvRow(brand));
207
- }
208
- cursor = snapshot.docs[snapshot.docs.length - 1];
209
- if (snapshot.size < PAGE_SIZE) break;
210
- }
211
- const csvBody = rows.join("\r\n");
212
- return includeBom ? "\uFEFF" + csvBody : csvBody;
213
- }
214
- brandToCsvRow(brand) {
215
- var _a, _b, _c, _d, _e, _f;
216
- const values = [
217
- (_a = brand.id) != null ? _a : "",
218
- (_b = brand.name) != null ? _b : "",
219
- (_c = brand.manufacturer) != null ? _c : "",
220
- (_d = brand.website) != null ? _d : "",
221
- (_e = brand.description) != null ? _e : "",
222
- String((_f = brand.isActive) != null ? _f : "")
223
- ];
224
- return values.map((v) => this.formatCsvValue(v)).join(",");
225
- }
226
- formatDateIso(value) {
227
- if (value instanceof Date) return value.toISOString();
228
- if (value && typeof value.toDate === "function") {
229
- const d = value.toDate();
230
- return d instanceof Date ? d.toISOString() : String(value);
231
- }
232
- return String(value != null ? value : "");
233
- }
234
- formatCsvValue(value) {
235
- const str = value === null || value === void 0 ? "" : String(value);
236
- const escaped = str.replace(/"/g, '""');
237
- return `"${escaped}"`;
238
- }
239
172
  };
240
173
 
241
174
  // src/backoffice/services/category.service.ts
@@ -434,71 +367,6 @@ var CategoryService = class extends BaseService {
434
367
  ...docSnap.data()
435
368
  };
436
369
  }
437
- /**
438
- * Exports categories to CSV string, suitable for Excel/Sheets.
439
- * Includes headers and optional UTF-8 BOM.
440
- * By default exports only active categories (set includeInactive to true to export all).
441
- */
442
- async exportToCsv(options) {
443
- var _a, _b;
444
- const includeInactive = (_a = options == null ? void 0 : options.includeInactive) != null ? _a : false;
445
- const includeBom = (_b = options == null ? void 0 : options.includeBom) != null ? _b : true;
446
- const headers = [
447
- "id",
448
- "name",
449
- "description",
450
- "family",
451
- "isActive"
452
- ];
453
- const rows = [];
454
- rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
455
- const PAGE_SIZE = 1e3;
456
- let cursor;
457
- const constraints = [];
458
- if (!includeInactive) {
459
- constraints.push(where2("isActive", "==", true));
460
- }
461
- constraints.push(orderBy2("name"));
462
- while (true) {
463
- const queryConstraints = [...constraints, limit2(PAGE_SIZE)];
464
- if (cursor) queryConstraints.push(startAfter2(cursor));
465
- const q = query2(this.categoriesRef, ...queryConstraints);
466
- const snapshot = await getDocs2(q);
467
- if (snapshot.empty) break;
468
- for (const d of snapshot.docs) {
469
- const category = { id: d.id, ...d.data() };
470
- rows.push(this.categoryToCsvRow(category));
471
- }
472
- cursor = snapshot.docs[snapshot.docs.length - 1];
473
- if (snapshot.size < PAGE_SIZE) break;
474
- }
475
- const csvBody = rows.join("\r\n");
476
- return includeBom ? "\uFEFF" + csvBody : csvBody;
477
- }
478
- categoryToCsvRow(category) {
479
- var _a, _b, _c, _d, _e;
480
- const values = [
481
- (_a = category.id) != null ? _a : "",
482
- (_b = category.name) != null ? _b : "",
483
- (_c = category.description) != null ? _c : "",
484
- (_d = category.family) != null ? _d : "",
485
- String((_e = category.isActive) != null ? _e : "")
486
- ];
487
- return values.map((v) => this.formatCsvValue(v)).join(",");
488
- }
489
- formatDateIso(value) {
490
- if (value instanceof Date) return value.toISOString();
491
- if (value && typeof value.toDate === "function") {
492
- const d = value.toDate();
493
- return d instanceof Date ? d.toISOString() : String(value);
494
- }
495
- return String(value != null ? value : "");
496
- }
497
- formatCsvValue(value) {
498
- const str = value === null || value === void 0 ? "" : String(value);
499
- const escaped = str.replace(/"/g, '""');
500
- return `"${escaped}"`;
501
- }
502
370
  };
503
371
 
504
372
  // src/services/documentation-templates/documentation-template.service.ts
@@ -1290,9 +1158,7 @@ import {
1290
1158
  limit as limit6,
1291
1159
  orderBy as orderBy6,
1292
1160
  startAfter as startAfter5,
1293
- getCountFromServer as getCountFromServer4,
1294
- arrayUnion,
1295
- arrayRemove
1161
+ getCountFromServer as getCountFromServer4
1296
1162
  } from "firebase/firestore";
1297
1163
 
1298
1164
  // src/backoffice/types/product.types.ts
@@ -1304,14 +1170,7 @@ var TECHNOLOGIES_COLLECTION = "technologies";
1304
1170
  // src/backoffice/services/product.service.ts
1305
1171
  var ProductService = class extends BaseService {
1306
1172
  /**
1307
- * Gets reference to top-level products collection (source of truth)
1308
- * @returns Firestore collection reference
1309
- */
1310
- getTopLevelProductsRef() {
1311
- return collection6(this.db, PRODUCTS_COLLECTION);
1312
- }
1313
- /**
1314
- * Gets reference to products collection under a technology (backward compatibility)
1173
+ * Gets reference to products collection under a technology
1315
1174
  * @param technologyId - ID of the technology
1316
1175
  * @returns Firestore collection reference
1317
1176
  */
@@ -1327,7 +1186,6 @@ var ProductService = class extends BaseService {
1327
1186
  ...product,
1328
1187
  brandId,
1329
1188
  technologyId,
1330
- // Required for old subcollection structure
1331
1189
  createdAt: now,
1332
1190
  updatedAt: now,
1333
1191
  isActive: true
@@ -1387,26 +1245,30 @@ var ProductService = class extends BaseService {
1387
1245
  }
1388
1246
  /**
1389
1247
  * Gets counts of active products grouped by category, subcategory, and technology.
1390
- * Queries technology subcollections which have the legacy fields synced by Cloud Functions.
1248
+ * This uses a single collectionGroup query for efficiency.
1391
1249
  */
1392
1250
  async getProductCounts() {
1251
+ const q = query6(collectionGroup(this.db, PRODUCTS_COLLECTION), where6("isActive", "==", true));
1252
+ const snapshot = await getDocs6(q);
1393
1253
  const counts = {
1394
1254
  byCategory: {},
1395
1255
  bySubcategory: {},
1396
1256
  byTechnology: {}
1397
1257
  };
1398
- const q = query6(collectionGroup(this.db, PRODUCTS_COLLECTION), where6("isActive", "==", true));
1399
- const snapshot = await getDocs6(q);
1258
+ if (snapshot.empty) {
1259
+ return counts;
1260
+ }
1400
1261
  snapshot.docs.forEach((doc11) => {
1401
1262
  const product = doc11.data();
1402
- if (product.categoryId) {
1403
- counts.byCategory[product.categoryId] = (counts.byCategory[product.categoryId] || 0) + 1;
1263
+ const { categoryId, subcategoryId, technologyId } = product;
1264
+ if (categoryId) {
1265
+ counts.byCategory[categoryId] = (counts.byCategory[categoryId] || 0) + 1;
1404
1266
  }
1405
- if (product.subcategoryId) {
1406
- counts.bySubcategory[product.subcategoryId] = (counts.bySubcategory[product.subcategoryId] || 0) + 1;
1267
+ if (subcategoryId) {
1268
+ counts.bySubcategory[subcategoryId] = (counts.bySubcategory[subcategoryId] || 0) + 1;
1407
1269
  }
1408
- if (product.technologyId) {
1409
- counts.byTechnology[product.technologyId] = (counts.byTechnology[product.technologyId] || 0) + 1;
1270
+ if (technologyId) {
1271
+ counts.byTechnology[technologyId] = (counts.byTechnology[technologyId] || 0) + 1;
1410
1272
  }
1411
1273
  });
1412
1274
  return counts;
@@ -1485,241 +1347,6 @@ var ProductService = class extends BaseService {
1485
1347
  ...docSnap.data()
1486
1348
  };
1487
1349
  }
1488
- // ==========================================
1489
- // NEW METHODS: Top-level collection (preferred)
1490
- // ==========================================
1491
- /**
1492
- * Creates a new product in the top-level collection
1493
- */
1494
- async createTopLevel(brandId, product, technologyIds = []) {
1495
- const now = /* @__PURE__ */ new Date();
1496
- const newProduct = {
1497
- ...product,
1498
- brandId,
1499
- assignedTechnologyIds: technologyIds,
1500
- createdAt: now,
1501
- updatedAt: now,
1502
- isActive: true
1503
- };
1504
- const productRef = await addDoc3(this.getTopLevelProductsRef(), newProduct);
1505
- return { id: productRef.id, ...newProduct };
1506
- }
1507
- /**
1508
- * Gets all products from the top-level collection
1509
- */
1510
- async getAllTopLevel(options) {
1511
- const { rowsPerPage, lastVisible, brandId } = options;
1512
- const constraints = [where6("isActive", "==", true), orderBy6("name")];
1513
- if (brandId) {
1514
- constraints.push(where6("brandId", "==", brandId));
1515
- }
1516
- if (lastVisible) {
1517
- constraints.push(startAfter5(lastVisible));
1518
- }
1519
- constraints.push(limit6(rowsPerPage));
1520
- const q = query6(this.getTopLevelProductsRef(), ...constraints);
1521
- const snapshot = await getDocs6(q);
1522
- const products = snapshot.docs.map(
1523
- (doc11) => ({
1524
- id: doc11.id,
1525
- ...doc11.data()
1526
- })
1527
- );
1528
- const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
1529
- return { products, lastVisible: newLastVisible };
1530
- }
1531
- /**
1532
- * Gets a product by ID from the top-level collection
1533
- */
1534
- async getByIdTopLevel(productId) {
1535
- const docRef = doc6(this.getTopLevelProductsRef(), productId);
1536
- const docSnap = await getDoc6(docRef);
1537
- if (!docSnap.exists()) return null;
1538
- return {
1539
- id: docSnap.id,
1540
- ...docSnap.data()
1541
- };
1542
- }
1543
- /**
1544
- * Updates a product in the top-level collection
1545
- */
1546
- async updateTopLevel(productId, product) {
1547
- const updateData = {
1548
- ...product,
1549
- updatedAt: /* @__PURE__ */ new Date()
1550
- };
1551
- const docRef = doc6(this.getTopLevelProductsRef(), productId);
1552
- await updateDoc6(docRef, updateData);
1553
- return this.getByIdTopLevel(productId);
1554
- }
1555
- /**
1556
- * Deletes a product from the top-level collection (soft delete)
1557
- */
1558
- async deleteTopLevel(productId) {
1559
- await this.updateTopLevel(productId, {
1560
- isActive: false
1561
- });
1562
- }
1563
- /**
1564
- * Assigns a product to a technology
1565
- */
1566
- async assignToTechnology(productId, technologyId) {
1567
- const docRef = doc6(this.getTopLevelProductsRef(), productId);
1568
- await updateDoc6(docRef, {
1569
- assignedTechnologyIds: arrayUnion(technologyId),
1570
- updatedAt: /* @__PURE__ */ new Date()
1571
- });
1572
- }
1573
- /**
1574
- * Unassigns a product from a technology
1575
- */
1576
- async unassignFromTechnology(productId, technologyId) {
1577
- const docRef = doc6(this.getTopLevelProductsRef(), productId);
1578
- await updateDoc6(docRef, {
1579
- assignedTechnologyIds: arrayRemove(technologyId),
1580
- updatedAt: /* @__PURE__ */ new Date()
1581
- });
1582
- }
1583
- /**
1584
- * Gets products assigned to a specific technology
1585
- */
1586
- async getAssignedProducts(technologyId) {
1587
- const q = query6(
1588
- this.getTopLevelProductsRef(),
1589
- where6("assignedTechnologyIds", "array-contains", technologyId),
1590
- where6("isActive", "==", true),
1591
- orderBy6("name")
1592
- );
1593
- const snapshot = await getDocs6(q);
1594
- return snapshot.docs.map(
1595
- (doc11) => ({
1596
- id: doc11.id,
1597
- ...doc11.data()
1598
- })
1599
- );
1600
- }
1601
- /**
1602
- * Gets products NOT assigned to a specific technology
1603
- */
1604
- async getUnassignedProducts(technologyId) {
1605
- const q = query6(
1606
- this.getTopLevelProductsRef(),
1607
- where6("isActive", "==", true),
1608
- orderBy6("name")
1609
- );
1610
- const snapshot = await getDocs6(q);
1611
- const allProducts = snapshot.docs.map(
1612
- (doc11) => ({
1613
- id: doc11.id,
1614
- ...doc11.data()
1615
- })
1616
- );
1617
- return allProducts.filter(
1618
- (product) => {
1619
- var _a;
1620
- return !((_a = product.assignedTechnologyIds) == null ? void 0 : _a.includes(technologyId));
1621
- }
1622
- );
1623
- }
1624
- /**
1625
- * Gets all products for a brand (from top-level collection)
1626
- */
1627
- async getByBrand(brandId) {
1628
- const q = query6(
1629
- this.getTopLevelProductsRef(),
1630
- where6("brandId", "==", brandId),
1631
- where6("isActive", "==", true),
1632
- orderBy6("name")
1633
- );
1634
- const snapshot = await getDocs6(q);
1635
- return snapshot.docs.map(
1636
- (doc11) => ({
1637
- id: doc11.id,
1638
- ...doc11.data()
1639
- })
1640
- );
1641
- }
1642
- /**
1643
- * Exports products to CSV string, suitable for Excel/Sheets.
1644
- * Includes headers and optional UTF-8 BOM.
1645
- * By default exports only active products (set includeInactive to true to export all).
1646
- */
1647
- async exportToCsv(options) {
1648
- var _a, _b;
1649
- const includeInactive = (_a = options == null ? void 0 : options.includeInactive) != null ? _a : false;
1650
- const includeBom = (_b = options == null ? void 0 : options.includeBom) != null ? _b : true;
1651
- const headers = [
1652
- "id",
1653
- "name",
1654
- "brandId",
1655
- "brandName",
1656
- "assignedTechnologyIds",
1657
- "description",
1658
- "technicalDetails",
1659
- "dosage",
1660
- "composition",
1661
- "indications",
1662
- "contraindications",
1663
- "warnings",
1664
- "isActive"
1665
- ];
1666
- const rows = [];
1667
- rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
1668
- const PAGE_SIZE = 1e3;
1669
- let cursor;
1670
- const constraints = [];
1671
- if (!includeInactive) {
1672
- constraints.push(where6("isActive", "==", true));
1673
- }
1674
- constraints.push(orderBy6("name"));
1675
- while (true) {
1676
- const queryConstraints = [...constraints, limit6(PAGE_SIZE)];
1677
- if (cursor) queryConstraints.push(startAfter5(cursor));
1678
- const q = query6(this.getTopLevelProductsRef(), ...queryConstraints);
1679
- const snapshot = await getDocs6(q);
1680
- if (snapshot.empty) break;
1681
- for (const d of snapshot.docs) {
1682
- const product = { id: d.id, ...d.data() };
1683
- rows.push(this.productToCsvRow(product));
1684
- }
1685
- cursor = snapshot.docs[snapshot.docs.length - 1];
1686
- if (snapshot.size < PAGE_SIZE) break;
1687
- }
1688
- const csvBody = rows.join("\r\n");
1689
- return includeBom ? "\uFEFF" + csvBody : csvBody;
1690
- }
1691
- productToCsvRow(product) {
1692
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
1693
- const values = [
1694
- (_a = product.id) != null ? _a : "",
1695
- (_b = product.name) != null ? _b : "",
1696
- (_c = product.brandId) != null ? _c : "",
1697
- (_d = product.brandName) != null ? _d : "",
1698
- (_f = (_e = product.assignedTechnologyIds) == null ? void 0 : _e.join(";")) != null ? _f : "",
1699
- (_g = product.description) != null ? _g : "",
1700
- (_h = product.technicalDetails) != null ? _h : "",
1701
- (_i = product.dosage) != null ? _i : "",
1702
- (_j = product.composition) != null ? _j : "",
1703
- (_l = (_k = product.indications) == null ? void 0 : _k.join(";")) != null ? _l : "",
1704
- (_n = (_m = product.contraindications) == null ? void 0 : _m.map((c) => c.name).join(";")) != null ? _n : "",
1705
- (_p = (_o = product.warnings) == null ? void 0 : _o.join(";")) != null ? _p : "",
1706
- String((_q = product.isActive) != null ? _q : "")
1707
- ];
1708
- return values.map((v) => this.formatCsvValue(v)).join(",");
1709
- }
1710
- formatDateIso(value) {
1711
- if (value instanceof Date) return value.toISOString();
1712
- if (value && typeof value.toDate === "function") {
1713
- const d = value.toDate();
1714
- return d instanceof Date ? d.toISOString() : String(value);
1715
- }
1716
- return String(value != null ? value : "");
1717
- }
1718
- formatCsvValue(value) {
1719
- const str = value === null || value === void 0 ? "" : String(value);
1720
- const escaped = str.replace(/"/g, '""');
1721
- return `"${escaped}"`;
1722
- }
1723
1350
  };
1724
1351
 
1725
1352
  // src/backoffice/services/requirement.service.ts
@@ -1731,8 +1358,7 @@ import {
1731
1358
  getDocs as getDocs7,
1732
1359
  query as query7,
1733
1360
  updateDoc as updateDoc7,
1734
- where as where7,
1735
- orderBy as orderBy7
1361
+ where as where7
1736
1362
  } from "firebase/firestore";
1737
1363
 
1738
1364
  // src/backoffice/types/requirement.types.ts
@@ -1853,65 +1479,6 @@ var RequirementService = class extends BaseService {
1853
1479
  ...docSnap.data()
1854
1480
  };
1855
1481
  }
1856
- /**
1857
- * Exports requirements to CSV string, suitable for Excel/Sheets.
1858
- * Includes headers and optional UTF-8 BOM.
1859
- * By default exports only active requirements (set includeInactive to true to export all).
1860
- */
1861
- async exportToCsv(options) {
1862
- var _a, _b;
1863
- const includeInactive = (_a = options == null ? void 0 : options.includeInactive) != null ? _a : false;
1864
- const includeBom = (_b = options == null ? void 0 : options.includeBom) != null ? _b : true;
1865
- const headers = [
1866
- "id",
1867
- "type",
1868
- "name",
1869
- "description",
1870
- "timeframe_duration",
1871
- "timeframe_unit",
1872
- "timeframe_notifyAt",
1873
- "importance",
1874
- "isActive"
1875
- ];
1876
- const rows = [];
1877
- rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
1878
- const q = includeInactive ? query7(this.requirementsRef, orderBy7("name")) : query7(this.requirementsRef, where7("isActive", "==", true), orderBy7("name"));
1879
- const snapshot = await getDocs7(q);
1880
- for (const d of snapshot.docs) {
1881
- const requirement = { id: d.id, ...d.data() };
1882
- rows.push(this.requirementToCsvRow(requirement));
1883
- }
1884
- const csvBody = rows.join("\r\n");
1885
- return includeBom ? "\uFEFF" + csvBody : csvBody;
1886
- }
1887
- requirementToCsvRow(requirement) {
1888
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
1889
- const values = [
1890
- (_a = requirement.id) != null ? _a : "",
1891
- (_b = requirement.type) != null ? _b : "",
1892
- (_c = requirement.name) != null ? _c : "",
1893
- (_d = requirement.description) != null ? _d : "",
1894
- (_g = (_f = (_e = requirement.timeframe) == null ? void 0 : _e.duration) == null ? void 0 : _f.toString()) != null ? _g : "",
1895
- (_i = (_h = requirement.timeframe) == null ? void 0 : _h.unit) != null ? _i : "",
1896
- (_l = (_k = (_j = requirement.timeframe) == null ? void 0 : _j.notifyAt) == null ? void 0 : _k.join(";")) != null ? _l : "",
1897
- (_m = requirement.importance) != null ? _m : "",
1898
- String((_n = requirement.isActive) != null ? _n : "")
1899
- ];
1900
- return values.map((v) => this.formatCsvValue(v)).join(",");
1901
- }
1902
- formatDateIso(value) {
1903
- if (value instanceof Date) return value.toISOString();
1904
- if (value && typeof value.toDate === "function") {
1905
- const d = value.toDate();
1906
- return d instanceof Date ? d.toISOString() : String(value);
1907
- }
1908
- return String(value != null ? value : "");
1909
- }
1910
- formatCsvValue(value) {
1911
- const str = value === null || value === void 0 ? "" : String(value);
1912
- const escaped = str.replace(/"/g, '""');
1913
- return `"${escaped}"`;
1914
- }
1915
1482
  };
1916
1483
 
1917
1484
  // src/backoffice/services/subcategory.service.ts
@@ -1925,7 +1492,7 @@ import {
1925
1492
  getDoc as getDoc8,
1926
1493
  getDocs as getDocs8,
1927
1494
  limit as limit7,
1928
- orderBy as orderBy8,
1495
+ orderBy as orderBy7,
1929
1496
  query as query8,
1930
1497
  setDoc as setDoc4,
1931
1498
  startAfter as startAfter6,
@@ -1999,7 +1566,7 @@ var SubcategoryService = class extends BaseService {
1999
1566
  const { active = true, limit: queryLimit = 10, lastVisible } = options;
2000
1567
  const constraints = [
2001
1568
  where8("isActive", "==", active),
2002
- orderBy8("name"),
1569
+ orderBy7("name"),
2003
1570
  queryLimit ? limit7(queryLimit) : void 0,
2004
1571
  lastVisible ? startAfter6(lastVisible) : void 0
2005
1572
  ].filter((c) => !!c);
@@ -2026,7 +1593,7 @@ var SubcategoryService = class extends BaseService {
2026
1593
  const { active = true, limit: queryLimit = 10, lastVisible } = options;
2027
1594
  const constraints = [
2028
1595
  where8("isActive", "==", active),
2029
- orderBy8("name"),
1596
+ orderBy7("name"),
2030
1597
  queryLimit ? limit7(queryLimit) : void 0,
2031
1598
  lastVisible ? startAfter6(lastVisible) : void 0
2032
1599
  ].filter((c) => !!c);
@@ -2155,74 +1722,6 @@ var SubcategoryService = class extends BaseService {
2155
1722
  ...docSnap.data()
2156
1723
  };
2157
1724
  }
2158
- /**
2159
- * Exports subcategories to CSV string, suitable for Excel/Sheets.
2160
- * Includes headers and optional UTF-8 BOM.
2161
- * By default exports only active subcategories (set includeInactive to true to export all).
2162
- */
2163
- async exportToCsv(options) {
2164
- var _a, _b;
2165
- const includeInactive = (_a = options == null ? void 0 : options.includeInactive) != null ? _a : false;
2166
- const includeBom = (_b = options == null ? void 0 : options.includeBom) != null ? _b : true;
2167
- const headers = [
2168
- "id",
2169
- "name",
2170
- "categoryId",
2171
- "description",
2172
- "isActive"
2173
- ];
2174
- const rows = [];
2175
- rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
2176
- const PAGE_SIZE = 1e3;
2177
- let cursor;
2178
- const constraints = [];
2179
- if (!includeInactive) {
2180
- constraints.push(where8("isActive", "==", true));
2181
- }
2182
- constraints.push(orderBy8("name"));
2183
- while (true) {
2184
- const queryConstraints = [...constraints, limit7(PAGE_SIZE)];
2185
- if (cursor) queryConstraints.push(startAfter6(cursor));
2186
- const q = query8(
2187
- collectionGroup2(this.db, SUBCATEGORIES_COLLECTION),
2188
- ...queryConstraints
2189
- );
2190
- const snapshot = await getDocs8(q);
2191
- if (snapshot.empty) break;
2192
- for (const d of snapshot.docs) {
2193
- const subcategory = { id: d.id, ...d.data() };
2194
- rows.push(this.subcategoryToCsvRow(subcategory));
2195
- }
2196
- cursor = snapshot.docs[snapshot.docs.length - 1];
2197
- if (snapshot.size < PAGE_SIZE) break;
2198
- }
2199
- const csvBody = rows.join("\r\n");
2200
- return includeBom ? "\uFEFF" + csvBody : csvBody;
2201
- }
2202
- subcategoryToCsvRow(subcategory) {
2203
- var _a, _b, _c, _d, _e;
2204
- const values = [
2205
- (_a = subcategory.id) != null ? _a : "",
2206
- (_b = subcategory.name) != null ? _b : "",
2207
- (_c = subcategory.categoryId) != null ? _c : "",
2208
- (_d = subcategory.description) != null ? _d : "",
2209
- String((_e = subcategory.isActive) != null ? _e : "")
2210
- ];
2211
- return values.map((v) => this.formatCsvValue(v)).join(",");
2212
- }
2213
- formatDateIso(value) {
2214
- if (value instanceof Date) return value.toISOString();
2215
- if (value && typeof value.toDate === "function") {
2216
- const d = value.toDate();
2217
- return d instanceof Date ? d.toISOString() : String(value);
2218
- }
2219
- return String(value != null ? value : "");
2220
- }
2221
- formatCsvValue(value) {
2222
- const str = value === null || value === void 0 ? "" : String(value);
2223
- const escaped = str.replace(/"/g, '""');
2224
- return `"${escaped}"`;
2225
- }
2226
1725
  };
2227
1726
 
2228
1727
  // src/backoffice/services/technology.service.ts
@@ -2233,14 +1732,13 @@ import {
2233
1732
  getDoc as getDoc9,
2234
1733
  getDocs as getDocs9,
2235
1734
  limit as limit8,
2236
- orderBy as orderBy9,
1735
+ orderBy as orderBy8,
2237
1736
  query as query9,
2238
1737
  startAfter as startAfter7,
2239
1738
  updateDoc as updateDoc9,
2240
1739
  where as where9,
2241
- arrayUnion as arrayUnion2,
2242
- arrayRemove as arrayRemove2,
2243
- writeBatch
1740
+ arrayUnion,
1741
+ arrayRemove
2244
1742
  } from "firebase/firestore";
2245
1743
 
2246
1744
  // src/backoffice/types/static/certification.types.ts
@@ -2347,7 +1845,7 @@ var TechnologyService = class extends BaseService {
2347
1845
  const { active = true, limit: queryLimit = 10, lastVisible } = options;
2348
1846
  const constraints = [
2349
1847
  where9("isActive", "==", active),
2350
- orderBy9("name"),
1848
+ orderBy8("name"),
2351
1849
  queryLimit ? limit8(queryLimit) : void 0,
2352
1850
  lastVisible ? startAfter7(lastVisible) : void 0
2353
1851
  ].filter((c) => !!c);
@@ -2373,7 +1871,7 @@ var TechnologyService = class extends BaseService {
2373
1871
  const constraints = [
2374
1872
  where9("categoryId", "==", categoryId),
2375
1873
  where9("isActive", "==", active),
2376
- orderBy9("name"),
1874
+ orderBy8("name"),
2377
1875
  queryLimit ? limit8(queryLimit) : void 0,
2378
1876
  lastVisible ? startAfter7(lastVisible) : void 0
2379
1877
  ].filter((c) => !!c);
@@ -2399,7 +1897,7 @@ var TechnologyService = class extends BaseService {
2399
1897
  const constraints = [
2400
1898
  where9("subcategoryId", "==", subcategoryId),
2401
1899
  where9("isActive", "==", active),
2402
- orderBy9("name"),
1900
+ orderBy8("name"),
2403
1901
  queryLimit ? limit8(queryLimit) : void 0,
2404
1902
  lastVisible ? startAfter7(lastVisible) : void 0
2405
1903
  ].filter((c) => !!c);
@@ -2429,18 +1927,7 @@ var TechnologyService = class extends BaseService {
2429
1927
  });
2430
1928
  updateData.updatedAt = /* @__PURE__ */ new Date();
2431
1929
  const docRef = doc9(this.technologiesRef, id);
2432
- const beforeTech = await this.getById(id);
2433
1930
  await updateDoc9(docRef, updateData);
2434
- const categoryChanged = beforeTech && updateData.categoryId && beforeTech.categoryId !== updateData.categoryId;
2435
- const subcategoryChanged = beforeTech && updateData.subcategoryId && beforeTech.subcategoryId !== updateData.subcategoryId;
2436
- const nameChanged = beforeTech && updateData.name && beforeTech.name !== updateData.name;
2437
- if (categoryChanged || subcategoryChanged || nameChanged) {
2438
- await this.updateProductsInSubcollection(id, {
2439
- categoryId: updateData.categoryId,
2440
- subcategoryId: updateData.subcategoryId,
2441
- technologyName: updateData.name
2442
- });
2443
- }
2444
1931
  return this.getById(id);
2445
1932
  }
2446
1933
  /**
@@ -2481,7 +1968,7 @@ var TechnologyService = class extends BaseService {
2481
1968
  const docRef = doc9(this.technologiesRef, technologyId);
2482
1969
  const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
2483
1970
  await updateDoc9(docRef, {
2484
- [requirementType]: arrayUnion2(requirement),
1971
+ [requirementType]: arrayUnion(requirement),
2485
1972
  updatedAt: /* @__PURE__ */ new Date()
2486
1973
  });
2487
1974
  return this.getById(technologyId);
@@ -2496,7 +1983,7 @@ var TechnologyService = class extends BaseService {
2496
1983
  const docRef = doc9(this.technologiesRef, technologyId);
2497
1984
  const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
2498
1985
  await updateDoc9(docRef, {
2499
- [requirementType]: arrayRemove2(requirement),
1986
+ [requirementType]: arrayRemove(requirement),
2500
1987
  updatedAt: /* @__PURE__ */ new Date()
2501
1988
  });
2502
1989
  return this.getById(technologyId);
@@ -2535,7 +2022,7 @@ var TechnologyService = class extends BaseService {
2535
2022
  async addBlockingCondition(technologyId, condition) {
2536
2023
  const docRef = doc9(this.technologiesRef, technologyId);
2537
2024
  await updateDoc9(docRef, {
2538
- blockingConditions: arrayUnion2(condition),
2025
+ blockingConditions: arrayUnion(condition),
2539
2026
  updatedAt: /* @__PURE__ */ new Date()
2540
2027
  });
2541
2028
  return this.getById(technologyId);
@@ -2549,7 +2036,7 @@ var TechnologyService = class extends BaseService {
2549
2036
  async removeBlockingCondition(technologyId, condition) {
2550
2037
  const docRef = doc9(this.technologiesRef, technologyId);
2551
2038
  await updateDoc9(docRef, {
2552
- blockingConditions: arrayRemove2(condition),
2039
+ blockingConditions: arrayRemove(condition),
2553
2040
  updatedAt: /* @__PURE__ */ new Date()
2554
2041
  });
2555
2042
  return this.getById(technologyId);
@@ -2828,7 +2315,7 @@ var TechnologyService = class extends BaseService {
2828
2315
  collection9(this.db, TECHNOLOGIES_COLLECTION),
2829
2316
  where9("isActive", "==", true),
2830
2317
  where9("subcategoryId", "==", subcategoryId),
2831
- orderBy9("name")
2318
+ orderBy8("name")
2832
2319
  );
2833
2320
  const snapshot = await getDocs9(q);
2834
2321
  return snapshot.docs.map(
@@ -2849,7 +2336,7 @@ var TechnologyService = class extends BaseService {
2849
2336
  where9("isActive", "==", true),
2850
2337
  where9("categoryId", "==", categoryId),
2851
2338
  where9("subcategoryId", "==", subcategoryId),
2852
- orderBy9("name")
2339
+ orderBy8("name")
2853
2340
  );
2854
2341
  const snapshot = await getDocs9(q);
2855
2342
  return snapshot.docs.map(
@@ -2866,7 +2353,7 @@ var TechnologyService = class extends BaseService {
2866
2353
  const q = query9(
2867
2354
  collection9(this.db, TECHNOLOGIES_COLLECTION),
2868
2355
  where9("isActive", "==", true),
2869
- orderBy9("name")
2356
+ orderBy8("name")
2870
2357
  );
2871
2358
  const snapshot = await getDocs9(q);
2872
2359
  return snapshot.docs.map(
@@ -2876,231 +2363,12 @@ var TechnologyService = class extends BaseService {
2876
2363
  })
2877
2364
  );
2878
2365
  }
2879
- // ==========================================
2880
- // NEW METHODS: Product assignment management
2881
- // ==========================================
2882
- /**
2883
- * Assigns multiple products to a technology
2884
- * Updates each product's assignedTechnologyIds array
2885
- */
2886
- async assignProducts(technologyId, productIds) {
2887
- const batch = writeBatch(this.db);
2888
- for (const productId of productIds) {
2889
- const productRef = doc9(this.db, PRODUCTS_COLLECTION, productId);
2890
- batch.update(productRef, {
2891
- assignedTechnologyIds: arrayUnion2(technologyId),
2892
- updatedAt: /* @__PURE__ */ new Date()
2893
- });
2894
- }
2895
- await batch.commit();
2896
- }
2897
- /**
2898
- * Unassigns multiple products from a technology
2899
- * Updates each product's assignedTechnologyIds array
2900
- */
2901
- async unassignProducts(technologyId, productIds) {
2902
- const batch = writeBatch(this.db);
2903
- for (const productId of productIds) {
2904
- const productRef = doc9(this.db, PRODUCTS_COLLECTION, productId);
2905
- batch.update(productRef, {
2906
- assignedTechnologyIds: arrayRemove2(technologyId),
2907
- updatedAt: /* @__PURE__ */ new Date()
2908
- });
2909
- }
2910
- await batch.commit();
2911
- }
2912
- /**
2913
- * Gets products assigned to a specific technology
2914
- * Reads from top-level collection for immediate consistency (Cloud Functions may lag)
2915
- */
2916
- async getAssignedProducts(technologyId) {
2917
- const q = query9(
2918
- collection9(this.db, PRODUCTS_COLLECTION),
2919
- where9("assignedTechnologyIds", "array-contains", technologyId),
2920
- where9("isActive", "==", true),
2921
- orderBy9("name")
2922
- );
2923
- const snapshot = await getDocs9(q);
2924
- return snapshot.docs.map(
2925
- (doc11) => ({
2926
- id: doc11.id,
2927
- ...doc11.data()
2928
- })
2929
- );
2930
- }
2931
- /**
2932
- * Gets products NOT assigned to a specific technology
2933
- */
2934
- async getUnassignedProducts(technologyId) {
2935
- const q = query9(
2936
- collection9(this.db, PRODUCTS_COLLECTION),
2937
- where9("isActive", "==", true),
2938
- orderBy9("name")
2939
- );
2940
- const snapshot = await getDocs9(q);
2941
- const allProducts = snapshot.docs.map(
2942
- (doc11) => ({
2943
- id: doc11.id,
2944
- ...doc11.data()
2945
- })
2946
- );
2947
- return allProducts.filter(
2948
- (product) => {
2949
- var _a;
2950
- return !((_a = product.assignedTechnologyIds) == null ? void 0 : _a.includes(technologyId));
2951
- }
2952
- );
2953
- }
2954
- /**
2955
- * Gets product assignment statistics for a technology
2956
- */
2957
- async getProductStats(technologyId) {
2958
- const products = await this.getAssignedProducts(technologyId);
2959
- const byBrand = {};
2960
- products.forEach((product) => {
2961
- byBrand[product.brandName] = (byBrand[product.brandName] || 0) + 1;
2962
- });
2963
- return {
2964
- totalAssigned: products.length,
2965
- byBrand
2966
- };
2967
- }
2968
- /**
2969
- * Updates products in technology subcollection when technology metadata changes
2970
- * @param technologyId - ID of the technology
2971
- * @param updates - Fields to update (categoryId, subcategoryId, technologyName)
2972
- */
2973
- async updateProductsInSubcollection(technologyId, updates) {
2974
- const productsRef = collection9(this.db, TECHNOLOGIES_COLLECTION, technologyId, PRODUCTS_COLLECTION);
2975
- const productsSnapshot = await getDocs9(productsRef);
2976
- if (productsSnapshot.empty) {
2977
- return;
2978
- }
2979
- const batch = writeBatch(this.db);
2980
- for (const productDoc of productsSnapshot.docs) {
2981
- const productRef = productDoc.ref;
2982
- const updateFields = {};
2983
- if (updates.categoryId !== void 0) {
2984
- updateFields.categoryId = updates.categoryId;
2985
- }
2986
- if (updates.subcategoryId !== void 0) {
2987
- updateFields.subcategoryId = updates.subcategoryId;
2988
- }
2989
- if (updates.technologyName !== void 0) {
2990
- updateFields.technologyName = updates.technologyName;
2991
- }
2992
- if (Object.keys(updateFields).length > 0) {
2993
- batch.update(productRef, updateFields);
2994
- }
2995
- }
2996
- await batch.commit();
2997
- }
2998
- /**
2999
- * Exports technologies to CSV string, suitable for Excel/Sheets.
3000
- * Includes headers and optional UTF-8 BOM.
3001
- * By default exports only active technologies (set includeInactive to true to export all).
3002
- * Includes product names from subcollections.
3003
- */
3004
- async exportToCsv(options) {
3005
- var _a, _b;
3006
- const includeInactive = (_a = options == null ? void 0 : options.includeInactive) != null ? _a : false;
3007
- const includeBom = (_b = options == null ? void 0 : options.includeBom) != null ? _b : true;
3008
- const headers = [
3009
- "id",
3010
- "name",
3011
- "description",
3012
- "family",
3013
- "categoryId",
3014
- "subcategoryId",
3015
- "technicalDetails",
3016
- "requirements_pre",
3017
- "requirements_post",
3018
- "blockingConditions",
3019
- "contraindications",
3020
- "benefits",
3021
- "certificationMinimumLevel",
3022
- "certificationRequiredSpecialties",
3023
- "documentationTemplateIds",
3024
- "productNames",
3025
- "isActive"
3026
- ];
3027
- const rows = [];
3028
- rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
3029
- const PAGE_SIZE = 1e3;
3030
- let cursor;
3031
- const constraints = [];
3032
- if (!includeInactive) {
3033
- constraints.push(where9("isActive", "==", true));
3034
- }
3035
- constraints.push(orderBy9("name"));
3036
- while (true) {
3037
- const queryConstraints = [...constraints, limit8(PAGE_SIZE)];
3038
- if (cursor) queryConstraints.push(startAfter7(cursor));
3039
- const q = query9(this.technologiesRef, ...queryConstraints);
3040
- const snapshot = await getDocs9(q);
3041
- if (snapshot.empty) break;
3042
- for (const d of snapshot.docs) {
3043
- const technology = { id: d.id, ...d.data() };
3044
- const productNames = await this.getProductNamesForTechnology(technology.id);
3045
- rows.push(this.technologyToCsvRow(technology, productNames));
3046
- }
3047
- cursor = snapshot.docs[snapshot.docs.length - 1];
3048
- if (snapshot.size < PAGE_SIZE) break;
3049
- }
3050
- const csvBody = rows.join("\r\n");
3051
- return includeBom ? "\uFEFF" + csvBody : csvBody;
3052
- }
3053
- /**
3054
- * Gets product names from the technology's product subcollection
3055
- */
3056
- async getProductNamesForTechnology(technologyId) {
3057
- try {
3058
- const productsRef = collection9(this.db, TECHNOLOGIES_COLLECTION, technologyId, PRODUCTS_COLLECTION);
3059
- const q = query9(productsRef, where9("isActive", "==", true));
3060
- const snapshot = await getDocs9(q);
3061
- return snapshot.docs.map((doc11) => {
3062
- const product = doc11.data();
3063
- return product.name || "";
3064
- }).filter((name) => name);
3065
- } catch (error) {
3066
- console.error(`Error fetching products for technology ${technologyId}:`, error);
3067
- return [];
3068
- }
3069
- }
3070
- technologyToCsvRow(technology, productNames = []) {
3071
- 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;
3072
- const values = [
3073
- (_a = technology.id) != null ? _a : "",
3074
- (_b = technology.name) != null ? _b : "",
3075
- (_c = technology.description) != null ? _c : "",
3076
- (_d = technology.family) != null ? _d : "",
3077
- (_e = technology.categoryId) != null ? _e : "",
3078
- (_f = technology.subcategoryId) != null ? _f : "",
3079
- (_g = technology.technicalDetails) != null ? _g : "",
3080
- (_j = (_i = (_h = technology.requirements) == null ? void 0 : _h.pre) == null ? void 0 : _i.map((r) => r.name).join(";")) != null ? _j : "",
3081
- (_m = (_l = (_k = technology.requirements) == null ? void 0 : _k.post) == null ? void 0 : _l.map((r) => r.name).join(";")) != null ? _m : "",
3082
- (_o = (_n = technology.blockingConditions) == null ? void 0 : _n.join(";")) != null ? _o : "",
3083
- (_q = (_p = technology.contraindications) == null ? void 0 : _p.map((c) => c.name).join(";")) != null ? _q : "",
3084
- (_s = (_r = technology.benefits) == null ? void 0 : _r.map((b) => b.name).join(";")) != null ? _s : "",
3085
- (_u = (_t = technology.certificationRequirement) == null ? void 0 : _t.minimumLevel) != null ? _u : "",
3086
- (_x = (_w = (_v = technology.certificationRequirement) == null ? void 0 : _v.requiredSpecialties) == null ? void 0 : _w.join(";")) != null ? _x : "",
3087
- (_z = (_y = technology.documentationTemplates) == null ? void 0 : _y.map((t) => t.templateId).join(";")) != null ? _z : "",
3088
- productNames.join(";"),
3089
- String((_A = technology.isActive) != null ? _A : "")
3090
- ];
3091
- return values.map((v) => this.formatCsvValue(v)).join(",");
3092
- }
3093
- formatCsvValue(value) {
3094
- const str = value === null || value === void 0 ? "" : String(value);
3095
- const escaped = str.replace(/"/g, '""');
3096
- return `"${escaped}"`;
3097
- }
3098
2366
  };
3099
2367
 
3100
2368
  // src/backoffice/services/constants.service.ts
3101
2369
  import {
3102
- arrayRemove as arrayRemove3,
3103
- arrayUnion as arrayUnion3,
2370
+ arrayRemove as arrayRemove2,
2371
+ arrayUnion as arrayUnion2,
3104
2372
  doc as doc10,
3105
2373
  getDoc as getDoc10,
3106
2374
  setDoc as setDoc5,
@@ -3168,7 +2436,7 @@ var ConstantsService = class extends BaseService {
3168
2436
  await setDoc5(this.treatmentBenefitsDocRef, { benefits: [newBenefit] });
3169
2437
  } else {
3170
2438
  await updateDoc10(this.treatmentBenefitsDocRef, {
3171
- benefits: arrayUnion3(newBenefit)
2439
+ benefits: arrayUnion2(newBenefit)
3172
2440
  });
3173
2441
  }
3174
2442
  return newBenefit;
@@ -3222,7 +2490,7 @@ var ConstantsService = class extends BaseService {
3222
2490
  return;
3223
2491
  }
3224
2492
  await updateDoc10(this.treatmentBenefitsDocRef, {
3225
- benefits: arrayRemove3(benefitToRemove)
2493
+ benefits: arrayRemove2(benefitToRemove)
3226
2494
  });
3227
2495
  }
3228
2496
  // =================================================================
@@ -3275,7 +2543,7 @@ var ConstantsService = class extends BaseService {
3275
2543
  });
3276
2544
  } else {
3277
2545
  await updateDoc10(this.contraindicationsDocRef, {
3278
- contraindications: arrayUnion3(newContraindication)
2546
+ contraindications: arrayUnion2(newContraindication)
3279
2547
  });
3280
2548
  }
3281
2549
  return newContraindication;
@@ -3331,69 +2599,9 @@ var ConstantsService = class extends BaseService {
3331
2599
  return;
3332
2600
  }
3333
2601
  await updateDoc10(this.contraindicationsDocRef, {
3334
- contraindications: arrayRemove3(toRemove)
2602
+ contraindications: arrayRemove2(toRemove)
3335
2603
  });
3336
2604
  }
3337
- // =================================================================
3338
- // CSV Export Methods
3339
- // =================================================================
3340
- /**
3341
- * Exports treatment benefits to CSV string, suitable for Excel/Sheets.
3342
- * Includes headers and optional UTF-8 BOM.
3343
- */
3344
- async exportBenefitsToCsv(options) {
3345
- var _a;
3346
- const includeBom = (_a = options == null ? void 0 : options.includeBom) != null ? _a : true;
3347
- const headers = ["id", "name", "description"];
3348
- const rows = [];
3349
- rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
3350
- const benefits = await this.getAllBenefitsForFilter();
3351
- for (const benefit of benefits) {
3352
- rows.push(this.benefitToCsvRow(benefit));
3353
- }
3354
- const csvBody = rows.join("\r\n");
3355
- return includeBom ? "\uFEFF" + csvBody : csvBody;
3356
- }
3357
- /**
3358
- * Exports contraindications to CSV string, suitable for Excel/Sheets.
3359
- * Includes headers and optional UTF-8 BOM.
3360
- */
3361
- async exportContraindicationsToCsv(options) {
3362
- var _a;
3363
- const includeBom = (_a = options == null ? void 0 : options.includeBom) != null ? _a : true;
3364
- const headers = ["id", "name", "description"];
3365
- const rows = [];
3366
- rows.push(headers.map((h) => this.formatCsvValue(h)).join(","));
3367
- const contraindications = await this.getAllContraindicationsForFilter();
3368
- for (const contraindication of contraindications) {
3369
- rows.push(this.contraindicationToCsvRow(contraindication));
3370
- }
3371
- const csvBody = rows.join("\r\n");
3372
- return includeBom ? "\uFEFF" + csvBody : csvBody;
3373
- }
3374
- benefitToCsvRow(benefit) {
3375
- var _a, _b, _c;
3376
- const values = [
3377
- (_a = benefit.id) != null ? _a : "",
3378
- (_b = benefit.name) != null ? _b : "",
3379
- (_c = benefit.description) != null ? _c : ""
3380
- ];
3381
- return values.map((v) => this.formatCsvValue(v)).join(",");
3382
- }
3383
- contraindicationToCsvRow(contraindication) {
3384
- var _a, _b, _c;
3385
- const values = [
3386
- (_a = contraindication.id) != null ? _a : "",
3387
- (_b = contraindication.name) != null ? _b : "",
3388
- (_c = contraindication.description) != null ? _c : ""
3389
- ];
3390
- return values.map((v) => this.formatCsvValue(v)).join(",");
3391
- }
3392
- formatCsvValue(value) {
3393
- const str = value === null || value === void 0 ? "" : String(value);
3394
- const escaped = str.replace(/"/g, '""');
3395
- return `"${escaped}"`;
3396
- }
3397
2605
  };
3398
2606
 
3399
2607
  // src/backoffice/types/static/blocking-condition.types.ts