arelle-release 2.37.20__py3-none-any.whl → 2.37.22__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.

Potentially problematic release.


This version of arelle-release might be problematic. Click here for more details.

@@ -6,13 +6,16 @@ from __future__ import annotations
6
6
  from datetime import date
7
7
  import zipfile
8
8
 
9
+ from arelle.ModelDtsObject import ModelLink
9
10
  from arelle.ModelInstanceObject import ModelInlineFact
11
+ from arelle.ModelObject import ModelObject
12
+ from arelle.PrototypeDtsObject import PrototypeObject
10
13
  from arelle.ValidateDuplicateFacts import getDuplicateFactSets
11
14
  from arelle.XmlValidateConst import VALID
12
15
  from collections.abc import Iterable
13
16
  from typing import Any, cast, TYPE_CHECKING
14
17
 
15
- from arelle import XmlUtil
18
+ from arelle import XmlUtil, XbrlConst, ModelDocument
16
19
  from arelle.ValidateXbrl import ValidateXbrl
17
20
  from arelle.typing import TypeGetText
18
21
  from arelle.utils.PluginHooks import ValidationHook
@@ -20,11 +23,16 @@ from arelle.utils.validate.Decorator import validation
20
23
  from arelle.utils.validate.Validation import Validation
21
24
  from arelle.ValidateDuplicateFacts import getHashEquivalentFactGroups, getAspectEqualFacts
22
25
  from arelle.utils.validate.ValidationUtil import etreeIterWithDepth
23
- from ..DisclosureSystems import DISCLOSURE_SYSTEM_NL_INLINE_2024
26
+ from ..DisclosureSystems import (ALL_NL_INLINE_DISCLOSURE_SYSTEMS, NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
27
+ NL_INLINE_GAAP_OTHER_DISCLOSURE_SYSTEMS)
28
+ from ..LinkbaseType import LinkbaseType
24
29
  from ..PluginValidationDataExtension import (PluginValidationDataExtension, ALLOWABLE_LANGUAGES,
25
- DISALLOWED_IXT_NAMESPACES, EFFECTIVE_TAXONOMY_URLS,
26
- MAX_REPORT_PACKAGE_SIZE_MBS, XBRLI_IDENTIFIER_PATTERN,
27
- XBRLI_IDENTIFIER_SCHEMA)
30
+ DEFAULT_MEMBER_ROLE_URI, DISALLOWED_IXT_NAMESPACES,
31
+ EFFECTIVE_KVK_GAAP_IFRS_ENTRYPOINT_FILES,
32
+ EFFECTIVE_KVK_GAAP_OTHER_ENTRYPOINT_FILES,
33
+ MAX_REPORT_PACKAGE_SIZE_MBS, TAXONOMY_URLS_BY_YEAR,
34
+ XBRLI_IDENTIFIER_PATTERN, XBRLI_IDENTIFIER_SCHEMA,
35
+ QN_DOMAIN_ITEM_TYPES)
28
36
 
29
37
  if TYPE_CHECKING:
30
38
  from arelle.ModelXbrl import ModelXbrl
@@ -44,9 +52,7 @@ def _getReportingPeriodDateValue(modelXbrl: ModelXbrl, qname: QName) -> date | N
44
52
 
45
53
  @validation(
46
54
  hook=ValidationHook.XBRL_FINALLY,
47
- disclosureSystems=[
48
- DISCLOSURE_SYSTEM_NL_INLINE_2024
49
- ],
55
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
50
56
  )
