@blackcode_sa/metaestetics-api 1.12.40 → 1.12.41
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 +12 -6
- package/dist/admin/index.d.ts +12 -6
- package/dist/backoffice/index.d.mts +178 -19
- package/dist/backoffice/index.d.ts +178 -19
- package/dist/backoffice/index.js +261 -17
- package/dist/backoffice/index.mjs +277 -30
- package/dist/index.d.mts +170 -11
- package/dist/index.d.ts +170 -11
- package/dist/index.js +288 -28
- package/dist/index.mjs +299 -36
- package/package.json +1 -1
- package/src/backoffice/services/migrate-products.ts +116 -0
- package/src/backoffice/services/product.service.ts +216 -21
- package/src/backoffice/services/technology.service.ts +111 -0
- package/src/backoffice/types/product.types.ts +115 -6
- package/src/services/appointment/appointment.service.ts +29 -5
|
@@ -1158,7 +1158,9 @@ import {
|
|
|
1158
1158
|
limit as limit6,
|
|
1159
1159
|
orderBy as orderBy6,
|
|
1160
1160
|
startAfter as startAfter5,
|
|
1161
|
-
getCountFromServer as getCountFromServer4
|
|
1161
|
+
getCountFromServer as getCountFromServer4,
|
|
1162
|
+
arrayUnion,
|
|
1163
|
+
arrayRemove
|
|
1162
1164
|
} from "firebase/firestore";
|
|
1163
1165
|
|
|
1164
1166
|
// src/backoffice/types/product.types.ts
|
|
@@ -1170,7 +1172,14 @@ var TECHNOLOGIES_COLLECTION = "technologies";
|
|
|
1170
1172
|
// src/backoffice/services/product.service.ts
|
|
1171
1173
|
var ProductService = class extends BaseService {
|
|
1172
1174
|
/**
|
|
1173
|
-
* Gets reference to products collection
|
|
1175
|
+
* Gets reference to top-level products collection (source of truth)
|
|
1176
|
+
* @returns Firestore collection reference
|
|
1177
|
+
*/
|
|
1178
|
+
getTopLevelProductsRef() {
|
|
1179
|
+
return collection6(this.db, PRODUCTS_COLLECTION);
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* Gets reference to products collection under a technology (backward compatibility)
|
|
1174
1183
|
* @param technologyId - ID of the technology
|
|
1175
1184
|
* @returns Firestore collection reference
|
|
1176
1185
|
*/
|
|
@@ -1186,6 +1195,7 @@ var ProductService = class extends BaseService {
|
|
|
1186
1195
|
...product,
|
|
1187
1196
|
brandId,
|
|
1188
1197
|
technologyId,
|
|
1198
|
+
// Required for old subcollection structure
|
|
1189
1199
|
createdAt: now,
|
|
1190
1200
|
updatedAt: now,
|
|
1191
1201
|
isActive: true
|
|
@@ -1244,31 +1254,24 @@ var ProductService = class extends BaseService {
|
|
|
1244
1254
|
return snapshot.data().count;
|
|
1245
1255
|
}
|
|
1246
1256
|
/**
|
|
1247
|
-
* Gets counts of active products grouped by
|
|
1248
|
-
*
|
|
1257
|
+
* Gets counts of active products grouped by technology.
|
|
1258
|
+
* NOTE: Only counts top-level collection to avoid duplication during migration.
|
|
1259
|
+
* Categories/subcategories not available in top-level structure.
|
|
1249
1260
|
*/
|
|
1250
1261
|
async getProductCounts() {
|
|
1251
|
-
const q = query6(collectionGroup(this.db, PRODUCTS_COLLECTION), where6("isActive", "==", true));
|
|
1252
|
-
const snapshot = await getDocs6(q);
|
|
1253
1262
|
const counts = {
|
|
1254
1263
|
byCategory: {},
|
|
1255
1264
|
bySubcategory: {},
|
|
1256
1265
|
byTechnology: {}
|
|
1257
1266
|
};
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
}
|
|
1267
|
+
const q = query6(this.getTopLevelProductsRef(), where6("isActive", "==", true));
|
|
1268
|
+
const snapshot = await getDocs6(q);
|
|
1261
1269
|
snapshot.docs.forEach((doc11) => {
|
|
1262
1270
|
const product = doc11.data();
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
if (subcategoryId) {
|
|
1268
|
-
counts.bySubcategory[subcategoryId] = (counts.bySubcategory[subcategoryId] || 0) + 1;
|
|
1269
|
-
}
|
|
1270
|
-
if (technologyId) {
|
|
1271
|
-
counts.byTechnology[technologyId] = (counts.byTechnology[technologyId] || 0) + 1;
|
|
1271
|
+
if (product.assignedTechnologyIds && Array.isArray(product.assignedTechnologyIds)) {
|
|
1272
|
+
product.assignedTechnologyIds.forEach((techId) => {
|
|
1273
|
+
counts.byTechnology[techId] = (counts.byTechnology[techId] || 0) + 1;
|
|
1274
|
+
});
|
|
1272
1275
|
}
|
|
1273
1276
|
});
|
|
1274
1277
|
return counts;
|
|
@@ -1347,6 +1350,160 @@ var ProductService = class extends BaseService {
|
|
|
1347
1350
|
...docSnap.data()
|
|
1348
1351
|
};
|
|
1349
1352
|
}
|
|
1353
|
+
// ==========================================
|
|
1354
|
+
// NEW METHODS: Top-level collection (preferred)
|
|
1355
|
+
// ==========================================
|
|
1356
|
+
/**
|
|
1357
|
+
* Creates a new product in the top-level collection
|
|
1358
|
+
*/
|
|
1359
|
+
async createTopLevel(brandId, product, technologyIds = []) {
|
|
1360
|
+
const now = /* @__PURE__ */ new Date();
|
|
1361
|
+
const newProduct = {
|
|
1362
|
+
...product,
|
|
1363
|
+
brandId,
|
|
1364
|
+
assignedTechnologyIds: technologyIds,
|
|
1365
|
+
createdAt: now,
|
|
1366
|
+
updatedAt: now,
|
|
1367
|
+
isActive: true
|
|
1368
|
+
};
|
|
1369
|
+
const productRef = await addDoc3(this.getTopLevelProductsRef(), newProduct);
|
|
1370
|
+
return { id: productRef.id, ...newProduct };
|
|
1371
|
+
}
|
|
1372
|
+
/**
|
|
1373
|
+
* Gets all products from the top-level collection
|
|
1374
|
+
*/
|
|
1375
|
+
async getAllTopLevel(options) {
|
|
1376
|
+
const { rowsPerPage, lastVisible, brandId } = options;
|
|
1377
|
+
const constraints = [where6("isActive", "==", true), orderBy6("name")];
|
|
1378
|
+
if (brandId) {
|
|
1379
|
+
constraints.push(where6("brandId", "==", brandId));
|
|
1380
|
+
}
|
|
1381
|
+
if (lastVisible) {
|
|
1382
|
+
constraints.push(startAfter5(lastVisible));
|
|
1383
|
+
}
|
|
1384
|
+
constraints.push(limit6(rowsPerPage));
|
|
1385
|
+
const q = query6(this.getTopLevelProductsRef(), ...constraints);
|
|
1386
|
+
const snapshot = await getDocs6(q);
|
|
1387
|
+
const products = snapshot.docs.map(
|
|
1388
|
+
(doc11) => ({
|
|
1389
|
+
id: doc11.id,
|
|
1390
|
+
...doc11.data()
|
|
1391
|
+
})
|
|
1392
|
+
);
|
|
1393
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
1394
|
+
return { products, lastVisible: newLastVisible };
|
|
1395
|
+
}
|
|
1396
|
+
/**
|
|
1397
|
+
* Gets a product by ID from the top-level collection
|
|
1398
|
+
*/
|
|
1399
|
+
async getByIdTopLevel(productId) {
|
|
1400
|
+
const docRef = doc6(this.getTopLevelProductsRef(), productId);
|
|
1401
|
+
const docSnap = await getDoc6(docRef);
|
|
1402
|
+
if (!docSnap.exists()) return null;
|
|
1403
|
+
return {
|
|
1404
|
+
id: docSnap.id,
|
|
1405
|
+
...docSnap.data()
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1408
|
+
/**
|
|
1409
|
+
* Updates a product in the top-level collection
|
|
1410
|
+
*/
|
|
1411
|
+
async updateTopLevel(productId, product) {
|
|
1412
|
+
const updateData = {
|
|
1413
|
+
...product,
|
|
1414
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1415
|
+
};
|
|
1416
|
+
const docRef = doc6(this.getTopLevelProductsRef(), productId);
|
|
1417
|
+
await updateDoc6(docRef, updateData);
|
|
1418
|
+
return this.getByIdTopLevel(productId);
|
|
1419
|
+
}
|
|
1420
|
+
/**
|
|
1421
|
+
* Deletes a product from the top-level collection (soft delete)
|
|
1422
|
+
*/
|
|
1423
|
+
async deleteTopLevel(productId) {
|
|
1424
|
+
await this.updateTopLevel(productId, {
|
|
1425
|
+
isActive: false
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1429
|
+
* Assigns a product to a technology
|
|
1430
|
+
*/
|
|
1431
|
+
async assignToTechnology(productId, technologyId) {
|
|
1432
|
+
const docRef = doc6(this.getTopLevelProductsRef(), productId);
|
|
1433
|
+
await updateDoc6(docRef, {
|
|
1434
|
+
assignedTechnologyIds: arrayUnion(technologyId),
|
|
1435
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1436
|
+
});
|
|
1437
|
+
}
|
|
1438
|
+
/**
|
|
1439
|
+
* Unassigns a product from a technology
|
|
1440
|
+
*/
|
|
1441
|
+
async unassignFromTechnology(productId, technologyId) {
|
|
1442
|
+
const docRef = doc6(this.getTopLevelProductsRef(), productId);
|
|
1443
|
+
await updateDoc6(docRef, {
|
|
1444
|
+
assignedTechnologyIds: arrayRemove(technologyId),
|
|
1445
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1449
|
+
* Gets products assigned to a specific technology
|
|
1450
|
+
*/
|
|
1451
|
+
async getAssignedProducts(technologyId) {
|
|
1452
|
+
const q = query6(
|
|
1453
|
+
this.getTopLevelProductsRef(),
|
|
1454
|
+
where6("assignedTechnologyIds", "array-contains", technologyId),
|
|
1455
|
+
where6("isActive", "==", true),
|
|
1456
|
+
orderBy6("name")
|
|
1457
|
+
);
|
|
1458
|
+
const snapshot = await getDocs6(q);
|
|
1459
|
+
return snapshot.docs.map(
|
|
1460
|
+
(doc11) => ({
|
|
1461
|
+
id: doc11.id,
|
|
1462
|
+
...doc11.data()
|
|
1463
|
+
})
|
|
1464
|
+
);
|
|
1465
|
+
}
|
|
1466
|
+
/**
|
|
1467
|
+
* Gets products NOT assigned to a specific technology
|
|
1468
|
+
*/
|
|
1469
|
+
async getUnassignedProducts(technologyId) {
|
|
1470
|
+
const q = query6(
|
|
1471
|
+
this.getTopLevelProductsRef(),
|
|
1472
|
+
where6("isActive", "==", true),
|
|
1473
|
+
orderBy6("name")
|
|
1474
|
+
);
|
|
1475
|
+
const snapshot = await getDocs6(q);
|
|
1476
|
+
const allProducts = snapshot.docs.map(
|
|
1477
|
+
(doc11) => ({
|
|
1478
|
+
id: doc11.id,
|
|
1479
|
+
...doc11.data()
|
|
1480
|
+
})
|
|
1481
|
+
);
|
|
1482
|
+
return allProducts.filter(
|
|
1483
|
+
(product) => {
|
|
1484
|
+
var _a;
|
|
1485
|
+
return !((_a = product.assignedTechnologyIds) == null ? void 0 : _a.includes(technologyId));
|
|
1486
|
+
}
|
|
1487
|
+
);
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Gets all products for a brand (from top-level collection)
|
|
1491
|
+
*/
|
|
1492
|
+
async getByBrand(brandId) {
|
|
1493
|
+
const q = query6(
|
|
1494
|
+
this.getTopLevelProductsRef(),
|
|
1495
|
+
where6("brandId", "==", brandId),
|
|
1496
|
+
where6("isActive", "==", true),
|
|
1497
|
+
orderBy6("name")
|
|
1498
|
+
);
|
|
1499
|
+
const snapshot = await getDocs6(q);
|
|
1500
|
+
return snapshot.docs.map(
|
|
1501
|
+
(doc11) => ({
|
|
1502
|
+
id: doc11.id,
|
|
1503
|
+
...doc11.data()
|
|
1504
|
+
})
|
|
1505
|
+
);
|
|
1506
|
+
}
|
|
1350
1507
|
};
|
|
1351
1508
|
|
|
1352
1509
|
// src/backoffice/services/requirement.service.ts
|
|
@@ -1737,8 +1894,9 @@ import {
|
|
|
1737
1894
|
startAfter as startAfter7,
|
|
1738
1895
|
updateDoc as updateDoc9,
|
|
1739
1896
|
where as where9,
|
|
1740
|
-
arrayUnion,
|
|
1741
|
-
arrayRemove
|
|
1897
|
+
arrayUnion as arrayUnion2,
|
|
1898
|
+
arrayRemove as arrayRemove2,
|
|
1899
|
+
writeBatch
|
|
1742
1900
|
} from "firebase/firestore";
|
|
1743
1901
|
|
|
1744
1902
|
// src/backoffice/types/static/certification.types.ts
|
|
@@ -1968,7 +2126,7 @@ var TechnologyService = class extends BaseService {
|
|
|
1968
2126
|
const docRef = doc9(this.technologiesRef, technologyId);
|
|
1969
2127
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
1970
2128
|
await updateDoc9(docRef, {
|
|
1971
|
-
[requirementType]:
|
|
2129
|
+
[requirementType]: arrayUnion2(requirement),
|
|
1972
2130
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1973
2131
|
});
|
|
1974
2132
|
return this.getById(technologyId);
|
|
@@ -1983,7 +2141,7 @@ var TechnologyService = class extends BaseService {
|
|
|
1983
2141
|
const docRef = doc9(this.technologiesRef, technologyId);
|
|
1984
2142
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
1985
2143
|
await updateDoc9(docRef, {
|
|
1986
|
-
[requirementType]:
|
|
2144
|
+
[requirementType]: arrayRemove2(requirement),
|
|
1987
2145
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1988
2146
|
});
|
|
1989
2147
|
return this.getById(technologyId);
|
|
@@ -2022,7 +2180,7 @@ var TechnologyService = class extends BaseService {
|
|
|
2022
2180
|
async addBlockingCondition(technologyId, condition) {
|
|
2023
2181
|
const docRef = doc9(this.technologiesRef, technologyId);
|
|
2024
2182
|
await updateDoc9(docRef, {
|
|
2025
|
-
blockingConditions:
|
|
2183
|
+
blockingConditions: arrayUnion2(condition),
|
|
2026
2184
|
updatedAt: /* @__PURE__ */ new Date()
|
|
2027
2185
|
});
|
|
2028
2186
|
return this.getById(technologyId);
|
|
@@ -2036,7 +2194,7 @@ var TechnologyService = class extends BaseService {
|
|
|
2036
2194
|
async removeBlockingCondition(technologyId, condition) {
|
|
2037
2195
|
const docRef = doc9(this.technologiesRef, technologyId);
|
|
2038
2196
|
await updateDoc9(docRef, {
|
|
2039
|
-
blockingConditions:
|
|
2197
|
+
blockingConditions: arrayRemove2(condition),
|
|
2040
2198
|
updatedAt: /* @__PURE__ */ new Date()
|
|
2041
2199
|
});
|
|
2042
2200
|
return this.getById(technologyId);
|
|
@@ -2363,12 +2521,101 @@ var TechnologyService = class extends BaseService {
|
|
|
2363
2521
|
})
|
|
2364
2522
|
);
|
|
2365
2523
|
}
|
|
2524
|
+
// ==========================================
|
|
2525
|
+
// NEW METHODS: Product assignment management
|
|
2526
|
+
// ==========================================
|
|
2527
|
+
/**
|
|
2528
|
+
* Assigns multiple products to a technology
|
|
2529
|
+
* Updates each product's assignedTechnologyIds array
|
|
2530
|
+
*/
|
|
2531
|
+
async assignProducts(technologyId, productIds) {
|
|
2532
|
+
const batch = writeBatch(this.db);
|
|
2533
|
+
for (const productId of productIds) {
|
|
2534
|
+
const productRef = doc9(this.db, PRODUCTS_COLLECTION, productId);
|
|
2535
|
+
batch.update(productRef, {
|
|
2536
|
+
assignedTechnologyIds: arrayUnion2(technologyId),
|
|
2537
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2540
|
+
await batch.commit();
|
|
2541
|
+
}
|
|
2542
|
+
/**
|
|
2543
|
+
* Unassigns multiple products from a technology
|
|
2544
|
+
* Updates each product's assignedTechnologyIds array
|
|
2545
|
+
*/
|
|
2546
|
+
async unassignProducts(technologyId, productIds) {
|
|
2547
|
+
const batch = writeBatch(this.db);
|
|
2548
|
+
for (const productId of productIds) {
|
|
2549
|
+
const productRef = doc9(this.db, PRODUCTS_COLLECTION, productId);
|
|
2550
|
+
batch.update(productRef, {
|
|
2551
|
+
assignedTechnologyIds: arrayRemove2(technologyId),
|
|
2552
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2553
|
+
});
|
|
2554
|
+
}
|
|
2555
|
+
await batch.commit();
|
|
2556
|
+
}
|
|
2557
|
+
/**
|
|
2558
|
+
* Gets products assigned to a specific technology
|
|
2559
|
+
* Reads from top-level collection for immediate consistency (Cloud Functions may lag)
|
|
2560
|
+
*/
|
|
2561
|
+
async getAssignedProducts(technologyId) {
|
|
2562
|
+
const q = query9(
|
|
2563
|
+
collection9(this.db, PRODUCTS_COLLECTION),
|
|
2564
|
+
where9("assignedTechnologyIds", "array-contains", technologyId),
|
|
2565
|
+
where9("isActive", "==", true),
|
|
2566
|
+
orderBy8("name")
|
|
2567
|
+
);
|
|
2568
|
+
const snapshot = await getDocs9(q);
|
|
2569
|
+
return snapshot.docs.map(
|
|
2570
|
+
(doc11) => ({
|
|
2571
|
+
id: doc11.id,
|
|
2572
|
+
...doc11.data()
|
|
2573
|
+
})
|
|
2574
|
+
);
|
|
2575
|
+
}
|
|
2576
|
+
/**
|
|
2577
|
+
* Gets products NOT assigned to a specific technology
|
|
2578
|
+
*/
|
|
2579
|
+
async getUnassignedProducts(technologyId) {
|
|
2580
|
+
const q = query9(
|
|
2581
|
+
collection9(this.db, PRODUCTS_COLLECTION),
|
|
2582
|
+
where9("isActive", "==", true),
|
|
2583
|
+
orderBy8("name")
|
|
2584
|
+
);
|
|
2585
|
+
const snapshot = await getDocs9(q);
|
|
2586
|
+
const allProducts = snapshot.docs.map(
|
|
2587
|
+
(doc11) => ({
|
|
2588
|
+
id: doc11.id,
|
|
2589
|
+
...doc11.data()
|
|
2590
|
+
})
|
|
2591
|
+
);
|
|
2592
|
+
return allProducts.filter(
|
|
2593
|
+
(product) => {
|
|
2594
|
+
var _a;
|
|
2595
|
+
return !((_a = product.assignedTechnologyIds) == null ? void 0 : _a.includes(technologyId));
|
|
2596
|
+
}
|
|
2597
|
+
);
|
|
2598
|
+
}
|
|
2599
|
+
/**
|
|
2600
|
+
* Gets product assignment statistics for a technology
|
|
2601
|
+
*/
|
|
2602
|
+
async getProductStats(technologyId) {
|
|
2603
|
+
const products = await this.getAssignedProducts(technologyId);
|
|
2604
|
+
const byBrand = {};
|
|
2605
|
+
products.forEach((product) => {
|
|
2606
|
+
byBrand[product.brandName] = (byBrand[product.brandName] || 0) + 1;
|
|
2607
|
+
});
|
|
2608
|
+
return {
|
|
2609
|
+
totalAssigned: products.length,
|
|
2610
|
+
byBrand
|
|
2611
|
+
};
|
|
2612
|
+
}
|
|
2366
2613
|
};
|
|
2367
2614
|
|
|
2368
2615
|
// src/backoffice/services/constants.service.ts
|
|
2369
2616
|
import {
|
|
2370
|
-
arrayRemove as
|
|
2371
|
-
arrayUnion as
|
|
2617
|
+
arrayRemove as arrayRemove3,
|
|
2618
|
+
arrayUnion as arrayUnion3,
|
|
2372
2619
|
doc as doc10,
|
|
2373
2620
|
getDoc as getDoc10,
|
|
2374
2621
|
setDoc as setDoc5,
|
|
@@ -2436,7 +2683,7 @@ var ConstantsService = class extends BaseService {
|
|
|
2436
2683
|
await setDoc5(this.treatmentBenefitsDocRef, { benefits: [newBenefit] });
|
|
2437
2684
|
} else {
|
|
2438
2685
|
await updateDoc10(this.treatmentBenefitsDocRef, {
|
|
2439
|
-
benefits:
|
|
2686
|
+
benefits: arrayUnion3(newBenefit)
|
|
2440
2687
|
});
|
|
2441
2688
|
}
|
|
2442
2689
|
return newBenefit;
|
|
@@ -2490,7 +2737,7 @@ var ConstantsService = class extends BaseService {
|
|
|
2490
2737
|
return;
|
|
2491
2738
|
}
|
|
2492
2739
|
await updateDoc10(this.treatmentBenefitsDocRef, {
|
|
2493
|
-
benefits:
|
|
2740
|
+
benefits: arrayRemove3(benefitToRemove)
|
|
2494
2741
|
});
|
|
2495
2742
|
}
|
|
2496
2743
|
// =================================================================
|
|
@@ -2543,7 +2790,7 @@ var ConstantsService = class extends BaseService {
|
|
|
2543
2790
|
});
|
|
2544
2791
|
} else {
|
|
2545
2792
|
await updateDoc10(this.contraindicationsDocRef, {
|
|
2546
|
-
contraindications:
|
|
2793
|
+
contraindications: arrayUnion3(newContraindication)
|
|
2547
2794
|
});
|
|
2548
2795
|
}
|
|
2549
2796
|
return newContraindication;
|
|
@@ -2599,7 +2846,7 @@ var ConstantsService = class extends BaseService {
|
|
|
2599
2846
|
return;
|
|
2600
2847
|
}
|
|
2601
2848
|
await updateDoc10(this.contraindicationsDocRef, {
|
|
2602
|
-
contraindications:
|
|
2849
|
+
contraindications: arrayRemove3(toRemove)
|
|
2603
2850
|
});
|
|
2604
2851
|
}
|
|
2605
2852
|
};
|