jupiter-dynamic-forms 1.22.3 → 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/core/concept-tree.d.ts +8 -1
- package/dist/core/concept-tree.d.ts.map +1 -1
- package/dist/core/dynamic-form.d.ts +45 -3
- package/dist/core/dynamic-form.d.ts.map +1 -1
- package/dist/core/form-field.d.ts +1 -0
- package/dist/core/form-field.d.ts.map +1 -1
- package/dist/core/form-section.d.ts +2 -1
- package/dist/core/form-section.d.ts.map +1 -1
- package/dist/core/formula-validation-dialog.d.ts +3 -0
- package/dist/core/formula-validation-dialog.d.ts.map +1 -1
- package/dist/index.js +384 -232
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +611 -95
- package/dist/index.mjs.map +1 -1
- package/dist/schema/types.d.ts +25 -0
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/utils/formula-expression-evaluator.d.ts +3 -0
- package/dist/utils/formula-expression-evaluator.d.ts.map +1 -1
- package/dist/utils/formula-precondition-evaluator.d.ts +5 -1
- package/dist/utils/formula-precondition-evaluator.d.ts.map +1 -1
- package/dist/utils/formula-variable-resolver.d.ts +16 -27
- package/dist/utils/formula-variable-resolver.d.ts.map +1 -1
- package/package.json +2 -1
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",
|
|
@@ -1857,6 +1858,18 @@ const typedDimensionWarning$1 = {
|
|
|
1857
1858
|
"continue": "Continue to validate",
|
|
1858
1859
|
cancel: "Cancel"
|
|
1859
1860
|
};
|
|
1861
|
+
const validateWarningPopup$1 = {
|
|
1862
|
+
title: "Validation warnings"
|
|
1863
|
+
};
|
|
1864
|
+
const duplicateFactWarning$1 = {
|
|
1865
|
+
title: "Duplicate facts with different values",
|
|
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.",
|
|
1867
|
+
role: "Role:",
|
|
1868
|
+
value: "Value:",
|
|
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"
|
|
1872
|
+
};
|
|
1860
1873
|
const calculationWarning$1 = {
|
|
1861
1874
|
title: "Calculation warning",
|
|
1862
1875
|
summaryLine: 'Total "{{label}}" should equal {{calculated}}, but you entered {{entered}}.',
|
|
@@ -1877,7 +1890,8 @@ const formulaValidation$1 = {
|
|
|
1877
1890
|
summaryCountBreakdown: "{{warnings}} warnings, {{errors}} errors",
|
|
1878
1891
|
severityWarning: "Warning",
|
|
1879
1892
|
severityError: "Error",
|
|
1880
|
-
close: "Close"
|
|
1893
|
+
close: "Close",
|
|
1894
|
+
breakdownLabel: "Values checked:"
|
|
1881
1895
|
};
|
|
1882
1896
|
const scrollToConcept$1 = {
|
|
1883
1897
|
revealRole: {
|
|
@@ -1899,6 +1913,8 @@ const enTranslations = {
|
|
|
1899
1913
|
xbrlValidation: xbrlValidation$1,
|
|
1900
1914
|
error: error$1,
|
|
1901
1915
|
typedDimensionWarning: typedDimensionWarning$1,
|
|
1916
|
+
validateWarningPopup: validateWarningPopup$1,
|
|
1917
|
+
duplicateFactWarning: duplicateFactWarning$1,
|
|
1902
1918
|
calculationWarning: calculationWarning$1,
|
|
1903
1919
|
balanceCheck: balanceCheck$1,
|
|
1904
1920
|
formulaValidation: formulaValidation$1,
|
|
@@ -2055,6 +2071,7 @@ const field = {
|
|
|
2055
2071
|
selectUnit: "Selecteer eenheid",
|
|
2056
2072
|
leaveBlankForInf: "Leeg laten voor INF",
|
|
2057
2073
|
prefilledLocked: "Vooraf ingevuld — kan hier niet worden gewijzigd",
|
|
2074
|
+
notApplicablePriorYear: "Niet vereist voor het voorgaande jaar",
|
|
2058
2075
|
invalidNumber: "Kan '{{value}}' niet lezen als getal",
|
|
2059
2076
|
noDecimalsAllowed: "Dit veld accepteert geen decimalen",
|
|
2060
2077
|
negativeNotAllowed: "Een negatieve waarde is hier niet toegestaan",
|
|
@@ -2104,6 +2121,18 @@ const typedDimensionWarning = {
|
|
|
2104
2121
|
"continue": "Doorgaan met valideren",
|
|
2105
2122
|
cancel: "Annuleren"
|
|
2106
2123
|
};
|
|
2124
|
+
const validateWarningPopup = {
|
|
2125
|
+
title: "Validatiewaarschuwingen"
|
|
2126
|
+
};
|
|
2127
|
+
const duplicateFactWarning = {
|
|
2128
|
+
title: "Dubbele feiten met verschillende waarden",
|
|
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.",
|
|
2130
|
+
role: "Rol:",
|
|
2131
|
+
value: "Waarde:",
|
|
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"
|
|
2135
|
+
};
|
|
2107
2136
|
const calculationWarning = {
|
|
2108
2137
|
title: "Berekeningswaarschuwing",
|
|
2109
2138
|
summaryLine: 'Totaal "{{label}}" zou {{calculated}} moeten zijn, maar u heeft {{entered}} ingevoerd.',
|
|
@@ -2124,7 +2153,8 @@ const formulaValidation = {
|
|
|
2124
2153
|
summaryCountBreakdown: "{{warnings}} waarschuwingen, {{errors}} fouten",
|
|
2125
2154
|
severityWarning: "Waarschuwing",
|
|
2126
2155
|
severityError: "Fout",
|
|
2127
|
-
close: "Sluiten"
|
|
2156
|
+
close: "Sluiten",
|
|
2157
|
+
breakdownLabel: "Gecontroleerde waarden:"
|
|
2128
2158
|
};
|
|
2129
2159
|
const scrollToConcept = {
|
|
2130
2160
|
revealRole: {
|
|
@@ -2146,6 +2176,8 @@ const nlTranslations = {
|
|
|
2146
2176
|
xbrlValidation,
|
|
2147
2177
|
error,
|
|
2148
2178
|
typedDimensionWarning,
|
|
2179
|
+
validateWarningPopup,
|
|
2180
|
+
duplicateFactWarning,
|
|
2149
2181
|
calculationWarning,
|
|
2150
2182
|
balanceCheck,
|
|
2151
2183
|
formulaValidation,
|
|
@@ -2528,6 +2560,19 @@ class Parser {
|
|
|
2528
2560
|
}
|
|
2529
2561
|
parseBoolTerm() {
|
|
2530
2562
|
const token = this.peek();
|
|
2563
|
+
if (token.type === "LPAREN") {
|
|
2564
|
+
const savedPos = this.pos;
|
|
2565
|
+
try {
|
|
2566
|
+
this.next();
|
|
2567
|
+
const inner = this.parseOrExpr();
|
|
2568
|
+
this.expect("RPAREN");
|
|
2569
|
+
return inner;
|
|
2570
|
+
} catch (error2) {
|
|
2571
|
+
if (!(error2 instanceof FormulaExpressionError))
|
|
2572
|
+
throw error2;
|
|
2573
|
+
this.pos = savedPos;
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2531
2576
|
if (token.type === "IDENT" && token.value === "not") {
|
|
2532
2577
|
this.next();
|
|
2533
2578
|
this.expect("LPAREN");
|
|
@@ -2988,8 +3033,8 @@ function collectDescendantConceptIds(childrenIndex, rootConceptId) {
|
|
|
2988
3033
|
function candidateKey(candidate) {
|
|
2989
3034
|
return `${candidate.conceptId}::${candidate.columnId}`;
|
|
2990
3035
|
}
|
|
2991
|
-
function resolveMatchedCandidates(variable, ctx) {
|
|
2992
|
-
return intersectCandidates(variable.filters.map((filter2) => resolveFilter(filter2, ctx.allCandidates, ctx, variable.filters)));
|
|
3036
|
+
function resolveMatchedCandidates(variable, ctx, roleURI) {
|
|
3037
|
+
return intersectCandidates(variable.filters.map((filter2) => resolveFilter(filter2, ctx.allCandidates, ctx, variable.filters, roleURI)));
|
|
2993
3038
|
}
|
|
2994
3039
|
function getColumn(ctx, candidate) {
|
|
2995
3040
|
var _a;
|
|
@@ -3103,7 +3148,7 @@ function resolveCrossRoleChildren(anchorQName, ownLinkrole, ctx) {
|
|
|
3103
3148
|
const otherRoles = Array.from(candidatesByRole.entries()).filter(([roleURI]) => roleURI !== ownLinkrole);
|
|
3104
3149
|
return otherRoles.length === 1 ? otherRoles[0][1] : [];
|
|
3105
3150
|
}
|
|
3106
|
-
function matchFilter(filter2, universe, ctx, siblingFilters) {
|
|
3151
|
+
function matchFilter(filter2, universe, ctx, siblingFilters, roleURI) {
|
|
3107
3152
|
var _a, _b;
|
|
3108
3153
|
switch (filter2.type) {
|
|
3109
3154
|
case "CONCEPT_NAME": {
|
|
@@ -3111,7 +3156,9 @@ function matchFilter(filter2, universe, ctx, siblingFilters) {
|
|
|
3111
3156
|
const infos = qname ? ctx.conceptByQName.get(qname) : void 0;
|
|
3112
3157
|
if (!infos || infos.length === 0)
|
|
3113
3158
|
return [];
|
|
3114
|
-
const
|
|
3159
|
+
const ownRoleInfos = roleURI ? infos.filter((info) => ctx.roleURIByConceptId.get(info.conceptId) === roleURI) : [];
|
|
3160
|
+
const scopedInfos = ownRoleInfos.length > 0 ? ownRoleInfos : infos;
|
|
3161
|
+
const conceptIds = new Set(scopedInfos.map((info) => info.conceptId));
|
|
3115
3162
|
return universe.filter((candidate) => conceptIds.has(candidate.conceptId));
|
|
3116
3163
|
}
|
|
3117
3164
|
case "CONCEPT_BALANCE": {
|
|
@@ -3171,7 +3218,7 @@ function matchFilter(filter2, universe, ctx, siblingFilters) {
|
|
|
3171
3218
|
return universe.filter((candidate) => columnMatchesPeriod(getColumn(ctx, candidate), dateAttribute, ctx));
|
|
3172
3219
|
}
|
|
3173
3220
|
case "OR_FILTER":
|
|
3174
|
-
return unionCandidates(filter2.children.map((child) => resolveFilter(child, universe, ctx, siblingFilters)));
|
|
3221
|
+
return unionCandidates(filter2.children.map((child) => resolveFilter(child, universe, ctx, siblingFilters, roleURI)));
|
|
3175
3222
|
case "ASPECT_COVER":
|
|
3176
3223
|
return universe;
|
|
3177
3224
|
case "UNKNOWN": {
|
|
@@ -3189,8 +3236,8 @@ function matchFilter(filter2, universe, ctx, siblingFilters) {
|
|
|
3189
3236
|
return [];
|
|
3190
3237
|
}
|
|
3191
3238
|
}
|
|
3192
|
-
function resolveFilter(filter2, universe, ctx, siblingFilters) {
|
|
3193
|
-
const matched = matchFilter(filter2, universe, ctx, siblingFilters);
|
|
3239
|
+
function resolveFilter(filter2, universe, ctx, siblingFilters, roleURI) {
|
|
3240
|
+
const matched = matchFilter(filter2, universe, ctx, siblingFilters, roleURI);
|
|
3194
3241
|
if (!filter2.complement)
|
|
3195
3242
|
return matched;
|
|
3196
3243
|
const matchedKeys = new Set(matched.map(candidateKey));
|
|
@@ -3220,12 +3267,9 @@ function hasExplicitPeriodFilter(filters) {
|
|
|
3220
3267
|
});
|
|
3221
3268
|
}
|
|
3222
3269
|
function narrowToCurrentPeriod(candidates, variable, ctx) {
|
|
3223
|
-
if (candidates.length
|
|
3270
|
+
if (candidates.length === 0 || hasExplicitPeriodFilter(variable.filters))
|
|
3224
3271
|
return candidates;
|
|
3225
|
-
|
|
3226
|
-
(candidate) => columnEffectivePeriod(getColumn(ctx, candidate), ctx).end === ctx.periodEndDate
|
|
3227
|
-
);
|
|
3228
|
-
return currentPeriodOnly.length > 0 ? currentPeriodOnly : candidates;
|
|
3272
|
+
return candidates.filter((candidate) => columnEffectivePeriod(getColumn(ctx, candidate), ctx).end === ctx.periodEndDate);
|
|
3229
3273
|
}
|
|
3230
3274
|
function narrowByPreferredOccurrence(candidates, ctx) {
|
|
3231
3275
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -3272,9 +3316,13 @@ function narrowToDirectChildOfDescendantAnchor(candidates, variable, ctx) {
|
|
|
3272
3316
|
return candidates;
|
|
3273
3317
|
return candidates.filter((candidate) => directChildren.has(candidate.conceptId));
|
|
3274
3318
|
}
|
|
3275
|
-
function resolveNarrowedCandidates(variable, ctx) {
|
|
3319
|
+
function resolveNarrowedCandidates(variable, ctx, roleURI) {
|
|
3276
3320
|
return narrowByPreferredOccurrence(
|
|
3277
|
-
narrowToDirectChildOfDescendantAnchor(
|
|
3321
|
+
narrowToDirectChildOfDescendantAnchor(
|
|
3322
|
+
narrowToCurrentPeriod(resolveMatchedCandidates(variable, ctx, roleURI), variable, ctx),
|
|
3323
|
+
variable,
|
|
3324
|
+
ctx
|
|
3325
|
+
),
|
|
3278
3326
|
ctx
|
|
3279
3327
|
);
|
|
3280
3328
|
}
|
|
@@ -3339,9 +3387,9 @@ function findUncoveredAxisAnchor(variables, axisId, candidatesByName, ctx) {
|
|
|
3339
3387
|
}
|
|
3340
3388
|
return void 0;
|
|
3341
3389
|
}
|
|
3342
|
-
function
|
|
3390
|
+
function computeAssertionNarrowedCandidatesByName(variables, ctx, implicitFiltering, roleURI) {
|
|
3343
3391
|
const candidatesByName = /* @__PURE__ */ new Map();
|
|
3344
|
-
variables.forEach((variable) => candidatesByName.set(variable.name, resolveNarrowedCandidates(variable, ctx)));
|
|
3392
|
+
variables.forEach((variable) => candidatesByName.set(variable.name, resolveNarrowedCandidates(variable, ctx, roleURI)));
|
|
3345
3393
|
if (implicitFiltering) {
|
|
3346
3394
|
const axisIds = /* @__PURE__ */ new Set();
|
|
3347
3395
|
variables.forEach((variable) => uncoveredExplicitDimensionAxisIds(variable, ctx).forEach((axisId) => axisIds.add(axisId)));
|
|
@@ -3362,10 +3410,35 @@ function resolveAssertionVariableBindings(variables, ctx, implicitFiltering) {
|
|
|
3362
3410
|
});
|
|
3363
3411
|
});
|
|
3364
3412
|
}
|
|
3413
|
+
return candidatesByName;
|
|
3414
|
+
}
|
|
3415
|
+
function resolveAssertionVariableBindings(variables, ctx, implicitFiltering, roleURI) {
|
|
3416
|
+
const candidatesByName = computeAssertionNarrowedCandidatesByName(variables, ctx, implicitFiltering, roleURI);
|
|
3365
3417
|
const bindings = /* @__PURE__ */ new Map();
|
|
3366
3418
|
variables.forEach((variable) => bindings.set(variable.name, valuesFromCandidates(variable, candidatesByName.get(variable.name) || [], ctx)));
|
|
3367
3419
|
return bindings;
|
|
3368
3420
|
}
|
|
3421
|
+
function buildFormulaVariableBreakdown(variables, ctx, implicitFiltering, roleURI) {
|
|
3422
|
+
const sequenceVariables = variables.filter((variable) => variable.bindAsSequence);
|
|
3423
|
+
if (sequenceVariables.length === 0)
|
|
3424
|
+
return void 0;
|
|
3425
|
+
const candidatesByName = computeAssertionNarrowedCandidatesByName(variables, ctx, implicitFiltering, roleURI);
|
|
3426
|
+
const breakdown = [];
|
|
3427
|
+
for (const variable of sequenceVariables) {
|
|
3428
|
+
const candidates = (candidatesByName.get(variable.name) || []).map((candidate) => {
|
|
3429
|
+
var _a, _b;
|
|
3430
|
+
return {
|
|
3431
|
+
conceptId: candidate.conceptId,
|
|
3432
|
+
conceptQName: (_a = ctx.conceptById.get(candidate.conceptId)) == null ? void 0 : _a.qname,
|
|
3433
|
+
columnId: candidate.columnId,
|
|
3434
|
+
value: resolveRawValue((_b = ctx.formData[candidate.conceptId]) == null ? void 0 : _b[candidate.columnId])
|
|
3435
|
+
};
|
|
3436
|
+
}).filter((candidate) => candidate.value !== void 0 && candidate.conceptQName !== void 0);
|
|
3437
|
+
if (candidates.length > 0)
|
|
3438
|
+
breakdown.push({ variableName: variable.name, candidates });
|
|
3439
|
+
}
|
|
3440
|
+
return breakdown.length > 0 ? breakdown : void 0;
|
|
3441
|
+
}
|
|
3369
3442
|
function filterSignature(filter2) {
|
|
3370
3443
|
const attrs = Object.entries(filter2.attributes).filter(([key]) => key !== "id").sort(([a2], [b2]) => a2.localeCompare(b2));
|
|
3371
3444
|
return JSON.stringify({ type: filter2.type, complement: filter2.complement, cover: filter2.cover, attrs });
|
|
@@ -3520,8 +3593,8 @@ function resolveVariableColumnsForConcept(variable, targetConceptId, ctx) {
|
|
|
3520
3593
|
const resolved = intersectCandidates(variable.filters.map((filter2) => resolveFilter(filter2, universe, ctx, variable.filters)));
|
|
3521
3594
|
return resolved.map((candidate) => candidate.columnId);
|
|
3522
3595
|
}
|
|
3523
|
-
function buildAssertionBindings(assertion, ctx) {
|
|
3524
|
-
return resolveAssertionVariableBindings(assertion.variables, ctx, assertion.implicitFiltering);
|
|
3596
|
+
function buildAssertionBindings(assertion, ctx, roleURI) {
|
|
3597
|
+
return resolveAssertionVariableBindings(assertion.variables, ctx, assertion.implicitFiltering, roleURI);
|
|
3525
3598
|
}
|
|
3526
3599
|
function buildAssertionFallbackUsage(assertion, ctx) {
|
|
3527
3600
|
var _a;
|
|
@@ -3613,7 +3686,7 @@ class FormulaValidationService {
|
|
|
3613
3686
|
}
|
|
3614
3687
|
_evaluateAssertion(assertion, role, ctx, language) {
|
|
3615
3688
|
try {
|
|
3616
|
-
const bindings = buildAssertionBindings(assertion, ctx);
|
|
3689
|
+
const bindings = buildAssertionBindings(assertion, ctx, role.roleURI);
|
|
3617
3690
|
const sumOfMembersShape = detectSumOfMembersOnAbstractShape(assertion);
|
|
3618
3691
|
const sumOfMembersResult = sumOfMembersShape ? resolveSumOfMembersOnAbstractSatisfaction(sumOfMembersShape, ctx) : void 0;
|
|
3619
3692
|
const usesSumOfMembersPath = sumOfMembersResult !== void 0 && sumOfMembersResult !== "not-applicable";
|
|
@@ -3640,7 +3713,8 @@ class FormulaValidationService {
|
|
|
3640
3713
|
return this._evaluatedResult(assertion, role, ctx, sumOfMembersResult, language);
|
|
3641
3714
|
}
|
|
3642
3715
|
const satisfied = evaluateFormulaTest(assertion.test, bindings, fallbackUsage);
|
|
3643
|
-
|
|
3716
|
+
const variableBreakdown = satisfied ? void 0 : buildFormulaVariableBreakdown(assertion.variables, ctx, assertion.implicitFiltering, role.roleURI);
|
|
3717
|
+
return this._evaluatedResult(assertion, role, ctx, satisfied, language, void 0, variableBreakdown);
|
|
3644
3718
|
} catch (error2) {
|
|
3645
3719
|
if (error2 instanceof FormulaExpressionError) {
|
|
3646
3720
|
console.warn(`[FormulaValidationService] Assertion "${assertion.id}" could not be evaluated (${error2.reason}): ${error2.message}`);
|
|
@@ -3661,7 +3735,7 @@ class FormulaValidationService {
|
|
|
3661
3735
|
skipReason
|
|
3662
3736
|
};
|
|
3663
3737
|
}
|
|
3664
|
-
_evaluatedResult(assertion, role, ctx, satisfied, language, matchedFactCount) {
|
|
3738
|
+
_evaluatedResult(assertion, role, ctx, satisfied, language, matchedFactCount, variableBreakdown) {
|
|
3665
3739
|
const message = satisfied ? void 0 : this._pickMessage(assertion, language);
|
|
3666
3740
|
return {
|
|
3667
3741
|
assertionId: assertion.id,
|
|
@@ -3673,7 +3747,8 @@ class FormulaValidationService {
|
|
|
3673
3747
|
skipped: false,
|
|
3674
3748
|
message,
|
|
3675
3749
|
matchedFactCount,
|
|
3676
|
-
conceptLinks: message ? this._buildConceptLinks(assertion, role.roleURI, ctx, message) : void 0
|
|
3750
|
+
conceptLinks: message ? this._buildConceptLinks(assertion, role.roleURI, ctx, message) : void 0,
|
|
3751
|
+
variableBreakdown
|
|
3677
3752
|
};
|
|
3678
3753
|
}
|
|
3679
3754
|
_pickMessage(assertion, language) {
|
|
@@ -4942,7 +5017,7 @@ let JupiterFormField = class extends LitElement {
|
|
|
4942
5017
|
if (changedProperties.has("value") || changedProperties.has("field")) {
|
|
4943
5018
|
this._validateField();
|
|
4944
5019
|
}
|
|
4945
|
-
if (changedProperties.has("unit") && this.unit) {
|
|
5020
|
+
if (changedProperties.has("unit") && this.unit && this.hasUpdated) {
|
|
4946
5021
|
console.log(`🏷️ [FormField willUpdate] Unit property changed to: ${this.unit}, conceptId: ${this.conceptId}, columnId: ${this.columnId}`);
|
|
4947
5022
|
this.dispatchEvent(new CustomEvent("unit-change", {
|
|
4948
5023
|
detail: {
|
|
@@ -4977,6 +5052,14 @@ let JupiterFormField = class extends LitElement {
|
|
|
4977
5052
|
_isRoundingLevelConcept() {
|
|
4978
5053
|
return !!this.conceptId && this.conceptId.includes("DocumentIntendedRoundingLevel");
|
|
4979
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
|
+
}
|
|
4980
5063
|
/**
|
|
4981
5064
|
* JDF-110: lock icon (SVG, not emoji) shown on a masterData-prefilled or rounding-level-locked
|
|
4982
5065
|
* cell, so a locked value reads as "filled and protected" rather than empty placeholder text.
|
|
@@ -5620,7 +5703,7 @@ let JupiterFormField = class extends LitElement {
|
|
|
5620
5703
|
const isMonetary = this._isMonetaryType();
|
|
5621
5704
|
return html`<span class="readonly-value ${isEmpty ? "empty" : ""} ${isMonetary ? "monetary" : ""}">${isEmpty ? "—" : displayValue}</span>`;
|
|
5622
5705
|
}
|
|
5623
|
-
_renderInput(effectiveValue = this.value, effectiveDisabled = this.disabled, isLocked = false) {
|
|
5706
|
+
_renderInput(effectiveValue = this.value, effectiveDisabled = this.disabled, isLocked = false, disabledTooltip) {
|
|
5624
5707
|
if (this.mode === "readonly") {
|
|
5625
5708
|
return this._renderReadonlyValue(effectiveValue);
|
|
5626
5709
|
}
|
|
@@ -5646,6 +5729,7 @@ let JupiterFormField = class extends LitElement {
|
|
|
5646
5729
|
class="${cssClass}"
|
|
5647
5730
|
.value="${effectiveValue ?? ""}"
|
|
5648
5731
|
?disabled="${effectiveDisabled || this.field.disabled}"
|
|
5732
|
+
title="${disabledTooltip || ""}"
|
|
5649
5733
|
@change="${this._handleInput}"
|
|
5650
5734
|
@focus="${this._handleFocus}"
|
|
5651
5735
|
@blur="${this._handleBlur}"
|
|
@@ -5997,6 +6081,7 @@ let JupiterFormField = class extends LitElement {
|
|
|
5997
6081
|
const baseConceptId = this._extractBaseConceptId(this.conceptId);
|
|
5998
6082
|
const isPredefinedValue = this.mode !== "admin" && this.masterData && baseConceptId in this.masterData;
|
|
5999
6083
|
const isRoundingLevelLocked = this._isRoundingLevelConcept();
|
|
6084
|
+
const isDisabledForPriorYear = this._isDisabledForPriorYear();
|
|
6000
6085
|
let factValue = null;
|
|
6001
6086
|
if (this.facts && this.facts.length > 0 && !isPredefinedValue) {
|
|
6002
6087
|
const cellContext = {
|
|
@@ -6050,8 +6135,8 @@ let JupiterFormField = class extends LitElement {
|
|
|
6050
6135
|
}
|
|
6051
6136
|
}
|
|
6052
6137
|
const hasUserValue = this.value !== null && this.value !== void 0;
|
|
6053
|
-
const effectiveValue = isPredefinedValue ? this.masterData[baseConceptId] : hasUserValue ? this.value : factValue;
|
|
6054
|
-
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";
|
|
6055
6140
|
const isLocked = (isPredefinedValue || isRoundingLevelLocked) && this.mode !== "readonly";
|
|
6056
6141
|
const typeConfigForLock = getInputTypeForConceptType(this.conceptType, this.datatypes);
|
|
6057
6142
|
const effectiveFieldTypeForLock = typeConfigForLock.fieldType || this.field.type || "text";
|
|
@@ -6065,7 +6150,7 @@ let JupiterFormField = class extends LitElement {
|
|
|
6065
6150
|
` : ""}
|
|
6066
6151
|
|
|
6067
6152
|
<div class="field-wrapper">
|
|
6068
|
-
${this._renderInput(effectiveValue, effectiveDisabled, isLocked)}
|
|
6153
|
+
${this._renderInput(effectiveValue, effectiveDisabled, isLocked, isDisabledForPriorYear ? I18n.t("field.notApplicablePriorYear") : void 0)}
|
|
6069
6154
|
|
|
6070
6155
|
${isLocked && !isTextareaField || hasPeriodControl && this.mode !== "readonly" && !isRoundingLevelLocked ? html`
|
|
6071
6156
|
<div class="field-trailing-icons">
|
|
@@ -6992,6 +7077,19 @@ let JupiterConceptTree = class extends LitElement {
|
|
|
6992
7077
|
`;
|
|
6993
7078
|
document.head.appendChild(style);
|
|
6994
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
|
+
}
|
|
6995
7093
|
_openCalculationWarningDialog(e2, mismatch) {
|
|
6996
7094
|
var _a;
|
|
6997
7095
|
e2.stopPropagation();
|
|
@@ -7066,7 +7164,7 @@ let JupiterConceptTree = class extends LitElement {
|
|
|
7066
7164
|
|
|
7067
7165
|
<!-- Input Field Cells (Period Columns) - Only for non-abstract concepts -->
|
|
7068
7166
|
${this.columns.map((column2) => {
|
|
7069
|
-
var _a, _b, _c, _d, _e;
|
|
7167
|
+
var _a, _b, _c, _d, _e, _f;
|
|
7070
7168
|
if (column2.hidden) {
|
|
7071
7169
|
return html`<td class="field-cell hidden-column"></td>`;
|
|
7072
7170
|
}
|
|
@@ -7075,8 +7173,9 @@ let JupiterConceptTree = class extends LitElement {
|
|
|
7075
7173
|
const storedUnit = (_b = (_a = this.unitData) == null ? void 0 : _a[this.concept.id]) == null ? void 0 : _b[column2.id];
|
|
7076
7174
|
const storedDecimals = (_d = (_c = this.decimalsData) == null ? void 0 : _c[this.concept.id]) == null ? void 0 : _d[column2.id];
|
|
7077
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;
|
|
7078
7177
|
return html`
|
|
7079
|
-
<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" : ""}">
|
|
7080
7179
|
${calcMismatch ? html`
|
|
7081
7180
|
<button
|
|
7082
7181
|
class="calc-warning-badge"
|
|
@@ -7086,6 +7185,15 @@ let JupiterConceptTree = class extends LitElement {
|
|
|
7086
7185
|
@click="${(e2) => this._openCalculationWarningDialog(e2, calcMismatch)}"
|
|
7087
7186
|
>!</button>
|
|
7088
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
|
+
` : ""}
|
|
7089
7197
|
${shouldShowField ? html`
|
|
7090
7198
|
<jupiter-form-field
|
|
7091
7199
|
.field="${field2}"
|
|
@@ -7338,6 +7446,38 @@ JupiterConceptTree.styles = css`
|
|
|
7338
7446
|
background: #e65100;
|
|
7339
7447
|
}
|
|
7340
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
|
+
|
|
7341
7481
|
/* Row-level highlight while a field in this row has focus. Applied to every
|
|
7342
7482
|
cell so the row stays identifiable even after the user scrolls the table
|
|
7343
7483
|
horizontally away from the focused input. */
|
|
@@ -7491,6 +7631,9 @@ __decorateClass$7([
|
|
|
7491
7631
|
__decorateClass$7([
|
|
7492
7632
|
n2({ type: Object })
|
|
7493
7633
|
], JupiterConceptTree.prototype, "calculationMismatches", 2);
|
|
7634
|
+
__decorateClass$7([
|
|
7635
|
+
n2({ type: Object })
|
|
7636
|
+
], JupiterConceptTree.prototype, "duplicateFactWarnings", 2);
|
|
7494
7637
|
__decorateClass$7([
|
|
7495
7638
|
n2({ type: String })
|
|
7496
7639
|
], JupiterConceptTree.prototype, "language", 2);
|
|
@@ -9278,6 +9421,7 @@ let JupiterFormSection = class extends LitElement {
|
|
|
9278
9421
|
.highlightColumnId="${(_b = this._highlightMap.get(instanceConcept.id)) == null ? void 0 : _b.columnId}"
|
|
9279
9422
|
.rowFocused="${this._focusedConceptId === instanceConcept.id}"
|
|
9280
9423
|
.calculationMismatches="${this._calculationMismatches}"
|
|
9424
|
+
.duplicateFactWarnings="${this.duplicateFactWarnings}"
|
|
9281
9425
|
@field-change="${this._handleFieldChange}"
|
|
9282
9426
|
@field-focus="${this._handleFieldFocusForHighlight}"
|
|
9283
9427
|
@period-change="${this._handlePeriodChange}"
|
|
@@ -9913,6 +10057,9 @@ __decorateClass$5([
|
|
|
9913
10057
|
__decorateClass$5([
|
|
9914
10058
|
n2({ type: Object })
|
|
9915
10059
|
], JupiterFormSection.prototype, "totalManuallyEditedData", 2);
|
|
10060
|
+
__decorateClass$5([
|
|
10061
|
+
n2({ type: Object })
|
|
10062
|
+
], JupiterFormSection.prototype, "duplicateFactWarnings", 2);
|
|
9916
10063
|
__decorateClass$5([
|
|
9917
10064
|
r()
|
|
9918
10065
|
], JupiterFormSection.prototype, "_expanded", 2);
|
|
@@ -12233,6 +12380,44 @@ let JupiterFormulaValidationDialog = class extends LitElement {
|
|
|
12233
12380
|
composed: true
|
|
12234
12381
|
}));
|
|
12235
12382
|
}
|
|
12383
|
+
// JDF-129: same navigate-and-close flow as `_handleConceptLinkClick`, for a breakdown line
|
|
12384
|
+
// rather than a message's backtick-quoted concept mention.
|
|
12385
|
+
_handleBreakdownCandidateClick(candidate) {
|
|
12386
|
+
this.dispatchEvent(new CustomEvent("formula-concept-click", {
|
|
12387
|
+
detail: { conceptId: candidate.conceptId, conceptQName: candidate.conceptQName, columnId: candidate.columnId },
|
|
12388
|
+
bubbles: true,
|
|
12389
|
+
composed: true
|
|
12390
|
+
}));
|
|
12391
|
+
}
|
|
12392
|
+
// JDF-129: local (non-prefixed) name for a breakdown candidate's concept — same derivation as
|
|
12393
|
+
// `_buildConceptLinks`'s own label in FormulaValidationService.
|
|
12394
|
+
_breakdownCandidateLabel(candidate) {
|
|
12395
|
+
return candidate.conceptQName.includes(":") ? candidate.conceptQName.split(":").pop() : candidate.conceptQName;
|
|
12396
|
+
}
|
|
12397
|
+
// JDF-129: plain, unflagged per-candidate breakdown for a bindAsSequence:true variable — the
|
|
12398
|
+
// real facts an aggregate sum/comparison summed, so a user can see one corrected line reflected
|
|
12399
|
+
// even though the assertion as a whole (a pure aggregate check) is still failing. Deliberately no
|
|
12400
|
+
// per-line pass/fail — see the ticket's own "Diff behavior" scoping decision.
|
|
12401
|
+
_renderBreakdown(result) {
|
|
12402
|
+
const breakdown = result.variableBreakdown;
|
|
12403
|
+
if (!breakdown || breakdown.length === 0)
|
|
12404
|
+
return "";
|
|
12405
|
+
return html`
|
|
12406
|
+
<div class="assertion-breakdown">
|
|
12407
|
+
<span class="assertion-breakdown-label">${I18n.t("formulaValidation.breakdownLabel")}</span>
|
|
12408
|
+
<ul class="assertion-breakdown-list">
|
|
12409
|
+
${breakdown.flatMap((variable) => variable.candidates.map((candidate) => html`
|
|
12410
|
+
<li class="assertion-breakdown-item">
|
|
12411
|
+
<button type="button" class="concept-link" @click="${() => this._handleBreakdownCandidateClick(candidate)}">
|
|
12412
|
+
${this._breakdownCandidateLabel(candidate)}
|
|
12413
|
+
</button>
|
|
12414
|
+
<span class="assertion-breakdown-value">${candidate.value}</span>
|
|
12415
|
+
</li>
|
|
12416
|
+
`))}
|
|
12417
|
+
</ul>
|
|
12418
|
+
</div>
|
|
12419
|
+
`;
|
|
12420
|
+
}
|
|
12236
12421
|
// Splits a message on its backtick-quoted concept mentions and renders the ones this
|
|
12237
12422
|
// assertion resolved a fact location for (`result.conceptLinks`) as click-to-focus buttons;
|
|
12238
12423
|
// any other backtick mention (e.g. an enumerated value like `Na`, not a concept) renders as
|
|
@@ -12299,7 +12484,10 @@ let JupiterFormulaValidationDialog = class extends LitElement {
|
|
|
12299
12484
|
<span class="severity-badge ${result.severity === "ERROR" ? "error" : "warning"}">
|
|
12300
12485
|
${result.severity === "ERROR" ? I18n.t("formulaValidation.severityError") : I18n.t("formulaValidation.severityWarning")}
|
|
12301
12486
|
</span>
|
|
12302
|
-
<
|
|
12487
|
+
<div class="assertion-row-body">
|
|
12488
|
+
<span class="assertion-message">${this._renderMessage(result)}</span>
|
|
12489
|
+
${this._renderBreakdown(result)}
|
|
12490
|
+
</div>
|
|
12303
12491
|
</div>
|
|
12304
12492
|
`)}
|
|
12305
12493
|
</div>
|
|
@@ -12488,12 +12676,53 @@ JupiterFormulaValidationDialog.styles = css`
|
|
|
12488
12676
|
background: var(--jupiter-error-color, #d32f2f);
|
|
12489
12677
|
}
|
|
12490
12678
|
|
|
12679
|
+
.assertion-row-body {
|
|
12680
|
+
display: flex;
|
|
12681
|
+
flex-direction: column;
|
|
12682
|
+
gap: 4px;
|
|
12683
|
+
min-width: 0;
|
|
12684
|
+
}
|
|
12685
|
+
|
|
12491
12686
|
.assertion-message {
|
|
12492
12687
|
font-size: 13px;
|
|
12493
12688
|
color: var(--primaryTextColor, var(--jupiter-text-primary, #333));
|
|
12494
12689
|
line-height: 1.4;
|
|
12495
12690
|
}
|
|
12496
12691
|
|
|
12692
|
+
.assertion-breakdown {
|
|
12693
|
+
display: flex;
|
|
12694
|
+
flex-direction: column;
|
|
12695
|
+
gap: 2px;
|
|
12696
|
+
}
|
|
12697
|
+
|
|
12698
|
+
.assertion-breakdown-label {
|
|
12699
|
+
font-size: 11px;
|
|
12700
|
+
font-weight: 600;
|
|
12701
|
+
color: var(--jupiter-text-secondary, #666);
|
|
12702
|
+
}
|
|
12703
|
+
|
|
12704
|
+
.assertion-breakdown-list {
|
|
12705
|
+
list-style: none;
|
|
12706
|
+
margin: 0;
|
|
12707
|
+
padding: 0;
|
|
12708
|
+
display: flex;
|
|
12709
|
+
flex-direction: column;
|
|
12710
|
+
gap: 2px;
|
|
12711
|
+
}
|
|
12712
|
+
|
|
12713
|
+
.assertion-breakdown-item {
|
|
12714
|
+
display: flex;
|
|
12715
|
+
align-items: baseline;
|
|
12716
|
+
justify-content: space-between;
|
|
12717
|
+
gap: 8px;
|
|
12718
|
+
font-size: 12px;
|
|
12719
|
+
}
|
|
12720
|
+
|
|
12721
|
+
.assertion-breakdown-value {
|
|
12722
|
+
color: var(--jupiter-text-secondary, #666);
|
|
12723
|
+
white-space: nowrap;
|
|
12724
|
+
}
|
|
12725
|
+
|
|
12497
12726
|
.concept-link {
|
|
12498
12727
|
font: inherit;
|
|
12499
12728
|
font-weight: 600;
|
|
@@ -12785,8 +13014,11 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
12785
13014
|
this._xbrlFormErrors = [];
|
|
12786
13015
|
this._calculationWarnings = /* @__PURE__ */ new Map();
|
|
12787
13016
|
this._showErrorPopup = false;
|
|
12788
|
-
this.
|
|
13017
|
+
this._showValidateWarningPopup = false;
|
|
12789
13018
|
this._typedDimensionWarningFacts = [];
|
|
13019
|
+
this._duplicateFactMismatches = [];
|
|
13020
|
+
this._duplicateFactWarnings = /* @__PURE__ */ new Map();
|
|
13021
|
+
this._duplicateWarningPopupMode = "validate";
|
|
12790
13022
|
this._submitDisabled = false;
|
|
12791
13023
|
this._allSections = [];
|
|
12792
13024
|
this._selectedRoleIds = [];
|
|
@@ -12844,6 +13076,15 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
12844
13076
|
this.addEventListener("calculation-mismatch-changed", (e2) => {
|
|
12845
13077
|
this._handleCalculationMismatchChanged(e2);
|
|
12846
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
|
+
});
|
|
12847
13088
|
this.addEventListener("total-manually-edited", (e2) => {
|
|
12848
13089
|
const { conceptId, columnId } = e2.detail;
|
|
12849
13090
|
const updated = { ...this._totalManuallyEditedData };
|
|
@@ -13057,6 +13298,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
13057
13298
|
if ((_a = this.xbrlInput) == null ? void 0 : _a.initialData) {
|
|
13058
13299
|
this._formData = { ...this._formData, ...this.xbrlInput.initialData };
|
|
13059
13300
|
}
|
|
13301
|
+
this._formData = this._stripPriorYearExcludedFacts(this._formData);
|
|
13060
13302
|
this._initializeGlobalDecimalsFromRoundingData();
|
|
13061
13303
|
this._extractTypedMembersFromFacts();
|
|
13062
13304
|
if (!this._skipDraftLoading) {
|
|
@@ -13737,8 +13979,15 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
13737
13979
|
// which reads as "still cut off" when its row height isn't an exact multiple of the container.
|
|
13738
13980
|
_scrollActiveRoleIntoView() {
|
|
13739
13981
|
var _a;
|
|
13740
|
-
const
|
|
13741
|
-
activeItem == null ? void 0 :
|
|
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;
|
|
13742
13991
|
}
|
|
13743
13992
|
// Re-locates the fact input identified by _lastFocusedFieldIdentity after a rebuild and restores
|
|
13744
13993
|
// focus to it, mirroring the shadow-DOM traversal scrollToConcept/_handleErrorFieldClick use.
|
|
@@ -13963,6 +14212,29 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
13963
14212
|
this._calculationWarnings = next;
|
|
13964
14213
|
this._validateForm();
|
|
13965
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
|
+
}
|
|
13966
14238
|
/**
|
|
13967
14239
|
* JDF-058: single source of truth for writing a value into `_formData` with the immutable-update
|
|
13968
14240
|
* pattern Lit reactivity needs — shared by a real user keystroke (`_handleFieldChange`) and the
|
|
@@ -13970,6 +14242,10 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
13970
14242
|
* duplicated. Returns the value that was previously stored, for event `oldValue` fields.
|
|
13971
14243
|
*/
|
|
13972
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
|
+
}
|
|
13973
14249
|
const updatedFormData = { ...this._formData };
|
|
13974
14250
|
if (!updatedFormData[conceptId]) {
|
|
13975
14251
|
updatedFormData[conceptId] = {};
|
|
@@ -14022,13 +14298,17 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
14022
14298
|
this.requestUpdate();
|
|
14023
14299
|
}
|
|
14024
14300
|
_handleUnitChange(event) {
|
|
14301
|
+
var _a;
|
|
14025
14302
|
console.log(`🏷️ [DynamicForm] _handleUnitChange called with event:`, event);
|
|
14026
14303
|
console.log(`🏷️ [DynamicForm] Event detail:`, event.detail);
|
|
14027
14304
|
const { conceptId, columnId, unit } = event.detail;
|
|
14028
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;
|
|
14029
14307
|
this._storeUnit(conceptId, columnId, unit);
|
|
14030
|
-
|
|
14031
|
-
|
|
14308
|
+
if (!isUnchanged) {
|
|
14309
|
+
this._dirty = true;
|
|
14310
|
+
this.hasUnsavedChanges = true;
|
|
14311
|
+
}
|
|
14032
14312
|
this.requestUpdate();
|
|
14033
14313
|
}
|
|
14034
14314
|
_storeUnit(conceptId, columnId, unit) {
|
|
@@ -14336,6 +14616,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
14336
14616
|
console.log(`🟧 [DynamicForm] Removed ${beforeLength - this._xbrlFormErrors.length} errors`);
|
|
14337
14617
|
}
|
|
14338
14618
|
console.log(`🔍 [Validation] Total errors: ${this._xbrlFormErrors.length}`, this._xbrlFormErrors);
|
|
14619
|
+
this._updateDuplicateFactWarnings(conceptId, columnId);
|
|
14339
14620
|
}
|
|
14340
14621
|
_getSectionTitle(sectionId) {
|
|
14341
14622
|
console.log(`🔍 [_getSectionTitle] Looking for sectionId: "${sectionId}"`);
|
|
@@ -14354,7 +14635,12 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
14354
14635
|
await this._focusFormField(conceptId, columnId, sectionId);
|
|
14355
14636
|
}
|
|
14356
14637
|
async _handleTypedDimensionFactClick(conceptId, columnId, sectionId) {
|
|
14357
|
-
this.
|
|
14638
|
+
this._showValidateWarningPopup = false;
|
|
14639
|
+
this.requestUpdate();
|
|
14640
|
+
await this._focusFormField(conceptId, columnId, sectionId);
|
|
14641
|
+
}
|
|
14642
|
+
async _handleDuplicateFactClick(conceptId, columnId, sectionId) {
|
|
14643
|
+
this._showValidateWarningPopup = false;
|
|
14358
14644
|
this.requestUpdate();
|
|
14359
14645
|
await this._focusFormField(conceptId, columnId, sectionId);
|
|
14360
14646
|
}
|
|
@@ -15047,6 +15333,164 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
15047
15333
|
}
|
|
15048
15334
|
return groups;
|
|
15049
15335
|
}
|
|
15336
|
+
/**
|
|
15337
|
+
* Validate pre-flight: finds entered facts that share their concept, period and dimensions
|
|
15338
|
+
* (i.e. would resolve to the same XBRL context) with at least one other entered fact — typically
|
|
15339
|
+
* because the same concept is presented in more than one disclosure role — but were given
|
|
15340
|
+
* different values. E.g. `IncomeTaxExpense` entered as 992 in one note and -992 in another for
|
|
15341
|
+
* the same year: only one can be correct, so this is a genuine conflict rather than a benign
|
|
15342
|
+
* duplicate (an identical value entered twice in two roles is left alone — see
|
|
15343
|
+
* `_normalizeFactValueForCompare` below). Walks every concept's own `fields` (not every
|
|
15344
|
+
* column x every concept) to stay cheap on large taxonomies.
|
|
15345
|
+
*/
|
|
15346
|
+
_findDuplicateFactMismatches() {
|
|
15347
|
+
const mismatches = [];
|
|
15348
|
+
if (!this._currentSchema)
|
|
15349
|
+
return mismatches;
|
|
15350
|
+
const groups = /* @__PURE__ */ new Map();
|
|
15351
|
+
for (const section2 of this._currentSchema.sections) {
|
|
15352
|
+
const columnsById = new Map((section2.columns || []).map((col) => [col.id, col]));
|
|
15353
|
+
this._collectDuplicateFactCandidates(section2.concepts, columnsById, section2, groups);
|
|
15354
|
+
}
|
|
15355
|
+
groups.forEach((group) => {
|
|
15356
|
+
if (group.entries.length < 2)
|
|
15357
|
+
return;
|
|
15358
|
+
const distinctValues = new Set(group.entries.map((e2) => this._normalizeFactValueForCompare(e2.value)));
|
|
15359
|
+
if (distinctValues.size < 2)
|
|
15360
|
+
return;
|
|
15361
|
+
mismatches.push({
|
|
15362
|
+
conceptId: group.conceptId,
|
|
15363
|
+
conceptLabel: group.conceptLabel,
|
|
15364
|
+
facts: group.entries
|
|
15365
|
+
});
|
|
15366
|
+
});
|
|
15367
|
+
return mismatches;
|
|
15368
|
+
}
|
|
15369
|
+
_collectDuplicateFactCandidates(concepts, columnsById, section2, groups) {
|
|
15370
|
+
var _a;
|
|
15371
|
+
for (const concept of concepts) {
|
|
15372
|
+
const conceptValues = this._formData[concept.id];
|
|
15373
|
+
if (conceptValues) {
|
|
15374
|
+
for (const field2 of concept.fields) {
|
|
15375
|
+
const value = conceptValues[field2.columnId];
|
|
15376
|
+
if (value === void 0 || value === null || String(value).trim() === "")
|
|
15377
|
+
continue;
|
|
15378
|
+
const column2 = columnsById.get(field2.columnId);
|
|
15379
|
+
if (!column2)
|
|
15380
|
+
continue;
|
|
15381
|
+
const contextKey = this._buildFactContextKey(concept, field2, column2, section2);
|
|
15382
|
+
if (!contextKey)
|
|
15383
|
+
continue;
|
|
15384
|
+
const entry = {
|
|
15385
|
+
conceptId: concept.id,
|
|
15386
|
+
conceptLabel: concept.label,
|
|
15387
|
+
columnId: column2.id,
|
|
15388
|
+
columnTitle: column2.title,
|
|
15389
|
+
sectionId: section2.id,
|
|
15390
|
+
sectionTitle: section2.title,
|
|
15391
|
+
value
|
|
15392
|
+
};
|
|
15393
|
+
let group = groups.get(contextKey);
|
|
15394
|
+
if (!group) {
|
|
15395
|
+
group = { conceptId: concept.originalConceptId || concept.id, conceptLabel: concept.label, entries: [] };
|
|
15396
|
+
groups.set(contextKey, group);
|
|
15397
|
+
}
|
|
15398
|
+
group.entries.push(entry);
|
|
15399
|
+
}
|
|
15400
|
+
}
|
|
15401
|
+
if ((_a = concept.children) == null ? void 0 : _a.length) {
|
|
15402
|
+
this._collectDuplicateFactCandidates(concept.children, columnsById, section2, groups);
|
|
15403
|
+
}
|
|
15404
|
+
}
|
|
15405
|
+
}
|
|
15406
|
+
/**
|
|
15407
|
+
* Canonical key for the XBRL context (concept + period + dimensions) `concept`'s value in
|
|
15408
|
+
* `column` would resolve to, independent of which role produced it. Returns null when a typed
|
|
15409
|
+
* dimension on this column has no value entered yet, since its true context can't be
|
|
15410
|
+
* determined without one (that gap is already surfaced by the typed-dimension warning).
|
|
15411
|
+
*/
|
|
15412
|
+
_buildFactContextKey(concept, field2, column2, section2) {
|
|
15413
|
+
var _a, _b, _c;
|
|
15414
|
+
const conceptKey = concept.originalConceptId || concept.id;
|
|
15415
|
+
const isInstant = concept.periodType === "instant";
|
|
15416
|
+
const fieldPeriodData = (_a = this._periodData[concept.id]) == null ? void 0 : _a[column2.id];
|
|
15417
|
+
const periodStartDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.startDate) || column2.periodStartDate || field2.periodStartDate || this.periodStartDate;
|
|
15418
|
+
const periodEndDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.endDate) || column2.periodEndDate || field2.periodEndDate || this.periodEndDate;
|
|
15419
|
+
const periodInstantDate = (fieldPeriodData == null ? void 0 : fieldPeriodData.instantDate) || field2.periodInstantDate || periodEndDate || periodStartDate;
|
|
15420
|
+
const periodKey = isInstant ? `instant:${periodInstantDate}` : `duration:${periodStartDate}_${periodEndDate}`;
|
|
15421
|
+
const dimensionData = column2.dimensionData;
|
|
15422
|
+
let dimensionKey = "base";
|
|
15423
|
+
if (dimensionData) {
|
|
15424
|
+
const typedMembers = dimensionData.typedMembers;
|
|
15425
|
+
if (typedMembers && typedMembers.length > 0) {
|
|
15426
|
+
const scoped = this._typedMemberData[this._scopedColumnKey(section2.id, column2.id)];
|
|
15427
|
+
const legacy = this._typedMemberData[column2.id];
|
|
15428
|
+
const typedParts = [];
|
|
15429
|
+
for (const tm of typedMembers) {
|
|
15430
|
+
const typedValue = (_b = (scoped == null ? void 0 : scoped[tm.axisId]) ?? (legacy == null ? void 0 : legacy[tm.axisId])) == null ? void 0 : _b.trim();
|
|
15431
|
+
if (!typedValue)
|
|
15432
|
+
return null;
|
|
15433
|
+
typedParts.push(`${tm.axisId}=${typedValue}`);
|
|
15434
|
+
}
|
|
15435
|
+
dimensionKey = typedParts.sort().join("|");
|
|
15436
|
+
} else if ((_c = dimensionData.combinations) == null ? void 0 : _c.length) {
|
|
15437
|
+
dimensionKey = dimensionData.combinations.map((c2) => `${c2.axisId}=${c2.memberId}`).sort().join("|");
|
|
15438
|
+
} else if (dimensionData.dimensionIdKey) {
|
|
15439
|
+
dimensionKey = dimensionData.dimensionIdKey;
|
|
15440
|
+
} else if (dimensionData.axisId && dimensionData.memberId) {
|
|
15441
|
+
dimensionKey = `${dimensionData.axisId}=${dimensionData.memberId}`;
|
|
15442
|
+
}
|
|
15443
|
+
}
|
|
15444
|
+
return `${conceptKey}||${periodKey}||${dimensionKey}`;
|
|
15445
|
+
}
|
|
15446
|
+
/** Numeric-aware value comparison for the duplicate-fact check — "992" and 992 (or "992.0") count as equal. */
|
|
15447
|
+
_normalizeFactValueForCompare(value) {
|
|
15448
|
+
if (typeof value === "number")
|
|
15449
|
+
return String(value);
|
|
15450
|
+
if (typeof value === "string") {
|
|
15451
|
+
const trimmed = value.trim();
|
|
15452
|
+
const asNumber = Number(trimmed);
|
|
15453
|
+
return trimmed !== "" && !isNaN(asNumber) ? String(asNumber) : trimmed;
|
|
15454
|
+
}
|
|
15455
|
+
return String(value);
|
|
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
|
+
}
|
|
15484
|
+
/** Popup header for the Validate pre-flight warning: specific when only one check found something, generic when both did. */
|
|
15485
|
+
_validateWarningPopupTitle() {
|
|
15486
|
+
const hasTypedDimensionWarning = this._typedDimensionWarningFacts.length > 0;
|
|
15487
|
+
const hasDuplicateFactWarning = this._duplicateFactMismatches.length > 0;
|
|
15488
|
+
if (hasTypedDimensionWarning && hasDuplicateFactWarning)
|
|
15489
|
+
return I18n.t("validateWarningPopup.title");
|
|
15490
|
+
if (hasDuplicateFactWarning)
|
|
15491
|
+
return I18n.t("duplicateFactWarning.title");
|
|
15492
|
+
return I18n.t("typedDimensionWarning.title");
|
|
15493
|
+
}
|
|
15050
15494
|
_handleSubmit() {
|
|
15051
15495
|
console.log("📝 Form submission started...");
|
|
15052
15496
|
this._submitted = true;
|
|
@@ -15058,10 +15502,14 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
15058
15502
|
return;
|
|
15059
15503
|
}
|
|
15060
15504
|
const missingTypedDimensionFacts = this._findMissingTypedDimensionFacts();
|
|
15061
|
-
|
|
15505
|
+
const duplicateFactMismatches = this._findDuplicateFactMismatches();
|
|
15506
|
+
if (missingTypedDimensionFacts.length > 0 || duplicateFactMismatches.length > 0) {
|
|
15062
15507
|
console.log("⚠️ [Submit] Typed dimension values missing for entered facts:", missingTypedDimensionFacts);
|
|
15508
|
+
console.log("⚠️ [Submit] Duplicate facts with mismatched values:", duplicateFactMismatches);
|
|
15063
15509
|
this._typedDimensionWarningFacts = missingTypedDimensionFacts;
|
|
15064
|
-
this.
|
|
15510
|
+
this._duplicateFactMismatches = duplicateFactMismatches;
|
|
15511
|
+
this._duplicateWarningPopupMode = "validate";
|
|
15512
|
+
this._showValidateWarningPopup = true;
|
|
15065
15513
|
this._submitDisabled = false;
|
|
15066
15514
|
this.requestUpdate();
|
|
15067
15515
|
return;
|
|
@@ -15070,8 +15518,8 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
15070
15518
|
}
|
|
15071
15519
|
/**
|
|
15072
15520
|
* The original Validate/submit logic (error checks + submission), extracted so "Continue to
|
|
15073
|
-
* validate" on the
|
|
15074
|
-
* (and re-triggering) the
|
|
15521
|
+
* validate" on the Validate pre-flight warning popup can re-enter it directly without
|
|
15522
|
+
* re-running (and re-triggering) the checks in _handleSubmit() above.
|
|
15075
15523
|
*/
|
|
15076
15524
|
_continueSubmit() {
|
|
15077
15525
|
this._submitted = true;
|
|
@@ -15431,6 +15879,10 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
15431
15879
|
return;
|
|
15432
15880
|
}
|
|
15433
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
|
+
}
|
|
15434
15886
|
const instanceKey = draftInstanceId || conceptId;
|
|
15435
15887
|
const baseConceptId = instanceKey.includes("__repeat_") ? instanceKey.split("__repeat_")[0] : instanceKey;
|
|
15436
15888
|
const actualBaseId = this._findActualConceptId(baseConceptId);
|
|
@@ -15974,6 +16426,8 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
15974
16426
|
}
|
|
15975
16427
|
_addConceptDataToSubmission(concept, columnId, value, submissionData, section2) {
|
|
15976
16428
|
var _a, _b, _c, _d, _e;
|
|
16429
|
+
if (this._isPriorYearExcludedFact(concept.id, columnId))
|
|
16430
|
+
return;
|
|
15977
16431
|
const field2 = concept.fields.find((f2) => f2.columnId === columnId);
|
|
15978
16432
|
if (!field2)
|
|
15979
16433
|
return;
|
|
@@ -16146,26 +16600,25 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16146
16600
|
}
|
|
16147
16601
|
if (concept.fields && concept.fields.length > 0) {
|
|
16148
16602
|
concept.fields.forEach((field2) => {
|
|
16149
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
16603
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
16604
|
+
if (this._isPriorYearExcludedFact(concept.id, field2.columnId)) {
|
|
16605
|
+
return;
|
|
16606
|
+
}
|
|
16150
16607
|
const conceptData = this._formData[concept.id];
|
|
16151
|
-
let fieldValue = conceptData == null ? void 0 : conceptData[field2.columnId];
|
|
16152
16608
|
const baseConceptId = field2.conceptId || concept.id.split("__").slice(0, -1).join("__") || concept.id;
|
|
16153
|
-
|
|
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()) {
|
|
16154
16614
|
const factValue = this._findFactValueForField(concept, field2, section2);
|
|
16155
16615
|
if (factValue !== void 0 && factValue !== null && factValue !== "") {
|
|
16156
16616
|
fieldValue = factValue;
|
|
16157
16617
|
}
|
|
16158
16618
|
}
|
|
16159
|
-
if ((fieldValue === void 0 || fieldValue === null || fieldValue === "") && this._effectiveMasterData) {
|
|
16160
|
-
const masterValue = (_a = this._effectiveMasterData) == null ? void 0 : _a[baseConceptId];
|
|
16161
|
-
if (masterValue !== void 0 && masterValue !== null && masterValue !== "") {
|
|
16162
|
-
fieldValue = masterValue;
|
|
16163
|
-
console.log(` 📦 [Submission] Using masterData for: ${baseConceptId} [${field2.columnId}] = ${JSON.stringify(fieldValue)}`);
|
|
16164
|
-
}
|
|
16165
|
-
}
|
|
16166
16619
|
if (fieldValue !== void 0 && fieldValue !== null && fieldValue !== "") {
|
|
16167
16620
|
const column2 = this._findColumnByIdInSection(field2.columnId, section2);
|
|
16168
|
-
const fieldPeriodData = (
|
|
16621
|
+
const fieldPeriodData = (_a = this._periodData[concept.id]) == null ? void 0 : _a[field2.columnId];
|
|
16169
16622
|
const submissionEntry = {
|
|
16170
16623
|
conceptId: concept.id,
|
|
16171
16624
|
draftInstanceId: concept.id,
|
|
@@ -16187,21 +16640,21 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16187
16640
|
submissionEntry.period.endDate = endDate;
|
|
16188
16641
|
}
|
|
16189
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}`}`);
|
|
16190
|
-
const fieldUnit = (
|
|
16643
|
+
const fieldUnit = (_b = this._unitData[concept.id]) == null ? void 0 : _b[field2.columnId];
|
|
16191
16644
|
if (fieldUnit) {
|
|
16192
16645
|
submissionEntry.unit = fieldUnit;
|
|
16193
16646
|
console.log(`✅ [Submission] Adding unit to entry: ${fieldUnit} for ${concept.id}/${field2.columnId}`);
|
|
16194
16647
|
} else {
|
|
16195
16648
|
console.log(`⚠️ [Submission] No unit found in _unitData for ${concept.id}/${field2.columnId}. _unitData state:`, JSON.stringify(this._unitData, null, 2));
|
|
16196
16649
|
}
|
|
16197
|
-
const isMonetary = (
|
|
16198
|
-
const fieldDecimals = (
|
|
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];
|
|
16199
16652
|
const decimalsValue = fieldDecimals || (this.decimals !== "INF" ? this.decimals : void 0);
|
|
16200
16653
|
if (isMonetary && decimalsValue) {
|
|
16201
16654
|
const parsed = parseFloat(decimalsValue);
|
|
16202
16655
|
submissionEntry.decimals = isNaN(parsed) ? decimalsValue : String(-Math.abs(parsed));
|
|
16203
16656
|
}
|
|
16204
|
-
if ((column2 == null ? void 0 : column2.type) === "dimension" && ((
|
|
16657
|
+
if ((column2 == null ? void 0 : column2.type) === "dimension" && ((_e = column2.dimensionData) == null ? void 0 : _e.dimensionIdKey)) {
|
|
16205
16658
|
submissionEntry.dimension = column2.dimensionData.dimensionIdKey;
|
|
16206
16659
|
console.log(`🔍 [DynamicForm] Using dimension key from field's column (${field2.columnId}):`, column2.dimensionData.dimensionIdKey);
|
|
16207
16660
|
} else {
|
|
@@ -16240,12 +16693,12 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16240
16693
|
console.log(`🔍 [DynamicForm] Column details:`, {
|
|
16241
16694
|
id: column2.id,
|
|
16242
16695
|
type: column2.type,
|
|
16243
|
-
hasTypedMembers: (
|
|
16696
|
+
hasTypedMembers: (_f = column2.dimensionData) == null ? void 0 : _f.hasTypedMembers,
|
|
16244
16697
|
dimensionData: column2.dimensionData
|
|
16245
16698
|
});
|
|
16246
16699
|
}
|
|
16247
16700
|
}
|
|
16248
|
-
if (!submissionEntry.typedMembers && ((
|
|
16701
|
+
if (!submissionEntry.typedMembers && ((_g = field2.crossRoleTypedMembers) == null ? void 0 : _g.length)) {
|
|
16249
16702
|
const crossRoleKey = `${concept.id}__${field2.columnId}`;
|
|
16250
16703
|
const crossRoleValues = this._typedMemberData[crossRoleKey];
|
|
16251
16704
|
if (crossRoleValues) {
|
|
@@ -16336,7 +16789,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
16336
16789
|
});
|
|
16337
16790
|
}
|
|
16338
16791
|
_handleReset() {
|
|
16339
|
-
this._formData =
|
|
16792
|
+
this._formData = this._stripPriorYearExcludedFacts(this.initialData);
|
|
16340
16793
|
this._touched.clear();
|
|
16341
16794
|
this._dirty = false;
|
|
16342
16795
|
this.hasUnsavedChanges = false;
|
|
@@ -17103,6 +17556,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
17103
17556
|
.periodEndDate="${this.periodEndDate}"
|
|
17104
17557
|
.calculationEnabled="${this.calculationEnabled}"
|
|
17105
17558
|
.totalManuallyEditedData="${this._totalManuallyEditedData}"
|
|
17559
|
+
.duplicateFactWarnings="${this._duplicateFactWarnings}"
|
|
17106
17560
|
@field-change="${this._handleFieldChange}"
|
|
17107
17561
|
@period-change="${this._handlePeriodChange}"
|
|
17108
17562
|
@typed-member-change="${this._handleTypedMemberChange}"
|
|
@@ -17310,6 +17764,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
17310
17764
|
.periodEndDate="${this.periodEndDate}"
|
|
17311
17765
|
.calculationEnabled="${this.calculationEnabled}"
|
|
17312
17766
|
.totalManuallyEditedData="${this._totalManuallyEditedData}"
|
|
17767
|
+
.duplicateFactWarnings="${this._duplicateFactWarnings}"
|
|
17313
17768
|
@field-change="${this._handleFieldChange}"
|
|
17314
17769
|
@typed-member-change="${this._handleTypedMemberChange}"
|
|
17315
17770
|
@add-concept-repeat="${this._handleAddConceptRepeat}"
|
|
@@ -17362,7 +17817,7 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
17362
17817
|
return { ...this._formData };
|
|
17363
17818
|
}
|
|
17364
17819
|
setData(data) {
|
|
17365
|
-
this._formData =
|
|
17820
|
+
this._formData = this._stripPriorYearExcludedFacts(data);
|
|
17366
17821
|
this._dirty = true;
|
|
17367
17822
|
this.hasUnsavedChanges = true;
|
|
17368
17823
|
this._validateForm();
|
|
@@ -18098,55 +18553,96 @@ let JupiterDynamicForm = class extends LitElement {
|
|
|
18098
18553
|
</div>
|
|
18099
18554
|
` : ""}
|
|
18100
18555
|
|
|
18101
|
-
<!--
|
|
18102
|
-
${this.
|
|
18556
|
+
<!-- Validate Pre-flight Warning Popup: typed-dimension-missing facts and/or duplicate-fact value mismatches -->
|
|
18557
|
+
${this._showValidateWarningPopup ? html`
|
|
18103
18558
|
<div class="error-popup-overlay" @click="${() => {
|
|
18104
|
-
this.
|
|
18559
|
+
this._showValidateWarningPopup = false;
|
|
18105
18560
|
this.requestUpdate();
|
|
18106
18561
|
}}">
|
|
18107
18562
|
<div class="error-popup" @click="${(e2) => e2.stopPropagation()}">
|
|
18108
18563
|
<div class="error-popup-header">
|
|
18109
|
-
<h3>⚠️ ${
|
|
18564
|
+
<h3>⚠️ ${this._validateWarningPopupTitle()}</h3>
|
|
18110
18565
|
<button class="error-popup-close" @click="${() => {
|
|
18111
|
-
this.
|
|
18566
|
+
this._showValidateWarningPopup = false;
|
|
18112
18567
|
this.requestUpdate();
|
|
18113
18568
|
}}">×</button>
|
|
18114
18569
|
</div>
|
|
18115
18570
|
<div class="error-popup-content">
|
|
18116
|
-
|
|
18117
|
-
|
|
18118
|
-
|
|
18119
|
-
<
|
|
18120
|
-
|
|
18121
|
-
|
|
18122
|
-
|
|
18123
|
-
<
|
|
18124
|
-
|
|
18125
|
-
|
|
18126
|
-
|
|
18127
|
-
|
|
18128
|
-
|
|
18129
|
-
|
|
18130
|
-
|
|
18131
|
-
|
|
18132
|
-
|
|
18133
|
-
|
|
18134
|
-
|
|
18135
|
-
|
|
18136
|
-
|
|
18137
|
-
|
|
18138
|
-
|
|
18139
|
-
|
|
18571
|
+
${this._typedDimensionWarningFacts.length > 0 ? html`
|
|
18572
|
+
<div class="validate-warning-section">
|
|
18573
|
+
${this._duplicateFactMismatches.length > 0 ? html`<h4>${I18n.t("typedDimensionWarning.title")}</h4>` : ""}
|
|
18574
|
+
<p>${I18n.t("typedDimensionWarning.message")}</p>
|
|
18575
|
+
<ul class="error-list">
|
|
18576
|
+
${this._groupTypedDimensionWarningFactsByRole().map((group) => html`
|
|
18577
|
+
<li>
|
|
18578
|
+
<strong>${I18n.t("typedDimensionWarning.role")}</strong> ${group.sectionTitle}
|
|
18579
|
+
<ul>
|
|
18580
|
+
${group.facts.map((fact) => html`
|
|
18581
|
+
<li>
|
|
18582
|
+
<strong>${I18n.t("typedDimensionWarning.field")}</strong>
|
|
18583
|
+
<a
|
|
18584
|
+
href="javascript:void(0)"
|
|
18585
|
+
class="error-field-link"
|
|
18586
|
+
@click="${() => this._handleTypedDimensionFactClick(fact.conceptId, fact.columnId, fact.sectionId)}"
|
|
18587
|
+
title="${I18n.t("typedDimensionWarning.clickToFocus")}"
|
|
18588
|
+
>
|
|
18589
|
+
${fact.conceptLabel} (${fact.columnTitle})
|
|
18590
|
+
</a>
|
|
18591
|
+
— <strong>${I18n.t("typedDimensionWarning.value")}</strong> ${fact.value}
|
|
18592
|
+
</li>
|
|
18593
|
+
`)}
|
|
18594
|
+
</ul>
|
|
18595
|
+
</li>
|
|
18596
|
+
`)}
|
|
18597
|
+
</ul>
|
|
18598
|
+
</div>
|
|
18599
|
+
` : ""}
|
|
18600
|
+
${this._duplicateFactMismatches.length > 0 ? html`
|
|
18601
|
+
<div class="validate-warning-section">
|
|
18602
|
+
${this._typedDimensionWarningFacts.length > 0 ? html`<h4>${I18n.t("duplicateFactWarning.title")}</h4>` : ""}
|
|
18603
|
+
<p>${I18n.t("duplicateFactWarning.message")}</p>
|
|
18604
|
+
<ul class="error-list">
|
|
18605
|
+
${this._duplicateFactMismatches.map((mismatch) => html`
|
|
18606
|
+
<li>
|
|
18607
|
+
<strong>${mismatch.conceptLabel}</strong>
|
|
18608
|
+
<ul>
|
|
18609
|
+
${mismatch.facts.map((fact) => html`
|
|
18610
|
+
<li>
|
|
18611
|
+
<strong>${I18n.t("duplicateFactWarning.role")}</strong> ${fact.sectionTitle} —
|
|
18612
|
+
<a
|
|
18613
|
+
href="javascript:void(0)"
|
|
18614
|
+
class="error-field-link"
|
|
18615
|
+
@click="${() => this._handleDuplicateFactClick(fact.conceptId, fact.columnId, fact.sectionId)}"
|
|
18616
|
+
title="${I18n.t("duplicateFactWarning.clickToFocus")}"
|
|
18617
|
+
>
|
|
18618
|
+
${fact.columnTitle}
|
|
18619
|
+
</a>
|
|
18620
|
+
— <strong>${I18n.t("duplicateFactWarning.value")}</strong> ${fact.value}
|
|
18621
|
+
</li>
|
|
18622
|
+
`)}
|
|
18623
|
+
</ul>
|
|
18624
|
+
</li>
|
|
18625
|
+
`)}
|
|
18626
|
+
</ul>
|
|
18627
|
+
</div>
|
|
18628
|
+
` : ""}
|
|
18140
18629
|
</div>
|
|
18141
18630
|
<div class="error-popup-footer">
|
|
18142
|
-
|
|
18143
|
-
|
|
18631
|
+
${this._duplicateWarningPopupMode === "validate" ? html`
|
|
18632
|
+
<button class="btn-secondary" @click="${() => {
|
|
18633
|
+
this._showValidateWarningPopup = false;
|
|
18144
18634
|
this.requestUpdate();
|
|
18145
18635
|
}}">${I18n.t("typedDimensionWarning.cancel")}</button>
|
|
18146
|
-
|
|
18147
|
-
this.
|
|
18636
|
+
<button class="btn-primary" @click="${() => {
|
|
18637
|
+
this._showValidateWarningPopup = false;
|
|
18148
18638
|
this._continueSubmit();
|
|
18149
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
|
+
`}
|
|
18150
18646
|
</div>
|
|
18151
18647
|
</div>
|
|
18152
18648
|
</div>
|
|
@@ -19023,6 +19519,17 @@ JupiterDynamicForm.styles = css`
|
|
|
19023
19519
|
color: var(--jupiter-text-primary, #333);
|
|
19024
19520
|
}
|
|
19025
19521
|
|
|
19522
|
+
.validate-warning-section + .validate-warning-section {
|
|
19523
|
+
margin-top: 24px;
|
|
19524
|
+
padding-top: 20px;
|
|
19525
|
+
border-top: 1px solid var(--jupiter-border-color, #ddd);
|
|
19526
|
+
}
|
|
19527
|
+
|
|
19528
|
+
.validate-warning-section h4 {
|
|
19529
|
+
margin: 0 0 8px 0;
|
|
19530
|
+
color: var(--jupiter-text-primary, #333);
|
|
19531
|
+
}
|
|
19532
|
+
|
|
19026
19533
|
.error-list {
|
|
19027
19534
|
list-style: none;
|
|
19028
19535
|
padding: 0;
|
|
@@ -19262,10 +19769,19 @@ __decorateClass([
|
|
|
19262
19769
|
], JupiterDynamicForm.prototype, "_showErrorPopup", 2);
|
|
19263
19770
|
__decorateClass([
|
|
19264
19771
|
r()
|
|
19265
|
-
], JupiterDynamicForm.prototype, "
|
|
19772
|
+
], JupiterDynamicForm.prototype, "_showValidateWarningPopup", 2);
|
|
19266
19773
|
__decorateClass([
|
|
19267
19774
|
r()
|
|
19268
19775
|
], JupiterDynamicForm.prototype, "_typedDimensionWarningFacts", 2);
|
|
19776
|
+
__decorateClass([
|
|
19777
|
+
r()
|
|
19778
|
+
], JupiterDynamicForm.prototype, "_duplicateFactMismatches", 2);
|
|
19779
|
+
__decorateClass([
|
|
19780
|
+
r()
|
|
19781
|
+
], JupiterDynamicForm.prototype, "_duplicateFactWarnings", 2);
|
|
19782
|
+
__decorateClass([
|
|
19783
|
+
r()
|
|
19784
|
+
], JupiterDynamicForm.prototype, "_duplicateWarningPopupMode", 2);
|
|
19269
19785
|
__decorateClass([
|
|
19270
19786
|
r()
|
|
19271
19787
|
], JupiterDynamicForm.prototype, "_submitDisabled", 2);
|