@7365admin1/core 3.42.2 → 3.42.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @iservice365/core
2
2
 
3
+ ## 3.42.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 854dd11: Editing a building no longer creates duplicate levels or orphaned units
8
+
9
+ Updating a block inserted a brand-new level document for every level name in the
10
+ payload, without checking whether that name was already a level on the block. A
11
+ client that posted the block's existing level names back — which the block
12
+ editor's own full-levels payload does — got a second "Level 1" document, a
13
+ second entry in `building.levels`, and units still pointing at the first one.
14
+
15
+ The submitted names are now reconciled against the block's existing ACTIVE
16
+ levels first. A name that already matches an existing level is left alone and
17
+ keeps its `_id`, so nothing that references it is orphaned; only genuinely new
18
+ names are inserted.
19
+
20
+ Matching is case- and whitespace-insensitive, using the same normalisation the
21
+ import path already uses, so "Level 1", "level 1" and "Level  1" are
22
+ one level. Only the match key is normalised — the stored name keeps its
23
+ original spelling, so two genuinely different levels are never merged.
24
+
25
+ Removals are deliberately not inferred from this payload; deleting a level keeps
26
+ its own guarded path.
27
+
28
+ Worth a QA pass on building edit — this changes what a block update writes.
29
+
3
30
  ## 3.42.2
4
31
 
5
32
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -7846,6 +7846,7 @@ declare function useBuildingLevelRepo(): {
7846
7846
  message: string;
7847
7847
  data: bson.Document[];
7848
7848
  }>;
7849
+ getActiveLevelsByIds: (ids: (string | ObjectId)[], session?: ClientSession) => Promise<TBuildingLevel[]>;
7849
7850
  };
7850
7851
 
7851
7852
  declare function useBuildingLevelService(): {
package/dist/index.js CHANGED
@@ -30292,6 +30292,20 @@ function useBuildingLevelRepo() {
30292
30292
  }
30293
30293
  }
30294
30294
  }
30295
+ async function getActiveLevelsByIds(ids, session) {
30296
+ if (!ids || ids.length === 0)
30297
+ return [];
30298
+ let objectIds;
30299
+ try {
30300
+ objectIds = ids.map((id) => new import_mongodb56.ObjectId(id));
30301
+ } catch {
30302
+ throw new import_node_server_utils88.BadRequestError("Invalid level ID format.");
30303
+ }
30304
+ return collection.find(
30305
+ { _id: { $in: objectIds }, status: "active" /* ACTIVE */ },
30306
+ { projection: { _id: 1, name: 1 }, session }
30307
+ ).toArray();
30308
+ }
30295
30309
  async function updateLevelById(_id, value, session) {
30296
30310
  try {
30297
30311
  _id = new import_mongodb56.ObjectId(_id);
@@ -30490,7 +30504,8 @@ function useBuildingLevelRepo() {
30490
30504
  deleteById,
30491
30505
  bulkWriteLevels,
30492
30506
  batchUpdateByIds,
30493
- getBuildingLevelList
30507
+ getBuildingLevelList,
30508
+ getActiveLevelsByIds
30494
30509
  };
30495
30510
  }
30496
30511
 
@@ -30511,7 +30526,10 @@ function useBuildingService() {
30511
30526
  } = useBuildingUnitRepo();
30512
30527
  const { updateStatusById } = useFileRepo();
30513
30528
  const { deleteFile } = useFileService();
30514
- const { bulkWriteLevels: _bulkWriteLevels } = useBuildingLevelRepo();
30529
+ const {
30530
+ bulkWriteLevels: _bulkWriteLevels,
30531
+ getActiveLevelsByIds: _getActiveLevelsByIds
30532
+ } = useBuildingLevelRepo();
30515
30533
  function normalizeImportKey(value) {
30516
30534
  return String(value ?? "").trim().replace(/\s+/g, " ").toLowerCase();
30517
30535
  }
@@ -30605,23 +30623,37 @@ function useBuildingService() {
30605
30623
  );
30606
30624
  }
30607
30625
  if (data.levels) {
30608
- const levelsPayload = (data.levels ?? []).map((levelName) => ({
30609
- blockId: id,
30610
- site: building.site.toString(),
30611
- name: levelName,
30612
- status: "active" /* ACTIVE */,
30613
- createdAt: /* @__PURE__ */ new Date(),
30614
- updatedAt: null,
30615
- deletedAt: null
30616
- }));
30617
- let levels;
30618
- if (levelsPayload.length > 0) {
30619
- levels = await _bulkWriteLevels(levelsPayload, session);
30620
- }
30621
- if (levels) {
30622
- building.levels.push(...Object.values(levels.insertedIds));
30623
- data.levels = building.levels.map((id2) => id2.toString());
30626
+ const submittedNames = data.levels ?? [];
30627
+ const existingLevels = await _getActiveLevelsByIds(
30628
+ building.levels,
30629
+ session
30630
+ );
30631
+ const seenKeys = new Set(
30632
+ existingLevels.map((level) => normalizeImportKey(level.name))
30633
+ );
30634
+ const newNames = submittedNames.filter((name) => {
30635
+ const key = normalizeImportKey(name);
30636
+ if (seenKeys.has(key))
30637
+ return false;
30638
+ seenKeys.add(key);
30639
+ return true;
30640
+ });
30641
+ if (newNames.length > 0) {
30642
+ const levelsPayload = newNames.map((name) => ({
30643
+ blockId: id,
30644
+ site: building.site.toString(),
30645
+ name,
30646
+ status: "active" /* ACTIVE */,
30647
+ createdAt: /* @__PURE__ */ new Date(),
30648
+ updatedAt: null,
30649
+ deletedAt: null
30650
+ }));
30651
+ const levels = await _bulkWriteLevels(levelsPayload, session);
30652
+ if (levels) {
30653
+ building.levels.push(...Object.values(levels.insertedIds));
30654
+ }
30624
30655
  }
30656
+ data.levels = building.levels.map((levelId) => levelId.toString());
30625
30657
  }
30626
30658
  const buildingUnitData = {};
30627
30659
  if (data.name && building.name !== data.name) {