arelle-release 2.37.46__py3-none-any.whl → 2.38.0__py3-none-any.whl
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.
- arelle/BetaFeatures.py +0 -21
- arelle/Cntlr.py +15 -8
- arelle/CntlrCmdLine.py +121 -56
- arelle/CntlrWinMain.py +143 -70
- arelle/DialogFind.py +1 -1
- arelle/DialogPluginManager.py +6 -4
- arelle/DisclosureSystem.py +7 -0
- arelle/ErrorManager.py +21 -6
- arelle/FileSource.py +11 -4
- arelle/FunctionIxt.py +16 -11
- arelle/HtmlUtil.py +5 -4
- arelle/LeiUtil.py +63 -43
- arelle/ModelDocument.py +20 -15
- arelle/ModelDtsObject.py +8 -0
- arelle/ModelInstanceObject.py +1 -1
- arelle/ModelObject.py +16 -18
- arelle/ModelObjectFactory.py +35 -17
- arelle/ModelXbrl.py +28 -11
- arelle/PluginManager.py +130 -105
- arelle/RuntimeOptions.py +1 -0
- arelle/UrlUtil.py +14 -0
- arelle/Validate.py +17 -12
- arelle/ValidateDuplicateFacts.py +3 -1
- arelle/ValidateFileSource.py +38 -0
- arelle/ValidateFilingText.py +3 -3
- arelle/ValidateXbrl.py +5 -2
- arelle/ValidateXbrlCalcs.py +210 -186
- arelle/ValidateXbrlDTS.py +1 -1
- arelle/ViewFile.py +1 -0
- arelle/ViewFileFactTable.py +2 -2
- arelle/ViewWinDTS.py +4 -1
- arelle/WebCache.py +28 -24
- arelle/XbrlConst.py +22 -0
- arelle/XmlUtil.py +16 -21
- arelle/XmlValidate.py +6 -9
- arelle/_version.py +16 -3
- arelle/api/Session.py +11 -2
- arelle/config/disclosuresystems.xsd +2 -0
- arelle/config/rosettaEntitlements.plist +8 -0
- arelle/conformance/CSVTestcaseLoader.py +1 -1
- arelle/formula/XPathContext.py +3 -3
- arelle/logging/formatters/LogFormatter.py +3 -1
- arelle/packages/report/ReportPackage.py +26 -13
- arelle/packages/report/ReportPackageConst.py +0 -1
- arelle/plugin/inlineXbrlDocumentSet.py +19 -5
- arelle/plugin/validate/DBA/DisclosureSystems.py +19 -1
- arelle/plugin/validate/DBA/PluginValidationDataExtension.py +2 -4
- arelle/plugin/validate/DBA/ValidationPluginExtension.py +2 -1
- arelle/plugin/validate/DBA/resources/config.xml +5 -0
- arelle/plugin/validate/DBA/rules/__init__.py +2 -2
- arelle/plugin/validate/DBA/rules/fr.py +19 -2
- arelle/plugin/validate/DBA/rules/tc.py +2 -0
- arelle/plugin/validate/DBA/rules/th.py +6 -0
- arelle/plugin/validate/DBA/rules/tm.py +18 -5
- arelle/plugin/validate/DBA/rules/tr.py +11 -5
- arelle/plugin/validate/EDINET/Constants.py +193 -9
- arelle/plugin/validate/EDINET/ContextRequirement.py +58 -0
- arelle/plugin/validate/EDINET/ControllerPluginData.py +220 -1
- arelle/plugin/validate/EDINET/CoverItemRequirements.py +42 -0
- arelle/plugin/validate/EDINET/DeiRequirements.py +118 -0
- arelle/plugin/validate/EDINET/FilingFormat.py +275 -0
- arelle/plugin/validate/EDINET/FormType.py +134 -0
- arelle/plugin/validate/EDINET/ManifestInstance.py +72 -5
- arelle/plugin/validate/EDINET/NamespaceConfig.py +50 -0
- arelle/plugin/validate/EDINET/PluginValidationDataExtension.py +493 -132
- arelle/plugin/validate/EDINET/{InstanceType.py → ReportFolderType.py} +72 -15
- arelle/plugin/validate/EDINET/Statement.py +139 -0
- arelle/plugin/validate/EDINET/TableOfContentsBuilder.py +595 -0
- arelle/plugin/validate/EDINET/UploadContents.py +48 -0
- arelle/plugin/validate/EDINET/ValidationPluginExtension.py +20 -2
- arelle/plugin/validate/EDINET/__init__.py +31 -6
- arelle/plugin/validate/EDINET/resources/config.xml +8 -1
- arelle/plugin/validate/EDINET/resources/cover-item-requirements.json +793 -0
- arelle/plugin/validate/EDINET/resources/dei-requirements.csv +27 -0
- arelle/plugin/validate/EDINET/resources/edinet-taxonomies.xml +2 -0
- arelle/plugin/validate/EDINET/rules/contexts.py +375 -14
- arelle/plugin/validate/EDINET/rules/edinet.py +1934 -45
- arelle/plugin/validate/EDINET/rules/frta.py +122 -3
- arelle/plugin/validate/EDINET/rules/gfm.py +1907 -11
- arelle/plugin/validate/EDINET/rules/upload.py +989 -141
- arelle/plugin/validate/ESEF/Const.py +3 -1
- arelle/plugin/validate/ESEF/ESEF_2021/DTS.py +5 -0
- arelle/plugin/validate/ESEF/ESEF_2021/Image.py +2 -2
- arelle/plugin/validate/ESEF/ESEF_2021/ValidateXbrlFinally.py +23 -20
- arelle/plugin/validate/ESEF/ESEF_Current/DTS.py +47 -14
- arelle/plugin/validate/ESEF/ESEF_Current/ValidateXbrlFinally.py +100 -25
- arelle/plugin/validate/ESEF/__init__.py +20 -6
- arelle/plugin/validate/ESEF/resources/authority-validations.json +76 -9
- arelle/plugin/validate/ESEF/resources/config.xml +20 -0
- arelle/plugin/validate/NL/DisclosureSystems.py +22 -0
- arelle/plugin/validate/NL/PluginValidationDataExtension.py +27 -9
- arelle/plugin/validate/NL/ValidationPluginExtension.py +51 -7
- arelle/plugin/validate/NL/resources/config.xml +18 -0
- arelle/plugin/validate/NL/rules/br_kvk.py +17 -61
- arelle/plugin/validate/NL/rules/fg_nl.py +7 -38
- arelle/plugin/validate/NL/rules/fr_kvk.py +7 -42
- arelle/plugin/validate/NL/rules/fr_nl.py +31 -147
- arelle/plugin/validate/NL/rules/nl_kvk.py +142 -28
- arelle/plugin/validate/ROS/PluginValidationDataExtension.py +2 -0
- arelle/plugin/validate/ROS/ValidationPluginExtension.py +4 -1
- arelle/plugin/validate/ROS/rules/ros.py +41 -9
- arelle/plugin/validate/UK/ValidateUK.py +130 -66
- arelle/plugin/validate/UK/__init__.py +89 -103
- arelle/utils/EntryPointDetection.py +79 -13
- arelle/utils/PluginHooks.py +125 -0
- arelle/utils/validate/ESEFImage.py +6 -6
- arelle/utils/validate/Validation.py +18 -0
- arelle/utils/validate/ValidationPlugin.py +76 -11
- arelle/utils/validate/ValidationUtil.py +35 -3
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/METADATA +30 -20
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/RECORD +115 -191
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/licenses/LICENSE.md +0 -3
- arelle/archive/CustomLogger.py +0 -43
- arelle/archive/LoadEFMvalidate.py +0 -32
- arelle/archive/LoadSavePreLbCsv.py +0 -26
- arelle/archive/LoadValidate.cs +0 -31
- arelle/archive/LoadValidate.py +0 -36
- arelle/archive/LoadValidateCmdLine.java +0 -69
- arelle/archive/LoadValidatePostedZip.java +0 -57
- arelle/archive/LoadValidateWebService.java +0 -34
- arelle/archive/SaveTableToExelle.py +0 -140
- arelle/archive/TR3toTR4.py +0 -88
- arelle/archive/plugin/ESEF_2022/__init__.py +0 -47
- arelle/archive/plugin/bigInstance.py +0 -394
- arelle/archive/plugin/cmdWebServerExtension.py +0 -43
- arelle/archive/plugin/crashTest.py +0 -38
- arelle/archive/plugin/functionsXmlCreation.py +0 -106
- arelle/archive/plugin/hello_i18n.pot +0 -26
- arelle/archive/plugin/hello_i18n.py +0 -32
- arelle/archive/plugin/importTestChild1.py +0 -21
- arelle/archive/plugin/importTestChild2.py +0 -22
- arelle/archive/plugin/importTestGrandchild1.py +0 -21
- arelle/archive/plugin/importTestGrandchild2.py +0 -21
- arelle/archive/plugin/importTestImported1.py +0 -23
- arelle/archive/plugin/importTestImported11.py +0 -22
- arelle/archive/plugin/importTestParent.py +0 -48
- arelle/archive/plugin/instanceInfo.py +0 -306
- arelle/archive/plugin/loadFromOIM-2018.py +0 -1282
- arelle/archive/plugin/locale/fr/LC_MESSAGES/hello_i18n.po +0 -25
- arelle/archive/plugin/objectmaker.py +0 -285
- arelle/archive/plugin/packagedImportTest/__init__.py +0 -47
- arelle/archive/plugin/packagedImportTest/importTestChild1.py +0 -21
- arelle/archive/plugin/packagedImportTest/importTestChild2.py +0 -22
- arelle/archive/plugin/packagedImportTest/importTestGrandchild1.py +0 -21
- arelle/archive/plugin/packagedImportTest/importTestGrandchild2.py +0 -21
- arelle/archive/plugin/packagedImportTest/importTestImported1.py +0 -24
- arelle/archive/plugin/packagedImportTest/importTestImported11.py +0 -21
- arelle/archive/plugin/packagedImportTest/subdir/importTestImported111.py +0 -21
- arelle/archive/plugin/packagedImportTest/subdir/subsubdir/importTestImported1111.py +0 -21
- arelle/archive/plugin/sakaCalendar.py +0 -215
- arelle/archive/plugin/saveInstanceInfoset.py +0 -121
- arelle/archive/plugin/sphinx/FormulaGenerator.py +0 -823
- arelle/archive/plugin/sphinx/SphinxContext.py +0 -404
- arelle/archive/plugin/sphinx/SphinxEvaluator.py +0 -783
- arelle/archive/plugin/sphinx/SphinxMethods.py +0 -1287
- arelle/archive/plugin/sphinx/SphinxParser.py +0 -1093
- arelle/archive/plugin/sphinx/SphinxValidator.py +0 -163
- arelle/archive/plugin/sphinx/US-GAAP Ratios Example.xsr +0 -52
- arelle/archive/plugin/sphinx/__init__.py +0 -285
- arelle/archive/plugin/streamingExtensions.py +0 -335
- arelle/archive/plugin/updateTableLB.py +0 -242
- arelle/archive/plugin/validate/SBRnl/CustomLoader.py +0 -19
- arelle/archive/plugin/validate/SBRnl/DTS.py +0 -305
- arelle/archive/plugin/validate/SBRnl/Dimensions.py +0 -357
- arelle/archive/plugin/validate/SBRnl/Document.py +0 -799
- arelle/archive/plugin/validate/SBRnl/Filing.py +0 -467
- arelle/archive/plugin/validate/SBRnl/__init__.py +0 -75
- arelle/archive/plugin/validate/SBRnl/config.xml +0 -26
- arelle/archive/plugin/validate/SBRnl/sbr-nl-taxonomies.xml +0 -754
- arelle/archive/plugin/validate/USBestPractices.py +0 -570
- arelle/archive/plugin/validate/USCorpAction.py +0 -557
- arelle/archive/plugin/validate/USSecTagging.py +0 -337
- arelle/archive/plugin/validate/XDC/__init__.py +0 -77
- arelle/archive/plugin/validate/XDC/config.xml +0 -20
- arelle/archive/plugin/validate/XFsyntax/__init__.py +0 -64
- arelle/archive/plugin/validate/XFsyntax/xf.py +0 -2227
- arelle/archive/plugin/validate/calc2.py +0 -536
- arelle/archive/plugin/validateSchemaLxml.py +0 -156
- arelle/archive/plugin/validateTableInfoset.py +0 -52
- arelle/archive/us-gaap-dei-docType-extraction-frm.xml +0 -90
- arelle/archive/us-gaap-dei-ratio-cash-frm.xml +0 -150
- arelle/examples/plugin/formulaSuiteConverter.py +0 -212
- arelle/examples/plugin/functionsCustom.py +0 -59
- arelle/examples/plugin/hello_dolly.py +0 -64
- arelle/examples/plugin/multi.py +0 -58
- arelle/examples/plugin/rssSaveOim.py +0 -96
- arelle/examples/plugin/validate/XYZ/DisclosureSystems.py +0 -2
- arelle/examples/plugin/validate/XYZ/PluginValidationDataExtension.py +0 -10
- arelle/examples/plugin/validate/XYZ/ValidationPluginExtension.py +0 -49
- arelle/examples/plugin/validate/XYZ/__init__.py +0 -75
- arelle/examples/plugin/validate/XYZ/resources/config.xml +0 -16
- arelle/examples/plugin/validate/XYZ/rules/__init__.py +0 -0
- arelle/examples/plugin/validate/XYZ/rules/rules01.py +0 -110
- arelle/examples/plugin/validate/XYZ/rules/rules02.py +0 -59
- arelle/model/CommentBase.py +0 -9
- arelle/model/ElementBase.py +0 -11
- arelle/model/PIBase.py +0 -10
- arelle/model/__init__.py +0 -15
- arelle/scripts-macOS/startWebServer.command +0 -3
- arelle/scripts-unix/startWebServer.sh +0 -1
- arelle/scripts-windows/startWebServer.bat +0 -5
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/WHEEL +0 -0
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/entry_points.txt +0 -0
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/top_level.txt +0 -0
|
@@ -3,37 +3,41 @@ See COPYRIGHT.md for copyright information.
|
|
|
3
3
|
"""
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
-
import re
|
|
7
6
|
from collections import defaultdict
|
|
8
7
|
from collections.abc import Iterable
|
|
9
8
|
from datetime import date
|
|
10
|
-
from typing import Any, cast
|
|
9
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
11
10
|
|
|
11
|
+
import regex
|
|
12
12
|
from lxml.etree import Element
|
|
13
13
|
|
|
14
|
+
from arelle import ModelDocument, XbrlConst, XmlUtil
|
|
14
15
|
from arelle.LinkbaseType import LinkbaseType
|
|
15
16
|
from arelle.ModelDtsObject import ModelConcept, ModelLink, ModelResource, ModelType
|
|
16
17
|
from arelle.ModelInstanceObject import ModelInlineFact
|
|
17
18
|
from arelle.ModelObject import ModelObject
|
|
18
19
|
from arelle.PrototypeDtsObject import PrototypeObject
|
|
19
|
-
from arelle.ValidateDuplicateFacts import getDuplicateFactSets
|
|
20
|
-
from arelle.XbrlConst import parentChild, standardLabel
|
|
21
|
-
from arelle.XmlValidateConst import VALID
|
|
22
|
-
|
|
23
|
-
from arelle import XbrlConst, XmlUtil, ModelDocument
|
|
24
|
-
from arelle.ValidateXbrl import ValidateXbrl
|
|
25
20
|
from arelle.typing import TypeGetText
|
|
26
21
|
from arelle.utils.PluginHooks import ValidationHook
|
|
27
22
|
from arelle.utils.validate.Decorator import validation
|
|
28
23
|
from arelle.utils.validate.DetectScriptsInXhtml import containsScriptMarkers
|
|
29
24
|
from arelle.utils.validate.ESEFImage import ImageValidationParameters, validateImage
|
|
30
25
|
from arelle.utils.validate.Validation import Validation
|
|
31
|
-
from arelle.ValidateDuplicateFacts import
|
|
32
|
-
from arelle.
|
|
33
|
-
from
|
|
34
|
-
|
|
26
|
+
from arelle.ValidateDuplicateFacts import getAspectEqualFacts, getDuplicateFactSets, getHashEquivalentFactGroups
|
|
27
|
+
from arelle.ValidateXbrl import ValidateXbrl
|
|
28
|
+
from arelle.XbrlConst import parentChild, standardLabel
|
|
29
|
+
from arelle.XmlValidateConst import VALID
|
|
30
|
+
|
|
31
|
+
from ..DisclosureSystems import (
|
|
32
|
+
DISCLOSURE_SYSTEM_NL_INLINE_2025,
|
|
33
|
+
DISCLOSURE_SYSTEM_NL_INLINE_MULTI_TARGET,
|
|
34
|
+
ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
|
|
35
|
+
NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
|
|
36
|
+
NL_INLINE_GAAP_OTHER_DISCLOSURE_SYSTEMS,
|
|
37
|
+
NL_INLINE_MULTI_TARGET_DISCLOSURE_SYSTEMS,
|
|
38
|
+
NL_INLINE_OTHER_DISCLOSURE_SYSTEMS,
|
|
39
|
+
)
|
|
35
40
|
from ..PluginValidationDataExtension import (
|
|
36
|
-
PluginValidationDataExtension,
|
|
37
41
|
ALLOWABLE_LANGUAGES,
|
|
38
42
|
DEFAULT_MEMBER_ROLE_URI,
|
|
39
43
|
DISALLOWED_IXT_NAMESPACES,
|
|
@@ -46,15 +50,16 @@ from ..PluginValidationDataExtension import (
|
|
|
46
50
|
TAXONOMY_URLS_BY_YEAR,
|
|
47
51
|
XBRLI_IDENTIFIER_PATTERN,
|
|
48
52
|
XBRLI_IDENTIFIER_SCHEMA,
|
|
53
|
+
PluginValidationDataExtension,
|
|
49
54
|
)
|
|
50
55
|
|
|
51
56
|
if TYPE_CHECKING:
|
|
52
|
-
from arelle.ModelXbrl import ModelXbrl
|
|
53
57
|
from arelle.ModelValue import QName
|
|
58
|
+
from arelle.ModelXbrl import ModelXbrl
|
|
54
59
|
|
|
55
60
|
_: TypeGetText
|
|
56
61
|
|
|
57
|
-
DOCTYPE_XHTML_PATTERN =
|
|
62
|
+
DOCTYPE_XHTML_PATTERN = regex.compile(r"^<!(?:DOCTYPE\s+)\s*html(?:PUBLIC\s+)?(?:.*-//W3C//DTD\s+(X?HTML)\s)?.*>$", regex.IGNORECASE)
|
|
58
63
|
|
|
59
64
|
|
|
60
65
|
def _getReportingPeriodDateValue(modelXbrl: ModelXbrl, qname: QName) -> date | None:
|
|
@@ -751,7 +756,7 @@ def rule_nl_kvk_3_5_2_3(
|
|
|
751
756
|
"""
|
|
752
757
|
badLangsUsed = set()
|
|
753
758
|
for ixdsHtmlRootElt in val.modelXbrl.ixdsHtmlElements:
|
|
754
|
-
for uncast_elt
|
|
759
|
+
for uncast_elt in ixdsHtmlRootElt.iter():
|
|
755
760
|
elt = cast(Any, uncast_elt)
|
|
756
761
|
xmlLang = elt.get("{http://www.w3.org/XML/1998/namespace}lang")
|
|
757
762
|
if xmlLang and xmlLang not in ALLOWABLE_LANGUAGES:
|
|
@@ -1244,7 +1249,8 @@ def rule_nl_kvk_4_2_2_2(
|
|
|
1244
1249
|
**kwargs: Any,
|
|
1245
1250
|
) -> Iterable[Validation]:
|
|
1246
1251
|
"""
|
|
1247
|
-
NL-KVK.4.2.2.2: Domain members MUST have domainItemType data type as defined in
|
|
1252
|
+
NL-KVK.4.2.2.2: Domain members MUST have domainItemType data type as defined in
|
|
1253
|
+
https://www.xbrl.org/dtr/type/2022-03-31/types.xsd or https://www.xbrl.org/dtr/type/2024-01-31/types.xsd
|
|
1248
1254
|
"""
|
|
1249
1255
|
domainMembersWrongType = []
|
|
1250
1256
|
domainMembers = pluginData.getDimensionalData(val.modelXbrl).domainMembers
|
|
@@ -1326,6 +1332,29 @@ def rule_nl_kvk_4_3_1_1(
|
|
|
1326
1332
|
)
|
|
1327
1333
|
|
|
1328
1334
|
|
|
1335
|
+
@validation(
|
|
1336
|
+
hook=ValidationHook.XBRL_FINALLY,
|
|
1337
|
+
disclosureSystems=DISCLOSURE_SYSTEM_NL_INLINE_2025,
|
|
1338
|
+
)
|
|
1339
|
+
def rule_nl_kvk_4_3_1_2(
|
|
1340
|
+
pluginData: PluginValidationDataExtension,
|
|
1341
|
+
val: ValidateXbrl,
|
|
1342
|
+
*args: Any,
|
|
1343
|
+
**kwargs: Any,
|
|
1344
|
+
) -> Iterable[Validation]:
|
|
1345
|
+
"""
|
|
1346
|
+
NL-KVK.4.3.1.2: An extension element SHOULD be anchored to a taxonomy element with a compatible data type.
|
|
1347
|
+
"""
|
|
1348
|
+
anchorData = pluginData.getAnchorData(val.modelXbrl)
|
|
1349
|
+
if len(anchorData.extConceptsNotAnchoredToSameDerivedType) > 0:
|
|
1350
|
+
yield Validation.warning(
|
|
1351
|
+
codes="NL.NL-KVK.4.3.1.2.incompatibleDataTypeAnchoringRelationship",
|
|
1352
|
+
msg=_("The extension and taxonomy concepts that participate in anchoring relationships must "
|
|
1353
|
+
"either have the same type or one concept type must derive from the other."),
|
|
1354
|
+
modelObject=anchorData.extConceptsNotAnchoredToSameDerivedType,
|
|
1355
|
+
)
|
|
1356
|
+
|
|
1357
|
+
|
|
1329
1358
|
@validation(
|
|
1330
1359
|
hook=ValidationHook.XBRL_FINALLY,
|
|
1331
1360
|
disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
|
|
@@ -1721,23 +1750,27 @@ def rule_nl_kvk_4_4_6_1(
|
|
|
1721
1750
|
|
|
1722
1751
|
@validation(
|
|
1723
1752
|
hook=ValidationHook.XBRL_FINALLY,
|
|
1724
|
-
disclosureSystems=
|
|
1753
|
+
disclosureSystems=NL_INLINE_OTHER_DISCLOSURE_SYSTEMS,
|
|
1725
1754
|
)
|
|
1726
|
-
def
|
|
1755
|
+
def rule_nl_kvk_5_1_3_1_and_6_1_3_1(
|
|
1727
1756
|
pluginData: PluginValidationDataExtension,
|
|
1728
1757
|
val: ValidateXbrl,
|
|
1729
1758
|
*args: Any,
|
|
1730
1759
|
**kwargs: Any,
|
|
1731
1760
|
) -> Iterable[Validation]:
|
|
1732
1761
|
"""
|
|
1733
|
-
NL-KVK.5.1.3.1: Validate that the imported taxonomy matches the KVK-specified entry point.
|
|
1762
|
+
NL-KVK.5.1.3.1 and NL-KVK.6.1.3.1: Validate that the imported taxonomy matches the KVK-specified entry point.
|
|
1734
1763
|
- https://www.nltaxonomie.nl/kvk/2024-12-31/kvk-annual-report-other-gaap.xsd
|
|
1764
|
+
- https://www.nltaxonomie.nl/kvk/2025-12-31/kvk-annual-report-other.xsd
|
|
1735
1765
|
"""
|
|
1736
1766
|
uris = {doc[0].uri for doc in val.modelXbrl.namespaceDocs.values()}
|
|
1737
1767
|
matches = uris & EFFECTIVE_KVK_GAAP_OTHER_ENTRYPOINT_FILES
|
|
1738
1768
|
if not matches:
|
|
1769
|
+
base_code = '5.1.3.1.requiredEntryPointOtherGaapNotReferenced'
|
|
1770
|
+
if str(val.disclosureSystem.name) in DISCLOSURE_SYSTEM_NL_INLINE_MULTI_TARGET:
|
|
1771
|
+
base_code = '6.1.3.1.requiredEntryPointOtherNotReferenced'
|
|
1739
1772
|
yield Validation.error(
|
|
1740
|
-
codes='NL.NL-KVK.
|
|
1773
|
+
codes=f'NL.NL-KVK.{base_code}',
|
|
1741
1774
|
msg=_('The extension taxonomy must import the entry point of the taxonomy files prepared by KVK.'),
|
|
1742
1775
|
modelObject=val.modelXbrl.modelDocument
|
|
1743
1776
|
)
|
|
@@ -1745,24 +1778,27 @@ def rule_nl_kvk_5_1_3_1(
|
|
|
1745
1778
|
|
|
1746
1779
|
@validation(
|
|
1747
1780
|
hook=ValidationHook.XBRL_FINALLY,
|
|
1748
|
-
disclosureSystems=
|
|
1781
|
+
disclosureSystems=NL_INLINE_OTHER_DISCLOSURE_SYSTEMS,
|
|
1749
1782
|
)
|
|
1750
|
-
def
|
|
1783
|
+
def rule_nl_kvk_5_1_3_2_and_6_1_3_2(
|
|
1751
1784
|
pluginData: PluginValidationDataExtension,
|
|
1752
1785
|
val: ValidateXbrl,
|
|
1753
1786
|
*args: Any,
|
|
1754
1787
|
**kwargs: Any,
|
|
1755
1788
|
) -> Iterable[Validation]:
|
|
1756
1789
|
"""
|
|
1757
|
-
NL-KVK.5.1.3.2: The legal entity's report MUST import the applicable version of
|
|
1790
|
+
NL-KVK.5.1.3.2 and NL-KVK.6.1.3.2: The legal entity's report MUST import the applicable version of
|
|
1758
1791
|
the taxonomy files prepared by KVK.
|
|
1759
1792
|
"""
|
|
1760
1793
|
reportingPeriod = pluginData.getReportingPeriod(val.modelXbrl)
|
|
1761
1794
|
uris = {doc[0].uri for doc in val.modelXbrl.namespaceDocs.values()}
|
|
1762
1795
|
matches = uris & TAXONOMY_URLS_BY_YEAR.get(reportingPeriod or '', set())
|
|
1763
1796
|
if not reportingPeriod or not matches:
|
|
1797
|
+
base_code = '5.1.3.2.incorrectVersionEntryPointOtherGaapReferenced'
|
|
1798
|
+
if str(val.disclosureSystem.name) in DISCLOSURE_SYSTEM_NL_INLINE_MULTI_TARGET:
|
|
1799
|
+
base_code = '6.1.3.2.incorrectVersionEntryPointOtherReferenced'
|
|
1764
1800
|
yield Validation.error(
|
|
1765
|
-
codes='NL.NL-KVK.
|
|
1801
|
+
codes=f'NL.NL-KVK.{base_code}',
|
|
1766
1802
|
msg=_('The report MUST import the applicable version of the taxonomy files prepared by KVK '
|
|
1767
1803
|
'for the reported financial reporting period. Verify the taxonomy version and make sure '
|
|
1768
1804
|
'that FinancialReportingPeriod are tagged correctly.'),
|
|
@@ -1770,25 +1806,103 @@ def rule_nl_kvk_5_1_3_2(
|
|
|
1770
1806
|
)
|
|
1771
1807
|
|
|
1772
1808
|
|
|
1809
|
+
@validation(
|
|
1810
|
+
hook=ValidationHook.XBRL_FINALLY,
|
|
1811
|
+
disclosureSystems=NL_INLINE_MULTI_TARGET_DISCLOSURE_SYSTEMS,
|
|
1812
|
+
)
|
|
1813
|
+
def rule_nl_kvk_6_1_3_3(
|
|
1814
|
+
pluginData: PluginValidationDataExtension,
|
|
1815
|
+
val: ValidateXbrl,
|
|
1816
|
+
*args: Any,
|
|
1817
|
+
**kwargs: Any,
|
|
1818
|
+
) -> Iterable[Validation]:
|
|
1819
|
+
"""
|
|
1820
|
+
NL-KVK.6.1.3.3: The target attribute “filing-information” MUST be used for the content of the required elements
|
|
1821
|
+
for filing with the Business Register
|
|
1822
|
+
"""
|
|
1823
|
+
targetElements = {elt.get("target") for elt in pluginData.getTargetElements(val.modelXbrl)}
|
|
1824
|
+
if len(targetElements) > 2 or 'filing-information' not in targetElements or 'default' not in targetElements:
|
|
1825
|
+
yield Validation.error(
|
|
1826
|
+
codes='NL.NL-KVK.6.1.3.3.requiredTargetAttributeNotUsed',
|
|
1827
|
+
msg=_('The target attribute `filing-information` MUST be used for the content of the required '
|
|
1828
|
+
'elements for filing with the Business Register.'),
|
|
1829
|
+
modelObject=targetElements
|
|
1830
|
+
)
|
|
1831
|
+
|
|
1832
|
+
|
|
1833
|
+
@validation(
|
|
1834
|
+
hook=ValidationHook.XBRL_FINALLY,
|
|
1835
|
+
disclosureSystems=NL_INLINE_GAAP_OTHER_DISCLOSURE_SYSTEMS,
|
|
1836
|
+
)
|
|
1837
|
+
def rule_nl_kvk_7_1_4_2(
|
|
1838
|
+
pluginData: PluginValidationDataExtension,
|
|
1839
|
+
val: ValidateXbrl,
|
|
1840
|
+
*args: Any,
|
|
1841
|
+
**kwargs: Any,
|
|
1842
|
+
) -> Iterable[Validation]:
|
|
1843
|
+
"""
|
|
1844
|
+
NL-KVK.7.1.4.2: The concept kvk:AnnualReportOfForeignGroupHeadForExemptionUnderArticle403 MUST NOT be reported with
|
|
1845
|
+
a value of “False”.
|
|
1846
|
+
"""
|
|
1847
|
+
factsInError = []
|
|
1848
|
+
articleFacts = val.modelXbrl.factsByQname.get(pluginData.AnnualReportOfForeignGroupHeadForExemptionUnderArticle403Qn, set())
|
|
1849
|
+
for fact in articleFacts:
|
|
1850
|
+
if fact is not None and fact.xValid >= VALID and fact.xValue == 'False':
|
|
1851
|
+
factsInError.append(fact)
|
|
1852
|
+
if len(factsInError) > 0:
|
|
1853
|
+
yield Validation.error(
|
|
1854
|
+
codes='NL.NL-KVK.7.1.4.2.reportedConcept403NotExpected',
|
|
1855
|
+
msg=_('A fact or facts tagged with `kvk:AnnualReportOfForeignGroupHeadForExemptionUnderArticle403` is incorrectly marked as False.'),
|
|
1856
|
+
modelObject=factsInError
|
|
1857
|
+
)
|
|
1858
|
+
|
|
1859
|
+
|
|
1860
|
+
@validation(
|
|
1861
|
+
hook=ValidationHook.XBRL_FINALLY,
|
|
1862
|
+
disclosureSystems=NL_INLINE_GAAP_OTHER_DISCLOSURE_SYSTEMS,
|
|
1863
|
+
)
|
|
1864
|
+
def rule_nl_kvk_7_2_1_2(
|
|
1865
|
+
pluginData: PluginValidationDataExtension,
|
|
1866
|
+
val: ValidateXbrl,
|
|
1867
|
+
*args: Any,
|
|
1868
|
+
**kwargs: Any,
|
|
1869
|
+
) -> Iterable[Validation]:
|
|
1870
|
+
"""
|
|
1871
|
+
NL-KVK.7.2.1.2: The concept kvk:AnnualReportOfForeignGroupHeadForExemptionUnderArticle408 MUST NOT be reported with
|
|
1872
|
+
a value of “False”.
|
|
1873
|
+
"""
|
|
1874
|
+
factsInError = []
|
|
1875
|
+
articleFacts = val.modelXbrl.factsByQname.get(pluginData.AnnualReportOfForeignGroupHeadForExemptionUnderArticle408Qn, set())
|
|
1876
|
+
for fact in articleFacts:
|
|
1877
|
+
if fact is not None and fact.xValid >= VALID and fact.xValue == 'False':
|
|
1878
|
+
factsInError.append(fact)
|
|
1879
|
+
if len(factsInError) > 0:
|
|
1880
|
+
yield Validation.error(
|
|
1881
|
+
codes='NL.NL-KVK.7.2.1.2.reportedConcept408NotExpected',
|
|
1882
|
+
msg=_('A fact or facts tagged with `kvk:AnnualReportOfForeignGroupHeadForExemptionUnderArticle408` is incorrectly marked as False.'),
|
|
1883
|
+
modelObject=factsInError
|
|
1884
|
+
)
|
|
1885
|
+
|
|
1886
|
+
|
|
1773
1887
|
@validation(
|
|
1774
1888
|
hook=ValidationHook.XBRL_FINALLY,
|
|
1775
1889
|
disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
|
|
1776
1890
|
)
|
|
1777
|
-
def
|
|
1891
|
+
def rule_nl_kvk_8_1_1_1(
|
|
1778
1892
|
pluginData: PluginValidationDataExtension,
|
|
1779
1893
|
val: ValidateXbrl,
|
|
1780
1894
|
*args: Any,
|
|
1781
1895
|
**kwargs: Any,
|
|
1782
1896
|
) -> Iterable[Validation]:
|
|
1783
1897
|
"""
|
|
1784
|
-
NL-KVK.
|
|
1898
|
+
NL-KVK.8.1.1.1: The size of the report package MUST NOT exceed 100 MB.
|
|
1785
1899
|
"""
|
|
1786
1900
|
size = val.modelXbrl.fileSource.getBytesSize()
|
|
1787
1901
|
if size is None:
|
|
1788
1902
|
return # File size is not available, cannot validate
|
|
1789
1903
|
if size > MAX_REPORT_PACKAGE_SIZE_MBS * 1_000_000: # Interpretting MB as megabytes (1,000,000 bytes)
|
|
1790
1904
|
yield Validation.error(
|
|
1791
|
-
codes='NL.NL-KVK.
|
|
1905
|
+
codes='NL.NL-KVK.8.1.1.1.reportPackageMaximumSizeExceeded',
|
|
1792
1906
|
msg=_('The size of the report package must not exceed %(maxSize)s MBs, size is %(size)s MBs.'),
|
|
1793
1907
|
modelObject=val.modelXbrl, maxSize=MAX_REPORT_PACKAGE_SIZE_MBS, size=int(size/1000000)
|
|
1794
1908
|
)
|
|
@@ -35,6 +35,8 @@ SCHEMA_PATTERNS = {
|
|
|
35
35
|
"http://www.cro.ie/": re.compile(r"^\d{1,6}$")
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
UK_REF_NS_PATTERN = re.compile(r"^http://xbrl.frc.org.uk/general/\d{4,}-\d{2,}-\d{2,}/ref$")
|
|
39
|
+
|
|
38
40
|
TR_NAMESPACES = {
|
|
39
41
|
"http://www.xbrl.org/inlineXBRL/transformation/2010-04-20",
|
|
40
42
|
"http://www.xbrl.org/inlineXBRL/transformation/2011-07-31",
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
See COPYRIGHT.md for copyright information.
|
|
3
3
|
"""
|
|
4
4
|
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from arelle.Cntlr import Cntlr
|
|
5
7
|
from arelle.ValidateXbrl import ValidateXbrl
|
|
6
8
|
from arelle.typing import TypeGetText
|
|
7
9
|
from arelle.utils.validate.ValidationPlugin import ValidationPlugin
|
|
@@ -10,6 +12,7 @@ from .PluginValidationDataExtension import PluginValidationDataExtension
|
|
|
10
12
|
|
|
11
13
|
_: TypeGetText
|
|
12
14
|
|
|
15
|
+
CURRENCIES_DIMENSION = 'CurrenciesDimension'
|
|
13
16
|
EQUITY = 'Equity'
|
|
14
17
|
IE_PROFIT_LOSS = 'ProfitLossBeforeTax'
|
|
15
18
|
IE_PROFIT_LOSS_ORDINARY = 'ProfitLossOnOrdinaryActivitiesBeforeTax'
|
|
@@ -18,7 +21,7 @@ TURNOVER_REVENUE = 'DPLTurnoverRevenue'
|
|
|
18
21
|
|
|
19
22
|
|
|
20
23
|
class ValidationPluginExtension(ValidationPlugin):
|
|
21
|
-
def newPluginData(self, validateXbrl: ValidateXbrl) -> PluginValidationDataExtension:
|
|
24
|
+
def newPluginData(self, cntlr: Cntlr, validateXbrl: ValidateXbrl | None) -> PluginValidationDataExtension:
|
|
22
25
|
return PluginValidationDataExtension(
|
|
23
26
|
self.name
|
|
24
27
|
)
|
|
@@ -10,6 +10,7 @@ from collections import Counter
|
|
|
10
10
|
from collections.abc import Iterable
|
|
11
11
|
from decimal import Decimal
|
|
12
12
|
|
|
13
|
+
from arelle import XbrlConst
|
|
13
14
|
from arelle.typing import TypeGetText
|
|
14
15
|
from arelle.ValidateXbrl import ValidateXbrl
|
|
15
16
|
from collections import defaultdict
|
|
@@ -28,8 +29,8 @@ from arelle.utils.validate.Validation import Validation
|
|
|
28
29
|
from arelle.ValidateXbrlCalcs import inferredDecimals, rangeValue
|
|
29
30
|
from arelle.XbrlConst import qnXbrliMonetaryItemType, qnXbrliXbrl, xhtml
|
|
30
31
|
from arelle.XmlValidateConst import VALID
|
|
31
|
-
from ..ValidationPluginExtension import EQUITY, PRINCIPAL_CURRENCY, TURNOVER_REVENUE
|
|
32
|
-
from ..PluginValidationDataExtension import MANDATORY_ELEMENTS,
|
|
32
|
+
from ..ValidationPluginExtension import CURRENCIES_DIMENSION, EQUITY, PRINCIPAL_CURRENCY, TURNOVER_REVENUE
|
|
33
|
+
from ..PluginValidationDataExtension import MANDATORY_ELEMENTS, SCHEMA_PATTERNS, TR_NAMESPACES, UK_REF_NS_PATTERN, PluginValidationDataExtension
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
def checkFileEncoding(modelXbrl: ModelXbrl) -> None:
|
|
@@ -302,14 +303,14 @@ def rule_ros19(
|
|
|
302
303
|
equity_facts = val.modelXbrl.factsByLocalName.get(EQUITY, set())
|
|
303
304
|
largest_equity_fact = None
|
|
304
305
|
for e_fact in equity_facts:
|
|
305
|
-
if e_fact.xValid >= VALID:
|
|
306
|
+
if e_fact.xValid >= VALID and e_fact.xValue is not None:
|
|
306
307
|
if largest_equity_fact is None or abs(convertToDecimal(e_fact.xValue)) > abs(convertToDecimal(largest_equity_fact.xValue)):
|
|
307
308
|
largest_equity_fact = e_fact
|
|
308
309
|
|
|
309
310
|
turnover_facts = val.modelXbrl.factsByLocalName.get(TURNOVER_REVENUE, set())
|
|
310
311
|
largest_turnover_fact = None
|
|
311
312
|
for t_fact in turnover_facts:
|
|
312
|
-
if t_fact.xValid >= VALID:
|
|
313
|
+
if t_fact.xValid >= VALID and t_fact.xValue is not None:
|
|
313
314
|
if largest_turnover_fact is None or convertToDecimal(t_fact.xValue) > convertToDecimal(largest_turnover_fact.xValue):
|
|
314
315
|
largest_turnover_fact = t_fact
|
|
315
316
|
|
|
@@ -337,27 +338,58 @@ def rule_ros20(
|
|
|
337
338
|
used for the majority of monetary facts.
|
|
338
339
|
"""
|
|
339
340
|
principal_currency_facts = val.modelXbrl.factsByLocalName.get(PRINCIPAL_CURRENCY, set())
|
|
340
|
-
principal_currency_values =
|
|
341
|
+
principal_currency_values = {
|
|
342
|
+
currencyDimensionCode
|
|
343
|
+
for pc_fact in principal_currency_facts
|
|
344
|
+
if (currencyDimensionCode := _getCurrencyDimensionCode(val.modelXbrl, pc_fact))
|
|
345
|
+
}
|
|
341
346
|
if len(principal_currency_values) != 1:
|
|
342
347
|
yield Validation.error(
|
|
343
348
|
"ROS.20",
|
|
344
349
|
_("'PrincipalCurrencyUsedInBusinessReport' must exist and have a single value. Values found: %(principal_currency_values)s."),
|
|
345
350
|
modelObject=principal_currency_facts,
|
|
346
|
-
principal_currency_values=principal_currency_values,
|
|
351
|
+
principal_currency_values=sorted(principal_currency_values),
|
|
347
352
|
)
|
|
348
353
|
else:
|
|
349
354
|
principal_currency_value = principal_currency_values.pop()
|
|
350
355
|
monetary_facts = list(val.modelXbrl.factsByDatatype(False, qnXbrliMonetaryItemType))
|
|
351
|
-
monetary_units = [
|
|
356
|
+
monetary_units = [
|
|
357
|
+
list(fact.utrEntries)[0].unitId for fact in monetary_facts if fact.unit is not None and len(fact.utrEntries) > 0
|
|
358
|
+
]
|
|
352
359
|
unit_counts = Counter(monetary_units)
|
|
353
360
|
principal_currency_value_count = unit_counts[principal_currency_value]
|
|
354
|
-
for
|
|
361
|
+
for count in unit_counts.values():
|
|
355
362
|
if count > principal_currency_value_count:
|
|
356
363
|
yield Validation.warning(
|
|
357
364
|
"ROS.20",
|
|
358
|
-
_("'PrincipalCurrencyUsedInBusinessReport' has a value of %(principal_currency_value)s, "
|
|
365
|
+
_("'PrincipalCurrencyUsedInBusinessReport' has a %(currencies_dimension)s value of %(principal_currency_value)s, "
|
|
359
366
|
"which must match the functional(majority) unit of the financial statement."),
|
|
360
367
|
modelObject=principal_currency_facts,
|
|
368
|
+
currencies_dimension=CURRENCIES_DIMENSION,
|
|
361
369
|
principal_currency_value=principal_currency_value,
|
|
362
370
|
)
|
|
363
371
|
break
|
|
372
|
+
|
|
373
|
+
def _getCurrencyDimensionCode(modelXbrl: ModelXbrl, fact: ModelInlineFact) -> str | None:
|
|
374
|
+
if fact.context is None:
|
|
375
|
+
return None
|
|
376
|
+
for dim, mem in fact.context.qnameDims.items():
|
|
377
|
+
if dim.localName != CURRENCIES_DIMENSION:
|
|
378
|
+
continue
|
|
379
|
+
if mem.xValid < VALID:
|
|
380
|
+
return None
|
|
381
|
+
mem_concept = modelXbrl.qnameConcepts.get(mem.xValue)
|
|
382
|
+
if mem_concept is None:
|
|
383
|
+
return None
|
|
384
|
+
for ref_rel in modelXbrl.relationshipSet(XbrlConst.conceptReference).fromModelObject(mem_concept):
|
|
385
|
+
concept_ref = ref_rel.toModelObject
|
|
386
|
+
uk_ref_ns = None
|
|
387
|
+
for ns in concept_ref.nsmap.values():
|
|
388
|
+
if UK_REF_NS_PATTERN.match(ns):
|
|
389
|
+
uk_ref_ns = ns
|
|
390
|
+
break
|
|
391
|
+
if uk_ref_ns is None:
|
|
392
|
+
continue
|
|
393
|
+
if code := concept_ref.findtext(f"{{{uk_ref_ns}}}Code"):
|
|
394
|
+
return code.strip()
|
|
395
|
+
return None
|