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.
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/CHANGELOG.md +16 -1
- {cbpr_usage_rules-0.1.0/src/cbpr_usage_rules.egg-info → cbpr_usage_rules-0.1.2}/PKG-INFO +2 -2
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/README.md +1 -1
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/__init__.py +1 -1
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/registry.py +47 -1
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/camt_052.py +1 -6
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/camt_054.py +1 -5
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_002.py +1 -5
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_004.py +1 -8
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_009.py +1 -5
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pain_001.py +1 -15
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/camt_052.py +0 -5
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/camt_054.py +1 -5
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_004.py +1 -8
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_008.py +1 -5
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_008_stp.py +1 -5
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2/src/cbpr_usage_rules.egg-info}/PKG-INFO +2 -2
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/LICENSE +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/MANIFEST.in +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/pyproject.toml +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/setup.cfg +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/cli.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/engine.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/helpers.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/loader.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/message.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/models.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/py.typed +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/reference/__init__.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/reference/countries.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/reference/currencies.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/__init__.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/__init__.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_008.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_008_stp.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_009_adv.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_009_cov.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/__init__.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_002.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_009.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_009_adv.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_009_cov.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pain_001.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/schema.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/validators/__init__.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/validators/bic.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/validators/country.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/validators/currency.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/validators/iban.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/validators/lei.py +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_usage_rules.egg-info/SOURCES.txt +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_usage_rules.egg-info/dependency_links.txt +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_usage_rules.egg-info/entry_points.txt +0 -0
- {cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_usage_rules.egg-info/requires.txt +0 -0
- {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
|
-
## [
|
|
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.
|
|
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":
|
|
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":
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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"))
|
{cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_008_stp.py
RENAMED
|
@@ -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
|
|
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.
|
|
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":
|
|
144
|
+
"rules_evaluated": 86,
|
|
145
145
|
"violations": [
|
|
146
146
|
{
|
|
147
147
|
"rule_number": "pacs.008:R41", # unique within the message type
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_008_stp.py
RENAMED
|
File without changes
|
{cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_009_adv.py
RENAMED
|
File without changes
|
{cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2025/pacs_009_cov.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_009_adv.py
RENAMED
|
File without changes
|
{cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_rules/rules/y2026/pacs_009_cov.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_usage_rules.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_usage_rules.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_usage_rules.egg-info/requires.txt
RENAMED
|
File without changes
|
{cbpr_usage_rules-0.1.0 → cbpr_usage_rules-0.1.2}/src/cbpr_usage_rules.egg-info/top_level.txt
RENAMED
|
File without changes
|