jupiter-dynamic-forms 1.19.8 → 1.20.0

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/index.mjs CHANGED
@@ -6432,50 +6432,87 @@ let JupiterFormSection = class extends LitElement {
6432
6432
  this._totalChildConceptsMap.clear();
6433
6433
  this._traverseTotalGroups(concepts);
6434
6434
  }
6435
+ /**
6436
+ * JDF-038: XBRL uses more than one preferredLabel role to mark a "total" row — the plain
6437
+ * `.../role/totalLabel` and the sign-flipped `.../role/negatedTotalLabel` (used for subtotals of
6438
+ * negated/expense items, e.g. "Total of sum of expenses"). A case-sensitive `includes('totalLabel')`
6439
+ * misses the latter, because "negatedTotalLabel" contains "TotalLabel" with a capital T. Case-insensitive
6440
+ * matching is the single source of truth for "is this row a total" everywhere in this file.
6441
+ */
6442
+ static _isTotalLabel(preferredLabel) {
6443
+ return !!(preferredLabel == null ? void 0 : preferredLabel.toLowerCase().includes("totallabel"));
6444
+ }
6445
+ /**
6446
+ * A member of a total's sibling/child group can itself be a presentation-only abstract wrapper
6447
+ * (e.g. "Group equity" wrapping Equity + Third party share + "Total of group equity") rather than
6448
+ * a value-bearing concept. Abstract concepts never have a form field, so resolve them to the nested
6449
+ * totalLabel concept that actually carries their aggregate value — otherwise the outer total's
6450
+ * calculation silently drops that whole subgroup (formData lookup on the abstract's id is always empty).
6451
+ */
6452
+ static _resolveValueConcept(node, depth = 0) {
6453
+ var _a;
6454
+ if (!node.abstract)
6455
+ return node;
6456
+ if (depth > 5 || !((_a = node.children) == null ? void 0 : _a.length))
6457
+ return null;
6458
+ const nestedTotal = node.children.find((c2) => JupiterFormSection._isTotalLabel(c2.preferredLabel));
6459
+ if (!nestedTotal)
6460
+ return null;
6461
+ return JupiterFormSection._resolveValueConcept(nestedTotal, depth + 1);
6462
+ }
6463
+ _registerTotalGroup(totalConcept, members) {
6464
+ const resolvedMembers = members.map((m) => JupiterFormSection._resolveValueConcept(m)).filter((m) => m !== null);
6465
+ if (resolvedMembers.length === 0)
6466
+ return;
6467
+ const memberIds = resolvedMembers.map((m) => m.id);
6468
+ this._totalChildrenMap.set(totalConcept.id, memberIds);
6469
+ this._totalConceptMap.set(totalConcept.id, totalConcept);
6470
+ this._totalChildConceptsMap.set(totalConcept.id, resolvedMembers);
6471
+ for (const memberId of memberIds) {
6472
+ this._memberParentMap.set(memberId, totalConcept.id);
6473
+ }
6474
+ }
6435
6475
  _traverseTotalGroups(concepts) {
6436
- var _a, _b, _c, _d;
6476
+ var _a, _b;
6437
6477
  for (let i2 = 0; i2 < concepts.length; i2++) {
6438
6478
  const concept = concepts[i2];
6439
- if ((_a = concept.preferredLabel) == null ? void 0 : _a.includes("totalLabel")) {
6440
- if ((_b = concept.children) == null ? void 0 : _b.length) {
6441
- const childIds = concept.children.map((c2) => c2.id);
6442
- this._totalChildrenMap.set(concept.id, childIds);
6443
- this._totalConceptMap.set(concept.id, concept);
6444
- this._totalChildConceptsMap.set(concept.id, concept.children);
6445
- for (const childId of childIds) {
6446
- this._memberParentMap.set(childId, concept.id);
6447
- }
6479
+ if (JupiterFormSection._isTotalLabel(concept.preferredLabel)) {
6480
+ if ((_a = concept.children) == null ? void 0 : _a.length) {
6481
+ this._registerTotalGroup(concept, concept.children);
6448
6482
  } else {
6449
6483
  let lastTotalIdx = -1;
6450
6484
  for (let j = i2 - 1; j >= 0; j--) {
6451
- if ((_c = concepts[j].preferredLabel) == null ? void 0 : _c.includes("totalLabel")) {
6485
+ if (JupiterFormSection._isTotalLabel(concepts[j].preferredLabel)) {
6452
6486
  lastTotalIdx = j;
6453
6487
  break;
6454
6488
  }
6455
6489
  }
6456
6490
  const siblings = concepts.slice(lastTotalIdx + 1, i2);
6457
6491
  if (siblings.length > 0) {
6458
- const siblingIds = siblings.map((s2) => s2.id);
6459
- this._totalChildrenMap.set(concept.id, siblingIds);
6460
- this._totalConceptMap.set(concept.id, concept);
6461
- this._totalChildConceptsMap.set(concept.id, siblings);
6462
- for (const siblingId of siblingIds) {
6463
- this._memberParentMap.set(siblingId, concept.id);
6464
- }
6492
+ this._registerTotalGroup(concept, siblings);
6493
+ } else if (lastTotalIdx >= 0) {
6494
+ this._registerTotalGroup(concept, [concepts[lastTotalIdx]]);
6465
6495
  }
6466
6496
  }
6467
6497
  }
6468
- if ((_d = concept.children) == null ? void 0 : _d.length) {
6498
+ if ((_b = concept.children) == null ? void 0 : _b.length) {
6469
6499
  this._traverseTotalGroups(concept.children);
6470
6500
  }
6471
6501
  }
6472
6502
  }
6473
6503
  _runCalculationCheck(conceptId, columnId) {
6504
+ const totalIds = /* @__PURE__ */ new Set();
6505
+ if (this._totalConceptMap.has(conceptId))
6506
+ totalIds.add(conceptId);
6507
+ const parentTotalId = this._memberParentMap.get(conceptId);
6508
+ if (parentTotalId)
6509
+ totalIds.add(parentTotalId);
6510
+ for (const totalConceptId of totalIds) {
6511
+ this._evaluateTotal(totalConceptId, columnId);
6512
+ }
6513
+ }
6514
+ _evaluateTotal(totalConceptId, columnId) {
6474
6515
  var _a;
6475
- const isSelfTotal = this._totalConceptMap.has(conceptId);
6476
- const totalConceptId = isSelfTotal ? conceptId : this._memberParentMap.get(conceptId);
6477
- if (!totalConceptId)
6478
- return;
6479
6516
  const totalConcept = this._totalConceptMap.get(totalConceptId);
6480
6517
  const totalRaw = (_a = this.formData[totalConceptId]) == null ? void 0 : _a[columnId];
6481
6518
  const key = `${totalConceptId}__${columnId}`;
@@ -10757,6 +10794,52 @@ let JupiterDynamicForm = class extends LitElement {
10757
10794
  }
10758
10795
  return instantDate || endDate || startDate || "2025-01-01";
10759
10796
  }
10797
+ /**
10798
+ * JDF-037: Self-heals legacy periodStartLabel instant dates.
10799
+ * Drafts saved before JDF-024 have periodStartLabel concepts with the instant date
10800
+ * set to the column's own year instead of one day before periodStartDate. Reuses
10801
+ * _resolveInstantDate (no new date math) to correct both _periodData and the live
10802
+ * field.periodInstantDate so UI and saved output never disagree. Idempotent: only
10803
+ * writes when the stored value actually differs from the corrected one.
10804
+ */
10805
+ _correctLegacyPeriodStartInstantDates() {
10806
+ this._allSections.forEach((section2) => {
10807
+ this._correctPeriodStartInstantDatesInConcepts(section2.concepts, section2);
10808
+ });
10809
+ }
10810
+ _correctPeriodStartInstantDatesInConcepts(concepts, section2) {
10811
+ concepts.forEach((concept) => {
10812
+ var _a, _b;
10813
+ if (((_a = concept.preferredLabel) == null ? void 0 : _a.includes("periodStartLabel")) && concept.periodType === "instant" && ((_b = concept.fields) == null ? void 0 : _b.length)) {
10814
+ concept.fields.forEach((field2) => {
10815
+ this._correctFieldPeriodStartInstantDate(concept, field2, concept.id, section2);
10816
+ const repeatCount = this._repeatCounts[concept.id] || 0;
10817
+ for (let n3 = 1; n3 <= repeatCount; n3++) {
10818
+ this._correctFieldPeriodStartInstantDate(concept, field2, `${concept.id}__repeat_${n3}`, section2);
10819
+ }
10820
+ });
10821
+ }
10822
+ if (concept.children) {
10823
+ this._correctPeriodStartInstantDatesInConcepts(concept.children, section2);
10824
+ }
10825
+ });
10826
+ }
10827
+ _correctFieldPeriodStartInstantDate(concept, field2, periodDataKey, section2) {
10828
+ var _a;
10829
+ const column2 = this._findColumnByIdInSection(field2.columnId, section2);
10830
+ const fieldPeriodData = (_a = this._periodData[periodDataKey]) == null ? void 0 : _a[field2.columnId];
10831
+ const periodStartDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.startDate) || (column2 == null ? void 0 : column2.periodStartDate) || field2.periodStartDate || this.periodStartDate;
10832
+ const periodEndDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || (column2 == null ? void 0 : column2.periodEndDate) || field2.periodEndDate || this.periodEndDate;
10833
+ const correctedInstantDate = this._resolveInstantDate(concept.preferredLabel, void 0, periodStartDate, periodEndDate);
10834
+ if (fieldPeriodData && fieldPeriodData.instantDate !== correctedInstantDate) {
10835
+ console.log(`🩹 [Legacy Period Correction] ${periodDataKey}/${field2.columnId}: instantDate ${fieldPeriodData.instantDate} → ${correctedInstantDate}`);
10836
+ fieldPeriodData.instantDate = correctedInstantDate;
10837
+ }
10838
+ if (field2.periodInstantDate !== correctedInstantDate) {
10839
+ console.log(`🩹 [Legacy Period Correction] field ${concept.id}/${field2.columnId}: periodInstantDate ${field2.periodInstantDate} → ${correctedInstantDate}`);
10840
+ field2.periodInstantDate = correctedInstantDate;
10841
+ }
10842
+ }
10760
10843
  _addColumnFromRequest(request, sectionId, insertAfterColumnId) {
10761
10844
  var _a, _b, _c, _d, _e;
10762
10845
  const timestamp = Date.now();
@@ -11056,6 +11139,7 @@ let JupiterDynamicForm = class extends LitElement {
11056
11139
  this.requestUpdate();
11057
11140
  return;
11058
11141
  }
11142
+ this._correctLegacyPeriodStartInstantDates();
11059
11143
  const submissionData = this._generateSubmissionData();
11060
11144
  console.log("📊 Form Submission Data:", JSON.stringify(submissionData, null, 2));
11061
11145
  console.log("📊 Submission Data Summary:");
@@ -11091,6 +11175,7 @@ let JupiterDynamicForm = class extends LitElement {
11091
11175
  console.log("💾 Raw form data before submission generation:", this._formData);
11092
11176
  console.log("🏷️ Unit data before submission generation:", this._unitData);
11093
11177
  console.log("📋 Enhanced selectedRoleIds with roleURI and order:", this._selectedRoleIds);
11178
+ this._correctLegacyPeriodStartInstantDates();
11094
11179
  const draftData = this._generateSubmissionData();
11095
11180
  console.log("📤 Generated submission data:", draftData);
11096
11181
  console.log("📊 Submission data breakdown:");
@@ -11349,6 +11434,7 @@ let JupiterDynamicForm = class extends LitElement {
11349
11434
  };
11350
11435
  console.log(`🏷️ [Unit Restore] Merged unit data: ${Object.keys(this._unitData).length} concepts with custom units`);
11351
11436
  console.log(`🏷️ [Unit Restore] Full _unitData after merge:`, JSON.stringify(this._unitData, null, 2));
11437
+ this._correctLegacyPeriodStartInstantDates();
11352
11438
  if (this._selectedRoleIds.length > 0) {
11353
11439
  this._applyRoleFilter();
11354
11440
  }