@blackcode_sa/metaestetics-api 1.12.42 → 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.
@@ -169,6 +169,73 @@ 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
+ }
172
239
  };
173
240
 
174
241
  // src/backoffice/services/category.service.ts
@@ -367,6 +434,71 @@ var CategoryService = class extends BaseService {
367
434
  ...docSnap.data()
368
435
  };
369
436
  }
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
+ }
370
502
  };
371
503
 
372
504
  // src/services/documentation-templates/documentation-template.service.ts
@@ -1507,6 +1639,87 @@ var ProductService = class extends BaseService {
1507
1639
  })
1508
1640
  );
1509
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
+ }
1510
1723
  };
1511
1724
 
1512
1725
  // src/backoffice/services/requirement.service.ts
@@ -1518,7 +1731,8 @@ import {
1518
1731
  getDocs as getDocs7,
1519
1732
  query as query7,
1520
1733
  updateDoc as updateDoc7,
1521
- where as where7
1734
+ where as where7,
1735
+ orderBy as orderBy7
1522
1736
  } from "firebase/firestore";
1523
1737
 
1524
1738
  // src/backoffice/types/requirement.types.ts
@@ -1639,6 +1853,65 @@ var RequirementService = class extends BaseService {
1639
1853
  ...docSnap.data()
1640
1854
  };
1641
1855
  }
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
+ }
1642
1915
  };
1643
1916
 
1644
1917
  // src/backoffice/services/subcategory.service.ts
@@ -1652,7 +1925,7 @@ import {
1652
1925
  getDoc as getDoc8,
1653
1926
  getDocs as getDocs8,
1654
1927
  limit as limit7,
1655
- orderBy as orderBy7,
1928
+ orderBy as orderBy8,
1656
1929
  query as query8,
1657
1930
  setDoc as setDoc4,
1658
1931
  startAfter as startAfter6,
@@ -1726,7 +1999,7 @@ var SubcategoryService = class extends BaseService {
1726
1999
  const { active = true, limit: queryLimit = 10, lastVisible } = options;
1727
2000
  const constraints = [
1728
2001
  where8("isActive", "==", active),
1729
- orderBy7("name"),
2002
+ orderBy8("name"),
1730
2003
  queryLimit ? limit7(queryLimit) : void 0,
1731
2004
  lastVisible ? startAfter6(lastVisible) : void 0
1732
2005
  ].filter((c) => !!c);
@@ -1753,7 +2026,7 @@ var SubcategoryService = class extends BaseService {
1753
2026
  const { active = true, limit: queryLimit = 10, lastVisible } = options;
1754
2027
  const constraints = [
1755
2028
  where8("isActive", "==", active),
1756
- orderBy7("name"),
2029
+ orderBy8("name"),
1757
2030
  queryLimit ? limit7(queryLimit) : void 0,
1758
2031
  lastVisible ? startAfter6(lastVisible) : void 0
1759
2032
  ].filter((c) => !!c);
@@ -1882,6 +2155,74 @@ var SubcategoryService = class extends BaseService {
1882
2155
  ...docSnap.data()
1883
2156
  };
1884
2157
  }
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
+ }
1885
2226
  };
1886
2227
 
1887
2228
  // src/backoffice/services/technology.service.ts
