cbpr-usage-rules 0.1.0__tar.gz → 0.1.2__tar.gz

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.
Files changed (55) hide show
  1. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/CHANGELOG.md +16 -1
  2. {cbpr_usage_rules-0.1.0/src/cbpr_usage_rules.egg-info → cbpr_usage_rules-0.1.2}/PKG-INFO +2 -2
  3. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/README.md +1 -1
  4. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/__init__.py +1 -1
  5. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/registry.py +47 -1
  6. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/camt_052.py +1 -6
  7. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/camt_054.py +1 -5
  8. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_002.py +1 -5
  9. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_004.py +1 -8
  10. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_009.py +1 -5
  11. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pain_001.py +1 -15
  12. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/camt_052.py +0 -5
  13. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/camt_054.py +1 -5
  14. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_004.py +1 -8
  15. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_008.py +1 -5
  16. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_008_stp.py +1 -5
  17. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2/src/cbpr_usage_rules.egg-info}/PKG-INFO +2 -2
  18. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/LICENSE +0 -0
  19. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/MANIFEST.in +0 -0
  20. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/pyproject.toml +0 -0
  21. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/setup.cfg +0 -0
  22. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/cli.py +0 -0
  23. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/engine.py +0 -0
  24. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/helpers.py +0 -0
  25. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/loader.py +0 -0
  26. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/message.py +0 -0
  27. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/models.py +0 -0
  28. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/py.typed +0 -0
  29. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/reference/__init__.py +0 -0
  30. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/reference/countries.py +0 -0
  31. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/reference/currencies.py +0 -0
  32. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/__init__.py +0 -0
  33. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/__init__.py +0 -0
  34. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_008.py +0 -0
  35. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_008_stp.py +0 -0
  36. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_009_adv.py +0 -0
  37. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_009_cov.py +0 -0
  38. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/__init__.py +0 -0
  39. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_002.py +0 -0
  40. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_009.py +0 -0
  41. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_009_adv.py +0 -0
  42. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_009_cov.py +0 -0
  43. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pain_001.py +0 -0
  44. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/schema.py +0 -0
  45. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/validators/__init__.py +0 -0
  46. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/validators/bic.py +0 -0
  47. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/validators/country.py +0 -0
  48. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/validators/currency.py +0 -0
  49. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/validators/iban.py +0 -0
  50. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/validators/lei.py +0 -0
  51. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_usage_rules.egg-info/SOURCES.txt +0 -0
  52. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_usage_rules.egg-info/dependency_links.txt +0 -0
  53. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_usage_rules.egg-info/entry_points.txt +0 -0
  54. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_usage_rules.egg-info/requires.txt +0 -0
  55. {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_usage_rules.egg-info/top_level.txt +0 -0
@@ -4,7 +4,22 @@ All notable changes to this project are documented here. The format is based on
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres
5
5
  to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased]
7
+ ## [0.1.2]
8
+
9
+ ### Changed
10
+ - LEI validation is now a single universal `VAL-LEI` rule (every `<LEI>` element,
11
+ all message types), replacing the per-module `VAL-LEI` checks that were missing
12
+ for several message types (e.g. pacs.008 2025) and scoped to specific party
13
+ paths where present. Malformed LEIs in any party position are now caught
14
+ consistently. `VAL-IBAN` and `VAL-LEI` share one document-wide implementation.
15
+
16
+ ## [0.1.1]
17
+
18
+ ### Fixed
19
+ - IBAN values are now actually validated. The `is_valid_iban` algorithm existed
20
+ but was wired into no rule, so malformed IBANs passed silently. A universal
21
+ `VAL-IBAN` check now validates every `<IBAN>` element (mod-97 / ISO 7064)
22
+ across all message types.
8
23
 
9
24
  ### Added
10
25
  - Initial package: validation engine, wrapper-tolerant loader, public API
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cbpr-usage-rules
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Validate ISO 20022 CBPR+ XML messages against SWIFT usage (business) rules.
5
5
  Author: Pete Houghton
6
6
  License: MIT License
