jupiter-dynamic-forms 1.22.4 → 1.22.5

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
@@ -1808,6 +1808,7 @@ const field$1 = {
1808
1808
  selectUnit: "Select Unit",
1809
1809
  leaveBlankForInf: "Leave blank for INF",
1810
1810
  prefilledLocked: "Pre-filled — cannot be changed here",
1811
+ notApplicablePriorYear: "Not required for the previous year",
1811
1812
  invalidNumber: `Can't read "{{value}}" as a number`,
1812
1813
  noDecimalsAllowed: "This field doesn't accept decimals",
1813
1814
  negativeNotAllowed: "A negative value isn't allowed here",
@@ -1865,7 +1866,9 @@ const duplicateFactWarning$1 = {
1865
1866
  message: "The same concept, period and dimensions were found with different values entered in different roles. Only one value can be correct — click a fact below to review and fix it.",
1866
1867
  role: "Role:",
1867
1868
  value: "Value:",
1868
- clickToFocus: "Click to go to this fact"
1869
+ clickToFocus: "Click to go to this fact",
1870
+ cellTooltip: "This value differs from the same fact entered elsewhere — click to review",
1871
+ close: "Close"
1869
1872
  };
1870
1873
  const calculationWarning$1 = {
1871
1874
  title: "Calculation warning",
@@ -2068,6 +2071,7 @@ const field = {
2068
2071
  selectUnit: "Selecteer eenheid",
2069
2072
  leaveBlankForInf: "Leeg laten voor INF",
2070
2073
  prefilledLocked: "Vooraf ingevuld — kan hier niet worden gewijzigd",
2074
+ notApplicablePriorYear: "Niet vereist voor het voorgaande jaar",
2071
2075
  invalidNumber: "Kan '{{value}}' niet lezen als getal",
2072
2076
  noDecimalsAllowed: "Dit veld accepteert geen decimalen",
2073
2077
  negativeNotAllowed: "Een negatieve waarde is hier niet toegestaan",
@@ -2125,7 +2129,9 @@ const duplicateFactWarning = {
2125
2129
  message: "Hetzelfde concept, dezelfde periode en dimensies zijn gevonden met verschillende waarden in verschillende rollen. Slechts één waarde kan juist zijn — klik op een feit hieronder om het te controleren en te corrigeren.",
2126
2130
  role: "Rol:",
2127
2131
  value: "Waarde:",
2128
- clickToFocus: "Klik om naar dit feit te gaan"
2132
+ clickToFocus: "Klik om naar dit feit te gaan",
2133
+ cellTooltip: "Deze waarde wijkt af van hetzelfde feit dat elders is ingevoerd — klik om te controleren",
2134
+ close: "Sluiten"
2129
2135
  };
2130
2136
  const calculationWarning = {
2131
2137
  title: "Berekeningswaarschuwing",
@@ -5011,7 +5017,7 @@ let JupiterFormField = class extends LitElement {
5011
5017
  if (changedProperties.has("value") || changedProperties.has("field")) {
5012
5018
  this._validateField();
5013
5019
  }
5014
- if (changedProperties.has("unit") && this.unit) {
5020
+ if (changedProperties.has("unit") && this.unit && this.hasUpdated) {
5015
5021
  console.log(`🏷️ [FormField willUpdate] Unit property changed to: ${this.unit}, conceptId: ${this.conceptId}, columnId: ${this.columnId}`);
5016
5022
  this.dispatchEvent(new CustomEvent("unit-change", {
5017
5023
  detail: {
@@ -5046,6 +5052,14 @@ let JupiterFormField = class extends LitElement {
5046
5052
  _isRoundingLevelConcept() {
5047
5053
  return !!this.conceptId && this.conceptId.includes("DocumentIntendedRoundingLevel");
5048
5054
  }
5055
+ // jenv-bw2-i:BalanceSheetBeforeAfterAppropriationResults records the profit-appropriation
5056
+ // decision for the current balance sheet only — the NL taxonomy's validation rules warn when
5057
+ // it's also reported for the comparative year, so the prior-year column doesn't accept it.
5058
+ // `columnId` carries the `_prev` marker `generatePreviousYearColumns` (xbrl-form-builder.ts)
5059
+ // gives every comparative-year column, whether dimensioned (`${id}_prev`) or not (`duration_prev_N`).
5060
+ _isDisabledForPriorYear() {
5061
+ return !!this.conceptId && !!this.columnId && this.conceptId.includes("BalanceSheetBeforeAfterAppropriationResults") && this.columnId.includes("_prev");
5062
+ }
5049
5063
  /**
5050
5064
  * JDF-110: lock icon (SVG, not emoji) shown on a masterData-prefilled or rounding-level-locked
5051
5065
  * cell, so a locked value reads as "filled and protected" rather than empty placeholder text.
@@ -5689,7 +5703,7 @@ let JupiterFormField = class extends LitElement {
5689
5703
  const isMonetary = this._isMonetaryType();
5690
5704
  return html`<span class="readonly-value ${isEmpty ? "empty" : ""} ${isMonetary ? "monetary" : ""}">${isEmpty ? "—" : displayValue}</span>`;
5691
5705
  }
5692
- _renderInput(effectiveValue = this.value, effectiveDisabled = this.disabled, isLocked = false) {
5706
+ _renderInput(effectiveValue = this.value, effectiveDisabled = this.disabled, isLocked = false, disabledTooltip) {
5693
5707
  if (this.mode === "readonly") {
5694
5708
  return this._renderReadonlyValue(effectiveValue);
5695
5709
  }
@@ -5715,6 +5729,7 @@ let JupiterFormField = class extends LitElement {
5715
5729
  class="${cssClass}"
5716
5730
  .value="${effectiveValue ?? ""}"
5717
5731
  ?disabled="${effectiveDisabled || this.field.disabled}"
5732
+ title="${disabledTooltip || ""}"
5718
5733
  @change="${this._handleInput}"
5719
5734
  @focus="${this._handleFocus}"
5720
5735
  @blur="${this._handleBlur}"
@@ -6066,6 +6081,7 @@ let JupiterFormField = class extends LitElement {
6066
6081
  const baseConceptId = this._extractBaseConceptId(this.conceptId);
6067
6082
  const isPredefinedValue = this.mode !== "admin" && this.masterData && baseConceptId in this.masterData;
6068
6083
  const isRoundingLevelLocked = this._isRoundingLevelConcept();
6084
+ const isDisabledForPriorYear = this._isDisabledForPriorYear();
6069
6085
  let factValue = null;
6070
6086
  if (this.facts && this.facts.length > 0 && !isPredefinedValue) {
6071
6087
  const cellContext = {
@@ -6119,8 +6135,8 @@ let JupiterFormField = class extends LitElement {
6119
6135
  }
6120
6136
  }
6121
6137
  const hasUserValue = this.value !== null && this.value !== void 0;
6122
- const effectiveValue = isPredefinedValue ? this.masterData[baseConceptId] : hasUserValue ? this.value : factValue;
6123
- const effectiveDisabled = isPredefinedValue || isRoundingLevelLocked || this.disabled || this.mode === "readonly";
6138
+ const effectiveValue = isDisabledForPriorYear ? null : isPredefinedValue ? this.masterData[baseConceptId] : hasUserValue ? this.value : factValue;
6139
+ const effectiveDisabled = isPredefinedValue || isRoundingLevelLocked || isDisabledForPriorYear || this.disabled || this.mode === "readonly";
6124
6140
  const isLocked = (isPredefinedValue || isRoundingLevelLocked) && this.mode !== "readonly";
6125
6141
  const typeConfigForLock = getInputTypeForConceptType(this.conceptType, this.datatypes);
6126
6142
  const effectiveFieldTypeForLock = typeConfigForLock.fieldType || this.field.type || "text";
@@ -6134,7 +6150,7 @@ let JupiterFormField = class extends LitElement {
6134
6150
  ` : ""}
6135
6151
 
6136
6152
  <div class="field-wrapper">
6137
- ${this._renderInput(effectiveValue, effectiveDisabled, isLocked)}
6153
+ ${this._renderInput(effectiveValue, effectiveDisabled, isLocked, isDisabledForPriorYear ? I18n.t("field.notApplicablePriorYear") : void 0)}
6138
6154
 
6139
6155
  ${isLocked && !isTextareaField || hasPeriodControl && this.mode !== "readonly" && !isRoundingLevelLocked ? html`
6140
6156
  <div class="field-trailing-icons">
@@ -7061,6 +7077,19 @@ let JupiterConceptTree = class extends LitElement {
7061
7077
  `;
7062
7078
  document.head.appendChild(style);
7063
7079
  }
7080
+ /**
7081
+ * Dispatches the clicked cell's duplicate-fact mismatch up to `jupiter-dynamic-form`, which owns
7082
+ * the click-to-navigate machinery (role/column reveal, side-panel switch, highlight) already
7083
+ * built for the Validate pre-flight popup — reused here to show this one mismatch's facts.
7084
+ */
7085
+ _handleDuplicateFactWarningBadgeClick(e2, mismatch) {
7086
+ e2.stopPropagation();
7087
+ this.dispatchEvent(new CustomEvent("duplicate-fact-warning-click", {
7088
+ detail: { mismatch },
7089
+ bubbles: true,
7090
+ composed: true
7091
+ }));
7092
+ }
7064
7093
  _openCalculationWarningDialog(e2, mismatch) {
7065
7094
  var _a;
7066
7095
  e2.stopPropagation();
@@ -7135,7 +7164,7 @@ let JupiterConceptTree = class extends LitElement {
7135
7164
 
7136
7165
  <!-- Input Field Cells (Period Columns) - Only for non-abstract concepts -->
7137
7166
  ${this.columns.map((column2) => {
7138
- var _a, _b, _c, _d, _e;
7167
+ var _a, _b, _c, _d, _e, _f;
7139
7168
  if (column2.hidden) {
7140
7169
  return html`<td class="field-cell hidden-column"></td>`;
7141
7170
  }
@@ -7144,8 +7173,9 @@ let JupiterConceptTree = class extends LitElement {
7144
7173
  const storedUnit = (_b = (_a = this.unitData) == null ? void 0 : _a[this.concept.id]) == null ? void 0 : _b[column2.id];
7145
7174
  const storedDecimals = (_d = (_c = this.decimalsData) == null ? void 0 : _c[this.concept.id]) == null ? void 0 : _d[column2.id];
7146
7175
  const calcMismatch = this.mode !== "readonly" ? (_e = this.calculationMismatches) == null ? void 0 : _e.get(`${this.concept.id}__${column2.id}`) : void 0;
7176
+ const dupWarning = this.mode !== "readonly" ? (_f = this.duplicateFactWarnings) == null ? void 0 : _f.get(`${this.concept.id}__${column2.id}`) : void 0;
7147
7177
  return html`
7148
- <td class="field-cell ${!shouldShowField ? "empty" : ""} ${isAbstract ? "abstract-row" : ""} ${isTotal ? "total-row" : ""} ${this.highlightType && column2.id === this.highlightColumnId ? "highlight-" + this.highlightType : ""} ${calcMismatch ? "calc-warning" : ""} ${this.rowFocused ? "row-focused" : ""}">
7178
+ <td class="field-cell ${!shouldShowField ? "empty" : ""} ${isAbstract ? "abstract-row" : ""} ${isTotal ? "total-row" : ""} ${this.highlightType && column2.id === this.highlightColumnId ? "highlight-" + this.highlightType : ""} ${calcMismatch ? "calc-warning" : ""} ${dupWarning ? "duplicate-fact-warning" : ""} ${this.rowFocused ? "row-focused" : ""}">
7149
7179
  ${calcMismatch ? html`
7150
7180
  <button
7151
7181
  class="calc-warning-badge"
@@ -7155,6 +7185,15 @@ let JupiterConceptTree = class extends LitElement {
7155
7185
  @click="${(e2) => this._openCalculationWarningDialog(e2, calcMismatch)}"
7156
7186
  >!</button>
7157
7187
  ` : ""}
7188
+ ${dupWarning ? html`
7189
+ <button
7190
+ class="duplicate-warning-badge"
7191
+ type="button"
7192
+ tabindex="-1"
7193
+ title="${I18n.t("duplicateFactWarning.cellTooltip")}"
7194
+ @click="${(e2) => this._handleDuplicateFactWarningBadgeClick(e2, dupWarning)}"
7195
+ >≠</button>
7196
+ ` : ""}
7158
7197
  ${shouldShowField ? html`
7159
7198
  <jupiter-form-field
7160
7199
  .field="${field2}"
@@ -7407,6 +7446,38 @@ JupiterConceptTree.styles = css`
7407
7446
  background: #e65100;
7408
7447
  }
7409
7448
 
7449
+ /* Live counterpart to the Validate pre-flight's duplicate-fact-value check — deliberately a
7450
+ distinct color from calc-warning's amber so the two non-blocking warnings never look like
7451
+ the same issue when both land on the same cell. */
7452
+ .field-cell.duplicate-fact-warning {
7453
+ box-shadow: inset 0 0 0 2px var(--jupiter-duplicate-warning-color, #8e24aa);
7454
+ }
7455
+
7456
+ .duplicate-warning-badge {
7457
+ position: absolute;
7458
+ top: 2px;
7459
+ left: 2px;
7460
+ width: 16px;
7461
+ height: 16px;
7462
+ border-radius: 50%;
7463
+ border: none;
7464
+ background: var(--jupiter-duplicate-warning-color, #8e24aa);
7465
+ color: #fff;
7466
+ font-size: 10px;
7467
+ font-weight: 700;
7468
+ line-height: 1;
7469
+ padding: 0;
7470
+ display: flex;
7471
+ align-items: center;
7472
+ justify-content: center;
7473
+ cursor: pointer;
7474
+ z-index: 3;
7475
+ }
7476
+
7477
+ .duplicate-warning-badge:hover {
7478
+ background: #6a1b9a;
7479
+ }
7480
+
7410
7481
  /* Row-level highlight while a field in this row has focus. Applied to every
7411
7482
  cell so the row stays identifiable even after the user scrolls the table
7412
7483
  horizontally away from the focused input. */
@@ -7560,6 +7631,9 @@ __decorateClass$7([
7560
7631
  __decorateClass$7([
7561
7632
  n2({ type: Object })
7562
7633
  ], JupiterConceptTree.prototype, "calculationMismatches", 2);
7634
+ __decorateClass$7([
7635
+ n2({ type: Object })
7636
+ ], JupiterConceptTree.prototype, "duplicateFactWarnings", 2);
7563
7637
  __decorateClass$7([
7564
7638
  n2({ type: String })
7565
7639
  ], JupiterConceptTree.prototype, "language", 2);
@@ -9347,6 +9421,7 @@ let JupiterFormSection = class extends LitElement {
9347
9421
  .highlightColumnId="${(_b = this._highlightMap.get(instanceConcept.id)) == null ? void 0 : _b.columnId}"
9348
9422
  .rowFocused="${this._focusedConceptId === instanceConcept.id}"
9349
9423
  .calculationMismatches="${this._calculationMismatches}"
9424
+ .duplicateFactWarnings="${this.duplicateFactWarnings}"
9350
9425
  @field-change="${this._handleFieldChange}"
9351
9426
  @field-focus="${this._handleFieldFocusForHighlight}"
9352
9427
  @period-change="${this._handlePeriodChange}"
@@ -9982,6 +10057,9 @@ __decorateClass$5([
9982
10057
  __decorateClass$5([
9983
10058
  n2({ type: Object })
9984
10059
  ], JupiterFormSection.prototype, "totalManuallyEditedData", 2);
10060
+ __decorateClass$5([
10061
+ n2({ type: Object })
10062
+ ], JupiterFormSection.prototype, "duplicateFactWarnings", 2);
9985
10063
  __decorateClass$5([
9986
10064
  r()
9987
10065
  ], JupiterFormSection.prototype, "_expanded", 2);
@@ -12939,6 +13017,8 @@ let JupiterDynamicForm = class extends LitElement {
12939
13017
  this._showValidateWarningPopup = false;
12940
13018
  this._typedDimensionWarningFacts = [];
12941
13019
  this._duplicateFactMismatches = [];
13020
+ this._duplicateFactWarnings = /* @__PURE__ */ new Map();
13021
+ this._duplicateWarningPopupMode = "validate";
12942
13022
  this._submitDisabled = false;
12943
13023
  this._allSections = [];
12944
13024
  this._selectedRoleIds = [];
@@ -12996,6 +13076,15 @@ let JupiterDynamicForm = class extends LitElement {
12996
13076
  this.addEventListener("calculation-mismatch-changed", (e2) => {
12997
13077
  this._handleCalculationMismatchChanged(e2);
12998
13078
  });
13079
+ this.addEventListener("duplicate-fact-warning-click", (e2) => {
13080
+ const { mismatch } = e2.detail || {};
13081
+ if (!mismatch)
13082
+ return;
13083
+ this._typedDimensionWarningFacts = [];
13084
+ this._duplicateFactMismatches = [mismatch];
13085
+ this._duplicateWarningPopupMode = "cellInfo";
13086
+ this._showValidateWarningPopup = true;
13087
+ });
12999
13088
  this.addEventListener("total-manually-edited", (e2) => {
13000
13089
  const { conceptId, columnId } = e2.detail;
13001
13090
  const updated = { ...this._totalManuallyEditedData };
@@ -13209,6 +13298,7 @@ let JupiterDynamicForm = class extends LitElement {
13209
13298
  if ((_a = this.xbrlInput) == null ? void 0 : _a.initialData) {
13210
13299
  this._formData = { ...this._formData, ...this.xbrlInput.initialData };
13211
13300
  }
13301
+ this._formData = this._stripPriorYearExcludedFacts(this._formData);
13212
13302
  this._initializeGlobalDecimalsFromRoundingData();
13213
13303
  this._extractTypedMembersFromFacts();
13214
13304
  if (!this._skipDraftLoading) {
@@ -13889,8 +13979,15 @@ let JupiterDynamicForm = class extends LitElement {
13889
13979
  // which reads as "still cut off" when its row height isn't an exact multiple of the container.
13890
13980
  _scrollActiveRoleIntoView() {
13891
13981
  var _a;
13892
- const activeItem = (_a = this.shadowRoot) == null ? void 0 : _a.querySelector(".side-panel-roles-list .side-panel-role-item.active");
13893
- activeItem == null ? void 0 : activeItem.scrollIntoView({ block: "center" });
13982
+ const rolesList = (_a = this.shadowRoot) == null ? void 0 : _a.querySelector(".side-panel-roles-list");
13983
+ const activeItem = rolesList == null ? void 0 : rolesList.querySelector(".side-panel-role-item.active");
13984
+ if (!rolesList || !activeItem)
13985
+ return;
13986
+ const listRect = rolesList.getBoundingClientRect();
13987
+ const itemRect = activeItem.getBoundingClientRect();
13988
+ const itemCenter = itemRect.top + itemRect.height / 2;
13989
+ const listCenter = listRect.top + listRect.height / 2;
13990
+ rolesList.scrollTop += itemCenter - listCenter;
13894
13991
  }
13895
13992
  // Re-locates the fact input identified by _lastFocusedFieldIdentity after a rebuild and restores
13896
13993
  // focus to it, mirroring the shadow-DOM traversal scrollToConcept/_handleErrorFieldClick use.
@@ -14115,6 +14212,29 @@ let JupiterDynamicForm = class extends LitElement {
14115
14212
  this._calculationWarnings = next;
14116
14213
  this._validateForm();
14117
14214
  }
14215
+ // jenv-bw2-i:BalanceSheetBeforeAfterAppropriationResults isn't applicable to the previous-year
14216
+ // column — mirrors `_isDisabledForPriorYear` in form-field.ts (which disables the input itself);
14217
+ // this is the `_formData`/submission-side counterpart so a value already sitting in a draft,
14218
+ // `initialData`, or preserved (hidden-role) data from before that UI restriction existed gets
14219
+ // scrubbed on load and can never resurface in a later draft save or submission.
14220
+ _isPriorYearExcludedFact(conceptId, columnId) {
14221
+ return !!conceptId && !!columnId && conceptId.includes("BalanceSheetBeforeAfterAppropriationResults") && columnId.includes("_prev");
14222
+ }
14223
+ /** Strips any prior-year-excluded concept/column entries from a `FormData` map (immutable). */
14224
+ _stripPriorYearExcludedFacts(data) {
14225
+ const cleaned = {};
14226
+ Object.keys(data).forEach((conceptId) => {
14227
+ const columns = data[conceptId] || {};
14228
+ const keptColumns = {};
14229
+ Object.keys(columns).forEach((columnId) => {
14230
+ if (!this._isPriorYearExcludedFact(conceptId, columnId)) {
14231
+ keptColumns[columnId] = columns[columnId];
14232
+ }
14233
+ });
14234
+ cleaned[conceptId] = keptColumns;
14235
+ });
14236
+ return cleaned;
14237
+ }
14118
14238
  /**
14119
14239
  * JDF-058: single source of truth for writing a value into `_formData` with the immutable-update
14120
14240
  * pattern Lit reactivity needs — shared by a real user keystroke (`_handleFieldChange`) and the
@@ -14122,6 +14242,10 @@ let JupiterDynamicForm = class extends LitElement {
14122
14242
  * duplicated. Returns the value that was previously stored, for event `oldValue` fields.
14123
14243
  */
14124
14244
  _writeFormDataValue(conceptId, columnId, value) {
14245
+ var _a;
14246
+ if (this._isPriorYearExcludedFact(conceptId, columnId)) {
14247
+ return (_a = this._formData[conceptId]) == null ? void 0 : _a[columnId];
14248
+ }
14125
14249
  const updatedFormData = { ...this._formData };
14126
14250
  if (!updatedFormData[conceptId]) {
14127
14251
  updatedFormData[conceptId] = {};
@@ -14174,13 +14298,17 @@ let JupiterDynamicForm = class extends LitElement {
14174
14298
  this.requestUpdate();
14175
14299
  }
14176
14300
  _handleUnitChange(event) {
14301
+ var _a;
14177
14302
  console.log(`🏷️ [DynamicForm] _handleUnitChange called with event:`, event);
14178
14303
  console.log(`🏷️ [DynamicForm] Event detail:`, event.detail);
14179
14304
  const { conceptId, columnId, unit } = event.detail;
14180
14305
  console.log(`🏷️ Unit change received: conceptId=${conceptId}, columnId=${columnId}, unit=${unit}`);
14306
+ const isUnchanged = ((_a = this._unitData[conceptId]) == null ? void 0 : _a[columnId]) === unit;
14181
14307
  this._storeUnit(conceptId, columnId, unit);
14182
- this._dirty = true;
14183
- this.hasUnsavedChanges = true;
14308
+ if (!isUnchanged) {
14309
+ this._dirty = true;
14310
+ this.hasUnsavedChanges = true;
14311
+ }
14184
14312
  this.requestUpdate();
14185
14313
  }
14186
14314
  _storeUnit(conceptId, columnId, unit) {
@@ -14488,6 +14616,7 @@ let JupiterDynamicForm = class extends LitElement {
14488
14616
  console.log(`🟧 [DynamicForm] Removed ${beforeLength - this._xbrlFormErrors.length} errors`);
14489
14617
  }
14490
14618
  console.log(`🔍 [Validation] Total errors: ${this._xbrlFormErrors.length}`, this._xbrlFormErrors);
14619
+ this._updateDuplicateFactWarnings(conceptId, columnId);
14491
14620
  }
14492
14621
  _getSectionTitle(sectionId) {
14493
14622
  console.log(`🔍 [_getSectionTitle] Looking for sectionId: "${sectionId}"`);
@@ -15325,6 +15454,33 @@ let JupiterDynamicForm = class extends LitElement {
15325
15454
  }
15326
15455
  return String(value);
15327
15456
  }
15457
+ /**
15458
+ * Live, blur-triggered counterpart to `_findDuplicateFactMismatches`. Re-runs the full duplicate
15459
+ * check (cheap — the same pass Validate already does) and rebuilds `_duplicateFactWarnings` from
15460
+ * scratch, so a resolved conflict clears itself and a newly created one appears without any
15461
+ * extra bookkeeping. Every fact in every current mismatch group gets flagged, not just the field
15462
+ * that was just blurred, so the user sees all the cells involved in a conflict — including one
15463
+ * they filled in earlier — the moment either side changes, rather than having to revisit them
15464
+ * one by one after Validate. Skipped when the blurred cell has no value and wasn't already
15465
+ * flagged, since a blank cell can never be part of a mismatch (`_collectDuplicateFactCandidates`
15466
+ * ignores blanks) — this keeps tabbing through empty cells cheap.
15467
+ */
15468
+ _updateDuplicateFactWarnings(conceptId, columnId) {
15469
+ var _a;
15470
+ const value = (_a = this._formData[conceptId]) == null ? void 0 : _a[columnId];
15471
+ const hasMeaningfulValue = value !== void 0 && value !== null && String(value).trim() !== "";
15472
+ const key = `${conceptId}__${columnId}`;
15473
+ if (!hasMeaningfulValue && !this._duplicateFactWarnings.has(key))
15474
+ return;
15475
+ const mismatches = this._findDuplicateFactMismatches();
15476
+ const updated = /* @__PURE__ */ new Map();
15477
+ for (const mismatch of mismatches) {
15478
+ for (const fact of mismatch.facts) {
15479
+ updated.set(`${fact.conceptId}__${fact.columnId}`, mismatch);
15480
+ }
15481
+ }
15482
+ this._duplicateFactWarnings = updated;
15483
+ }
15328
15484
  /** Popup header for the Validate pre-flight warning: specific when only one check found something, generic when both did. */
15329
15485
  _validateWarningPopupTitle() {
15330
15486
  const hasTypedDimensionWarning = this._typedDimensionWarningFacts.length > 0;
@@ -15352,6 +15508,7 @@ let JupiterDynamicForm = class extends LitElement {
15352
15508
  console.log("⚠️ [Submit] Duplicate facts with mismatched values:", duplicateFactMismatches);
15353
15509
  this._typedDimensionWarningFacts = missingTypedDimensionFacts;
15354
15510
  this._duplicateFactMismatches = duplicateFactMismatches;
15511
+ this._duplicateWarningPopupMode = "validate";
15355
15512
  this._showValidateWarningPopup = true;
15356
15513
  this._submitDisabled = false;
15357
15514
  this.requestUpdate();
@@ -15722,6 +15879,10 @@ let JupiterDynamicForm = class extends LitElement {
15722
15879
  return;
15723
15880
  }
15724
15881
  }
15882
+ if (this._isPriorYearExcludedFact(conceptId, columnId)) {
15883
+ console.log(`⏭️ Dropping legacy draft value for ${conceptId}/${columnId} — not applicable to the previous year`);
15884
+ return;
15885
+ }
15725
15886
  const instanceKey = draftInstanceId || conceptId;
15726
15887
  const baseConceptId = instanceKey.includes("__repeat_") ? instanceKey.split("__repeat_")[0] : instanceKey;
15727
15888
  const actualBaseId = this._findActualConceptId(baseConceptId);
@@ -16265,6 +16426,8 @@ let JupiterDynamicForm = class extends LitElement {
16265
16426
  }
16266
16427
  _addConceptDataToSubmission(concept, columnId, value, submissionData, section2) {
16267
16428
  var _a, _b, _c, _d, _e;
16429
+ if (this._isPriorYearExcludedFact(concept.id, columnId))
16430
+ return;
16268
16431
  const field2 = concept.fields.find((f2) => f2.columnId === columnId);
16269
16432
  if (!field2)
16270
16433
  return;
@@ -16437,26 +16600,25 @@ let JupiterDynamicForm = class extends LitElement {
16437
16600
  }
16438
16601
  if (concept.fields && concept.fields.length > 0) {
16439
16602
  concept.fields.forEach((field2) => {
16440
- var _a, _b, _c, _d, _e, _f, _g, _h;
16603
+ var _a, _b, _c, _d, _e, _f, _g;
16604
+ if (this._isPriorYearExcludedFact(concept.id, field2.columnId)) {
16605
+ return;
16606
+ }
16441
16607
  const conceptData = this._formData[concept.id];
16442
- let fieldValue = conceptData == null ? void 0 : conceptData[field2.columnId];
16443
16608
  const baseConceptId = field2.conceptId || concept.id.split("__").slice(0, -1).join("__") || concept.id;
16444
- if ((fieldValue === void 0 || fieldValue === null || fieldValue === "") && this._isRoundingLevelConcept(baseConceptId) && !this._hasValidGlobalDecimals()) {
16609
+ const masterDataWins = this.mode !== "admin" && !!this._effectiveMasterData && baseConceptId in this._effectiveMasterData;
16610
+ let fieldValue = masterDataWins ? this._effectiveMasterData[baseConceptId] : conceptData == null ? void 0 : conceptData[field2.columnId];
16611
+ if (masterDataWins) {
16612
+ console.log(` 📦 [Submission] Using masterData for: ${baseConceptId} [${field2.columnId}] = ${JSON.stringify(fieldValue)}`);
16613
+ } else if ((fieldValue === void 0 || fieldValue === null || fieldValue === "") && this._isRoundingLevelConcept(baseConceptId) && !this._hasValidGlobalDecimals()) {
16445
16614
  const factValue = this._findFactValueForField(concept, field2, section2);
16446
16615
  if (factValue !== void 0 && factValue !== null && factValue !== "") {
16447
16616
  fieldValue = factValue;
16448
16617
  }
16449
16618
  }
16450
- if ((fieldValue === void 0 || fieldValue === null || fieldValue === "") && this._effectiveMasterData) {
16451
- const masterValue = (_a = this._effectiveMasterData) == null ? void 0 : _a[baseConceptId];
16452
- if (masterValue !== void 0 && masterValue !== null && masterValue !== "") {
16453
- fieldValue = masterValue;
16454
- console.log(` 📦 [Submission] Using masterData for: ${baseConceptId} [${field2.columnId}] = ${JSON.stringify(fieldValue)}`);
16455
- }
16456
- }
16457
16619
  if (fieldValue !== void 0 && fieldValue !== null && fieldValue !== "") {
16458
16620
  const column2 = this._findColumnByIdInSection(field2.columnId, section2);
16459
- const fieldPeriodData = (_b = this._periodData[concept.id]) == null ? void 0 : _b[field2.columnId];
16621
+ const fieldPeriodData = (_a = this._periodData[concept.id]) == null ? void 0 : _a[field2.columnId];
16460
16622
  const submissionEntry = {
16461
16623
  conceptId: concept.id,
16462
16624
  draftInstanceId: concept.id,
@@ -16478,21 +16640,21 @@ let JupiterDynamicForm = class extends LitElement {
16478
16640
  submissionEntry.period.endDate = endDate;
16479
16641
  }
16480
16642
  console.log(`🔍 [Submission] Concept: ${concept.id}, Column: ${field2.columnId}, Field Period: ${fieldPeriodData ? JSON.stringify(fieldPeriodData) : "none"}, Column Period: ${(column2 == null ? void 0 : column2.periodStartDate) || "none"} - ${(column2 == null ? void 0 : column2.periodEndDate) || "none"}, Used Period: ${submissionEntry.period.type === "instant" ? submissionEntry.period.date : `${submissionEntry.period.startDate} - ${submissionEntry.period.endDate}`}`);
16481
- const fieldUnit = (_c = this._unitData[concept.id]) == null ? void 0 : _c[field2.columnId];
16643
+ const fieldUnit = (_b = this._unitData[concept.id]) == null ? void 0 : _b[field2.columnId];
16482
16644
  if (fieldUnit) {
16483
16645
  submissionEntry.unit = fieldUnit;
16484
16646
  console.log(`✅ [Submission] Adding unit to entry: ${fieldUnit} for ${concept.id}/${field2.columnId}`);
16485
16647
  } else {
16486
16648
  console.log(`⚠️ [Submission] No unit found in _unitData for ${concept.id}/${field2.columnId}. _unitData state:`, JSON.stringify(this._unitData, null, 2));
16487
16649
  }
16488
- const isMonetary = (_d = concept.type) == null ? void 0 : _d.toLowerCase().includes("monetary");
16489
- const fieldDecimals = (_e = this._decimalsData[concept.id]) == null ? void 0 : _e[field2.columnId];
16650
+ const isMonetary = (_c = concept.type) == null ? void 0 : _c.toLowerCase().includes("monetary");
16651
+ const fieldDecimals = (_d = this._decimalsData[concept.id]) == null ? void 0 : _d[field2.columnId];
16490
16652
  const decimalsValue = fieldDecimals || (this.decimals !== "INF" ? this.decimals : void 0);
16491
16653
  if (isMonetary && decimalsValue) {
16492
16654
  const parsed = parseFloat(decimalsValue);
16493
16655
  submissionEntry.decimals = isNaN(parsed) ? decimalsValue : String(-Math.abs(parsed));
16494
16656
  }
16495
- if ((column2 == null ? void 0 : column2.type) === "dimension" && ((_f = column2.dimensionData) == null ? void 0 : _f.dimensionIdKey)) {
16657
+ if ((column2 == null ? void 0 : column2.type) === "dimension" && ((_e = column2.dimensionData) == null ? void 0 : _e.dimensionIdKey)) {
16496
16658
  submissionEntry.dimension = column2.dimensionData.dimensionIdKey;
16497
16659
  console.log(`🔍 [DynamicForm] Using dimension key from field's column (${field2.columnId}):`, column2.dimensionData.dimensionIdKey);
16498
16660
  } else {
@@ -16531,12 +16693,12 @@ let JupiterDynamicForm = class extends LitElement {
16531
16693
  console.log(`🔍 [DynamicForm] Column details:`, {
16532
16694
  id: column2.id,
16533
16695
  type: column2.type,
16534
- hasTypedMembers: (_g = column2.dimensionData) == null ? void 0 : _g.hasTypedMembers,
16696
+ hasTypedMembers: (_f = column2.dimensionData) == null ? void 0 : _f.hasTypedMembers,
16535
16697
  dimensionData: column2.dimensionData
16536
16698
  });
16537
16699
  }
16538
16700
  }
16539
- if (!submissionEntry.typedMembers && ((_h = field2.crossRoleTypedMembers) == null ? void 0 : _h.length)) {
16701
+ if (!submissionEntry.typedMembers && ((_g = field2.crossRoleTypedMembers) == null ? void 0 : _g.length)) {
16540
16702
  const crossRoleKey = `${concept.id}__${field2.columnId}`;
16541
16703
  const crossRoleValues = this._typedMemberData[crossRoleKey];
16542
16704
  if (crossRoleValues) {
@@ -16627,7 +16789,7 @@ let JupiterDynamicForm = class extends LitElement {
16627
16789
  });
16628
16790
  }
16629
16791
  _handleReset() {
16630
- this._formData = { ...this.initialData };
16792
+ this._formData = this._stripPriorYearExcludedFacts(this.initialData);
16631
16793
  this._touched.clear();
16632
16794
  this._dirty = false;
16633
16795
  this.hasUnsavedChanges = false;
@@ -17394,6 +17556,7 @@ let JupiterDynamicForm = class extends LitElement {
17394
17556
  .periodEndDate="${this.periodEndDate}"
17395
17557
  .calculationEnabled="${this.calculationEnabled}"
17396
17558
  .totalManuallyEditedData="${this._totalManuallyEditedData}"
17559
+ .duplicateFactWarnings="${this._duplicateFactWarnings}"
17397
17560
  @field-change="${this._handleFieldChange}"
17398
17561
  @period-change="${this._handlePeriodChange}"
17399
17562
  @typed-member-change="${this._handleTypedMemberChange}"
@@ -17601,6 +17764,7 @@ let JupiterDynamicForm = class extends LitElement {
17601
17764
  .periodEndDate="${this.periodEndDate}"
17602
17765
  .calculationEnabled="${this.calculationEnabled}"
17603
17766
  .totalManuallyEditedData="${this._totalManuallyEditedData}"
17767
+ .duplicateFactWarnings="${this._duplicateFactWarnings}"
17604
17768
  @field-change="${this._handleFieldChange}"
17605
17769
  @typed-member-change="${this._handleTypedMemberChange}"
17606
17770
  @add-concept-repeat="${this._handleAddConceptRepeat}"
@@ -17653,7 +17817,7 @@ let JupiterDynamicForm = class extends LitElement {
17653
17817
  return { ...this._formData };
17654
17818
  }
17655
17819
  setData(data) {
17656
- this._formData = { ...data };
17820
+ this._formData = this._stripPriorYearExcludedFacts(data);
17657
17821
  this._dirty = true;
17658
17822
  this.hasUnsavedChanges = true;
17659
17823
  this._validateForm();
@@ -18464,14 +18628,21 @@ let JupiterDynamicForm = class extends LitElement {
18464
18628
  ` : ""}
18465
18629
  </div>
18466
18630
  <div class="error-popup-footer">
18467
- <button class="btn-secondary" @click="${() => {
18631
+ ${this._duplicateWarningPopupMode === "validate" ? html`
18632
+ <button class="btn-secondary" @click="${() => {
18468
18633
  this._showValidateWarningPopup = false;
18469
18634
  this.requestUpdate();
18470
18635
  }}">${I18n.t("typedDimensionWarning.cancel")}</button>
18471
- <button class="btn-primary" @click="${() => {
18636
+ <button class="btn-primary" @click="${() => {
18472
18637
  this._showValidateWarningPopup = false;
18473
18638
  this._continueSubmit();
18474
18639
  }}">${I18n.t("typedDimensionWarning.continue")}</button>
18640
+ ` : html`
18641
+ <button class="btn-primary" @click="${() => {
18642
+ this._showValidateWarningPopup = false;
18643
+ this.requestUpdate();
18644
+ }}">${I18n.t("duplicateFactWarning.close")}</button>
18645
+ `}
18475
18646
  </div>
18476
18647
  </div>
18477
18648
  </div>
@@ -19605,6 +19776,12 @@ __decorateClass([
19605
19776
  __decorateClass([
19606
19777
  r()
19607
19778
  ], JupiterDynamicForm.prototype, "_duplicateFactMismatches", 2);
19779
+ __decorateClass([
19780
+ r()
19781
+ ], JupiterDynamicForm.prototype, "_duplicateFactWarnings", 2);
19782
+ __decorateClass([
19783
+ r()
19784
+ ], JupiterDynamicForm.prototype, "_duplicateWarningPopupMode", 2);
19608
19785
  __decorateClass([
19609
19786
  r()
19610
19787
  ], JupiterDynamicForm.prototype, "_submitDisabled", 2);