@@ -1892,7 +2233,7 @@ import {
1892
2233
  getDoc as getDoc9,
1893
2234
  getDocs as getDocs9,
1894
2235
  limit as limit8,
1895
- orderBy as orderBy8,
2236
+ orderBy as orderBy9,
1896
2237
  query as query9,
1897
2238
  startAfter as startAfter7,
1898
2239
  updateDoc as updateDoc9,
@@ -2006,7 +2347,7 @@ var TechnologyService = class extends BaseService {
2006
2347
  const { active = true, limit: queryLimit = 10, lastVisible } = options;
2007
2348
  const constraints = [
2008
2349
  where9("isActive", "==", active),
2009
- orderBy8("name"),
2350
+ orderBy9("name"),
2010
2351
  queryLimit ? limit8(queryLimit) : void 0,
2011
2352
  lastVisible ? startAfter7(lastVisible) : void 0
2012
2353
  ].filter((c) => !!c);
@@ -2032,7 +2373,7 @@ var TechnologyService = class extends BaseService {
2032
2373
  const constraints = [
2033
2374
  where9("categoryId", "==", categoryId),
2034
2375
  where9("isActive", "==", active),
2035
- orderBy8("name"),
2376
+ orderBy9("name"),
2036
2377
  queryLimit ? limit8(queryLimit) : void 0,
2037
2378
  lastVisible ? startAfter7(lastVisible) : void 0
2038
2379
  ].filter((c) => !!c);
@@ -2058,7 +2399,7 @@ var TechnologyService = class extends BaseService {
2058
2399
  const constraints = [
2059
2400
  where9("subcategoryId", "==", subcategoryId),
2060
2401
  where9("isActive", "==", active),
2061
- orderBy8("name"),
2402
+ orderBy9("name"),
2062
2403
  queryLimit ? limit8(queryLimit) : void 0,
2063
2404
  lastVisible ? startAfter7(lastVisible) : void 0
2064
2405
  ].filter((c) => !!c);
@@ -2487,7 +2828,7 @@ var TechnologyService = class extends BaseService {
2487
2828
  collection9(this.db, TECHNOLOGIES_COLLECTION),
2488
2829
  where9("isActive", "==", true),
2489
2830
  where9("subcategoryId", "==", subcategoryId),
2490
- orderBy8("name")
2831
+ orderBy9("name")
2491
2832
  );
2492
2833
  const snapshot = await getDocs9(q);
2493
2834
  return snapshot.docs.map(
@@ -2508,7 +2849,7 @@ var TechnologyService = class extends BaseService {
2508
2849
  where9("isActive", "==", true),
2509
2850
  where9("categoryId", "==", categoryId),
2510
2851
  where9("subcategoryId", "==", subcategoryId),
2511
- orderBy8("name")
2852
+ orderBy9("name")
2512
2853
  );
2513
2854
  const snapshot = await getDocs9(q);
2514
2855
  return snapshot.docs.map(
@@ -2525,7 +2866,7 @@ var TechnologyService = class extends BaseService {
2525
2866
  const q = query9(
2526
2867
  collection9(this.db, TECHNOLOGIES_COLLECTION),
2527
2868
  where9("isActive", "==", true),
2528
- orderBy8("name")
2869
+ orderBy9("name")
2529
2870
  );
2530
2871
  const snapshot = await getDocs9(q);
2531
2872
  return snapshot.docs.map(
@@ -2577,7 +2918,7 @@ var TechnologyService = class extends BaseService {
2577
2918
  collection9(this.db, PRODUCTS_COLLECTION),
2578
2919
  where9("assignedTechnologyIds", "array-contains", technologyId),
2579
2920
  where9("isActive", "==", true),
2580
- orderBy8("name")
2921
+ orderBy9("name")
2581
2922
  );
2582
2923
  const snapshot = await getDocs9(q);
2583
2924
  return snapshot.docs.map(
@@ -2594,7 +2935,7 @@ var TechnologyService = class extends BaseService {
2594
2935
  const q = query9(
2595
2936
  collection9(this.db, PRODUCTS_COLLECTION),
2596
2937
  where9("isActive", "==", true),
2597
- orderBy8("name")
2938
+ orderBy9("name")
2598
2939
  );
2599
2940
  const snapshot = await getDocs9(q);
2600
2941
  const allProducts = snapshot.docs.map(
@@ -2654,6 +2995,106 @@ var TechnologyService = class extends BaseService {
2654
2995
  }
2655
2996
  await batch.commit();
2656
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
+ }
2657
3098
  };
2658
3099
 
2659
3100
  // src/backoffice/services/constants.service.ts
@@ -2893,6 +3334,66 @@ var ConstantsService = class extends BaseService {
2893
3334
  contraindications: arrayRemove3(toRemove)
2894
3335
  });
2895
3336
  }
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
+ }
2896
3397
  };
2897
3398
 
2898
3399
  // src/backoffice/types/static/blocking-condition.types.ts