@@ -141,7 +141,7 @@ Both `validate_file` and `validate_string` return a dictionary:
141
141
  "message_type": "pacs.008", # the rule set that was applied
142
142
  "detected_message_type": "pacs.008",# auto-detected from the Document namespace
143
143
  "year": 2025,
144
- "rules_evaluated": 84,
144
+ "rules_evaluated": 86,
145
145
  "violations": [
146
146
  {
147
147
  "rule_number": "pacs.008:R41", # unique within the message type
@@ -86,7 +86,7 @@ Both `validate_file` and `validate_string` return a dictionary:
86
86
  "message_type": "pacs.008", # the rule set that was applied
87
87
  "detected_message_type": "pacs.008",# auto-detected from the Document namespace
88
88
  "year": 2025,
89
- "rules_evaluated": 84,
89
+ "rules_evaluated": 86,
90
90
  "violations": [
91
91
  {
92
92
  "rule_number": "pacs.008:R41", # unique within the message type
@@ -4,7 +4,7 @@ This package is AI generated. See the README for details and caveats.
4
4
  """
5
5
  from __future__ import annotations
6
6
 
7
- __version__ = "0.1.0"
7
+ __version__ = "0.1.2"
8
8
 
9
9
  from .models import Rule, Severity, Violation
10
10
  from .engine import validate_file, validate_string, list_rules, available
@@ -11,6 +11,7 @@ import pkgutil
11
11
  from typing import Callable, Dict, List, Tuple
12
12
 
13
13
  from .models import Rule, Severity, Violation
14
+ from .validators import is_valid_iban, is_valid_lei
14
15
 
15
16
  # (year, message_type) -> list[Rule]
16
17
  _REGISTRY: Dict[Tuple[int, str], List[Rule]] = {}
@@ -97,9 +98,54 @@ def _discover(year: int) -> None:
97
98
  _LOADED.add(year)
98
99
 
99
100
 
101
+ # Cross-cutting datatype validations applied to every message type. In ISO 20022
102
+ # these elements are self-validating datatypes wherever they appear, so a single
103
+ # document-wide scan covers all message types (and all party positions - Debtor,
104
+ # Creditor, Agent, Intermediary) correctly:
105
+ # <IBAN> is IBAN2007Identifier (ISO 7064 mod-97);
106
+ # <LEI> is LEIIdentifier (ISO 17442, 18 alphanumerics + 2 ISO 7064 check digits).
107
+ # (number, element, validator, name, description)
108
+ _UNIVERSAL = [
109
+ ("VAL-IBAN", "IBAN", is_valid_iban, "CBPR_Valid_IBAN",
110
+ "Every IBAN must be structurally valid and pass the ISO 7064 mod-97 check."),
111
+ ("VAL-LEI", "LEI", is_valid_lei, "CBPR_Valid_LEI",
112
+ "Every LEI must be a structurally valid ISO 17442 identifier with correct check digits."),
113
+ ]
114
+
115
+
116
+ def _universal_rules(msgtype: str) -> List[Rule]:
117
+ """Build the cross-cutting datatype rules (IBAN, LEI) for a message type."""
118
+ rules: List[Rule] = []
119
+ for number, element, validator, name, description in _UNIVERSAL:
120
+ rule_id = f"{msgtype}:{number}"
121
+
122
+ def check(msg, _el=element, _val=validator, _id=rule_id, _name=name, _desc=description):
123
+ out: List[Violation] = []
124
+ for el in msg.iter_local(_el):
125
+ value = msg.text_of(el)
126
+ if value and not _val(value):
127
+ out.append(
128
+ Violation(
129
+ rule_number=_id,
130
+ name=_name,
131
+ description=_desc,
132
+ detail=f"invalid {_el}: '{value}'",
133
+ found=msg.snippet_of(el),
134
+ xpath=msg.xpath_of(el),
135
+ line=msg.line_of(el),
136
+ )
137
+ )
138
+ return out
139
+
140
+ rules.append(Rule(rule_id, name, description, Severity.VIOLATION, check))
141
+ return rules
142
+
143
+
100
144
  def load_rules(year: int, msgtype: str) -> List[Rule]:
101
145
  _discover(int(year))
102
- return list(_REGISTRY.get(_key(year, msgtype), []))
146
+ rules = list(_REGISTRY.get(_key(year, msgtype), []))
147
+ rules.extend(_universal_rules(msgtype))
148
+ return rules
103
149
 
104
150
 
105
151
  def available_message_types(year: int) -> List[str]:
@@ -11,7 +11,7 @@ rules are surfaced as advisory guidance. Algorithmic field validations
11
11
  from __future__ import annotations
12
12
 
13
13
  from ...registry import advisory, rule
14
- from ...validators import is_valid_bic, is_valid_country, is_valid_currency, is_valid_lei
14
+ from ...validators import is_valid_bic, is_valid_country, is_valid_currency
15
15
  from ...helpers import (
16
16
  amount_equals_sum,
17
17
  business_msg_id_carries_group_id,
@@ -117,11 +117,6 @@ reg("VAL-BIC", "CBPR_Valid_Agent_BIC",
117
117
  _val_bic)
118
118
 
119
119
 
120
- reg("VAL-LEI", "CBPR_Valid_LEI",
121
- "Account Owner / Account Servicer LEI must be a structurally valid ISO 17442 LEI.",
122
- each_value_valid(RPT + "/Acct/Svcr/FinInstnId/LEI", is_valid_lei, "LEI"))
123
-
124
-
125
120
  def _val_ctry(msg, report):
126
121
  for node in msg.find(RPT + "/Acct/Svcr/FinInstnId/PstlAdr/Ctry"):
127
122
  val = msg.text_of(node)
@@ -8,7 +8,7 @@ mechanizable textual rules are enforced, the rest are surfaced as advisories.
8
8
  from __future__ import annotations
9
9
 
10
10
  from ...registry import advisory, rule
11
- from ...validators import is_valid_bic, is_valid_country, is_valid_currency, is_valid_lei
11
+ from ...validators import is_valid_bic, is_valid_country, is_valid_currency
12
12
  from ...helpers import (
13
13
  business_msg_id_carries_group_id,
14
14
  code_in,
@@ -88,10 +88,6 @@ reg("VAL-BIC", "CBPR_Valid_Account_Servicer_BIC",
88
88
  "Account Servicer BICFI must be a structurally valid BIC.",
89
89
  each_value_valid(NTFCTN + "/Acct/Svcr/FinInstnId/BICFI", is_valid_bic, "BIC"))
90
90
 
91
- reg("VAL-LEI", "CBPR_Valid_Account_Servicer_LEI",
92
- "Account Servicer LEI must be a structurally valid LEI.",
93
- each_value_valid(NTFCTN + "/Acct/Svcr/FinInstnId/LEI", is_valid_lei, "LEI"))
94
-
95
91
  reg("VAL-CTRY", "CBPR_Valid_Account_Owner_Country",
96
92
  "Account Owner postal address Country must be a valid ISO 3166 code.",
97
93
  each_value_valid(NTFCTN + "/Acct/Ownr/PstlAdr/Ctry", is_valid_country, "country"))
@@ -12,7 +12,7 @@ Paths are the short ISO 20022 tags from the guideline's XML Path column.
12
12
  from __future__ import annotations
13
13
 
14
14
  from ...registry import advisory, rule
15
- from ...validators import is_valid_bic, is_valid_country, is_valid_lei
15
+ from ...validators import is_valid_bic, is_valid_country
16
16
  from ...helpers import (
17
17
  address_hybrid,
18
18
  address_lines_max_length,
@@ -172,10 +172,6 @@ reg("VAL-BIC", "CBPR_Valid_Agent_BIC",
172
172
  "Instructing/Instructed Agent BICFI must be a structurally valid BIC.",
173
173
  each_value_valid(TX + "/InstgAgt/FinInstnId/BICFI", is_valid_bic, "BIC"))
174
174
 
175
- reg("VAL-LEI", "CBPR_Valid_Originator_LEI",
176
- "Originator Organisation Identification LEI must be a structurally valid LEI.",
177
- each_value_valid(ORGTR + "/Id/OrgId/LEI", is_valid_lei, "LEI"))
178
-
179
175
  reg("VAL-CTRY", "CBPR_Valid_Originator_Country",
180
176
  "Originator Postal Address Country must be a valid ISO 3166 country code.",
181
177
  each_value_valid(ORGTR + "/PstlAdr/Ctry", is_valid_country, "country"))
@@ -12,7 +12,7 @@ from __future__ import annotations
12
12
  import re
13
13
 
14
14
  from ...registry import advisory, rule
15
- from ...validators import is_valid_bic, is_valid_country, is_valid_currency, is_valid_lei
15
+ from ...validators import is_valid_bic, is_valid_country, is_valid_currency
16
16
  from ...helpers import (
17
17
  address_hybrid,
18
18
  address_lines_max_length,
@@ -715,13 +715,6 @@ reg("VAL-BIC", "CBPR_Valid_Agent_BIC",
715
715
  each_value_valid(TX + "/InstdAgt/FinInstnId/BICFI", is_valid_bic, "BIC"),
716
716
  ))
717
717
 
718
- reg("VAL-LEI", "CBPR_Valid_Agent_LEI",
719
- "Every Agent LEI must be a structurally valid LEI.",
720
- _run_all(
721
- each_value_valid(TX + "/InstgAgt/FinInstnId/LEI", is_valid_lei, "LEI"),
722
- each_value_valid(TX + "/InstdAgt/FinInstnId/LEI", is_valid_lei, "LEI"),
723
- ))
724
-
725
718
  reg("VAL-CTRY", "CBPR_Valid_Country",
726
719
  "Every Country code must be a valid ISO 3166 country code.",
727
720
  _run_all(
@@ -11,7 +11,7 @@ Name/PostalAddress follow the *agent* (present-together) rule via FinInstnId.
11
11
  from __future__ import annotations
12
12
 
13
13
  from ...registry import advisory, rule
14
- from ...validators import is_valid_bic, is_valid_country, is_valid_currency, is_valid_lei
14
+ from ...validators import is_valid_bic, is_valid_country, is_valid_currency
15
15
  from ...helpers import (
16
16
  address_hybrid,
17
17
  address_lines_max_length,
@@ -211,10 +211,6 @@ reg("VAL-BIC", "CBPR_Valid_Agent_BIC",
211
211
  "Instructing/Instructed Agent BICFI must be a structurally valid BIC.",
212
212
  each_value_valid(TX + "/InstgAgt/FinInstnId/BICFI", is_valid_bic, "BIC"))
213
213
 
214
- reg("VAL-LEI", "CBPR_Valid_Agent_LEI",
215
- "Every Financial Institution LEI must be a structurally valid LEI.",
216
- each_value_valid(TX + "/DbtrAgt/FinInstnId/LEI", is_valid_lei, "LEI"))
217
-
218
214
  reg("VAL-CTRY", "CBPR_Valid_Postal_Country",
219
215
  "Every Postal Address Country must be a valid ISO 3166 country code.",
220
216
  each_value_valid(TX + "/CdtrAgt/FinInstnId/PstlAdr/Ctry", is_valid_country, "country"))
@@ -9,7 +9,7 @@ module (``pacs_008``): combinator-built rules go through ``reg``/``_agent_block`
9
9
  from __future__ import annotations
10
10
 
11
11
  from ...registry import advisory, rule
12
- from ...validators import is_valid_bic, is_valid_country, is_valid_currency, is_valid_lei
12
+ from ...validators import is_valid_bic, is_valid_country, is_valid_currency
13
13
  from ...helpers import (
14
14
  address_hybrid,
15
15
  address_lines_max_length,
@@ -164,20 +164,6 @@ reg("VAL-BIC", "CBPR_Valid_Agent_BIC",
164
164
  if msg.text_of(node) and not is_valid_bic(msg.text_of(node))
165
165
  ])
166
166
 
167
- reg("VAL-LEI", "CBPR_Valid_LEI",
168
- "Every LEI must be a structurally valid ISO 17442 LEI.",
169
- lambda msg, report: [
170
- report(node, detail=f"invalid LEI: '{msg.text_of(node)}'")
171
- for path in (
172
- PMTINF + "/Dbtr/Id/OrgId/LEI",
173
- PMTINF + "/DbtrAgt/FinInstnId/LEI",
174
- TX + "/Cdtr/Id/OrgId/LEI",
175
- TX + "/CdtrAgt/FinInstnId/LEI",
176
- )
177
- for node in msg.find(path)
178
- if msg.text_of(node) and not is_valid_lei(msg.text_of(node))
179
- ])
180
-
181
167
  reg("VAL-CTRY", "CBPR_Valid_Country",
182
168
  "Every Country must be a valid ISO 3166-1 alpha-2 code.",
183
169
  lambda msg, report: [
@@ -13,7 +13,6 @@ from ...validators import (
13
13
  is_valid_bic,
14
14
  is_valid_country,
15
15
  is_valid_currency,
16
- is_valid_lei,
17
16
  )
18
17
  from ...helpers import (
19
18
  amount_equals_sum,
@@ -102,10 +101,6 @@ reg("VAL-BIC", "CBPR_Valid_Account_Servicer_BIC",
102
101
  "Account Servicer BICFI must be a structurally valid BIC.",
103
102
  each_value_valid(RPT + "/Acct/Svcr/FinInstnId/BICFI", is_valid_bic, "BIC"))
104
103
 
105
- reg("VAL-LEI", "CBPR_Valid_Account_Servicer_LEI",
106
- "Account Servicer LEI must be a structurally valid LEI.",
107
- each_value_valid(RPT + "/Acct/Svcr/FinInstnId/LEI", is_valid_lei, "LEI"))
108
-
109
104
  reg("VAL-CTRY", "CBPR_Valid_Account_Owner_Country",
110
105
  "Account Owner Postal Address Country must be a valid ISO 3166 code.",
111
106
  each_value_valid(RPT + "/Acct/Ownr/PstlAdr/Ctry", is_valid_country, "Country"))
@@ -11,7 +11,7 @@ rules are surfaced via ``advisory``.
11
11
  from __future__ import annotations
12
12
 
13
13
  from ...registry import advisory, rule
14
- from ...validators import is_valid_bic, is_valid_country, is_valid_currency, is_valid_lei
14
+ from ...validators import is_valid_bic, is_valid_country, is_valid_currency
15
15
  from ...helpers import (
16
16
  business_msg_id_carries_group_id,
17
17
  each_value_valid,
@@ -109,10 +109,6 @@ reg("VAL-BIC", "CBPR_Valid_Account_Servicer_BIC",
109
109
  "Account Servicer BICFI must be a structurally valid BIC.",
110
110
  each_value_valid(NTFCTN + "/Acct/Svcr/FinInstnId/BICFI", is_valid_bic, "BIC"))
111
111
 
112
- reg("VAL-LEI", "CBPR_Valid_Account_Servicer_LEI",
113
- "Account Servicer LEI must be a structurally valid ISO 17442 LEI.",
114
- each_value_valid(NTFCTN + "/Acct/Svcr/FinInstnId/LEI", is_valid_lei, "LEI"))
115
-
116
112
  reg("VAL-CTRY", "CBPR_Valid_Account_Servicer_Country",
117
113
  "Account Servicer postal address Country must be a valid ISO 3166 code.",
118
114
  each_value_valid(NTFCTN + "/Acct/Svcr/FinInstnId/PstlAdr/Ctry",
@@ -10,7 +10,7 @@ Structure mirrors the reference module ``y2025/pacs_008.py``.
10
10
  from __future__ import annotations
11
11
 
12
12
  from ...registry import advisory, rule
13
- from ...validators import is_valid_bic, is_valid_country, is_valid_currency, is_valid_lei
13
+ from ...validators import is_valid_bic, is_valid_country, is_valid_currency
14
14
  from ...helpers import (
15
15
  bic_presence_exclusive,
16
16
  business_msg_id_carries_group_id,
@@ -282,13 +282,6 @@ reg("VAL-BIC", "CBPR_Valid_Agent_BIC",
282
282
  each_value_valid(TX + "/InstdAgt/FinInstnId/BICFI", is_valid_bic, "BIC"),
283
283
  ))
284
284
 
285
- reg("VAL-LEI", "CBPR_Valid_Agent_LEI",
286
- "Every Agent LEI must be a structurally valid LEI.",
287
- _run_all(
288
- each_value_valid(TX + "/InstgAgt/FinInstnId/LEI", is_valid_lei, "LEI"),
289
- each_value_valid(TX + "/InstdAgt/FinInstnId/LEI", is_valid_lei, "LEI"),
290
- ))
291
-
292
285
  reg("VAL-CTRY", "CBPR_Valid_Country",
293
286
  "Every Country code must be a valid ISO 3166 country code.",
294
287
  _run_all(
@@ -9,7 +9,7 @@ registered as advisories.
9
9
  from __future__ import annotations
10
10
 
11
11
  from ...registry import advisory, rule
12
- from ...validators import is_valid_bic, is_valid_country, is_valid_currency, is_valid_lei
12
+ from ...validators import is_valid_bic, is_valid_country, is_valid_currency
13
13
  from ...helpers import (
14
14
  bic_presence_exclusive,
15
15
  business_msg_id_carries_group_id,
@@ -319,10 +319,6 @@ reg("VAL-BIC", "CBPR_Valid_Agent_BIC",
319
319
  "Every BICFI in the message must be a structurally valid BIC.",
320
320
  each_value_valid(TX + "/InstgAgt/FinInstnId/BICFI", is_valid_bic, "BIC"))
321
321
 
322
- reg("VAL-LEI", "CBPR_Valid_LEI",
323
- "Every LEI in the message must be a structurally valid LEI.",
324
- each_value_valid(TX + "/Dbtr/Id/OrgId/LEI", is_valid_lei, "LEI"))
325
-
326
322
  reg("VAL-CTRY", "CBPR_Valid_Country",
327
323
  "Every Country code must be a valid ISO 3166 code.",
328
324
  each_value_valid(TX + "/Dbtr/PstlAdr/Ctry", is_valid_country, "Country"))
@@ -11,7 +11,7 @@ from __future__ import annotations
11
11
  import re
12
12
 
13
13
  from ...registry import advisory, rule
14
- from ...validators import is_valid_bic, is_valid_country, is_valid_currency, is_valid_lei
14
+ from ...validators import is_valid_bic, is_valid_country, is_valid_currency
15
15
  from ...helpers import (
16
16
  bic_presence_exclusive,
17
17
  business_msg_id_carries_group_id,
@@ -321,10 +321,6 @@ reg("VAL-BIC", "CBPR_Valid_Agent_BIC",
321
321
  "Instructing/Instructed Agent BICFI must be a structurally valid BIC.",
322
322
  each_value_valid(TX + "/InstgAgt/FinInstnId/BICFI", is_valid_bic, "BIC"))
323
323
 
324
- reg("VAL-LEI", "CBPR_Valid_Agent_LEI",
325
- "Any Debtor Agent LEI must be a structurally valid LEI.",
326
- each_value_valid(TX + "/DbtrAgt/FinInstnId/LEI", is_valid_lei, "LEI"))
327
-
328
324
  reg("VAL-CTRY", "CBPR_Valid_Country",
329
325
  "Every PostalAddress Country must be a valid ISO 3166 alpha-2 code.",
330
326
  each_value_valid(TX + "/Dbtr/PstlAdr/Ctry", is_valid_country, "country"))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cbpr-usage-rules
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Validate ISO 20022 CBPR+ XML messages against SWIFT usage (business) rules.
5
5
  Author: Pete Houghton
6
6
  License: MIT License
@@ -141,7 +141,7 @@ Both `validate_file` and `validate_string` return a dictionary:
141
141
  "message_type": "pacs.008", # the rule set that was applied
142
142
  "detected_message_type": "pacs.008",# auto-detected from the Document namespace
143
143
  "year": 2025,
144
- "rules_evaluated": 84,
144
+ "rules_evaluated": 86,
145
145
  "violations": [
146
146
  {
147
147
  "rule_number": "pacs.008:R41", # unique within the message type