51
57
  def rule_nl_kvk_3_1_1_1(
52
58
  pluginData: PluginValidationDataExtension,
@@ -72,9 +78,7 @@ def rule_nl_kvk_3_1_1_1(
72
78
 
73
79
  @validation(
74
80
  hook=ValidationHook.XBRL_FINALLY,
75
- disclosureSystems=[
76
- DISCLOSURE_SYSTEM_NL_INLINE_2024
77
- ],
81
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
78
82
  )
79
83
  def rule_nl_kvk_3_1_1_2(
80
84
  pluginData: PluginValidationDataExtension,
@@ -99,9 +103,7 @@ def rule_nl_kvk_3_1_1_2(
99
103
 
100
104
  @validation(
101
105
  hook=ValidationHook.XBRL_FINALLY,
102
- disclosureSystems=[
103
- DISCLOSURE_SYSTEM_NL_INLINE_2024
104
- ],
106
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
105
107
  )
106
108
  def rule_nl_kvk_3_1_2_1(
107
109
  pluginData: PluginValidationDataExtension,
@@ -123,9 +125,7 @@ def rule_nl_kvk_3_1_2_1(
123
125
 
124
126
  @validation(
125
127
  hook=ValidationHook.XBRL_FINALLY,
126
- disclosureSystems=[
127
- DISCLOSURE_SYSTEM_NL_INLINE_2024
128
- ],
128
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
129
129
  )
130
130
  def rule_nl_kvk_3_1_2_2(
131
131
  pluginData: PluginValidationDataExtension,
@@ -147,9 +147,7 @@ def rule_nl_kvk_3_1_2_2(
147
147
 
148
148
  @validation(
149
149
  hook=ValidationHook.XBRL_FINALLY,
150
- disclosureSystems=[
151
- DISCLOSURE_SYSTEM_NL_INLINE_2024
152
- ],
150
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
153
151
  )
154
152
  def rule_nl_kvk_3_1_3_1 (
155
153
  pluginData: PluginValidationDataExtension,
@@ -171,9 +169,7 @@ def rule_nl_kvk_3_1_3_1 (
171
169
 
172
170
  @validation(
173
171
  hook=ValidationHook.XBRL_FINALLY,
174
- disclosureSystems=[
175
- DISCLOSURE_SYSTEM_NL_INLINE_2024
176
- ],
172
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
177
173
  )
178
174
  def rule_nl_kvk_3_1_3_2 (
179
175
  pluginData: PluginValidationDataExtension,
@@ -195,9 +191,7 @@ def rule_nl_kvk_3_1_3_2 (
195
191
 
196
192
  @validation(
197
193
  hook=ValidationHook.XBRL_FINALLY,
198
- disclosureSystems=[
199
- DISCLOSURE_SYSTEM_NL_INLINE_2024
200
- ],
194
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
201
195
  )
202
196
  def rule_nl_kvk_3_1_4_1 (
203
197
  pluginData: PluginValidationDataExtension,
@@ -220,9 +214,7 @@ def rule_nl_kvk_3_1_4_1 (
220
214
 
221
215
  @validation(
222
216
  hook=ValidationHook.XBRL_FINALLY,
223
- disclosureSystems=[
224
- DISCLOSURE_SYSTEM_NL_INLINE_2024
225
- ],
217
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
226
218
  )
227
219
  def rule_nl_kvk_3_1_4_2 (
228
220
  pluginData: PluginValidationDataExtension,
@@ -249,9 +241,7 @@ def rule_nl_kvk_3_1_4_2 (
249
241
 
250
242
  @validation(
251
243
  hook=ValidationHook.XBRL_FINALLY,
252
- disclosureSystems=[
253
- DISCLOSURE_SYSTEM_NL_INLINE_2024
254
- ],
244
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
255
245
  )
256
246
  def rule_nl_kvk_3_2_1_1 (
257
247
  pluginData: PluginValidationDataExtension,
@@ -276,9 +266,7 @@ def rule_nl_kvk_3_2_1_1 (
276
266
 
277
267
  @validation(
278
268
  hook=ValidationHook.XBRL_FINALLY,
279
- disclosureSystems=[
280
- DISCLOSURE_SYSTEM_NL_INLINE_2024
281
- ],
269
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
282
270
  )
283
271
  def rule_nl_kvk_3_2_3_1 (
284
272
  pluginData: PluginValidationDataExtension,
@@ -304,9 +292,7 @@ def rule_nl_kvk_3_2_3_1 (
304
292
 
305
293
  @validation(
306
294
  hook=ValidationHook.XBRL_FINALLY,
307
- disclosureSystems=[
308
- DISCLOSURE_SYSTEM_NL_INLINE_2024
309
- ],
295
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
310
296
  )
311
297
  def rule_nl_kvk_3_2_4_1 (
312
298
  pluginData: PluginValidationDataExtension,
@@ -334,9 +320,7 @@ def rule_nl_kvk_3_2_4_1 (
334
320
 
335
321
  @validation(
336
322
  hook=ValidationHook.XBRL_FINALLY,
337
- disclosureSystems=[
338
- DISCLOSURE_SYSTEM_NL_INLINE_2024
339
- ],
323
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
340
324
  )
341
325
  def rule_nl_kvk_3_2_4_2 (
342
326
  pluginData: PluginValidationDataExtension,
@@ -364,9 +348,7 @@ def rule_nl_kvk_3_2_4_2 (
364
348
 
365
349
  @validation(
366
350
  hook=ValidationHook.XBRL_FINALLY,
367
- disclosureSystems=[
368
- DISCLOSURE_SYSTEM_NL_INLINE_2024
369
- ],
351
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
370
352
  )
371
353
  def rule_nl_kvk_3_2_7_1 (
372
354
  pluginData: PluginValidationDataExtension,
@@ -393,9 +375,7 @@ def rule_nl_kvk_3_2_7_1 (
393
375
 
394
376
  @validation(
395
377
  hook=ValidationHook.XBRL_FINALLY,
396
- disclosureSystems=[
397
- DISCLOSURE_SYSTEM_NL_INLINE_2024
398
- ],
378
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
399
379
  )
400
380
  def rule_nl_kvk_3_3_1_1 (
401
381
  pluginData: PluginValidationDataExtension,
@@ -416,9 +396,7 @@ def rule_nl_kvk_3_3_1_1 (
416
396
 
417
397
  @validation(
418
398
  hook=ValidationHook.XBRL_FINALLY,
419
- disclosureSystems=[
420
- DISCLOSURE_SYSTEM_NL_INLINE_2024
421
- ],
399
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
422
400
  )
423
401
  def rule_nl_kvk_3_3_1_2 (
424
402
  pluginData: PluginValidationDataExtension,
@@ -440,9 +418,7 @@ def rule_nl_kvk_3_3_1_2 (
440
418
 
441
419
  @validation(
442
420
  hook=ValidationHook.XBRL_FINALLY,
443
- disclosureSystems=[
444
- DISCLOSURE_SYSTEM_NL_INLINE_2024
445
- ],
421
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
446
422
  )
447
423
  def rule_nl_kvk_3_3_1_3 (
448
424
  pluginData: PluginValidationDataExtension,
@@ -466,9 +442,7 @@ def rule_nl_kvk_3_3_1_3 (
466
442
 
467
443
  @validation(
468
444
  hook=ValidationHook.XBRL_FINALLY,
469
- disclosureSystems=[
470
- DISCLOSURE_SYSTEM_NL_INLINE_2024
471
- ],
445
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
472
446
  )
473
447
  def rule_nl_kvk_3_4_1_1 (
474
448
  pluginData: PluginValidationDataExtension,
@@ -490,9 +464,7 @@ def rule_nl_kvk_3_4_1_1 (
490
464
 
491
465
  @validation(
492
466
  hook=ValidationHook.XBRL_FINALLY,
493
- disclosureSystems=[
494
- DISCLOSURE_SYSTEM_NL_INLINE_2024
495
- ],
467
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
496
468
  )
497
469
  def rule_nl_kvk_3_4_1_2 (
498
470
  pluginData: PluginValidationDataExtension,
@@ -514,9 +486,7 @@ def rule_nl_kvk_3_4_1_2 (
514
486
 
515
487
  @validation(
516
488
  hook=ValidationHook.XBRL_FINALLY,
517
- disclosureSystems=[
518
- DISCLOSURE_SYSTEM_NL_INLINE_2024
519
- ],
489
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
520
490
  )
521
491
  def rule_nl_kvk_3_4_1_3 (
522
492
  pluginData: PluginValidationDataExtension,
@@ -532,7 +502,7 @@ def rule_nl_kvk_3_4_1_3 (
532
502
  if len(facts) > 0:
533
503
  yield Validation.error(
534
504
  codes='NL.NL-KVK.3.4.1.3.transformableElementIncludedInHiddenSection',
535
- msg=_('The ix:hidden section should not include elements that are eligible for transformation'
505
+ msg=_('The ix:hidden section should not include elements that are eligible for transformation '
536
506
  'according to the latest recommended Transformation Rules Registry.'),
537
507
  modelObject=facts
538
508
  )
@@ -540,9 +510,7 @@ def rule_nl_kvk_3_4_1_3 (
540
510
 
541
511
  @validation(
542
512
  hook=ValidationHook.XBRL_FINALLY,
543
- disclosureSystems=[
544
- DISCLOSURE_SYSTEM_NL_INLINE_2024
545
- ],
513
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
546
514
  )
547
515
  def rule_nl_kvk_3_4_1_4 (
548
516
  pluginData: PluginValidationDataExtension,
@@ -564,9 +532,7 @@ def rule_nl_kvk_3_4_1_4 (
564
532
 
565
533
  @validation(
566
534
  hook=ValidationHook.XBRL_FINALLY,
567
- disclosureSystems=[
568
- DISCLOSURE_SYSTEM_NL_INLINE_2024
569
- ],
535
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
570
536
  )
571
537
  def rule_nl_kvk_3_4_1_5 (
572
538
  pluginData: PluginValidationDataExtension,
@@ -588,9 +554,7 @@ def rule_nl_kvk_3_4_1_5 (
588
554
 
589
555
  @validation(
590
556
  hook=ValidationHook.XBRL_FINALLY,
591
- disclosureSystems=[
592
- DISCLOSURE_SYSTEM_NL_INLINE_2024
593
- ],
557
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
594
558
  )
595
559
  def rule_nl_kvk_3_4_2_1 (
596
560
  pluginData: PluginValidationDataExtension,
@@ -612,9 +576,7 @@ def rule_nl_kvk_3_4_2_1 (
612
576
 
613
577
  @validation(
614
578
  hook=ValidationHook.XBRL_FINALLY,
615
- disclosureSystems=[
616
- DISCLOSURE_SYSTEM_NL_INLINE_2024
617
- ],
579
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
618
580
  )
619
581
  def rule_nl_kvk_3_5_2_1(
620
582
  pluginData: PluginValidationDataExtension,
@@ -643,9 +605,7 @@ def rule_nl_kvk_3_5_2_1(
643
605
 
644
606
  @validation(
645
607
  hook=ValidationHook.XBRL_FINALLY,
646
- disclosureSystems=[
647
- DISCLOSURE_SYSTEM_NL_INLINE_2024
648
- ],
608
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
649
609
  )
650
610
  def rule_nl_kvk_3_5_2_2(
651
611
  pluginData: PluginValidationDataExtension,
@@ -674,9 +634,7 @@ def rule_nl_kvk_3_5_2_2(
674
634
 
675
635
  @validation(
676
636
  hook=ValidationHook.XBRL_FINALLY,
677
- disclosureSystems=[
678
- DISCLOSURE_SYSTEM_NL_INLINE_2024
679
- ],
637
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
680
638
  )
681
639
  def rule_nl_kvk_3_5_2_3(
682
640
  pluginData: PluginValidationDataExtension,
@@ -705,9 +663,7 @@ def rule_nl_kvk_3_5_2_3(
705
663
 
706
664
  @validation(
707
665
  hook=ValidationHook.XBRL_FINALLY,
708
- disclosureSystems=[
709
- DISCLOSURE_SYSTEM_NL_INLINE_2024
710
- ],
666
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
711
667
  )
712
668
  def rule_nl_kvk_3_5_3_1(
713
669
  pluginData: PluginValidationDataExtension,
@@ -729,9 +685,7 @@ def rule_nl_kvk_3_5_3_1(
729
685
 
730
686
  @validation(
731
687
  hook=ValidationHook.XBRL_FINALLY,
732
- disclosureSystems=[
733
- DISCLOSURE_SYSTEM_NL_INLINE_2024
734
- ],
688
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
735
689
  )
736
690
  def rule_nl_kvk_3_5_4_1 (
737
691
  pluginData: PluginValidationDataExtension,
@@ -754,9 +708,7 @@ def rule_nl_kvk_3_5_4_1 (
754
708
 
755
709
  @validation(
756
710
  hook=ValidationHook.XBRL_FINALLY,
757
- disclosureSystems=[
758
- DISCLOSURE_SYSTEM_NL_INLINE_2024
759
- ],
711
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
760
712
  )
761
713
  def rule_nl_kvk_3_6_3_1(
762
714
  pluginData: PluginValidationDataExtension,
@@ -770,7 +722,7 @@ def rule_nl_kvk_3_6_3_1(
770
722
  """
771
723
  invalidBasenames = []
772
724
  for basename in pluginData.getIxdsDocBasenames(val.modelXbrl):
773
- filenameParts = pluginData.getFilenameParts(basename)
725
+ filenameParts = pluginData.getFilenameParts(basename, pluginData.getFilenameFormatPattern())
774
726
  if not filenameParts:
775
727
  continue # Filename is not formatted correctly enough to determine {base}
776
728
  if len(filenameParts.get('base', '')) > 20:
@@ -787,9 +739,7 @@ def rule_nl_kvk_3_6_3_1(
787
739
 
788
740
  @validation(
789
741
  hook=ValidationHook.XBRL_FINALLY,
790
- disclosureSystems=[
791
- DISCLOSURE_SYSTEM_NL_INLINE_2024
792
- ],
742
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
793
743
  )
794
744
  def rule_nl_kvk_3_6_3_2(
795
745
  pluginData: PluginValidationDataExtension,
@@ -803,7 +753,7 @@ def rule_nl_kvk_3_6_3_2(
803
753
  """
804
754
  invalidBasenames = []
805
755
  for basename in pluginData.getIxdsDocBasenames(val.modelXbrl):
806
- filenameParts = pluginData.getFilenameParts(basename)
756
+ filenameParts = pluginData.getFilenameParts(basename, pluginData.getFilenameFormatPattern())
807
757
  if not filenameParts:
808
758
  invalidBasenames.append(basename)
809
759
  if len(invalidBasenames) > 0:
@@ -819,9 +769,7 @@ def rule_nl_kvk_3_6_3_2(
819
769
 
820
770
  @validation(
821
771
  hook=ValidationHook.XBRL_FINALLY,
822
- disclosureSystems=[
823
- DISCLOSURE_SYSTEM_NL_INLINE_2024
824
- ],
772
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
825
773
  )
826
774
  def rule_nl_kvk_3_6_3_3(
827
775
  pluginData: PluginValidationDataExtension,
@@ -849,9 +797,7 @@ def rule_nl_kvk_3_6_3_3(
849
797
 
850
798
  @validation(
851
799
  hook=ValidationHook.FINALLY,
852
- disclosureSystems=[
853
- DISCLOSURE_SYSTEM_NL_INLINE_2024
854
- ],
800
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
855
801
  )
856
802
  def rule_nl_kvk_3_7_1_1(
857
803
  pluginData: PluginValidationDataExtension,
@@ -879,9 +825,7 @@ def rule_nl_kvk_3_7_1_1(
879
825
 
880
826
  @validation(
881
827
  hook=ValidationHook.FINALLY,
882
- disclosureSystems=[
883
- DISCLOSURE_SYSTEM_NL_INLINE_2024
884
- ],
828
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
885
829
  )
886
830
  def rule_nl_kvk_3_7_1_2(
887
831
  pluginData: PluginValidationDataExtension,
@@ -909,9 +853,93 @@ def rule_nl_kvk_3_7_1_2(
909
853
 
910
854
  @validation(
911
855
  hook=ValidationHook.XBRL_FINALLY,
912
- disclosureSystems=[
913
- DISCLOSURE_SYSTEM_NL_INLINE_2024
914
- ],
856
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
857
+ )
858
+ def rule_nl_kvk_4_1_1_1(
859
+ pluginData: PluginValidationDataExtension,
860
+ val: ValidateXbrl,
861
+ *args: Any,
862
+ **kwargs: Any,
863
+ ) -> Iterable[Validation]:
864
+ """
865
+ NL-KVK.4.1.1.1: Extension taxonomies MUST consist of at least a schema file and presentation,
866
+ calculation and definition linkbases.
867
+ A label linkbase is also required if extension elements are present.
868
+ """
869
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
870
+ linkbaseIsMissing = {
871
+ LinkbaseType.CALCULATION: True,
872
+ LinkbaseType.DEFINITION: True,
873
+ LinkbaseType.LABEL: len(extensionData.extensionConcepts) > 0,
874
+ LinkbaseType.PRESENTATION: True,
875
+ }
876
+ for modelDocument, extensionDocumentData in extensionData.extensionDocuments.items():
877
+ hasArcs = False
878
+ linkbaseType = LinkbaseType.fromRefUri(extensionDocumentData.hrefXlinkRole)
879
+ for linkbaseData in extensionDocumentData.linkbases:
880
+ if linkbaseType is not None:
881
+ if linkbaseType == linkbaseData.linkbaseType:
882
+ if linkbaseData.hasArcs:
883
+ hasArcs = True
884
+ break
885
+ elif linkbaseData.hasArcs:
886
+ linkbaseType = linkbaseData.linkbaseType
887
+ hasArcs = True
888
+ break
889
+ if linkbaseType is None:
890
+ continue
891
+ if hasArcs and linkbaseIsMissing.get(linkbaseType, False):
892
+ linkbaseIsMissing[linkbaseType] = False
893
+ missingFiles = set(linkbaseType.getLowerName() for linkbaseType, isMissing in linkbaseIsMissing.items() if isMissing)
894
+ if len(missingFiles) > 0:
895
+ yield Validation.error(
896
+ codes='NL.NL-KVK.4.1.1.1.extensionTaxonomyWrongFilesStructure',
897
+ msg=_('The extension taxonomy is missing one or more required components: %(missingFiles)s '
898
+ 'Review to ensure that the schema file, presentation, calculation, '
899
+ 'and definition linkbases are included and not empty. '
900
+ 'A label linkbase is also required if extension elements are present.'),
901
+ modelObject=val.modelXbrl, missingFiles=", ".join(missingFiles)
902
+ )
903
+
904
+
905
+ @validation(
906
+ hook=ValidationHook.XBRL_FINALLY,
907
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
908
+ )
909
+ def rule_nl_kvk_4_1_1_2(
910
+ pluginData: PluginValidationDataExtension,
911
+ val: ValidateXbrl,
912
+ *args: Any,
913
+ **kwargs: Any,
914
+ ) -> Iterable[Validation]:
915
+ """
916
+ NL-KVK.4.1.1.2: Each linkbase type MUST be provided in a separate linkbase file.
917
+ """
918
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
919
+ errors = []
920
+ for modelDocument, extensionDocumentData in extensionData.extensionDocuments.items():
921
+ linkbasesFound = set(
922
+ linkbase.linkbaseType.getLowerName()
923
+ for linkbase in extensionDocumentData.linkbases
924
+ if linkbase.linkbaseType is not None
925
+ )
926
+ if len(linkbasesFound) > 1:
927
+ errors.append((modelDocument, linkbasesFound))
928
+ for modelDocument, linkbasesFound in errors:
929
+ yield Validation.error(
930
+ codes='NL.NL-KVK.4.1.1.2.linkbasesNotSeparateFiles',
931
+ msg=_('Linkbase types are not stored in separate files. '
932
+ 'Review linkbase files and ensure they are provided as individual files. '
933
+ 'Found: %(linkbasesFound)s. in %(basename)s.'),
934
+ modelObject=modelDocument.xmlRootElement,
935
+ basename=modelDocument.basename,
936
+ linkbasesFound=", ".join(sorted(linkbasesFound))
937
+ )
938
+
939
+
940
+ @validation(
941
+ hook=ValidationHook.XBRL_FINALLY,
942
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
915
943
  )
916
944
  def rule_nl_kvk_4_1_2_1(
917
945
  pluginData: PluginValidationDataExtension,
@@ -921,24 +949,474 @@ def rule_nl_kvk_4_1_2_1(
921
949
  ) -> Iterable[Validation]:
922
950
  """
923
951
  NL-KVK.4.1.2.1: Validate that the imported taxonomy matches the KVK-specified entry point.
924
- - https://www.nltaxonomie.nl/kvk/2024-12-31/kvk-annual-report-nlgaap-ext.xsd,
925
- - https://www.nltaxonomie.nl/kvk/2024-12-31/kvk-annual-report-ifrs-ext.xsd.
952
+ - https://www.nltaxonomie.nl/kvk/2024-12-31/kvk-annual-report-nlgaap-ext.xsd
953
+ - https://www.nltaxonomie.nl/kvk/2024-12-31/kvk-annual-report-ifrs-ext.xsd
954
+ """
955
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
956
+ matches = extensionData.extensionImportedUrls & EFFECTIVE_KVK_GAAP_IFRS_ENTRYPOINT_FILES
957
+ if not matches:
958
+ yield Validation.error(
959
+ codes='NL.NL-KVK.4.1.2.1.requiredEntryPointNotImported',
960
+ msg=_('The extension taxonomy must import the entry point of the taxonomy files prepared by KVK.'),
961
+ modelObject=val.modelXbrl.modelDocument
962
+ )
963
+
964
+
965
+ @validation(
966
+ hook=ValidationHook.XBRL_FINALLY,
967
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
968
+ )
969
+ def rule_nl_kvk_4_1_2_2(
970
+ pluginData: PluginValidationDataExtension,
971
+ val: ValidateXbrl,
972
+ *args: Any,
973
+ **kwargs: Any,
974
+ ) -> Iterable[Validation]:
975
+ """
976
+ NL-KVK.4.1.2.2: The legal entity’s extension taxonomy MUST import the applicable version of
977
+ the taxonomy files prepared by KVK.
978
+ """
979
+ reportingPeriod = pluginData.getReportingPeriod(val.modelXbrl)
980
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
981
+ matches = extensionData.extensionImportedUrls & TAXONOMY_URLS_BY_YEAR.get(reportingPeriod or '', set())
982
+ if not reportingPeriod or not matches:
983
+ yield Validation.error(
984
+ codes='NL.NL-KVK.4.1.2.2.incorrectKvkTaxonomyVersionUsed',
985
+ msg=_('The extension taxonomy MUST import the applicable version of the taxonomy files prepared by KVK '
986
+ 'for the reported financial reporting period. Verify the taxonomy version and make sure '
987
+ 'that FinancialReportingPeriod are tagged correctly.'),
988
+ modelObject=val.modelXbrl.modelDocument
989
+ )
990
+
991
+
992
+ @validation(
993
+ hook=ValidationHook.XBRL_FINALLY,
994
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
995
+ )
996
+ def rule_nl_kvk_4_1_5_1(
997
+ pluginData: PluginValidationDataExtension,
998
+ val: ValidateXbrl,
999
+ *args: Any,
1000
+ **kwargs: Any,
1001
+ ) -> Iterable[Validation]:
1002
+ """
1003
+ NL-KVK.4.1.5.1: The `{base}` component of the extension document filename SHOULD not exceed twenty characters.
1004
+ """
1005
+ invalidBasenames = []
1006
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
1007
+ for extensionDocument in extensionData.extensionDocuments.values():
1008
+ basename = extensionDocument.basename
1009
+ filenameParts = pluginData.getFilenameParts(basename, pluginData.getExtensionFilenameFormatPattern())
1010
+ if not filenameParts:
1011
+ continue # Filename is not formatted correctly enough to determine {base}
1012
+ if len(filenameParts.get('base', '')) > 20:
1013
+ invalidBasenames.append(basename)
1014
+ if len(invalidBasenames) > 0:
1015
+ yield Validation.warning(
1016
+ codes='NL.NL-KVK.4.1.5.1.baseComponentInNameOfTaxonomyFileExceedsTwentyCharacters',
1017
+ invalidBasenames=', '.join(invalidBasenames),
1018
+ msg=_('The {base} component of the extension document filename is greater than twenty characters. '
1019
+ 'The {base} component can either be the KVK number or the legal entity\'s name. '
1020
+ 'If the legal entity\'s name has been utilized, review to shorten the name to twenty characters or less. '
1021
+ 'Invalid filenames: %(invalidBasenames)s'))
1022
+
1023
+
1024
+ @validation(
1025
+ hook=ValidationHook.XBRL_FINALLY,
1026
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
1027
+ )
1028
+ def rule_nl_kvk_4_1_5_2(
1029
+ pluginData: PluginValidationDataExtension,
1030
+ val: ValidateXbrl,
1031
+ *args: Any,
1032
+ **kwargs: Any,
1033
+ ) -> Iterable[Validation]:
1034
+ """
1035
+ NL-KVK.4.1.5.2: Extension document filename SHOULD match the {base}-{date}_{suffix}-{lang}.{extension} pattern.
1036
+ """
1037
+ invalidBasenames = []
1038
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
1039
+ for extensionDocument in extensionData.extensionDocuments.values():
1040
+ basename = extensionDocument.basename
1041
+ filenameParts = pluginData.getFilenameParts(basename, pluginData.getExtensionFilenameFormatPattern())
1042
+ if not filenameParts:
1043
+ invalidBasenames.append(basename)
1044
+ if len(invalidBasenames) > 0:
1045
+ yield Validation.warning(
1046
+ codes='NL.NL-KVK.4.1.5.2.extensionTaxonomyDocumentNameDoesNotFollowNamingConvention',
1047
+ invalidBasenames=', '.join(invalidBasenames),
1048
+ msg=_('The extension document filename does not match the naming convention outlined by the KVK. '
1049
+ 'It is recommended to be in the {base}-{date}_{suffix}-{lang}.{extension} format. '
1050
+ '{extension} must be one of the following: html, htm, xhtml. '
1051
+ 'Review formatting and update as appropriate. '
1052
+ 'Invalid filenames: %(invalidBasenames)s'))
1053
+
1054
+
1055
+ @validation(
1056
+ hook=ValidationHook.XBRL_FINALLY,
1057
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
1058
+ )
1059
+ def rule_nl_kvk_4_2_0_1(
1060
+ pluginData: PluginValidationDataExtension,
1061
+ val: ValidateXbrl,
1062
+ *args: Any,
1063
+ **kwargs: Any,
1064
+ ) -> Iterable[Validation]:
926
1065
  """
927
- if val.modelXbrl.modelDocument is not None:
928
- pluginData.checkFilingDTS(val, val.modelXbrl.modelDocument, [])
929
- if not any(e in val.extensionImportedUrls for e in EFFECTIVE_TAXONOMY_URLS):
1066
+ NL-KVK.4.2.0.1: Tuples MUST NOT be defined in extension taxonomy.
1067
+ """
1068
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
1069
+ tupleConcepts = [
1070
+ concept for concept in extensionData.extensionConcepts if concept.isTuple
1071
+ ]
1072
+ if len(tupleConcepts) > 0:
1073
+ yield Validation.error(
1074
+ codes='NL.NL-KVK.4.2.0.1.tupleElementUsed',
1075
+ modelObject=tupleConcepts,
1076
+ msg=_('The extension taxonomy must not define tuple concepts.'))
1077
+
1078
+
1079
+ @validation(
1080
+ hook=ValidationHook.XBRL_FINALLY,
1081
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
1082
+ )
1083
+ def rule_nl_kvk_4_2_0_2(
1084
+ pluginData: PluginValidationDataExtension,
1085
+ val: ValidateXbrl,
1086
+ *args: Any,
1087
+ **kwargs: Any,
1088
+ ) -> Iterable[Validation]:
1089
+ """
1090
+ NL-KVK.4.2.0.2: Items with xbrli:fractionItemType data type MUST NOT be defined in extension taxonomy
1091
+ """
1092
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
1093
+ fractionConcepts = [
1094
+ concept for concept in extensionData.extensionConcepts if concept.isFraction
1095
+ ]
1096
+ if len(fractionConcepts) > 0:
1097
+ yield Validation.error(
1098
+ codes='NL.NL-KVK.4.2.0.2.fractionElementUsed',
1099
+ modelObject=fractionConcepts,
1100
+ msg=_('The extension taxonomy must not define fraction concepts.'))
1101
+
1102
+
1103
+ @validation(
1104
+ hook=ValidationHook.XBRL_FINALLY,
1105
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
1106
+ )
1107
+ def rule_nl_kvk_4_2_1_1(
1108
+ pluginData: PluginValidationDataExtension,
1109
+ val: ValidateXbrl,
1110
+ *args: Any,
1111
+ **kwargs: Any,
1112
+ ) -> Iterable[Validation]:
1113
+ """
1114
+ NL-KVK.4.2.1.1: Extension taxonomy MUST set xbrli:scenario as context element on definition arcs with
1115
+ http://xbrl.org/int/dim/arcrole/all and http://xbrl.org/int/dim/arcrole/notAll arcroles.
1116
+ """
1117
+ errors = []
1118
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
1119
+ for modelDocument, extensionDocumentData in extensionData.extensionDocuments.items():
1120
+ for arc in extensionDocumentData.iterArcsByType(LinkbaseType.DEFINITION, includeArcroles={XbrlConst.all, XbrlConst.notAll}):
1121
+ if arc.get(XbrlConst.qnXbrldtContextElement.clarkNotation) != "scenario":
1122
+ errors.append(arc)
1123
+ if len(errors) > 0:
1124
+ yield Validation.error(
1125
+ codes='NL.NL-KVK.4.2.1.1.scenarioNotUsedInExtensionTaxonomy',
1126
+ modelObject=errors,
1127
+ msg=_('The definition linkbase is missing xbrli:scenario in extension taxonomy. '
1128
+ 'Review definition linkbase and update as appropriate.'),
1129
+ )
1130
+
1131
+
1132
+ @validation(
1133
+ hook=ValidationHook.XBRL_FINALLY,
1134
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
1135
+ )
1136
+ def rule_nl_kvk_4_2_2_2(
1137
+ pluginData: PluginValidationDataExtension,
1138
+ val: ValidateXbrl,
1139
+ *args: Any,
1140
+ **kwargs: Any,
1141
+ ) -> Iterable[Validation]:
1142
+ """
1143
+ NL-KVK.4.2.2.2: Domain members MUST have domainItemType data type as defined in https://www.xbrl.org/dtr/type/2022-03-31/types.xsd.
1144
+ """
1145
+ domainMembersWrongType = []
1146
+ domainMembers = pluginData.getDomainMembers(val.modelXbrl)
1147
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
1148
+ for concept in extensionData.extensionConcepts:
1149
+ if concept.isDomainMember and concept in domainMembers and concept.typeQname not in QN_DOMAIN_ITEM_TYPES:
1150
+ domainMembersWrongType.append(concept)
1151
+ if len(domainMembersWrongType) > 0:
1152
+ yield Validation.error(
1153
+ codes='NL.NL-KVK.4.2.2.2.domainMemberWrongDataType',
1154
+ modelObject=domainMembersWrongType,
1155
+ msg=_('Domain members must have domainItemType data type as defined in "https://www.xbrl.org/dtr/type/2022-03-31/types.xsd".'
1156
+ 'Update to follow appropriate Data Type Registry. '))
1157
+
1158
+
1159
+ @validation(
1160
+ hook=ValidationHook.XBRL_FINALLY,
1161
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
1162
+ )
1163
+ def rule_nl_kvk_4_2_3_1(
1164
+ pluginData: PluginValidationDataExtension,
1165
+ val: ValidateXbrl,
1166
+ *args: Any,
1167
+ **kwargs: Any,
1168
+ ) -> Iterable[Validation]:
1169
+ """
1170
+ NL-KVK.4.2.3.1: Extension taxonomy MUST NOT define typed dimensions.
1171
+ """
1172
+ typedDims = []
1173
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
1174
+ for concept in extensionData.extensionConcepts:
1175
+ if concept.isTypedDimension:
1176
+ typedDims.append(concept)
1177
+ if len(typedDims) > 0:
1178
+ yield Validation.error(
1179
+ codes='NL.NL-KVK.4.3.2.1.typedDimensionDefinitionInExtensionTaxonomy',
1180
+ modelObject=typedDims,
1181
+ msg=_('Typed dimensions are not allowed in the extension taxonomy. Update to remove the typed dimension.'))
1182
+
1183
+
1184
+ @validation(
1185
+ hook=ValidationHook.XBRL_FINALLY,
1186
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
1187
+ )
1188
+ def rule_nl_kvk_4_4_1_1(
1189
+ pluginData: PluginValidationDataExtension,
1190
+ val: ValidateXbrl,
1191
+ *args: Any,
1192
+ **kwargs: Any,
1193
+ ) -> Iterable[Validation]:
1194
+ """
1195
+ NL-KVK.4.4.1.1: Arithmetical relationships defined in the calculation linkbase of an extension taxonomy
1196
+ MUST use the https://xbrl.org/2023/arcrole/summation-item arcrole as defined in Calculation 1.1 specification.
1197
+ """
1198
+ errors = []
1199
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
1200
+ for modelDocument, extensionDocumentData in extensionData.extensionDocuments.items():
1201
+ for arc in extensionDocumentData.iterArcsByType(LinkbaseType.CALCULATION, excludeArcroles={XbrlConst.summationItem11}):
1202
+ errors.append(arc)
1203
+ if len(errors) > 0:
1204
+ yield Validation.error(
1205
+ codes='NL.NL-KVK.4.4.1.1.incorrectSummationItemArcroleUsed',
1206
+ modelObject=errors,
1207
+ msg=_('Calculation relationships should follow the requirements of the Calculation 1.1 specification. '
1208
+ 'Update to ensure use of summation-item arcrole in the calculation linkbase.'),
1209
+ )
1210
+
1211
+
1212
+ @validation(
1213
+ hook=ValidationHook.XBRL_FINALLY,
1214
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
1215
+ )
1216
+ def rule_nl_kvk_4_4_2_1(
1217
+ pluginData: PluginValidationDataExtension,
1218
+ val: ValidateXbrl,
1219
+ *args: Any,
1220
+ **kwargs: Any,
1221
+ ) -> Iterable[Validation]:
1222
+ """
1223
+ NL-KVK.4.4.2.1: Extension taxonomies MUST NOT define definition arcs
1224
+ with http://xbrl.org/int/dim/arcrole/notAll arcrole.
1225
+ """
1226
+ errors = []
1227
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
1228
+ for modelDocument, extensionDocumentData in extensionData.extensionDocuments.items():
1229
+ for arc in extensionDocumentData.iterArcsByType(LinkbaseType.DEFINITION, includeArcroles={XbrlConst.notAll}):
1230
+ errors.append(arc)
1231
+ if len(errors) > 0:
1232
+ yield Validation.error(
1233
+ codes='NL.NL-KVK.4.4.2.1.notAllArcroleUsedInDefinitionLinkbase',
1234
+ modelObject=errors,
1235
+ msg=_('Incorrect hypercube settings are found. Ensure that positive hypercubes are in use.'),
1236
+ )
1237
+
1238
+
1239
+ @validation(
1240
+ hook=ValidationHook.XBRL_FINALLY,
1241
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
1242
+ )
1243
+ def rule_nl_kvk_4_4_2_2(
1244
+ pluginData: PluginValidationDataExtension,
1245
+ val: ValidateXbrl,
1246
+ *args: Any,
1247
+ **kwargs: Any,
1248
+ ) -> Iterable[Validation]:
1249
+ """
1250
+ NL-KVK.4.4.2.2: Hypercubes appearing as target of definition arc with
1251
+ http://xbrl.org/int/dim/arcrole/all arcrole MUST have xbrldt:closed attribute set to “true”.
1252
+ """
1253
+ errors = []
1254
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
1255
+ for modelDocument, extensionDocumentData in extensionData.extensionDocuments.items():
1256
+ for arc in extensionDocumentData.iterArcsByType(LinkbaseType.DEFINITION, includeArcroles={XbrlConst.all}):
1257
+ if arc.get(XbrlConst.qnXbrldtClosed.clarkNotation, "false") != "true":
1258
+ errors.append(arc)
1259
+ if len(errors) > 0:
1260
+ yield Validation.error(
1261
+ codes='NL.NL-KVK.4.4.2.2.openPositiveHypercubeInDefinitionLinkbase',
1262
+ modelObject=errors,
1263
+ msg=_('Incorrect hypercube settings are found. Ensure that positive hypercubes are closed.'),
1264
+ )
1265
+
1266
+
1267
+ @validation(
1268
+ hook=ValidationHook.XBRL_FINALLY,
1269
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
1270
+ )
1271
+ def rule_nl_kvk_4_4_2_3(
1272
+ pluginData: PluginValidationDataExtension,
1273
+ val: ValidateXbrl,
1274
+ *args: Any,
1275
+ **kwargs: Any,
1276
+ ) -> Iterable[Validation]:
1277
+ """
1278
+ NL-KVK.4.4.2.3: Hypercubes appearing as target of definition arc with
1279
+ http://xbrl.org/int/dim/arcrole/notAll arcrole MUST have xbrldt:closed attribute set to “false”.
1280
+ """
1281
+ errors = []
1282
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
1283
+ for modelDocument, extensionDocumentData in extensionData.extensionDocuments.items():
1284
+ for arc in extensionDocumentData.iterArcsByType(LinkbaseType.DEFINITION, includeArcroles={XbrlConst.notAll}):
1285
+ if arc.get(XbrlConst.qnXbrldtClosed.clarkNotation, "true") != "false":
1286
+ errors.append(arc)
1287
+ if len(errors) > 0:
1288
+ yield Validation.error(
1289
+ codes='NL.NL-KVK.4.4.2.3.closedNegativeHypercubeInDefinitionLinkbase',
1290
+ modelObject=errors,
1291
+ msg=_('Incorrect hypercube settings are found. Ensure that negative hypercubes are not closed.'),
1292
+ )
1293
+
1294
+
1295
+ @validation(
1296
+ hook=ValidationHook.XBRL_FINALLY,
1297
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
1298
+ )
1299
+ def rule_nl_kvk_4_4_3_1(
1300
+ pluginData: PluginValidationDataExtension,
1301
+ val: ValidateXbrl,
1302
+ *args: Any,
1303
+ **kwargs: Any,
1304
+ ) -> Iterable[Validation]:
1305
+ """
1306
+ NL-KVK.4.4.3.1: The extension taxonomy MUST not modify (prohibit and/or override) default members assigned to dimensions by the KVK taxonomy
1307
+ """
1308
+ for modelLink in cast(list[ModelLink], val.modelXbrl.baseSets[XbrlConst.dimensionDefault, None, None, None]):
1309
+ if not pluginData.isExtensionUri(modelLink.modelDocument.uri, val.modelXbrl):
1310
+ continue
1311
+ for linkChild in modelLink:
1312
+ if (
1313
+ isinstance(linkChild,(ModelObject,PrototypeObject))
1314
+ and linkChild.get(XbrlConst.qnXlinkType.clarkNotation) == "arc"
1315
+ and linkChild.get(XbrlConst.qnXlinkArcRole.clarkNotation) == XbrlConst.dimensionDefault
1316
+ ):
1317
+ fromLabel = linkChild.get(XbrlConst.qnXlinkFrom.clarkNotation)
1318
+ for fromResource in modelLink.labeledResources[fromLabel]:
1319
+ if not pluginData.isExtensionUri(fromResource.modelDocument.uri, val.modelXbrl):
1320
+ yield Validation.error(
1321
+ codes='NL.NL-KVK.4.4.3.1.extensionTaxonomyOverridesDefaultMembers',
1322
+ msg=_('A default member does not match the default member settings of the taxonomy. '
1323
+ 'Update the default member to taxonomy defaults.'
1324
+ ),
1325
+ modelObject=linkChild
1326
+ )
1327
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
1328
+ for modelDocument, extensionDocumentData in extensionData.extensionDocuments.items():
1329
+ for arc in extensionDocumentData.iterArcsByType(LinkbaseType.DEFINITION, includeArcroles={XbrlConst.dimensionDefault}):
1330
+ if arc.get("use") == "prohibited":
1331
+ yield Validation.error(
1332
+ codes='NL.NL-KVK.4.4.3.1.extensionTaxonomyOverridesDefaultMembers',
1333
+ msg=_('A default member is forbidden in the extension taxonomy. '
1334
+ 'Update the default member to taxonomy defaults.'
1335
+ ),
1336
+ modelObject=arc
1337
+ )
1338
+
1339
+
1340
+ @validation(
1341
+ hook=ValidationHook.XBRL_FINALLY,
1342
+ disclosureSystems=NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS,
1343
+ )
1344
+ def rule_nl_kvk_4_4_3_2(
1345
+ pluginData: PluginValidationDataExtension,
1346
+ val: ValidateXbrl,
1347
+ *args: Any,
1348
+ **kwargs: Any,
1349
+ ) -> Iterable[Validation]:
1350
+ """
1351
+ NL-KVK.4.4.3.2: Each dimension in an extension taxonomy MUST be assigned to a default member in the ELR with role URI https://www.nltaxonomie.nl/kvk/role/axis-defaults.
1352
+ """
1353
+ dimensionDefaults =val.modelXbrl.relationshipSet(XbrlConst.dimensionDefault, DEFAULT_MEMBER_ROLE_URI)
1354
+ extensionData = pluginData.getExtensionData(val.modelXbrl)
1355
+ for modelConcept in extensionData.extensionConcepts:
1356
+ if modelConcept.isExplicitDimension and not dimensionDefaults.fromModelObject(modelConcept):
930
1357
  yield Validation.error(
931
- codes='NL.NL-KVK.4.1.2.1.requiredEntryPointNotImported',
932
- msg=_('The extension taxonomy must import the entry point of the taxonomy files prepared by KVK.'),
933
- modelObject=val.modelXbrl.modelDocument
1358
+ codes='NL.NL-KVK.4.4.2.3.extensionTaxonomyDimensionNotAssignedDefaultMemberInDedicatedPlaceholder',
1359
+ modelObject=modelConcept,
1360
+ msg=_('Axis is missing a default member or the default member does not match the taxonomy defaults. '
1361
+ 'Update to set default member based on taxonomy defaults.'
1362
+ ),
934
1363
  )
935
1364
 
936
1365
 
937
1366
  @validation(
938
1367
  hook=ValidationHook.XBRL_FINALLY,
939
- disclosureSystems=[
940
- DISCLOSURE_SYSTEM_NL_INLINE_2024
941
- ],
1368
+ disclosureSystems=NL_INLINE_GAAP_OTHER_DISCLOSURE_SYSTEMS,
1369
+ )
1370
+ def rule_nl_kvk_5_1_3_1(
1371
+ pluginData: PluginValidationDataExtension,
1372
+ val: ValidateXbrl,
1373
+ *args: Any,
1374
+ **kwargs: Any,
1375
+ ) -> Iterable[Validation]:
1376
+ """
1377
+ NL-KVK.5.1.3.1: Validate that the imported taxonomy matches the KVK-specified entry point.
1378
+ - https://www.nltaxonomie.nl/kvk/2024-12-31/kvk-annual-report-other-gaap.xsd
1379
+ """
1380
+ uris = {doc[0].uri for doc in val.modelXbrl.namespaceDocs.values()}
1381
+ matches = uris & EFFECTIVE_KVK_GAAP_OTHER_ENTRYPOINT_FILES
1382
+ if not matches:
1383
+ yield Validation.error(
1384
+ codes='NL.NL-KVK.5.1.3.1.requiredEntryPointOtherGaapNotReferenced',
1385
+ msg=_('The extension taxonomy must import the entry point of the taxonomy files prepared by KVK.'),
1386
+ modelObject=val.modelXbrl.modelDocument
1387
+ )
1388
+
1389
+
1390
+ @validation(
1391
+ hook=ValidationHook.XBRL_FINALLY,
1392
+ disclosureSystems=NL_INLINE_GAAP_OTHER_DISCLOSURE_SYSTEMS,
1393
+ )
1394
+ def rule_nl_kvk_5_1_3_2(
1395
+ pluginData: PluginValidationDataExtension,
1396
+ val: ValidateXbrl,
1397
+ *args: Any,
1398
+ **kwargs: Any,
1399
+ ) -> Iterable[Validation]:
1400
+ """
1401
+ NL-KVK.5.1.3.2: The legal entity’s report MUST import the applicable version of
1402
+ the taxonomy files prepared by KVK.
1403
+ """
1404
+ reportingPeriod = pluginData.getReportingPeriod(val.modelXbrl)
1405
+ uris = {doc[0].uri for doc in val.modelXbrl.namespaceDocs.values()}
1406
+ matches = uris & TAXONOMY_URLS_BY_YEAR.get(reportingPeriod or '', set())
1407
+ if not reportingPeriod or not matches:
1408
+ yield Validation.error(
1409
+ codes='NL.NL-KVK.5.1.3.2.incorrectVersionEntryPointOtherGaapReferenced',
1410
+ msg=_('The report MUST import the applicable version of the taxonomy files prepared by KVK '
1411
+ 'for the reported financial reporting period. Verify the taxonomy version and make sure '
1412
+ 'that FinancialReportingPeriod are tagged correctly.'),
1413
+ modelObject=val.modelXbrl.modelDocument
1414
+ )
1415
+
1416
+
1417
+ @validation(
1418
+ hook=ValidationHook.XBRL_FINALLY,
1419
+ disclosureSystems=ALL_NL_INLINE_DISCLOSURE_SYSTEMS,
942
1420
  )
943
1421
  def rule_nl_kvk_6_1_1_1(
944
1422
  pluginData: PluginValidationDataExtension,