cbpr-usage-rules 0.1.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.
Files changed (48) hide show
  1. cbpr_rules/__init__.py +21 -0
  2. cbpr_rules/cli.py +176 -0
  3. cbpr_rules/engine.py +100 -0
  4. cbpr_rules/helpers.py +420 -0
  5. cbpr_rules/loader.py +77 -0
  6. cbpr_rules/message.py +170 -0
  7. cbpr_rules/models.py +83 -0
  8. cbpr_rules/py.typed +0 -0
  9. cbpr_rules/reference/__init__.py +9 -0
  10. cbpr_rules/reference/countries.py +28 -0
  11. cbpr_rules/reference/currencies.py +25 -0
  12. cbpr_rules/registry.py +107 -0
  13. cbpr_rules/rules/__init__.py +1 -0
  14. cbpr_rules/rules/y2025/__init__.py +1 -0
  15. cbpr_rules/rules/y2025/camt_052.py +224 -0
  16. cbpr_rules/rules/y2025/camt_054.py +176 -0
  17. cbpr_rules/rules/y2025/pacs_002.py +212 -0
  18. cbpr_rules/rules/y2025/pacs_004.py +831 -0
  19. cbpr_rules/rules/y2025/pacs_008.py +375 -0
  20. cbpr_rules/rules/y2025/pacs_008_stp.py +367 -0
  21. cbpr_rules/rules/y2025/pacs_009.py +273 -0
  22. cbpr_rules/rules/y2025/pacs_009_adv.py +255 -0
  23. cbpr_rules/rules/y2025/pacs_009_cov.py +358 -0
  24. cbpr_rules/rules/y2025/pain_001.py +306 -0
  25. cbpr_rules/rules/y2026/__init__.py +1 -0
  26. cbpr_rules/rules/y2026/camt_052.py +191 -0
  27. cbpr_rules/rules/y2026/camt_054.py +182 -0
  28. cbpr_rules/rules/y2026/pacs_002.py +208 -0
  29. cbpr_rules/rules/y2026/pacs_004.py +491 -0
  30. cbpr_rules/rules/y2026/pacs_008.py +377 -0
  31. cbpr_rules/rules/y2026/pacs_008_stp.py +369 -0
  32. cbpr_rules/rules/y2026/pacs_009.py +260 -0
  33. cbpr_rules/rules/y2026/pacs_009_adv.py +256 -0
  34. cbpr_rules/rules/y2026/pacs_009_cov.py +324 -0
  35. cbpr_rules/rules/y2026/pain_001.py +272 -0
  36. cbpr_rules/schema.py +97 -0
  37. cbpr_rules/validators/__init__.py +16 -0
  38. cbpr_rules/validators/bic.py +21 -0
  39. cbpr_rules/validators/country.py +11 -0
  40. cbpr_rules/validators/currency.py +11 -0
  41. cbpr_rules/validators/iban.py +26 -0
  42. cbpr_rules/validators/lei.py +17 -0
  43. cbpr_usage_rules-0.1.0.dist-info/METADATA +335 -0
  44. cbpr_usage_rules-0.1.0.dist-info/RECORD +48 -0
  45. cbpr_usage_rules-0.1.0.dist-info/WHEEL +5 -0
  46. cbpr_usage_rules-0.1.0.dist-info/entry_points.txt +2 -0
  47. cbpr_usage_rules-0.1.0.dist-info/licenses/LICENSE +21 -0
  48. cbpr_usage_rules-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,176 @@
1
+ """CBPR+ SR2025 usage rules for camt.054.001.08 (BankToCustomerDebitCreditNotification).
2
+
3
+ Rules and text are taken from the published usage guideline's Rules sheet; XML
4
+ paths are the short ISO 20022 tags from its XML Path column. Formal rules are
5
+ implemented with shared combinators from ``helpers`` or bespoke ``fn(msg, report)``;
6
+ mechanizable textual rules are enforced, the rest are surfaced as advisories.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ from ...registry import advisory, rule
11
+ from ...validators import is_valid_bic, is_valid_country, is_valid_currency, is_valid_lei
12
+ from ...helpers import (
13
+ business_msg_id_carries_group_id,
14
+ code_in,
15
+ each_value_valid,
16
+ header_msg_def_id_matches,
17
+ not_matching_pattern,
18
+ )
19
+
20
+ MT = "camt.054"
21
+ YEAR = 2025
22
+ ROOT = "/Document/BkToCstmrDbtCdtNtfctn"
23
+ NTFCTN = ROOT + "/Ntfctn"
24
+ ENTRY = NTFCTN + "/Ntry"
25
+ TX = ENTRY + "/NtryDtls/TxDtls"
26
+
27
+
28
+ def reg(number: str, name: str, description: str, check) -> None:
29
+ """Register a combinator-built check as a rule."""
30
+ rule(MT, YEAR, number, name, description)(check)
31
+
32
+
33
+ # ---------------------------------------------------------------------------
34
+ # Formal rules
35
+ # ---------------------------------------------------------------------------
36
+
37
+ @rule(MT, YEAR, "R1", "CBPR_Copy_Duplicate_FormalRule",
38
+ "If Copy Duplicate indicator is used in the Business Application Header, it "
39
+ "must be identical to the Copy Duplicate indicator in the business document "
40
+ "(if the latter is present).")
41
+ def _r1(msg, report):
42
+ bah = msg.find("/AppHdr/CpyDplct")
43
+ doc = msg.find(NTFCTN + "/CpyDplctInd")
44
+ if not bah or not doc:
45
+ return
46
+ bah_vals = {msg.text_of(n) for n in bah}
47
+ doc_vals = {msg.text_of(n) for n in doc}
48
+ if bah_vals != doc_vals:
49
+ report(bah[0], detail="BAH CopyDuplicate must equal Notification/CopyDuplicateIndicator")
50
+
51
+
52
+ reg("R20", "CBPR_Original_Instruction_Identification_FormalRule",
53
+ "This field must not start or end with a slash '/' and must not contain two "
54
+ "consecutive slashes '//'.",
55
+ not_matching_pattern(TX + "/Refs/InstrId", r"(/.*)|(.*/)|(.*//.*)"))
56
+
57
+
58
+ # ---------------------------------------------------------------------------
59
+ # Mechanizable textual rules (enforced)
60
+ # ---------------------------------------------------------------------------
61
+ reg("R6", "CBPR_Business_Service_Usage_TextualRule",
62
+ 'The value "swift.cbprplus.03" must be used.',
63
+ code_in("/AppHdr/BizSvc", ["swift.cbprplus.03"]))
64
+
65
+ reg("R3", "CBPR_Business_Message_Identifier_TextualRule",
66
+ "The Business Message Identifier is the unique identifier of the Business Message instance "
67
+ "being transported with this header, as defined by the sending application or system.",
68
+ business_msg_id_carries_group_id())
69
+
70
+ reg("R4", "CBPR_Message_Definition_Identifier_TextualRule",
71
+ "The Message Definition Identifier of the Business Message instance must in general be "
72
+ "formatted exactly as it appears in the namespace of the Business Message instance.",
73
+ header_msg_def_id_matches())
74
+
75
+
76
+ # ---------------------------------------------------------------------------
77
+ # Algorithmic field validations (brief), only for fields present in camt.054
78
+ # ---------------------------------------------------------------------------
79
+ reg("VAL-CCY", "CBPR_Valid_Entry_Currency",
80
+ "Entry Amount currency must be a valid ISO 4217 code.",
81
+ lambda msg, report: [
82
+ report(el, detail=f"invalid currency '{ccy}'")
83
+ for el, ccy in msg.attr_nodes(ENTRY + "/Amt", "Ccy")
84
+ if ccy and not is_valid_currency(ccy)
85
+ ])
86
+
87
+ reg("VAL-BIC", "CBPR_Valid_Account_Servicer_BIC",
88
+ "Account Servicer BICFI must be a structurally valid BIC.",
89
+ each_value_valid(NTFCTN + "/Acct/Svcr/FinInstnId/BICFI", is_valid_bic, "BIC"))
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
+ reg("VAL-CTRY", "CBPR_Valid_Account_Owner_Country",
96
+ "Account Owner postal address Country must be a valid ISO 3166 code.",
97
+ each_value_valid(NTFCTN + "/Acct/Ownr/PstlAdr/Ctry", is_valid_country, "country"))
98
+
99
+
100
+ # ---------------------------------------------------------------------------
101
+ # Advisory textual / guideline rules (not mechanically enforceable)
102
+ # ---------------------------------------------------------------------------
103
+ _ADVISORY = {
104
+ "R2": ("CBPR_Character_Set_Usage_TextualRule",
105
+ "For further description on the usage of the field, please refer to the CBPR Plus UHB."),
106
+ "R5": ("CBPR_Business_Service_TextualRule",
107
+ "This field may be used by SWIFT to support differentiated processing on SWIFT-administered "
108
+ "services such as FINplus."),
109
+ "R7": ("CBPR_Market_Practice_TextualRule",
110
+ "This field may be used by SWIFT on SWIFT-administered services."),
111
+ "R8": ("CBPR_Related_Business_Application_Header_TextualRule",
112
+ "If used, the Related BAH must transport the exact same information as in the BAH of the "
113
+ "related message."),
114
+ "R9": ("CBPR_Related_BAH_Business_Service_TextualRule",
115
+ "If related BAH is present, it should transport the element Business Service."),
116
+ "R10": ("CBPR_Additional_Information_TextualRule",
117
+ "May be used to indicate type of Notification. Where used, all transactions within the "
118
+ "message are of the same type."),
119
+ "R11": ("CBPR_Copy_Duplicate_Indicator_TextualRule",
120
+ "If applicable, for Copy or Duplicate, the electronic sequence and legal sequence must be "
121
+ "the same as the original report."),
122
+ "R12": ("CBPR_Transaction_Summary_Guideline",
123
+ "If used, Total Credit and/or Total Debit should at a minimum be provided if summary data "
124
+ "is available."),
125
+ "R13": ("CBPR_Domain_Proprietary_Recommendation_TextualRule",
126
+ "BankTransactionCode/Domain/Code is the preferred option and should be used when possible."),
127
+ "R14": ("CBPR_Amount_TextualRule",
128
+ "Amount in the currency of the account reported. Note: this amount can be Zero."),
129
+ "R15": ("CBPR_Reversal_Indicator_TextualRule",
130
+ "Value is TRUE or FALSE. Should only be shown if TRUE."),
131
+ "R16": ("CBPR_Booking_Date_TextualRule",
132
+ "Mandatory when Status is booked, bilaterally determined when status is Pending or Information."),
133
+ "R17": ("CBPR_Value_Date_TextualRule",
134
+ "Mandatory when Status is booked, bilaterally determined when status is Pending or Information."),
135
+ "R18": ("CBPR_Account_Servicer_Reference_Guideline",
136
+ "When the same booked entry is reported in both the camt.052 or camt.054, the Account "
137
+ "Servicer reference should be the same as reported in camt.053."),
138
+ "R19": ("CBPR_Charges_TextualRule",
139
+ "Charges applied to Entry level amount only for a batch booked amount."),
140
+ "R21": ("CBPR_UETR_TextualRule",
141
+ "If the underlying transaction contains/owns a UETR then it should be reported in the "
142
+ "camt.054 message."),
143
+ "R22": ("CBPR_Date_Guideline",
144
+ "Recommendation is to use Actual Date."),
145
+ "R23": ("CBPR_Bank_Transaction_Code_TextualRule",
146
+ "Bank Transaction Code must be provided at entry level and may be provided at transaction "
147
+ "detail level."),
148
+ "R24": ("CBPR_Charges_TextualRule",
149
+ "Charges against the amount reported at Entry level (single, batch or aggregate amount "
150
+ "booking)."),
151
+ "R25": ("CBPR_Bearer_Guideline",
152
+ "Recommended to always be provided when charges are reported."),
153
+ "R26": ("CBPR_Initiating_Party_TextualRule",
154
+ "Party initiating the payment to an agent."),
155
+ "R27": ("CBPR_Debtor_TextualRule",
156
+ "For outward payments, report if different from account owner. For inward payments, report "
157
+ "where available. When ReversalIndicator is TRUE, the Creditor and Debtor must be the same "
158
+ "as the Creditor and Debtor of the original entry."),
159
+ "R28": ("CBPR_Debtor_Account_TextualRule",
160
+ "For inward payment, report where available. Recommendation: if IBAN is available populate "
161
+ "the IBAN tag, else populate Other."),
162
+ "R29": ("CBPR_Ultimate_Debtor_TextualRule",
163
+ "When ReversalIndicator is TRUE, the Ultimate Creditor and Ultimate Debtor must be the same "
164
+ "as the Ultimate Creditor and Ultimate Debtor of the original entry."),
165
+ "R30": ("CBPR_Creditor_TextualRule",
166
+ "For outward payment, report where available. When ReversalIndicator is TRUE, the Creditor "
167
+ "and Debtor must be the same as the Creditor and Debtor of the original entry."),
168
+ "R31": ("CBPR_Creditor_Account_TextualRule",
169
+ "For outward payment, report where available. Recommendation: if IBAN is available populate "
170
+ "the IBAN tag, else populate Other."),
171
+ "R32": ("CBPR_Ultimate_Creditor_TextualRule",
172
+ "When ReversalIndicator is TRUE, the Ultimate Creditor and Ultimate Debtor must be the same "
173
+ "as the Ultimate Creditor and Ultimate Debtor of the original entry."),
174
+ }
175
+ for _num, (_name, _desc) in _ADVISORY.items():
176
+ advisory(MT, YEAR, _num, _name, _desc)
@@ -0,0 +1,212 @@
1
+ """CBPR+ SR2025 usage rules for pacs.002.001.10 (FIToFIPaymentStatusReport).
2
+
3
+ Authored to mirror the reference module ``pacs_008``: every rule from the
4
+ published usage guideline's Rules sheet is registered with its real rule
5
+ number, name and description, implemented with a shared combinator from
6
+ ``helpers`` where the formal definition matches a known shape, or a bespoke
7
+ ``fn(msg, report)`` for cross-field / cross-schema logic. Non-mechanizable
8
+ textual rules are surfaced via ``advisory``.
9
+
10
+ Paths are the short ISO 20022 tags from the guideline's XML Path column.
11
+ """
12
+ from __future__ import annotations
13
+
14
+ from ...registry import advisory, rule
15
+ from ...validators import is_valid_bic, is_valid_country, is_valid_lei
16
+ from ...helpers import (
17
+ address_hybrid,
18
+ address_lines_max_length,
19
+ business_msg_id_carries_group_id,
20
+ code_in,
21
+ each_value_valid,
22
+ header_msg_def_id_matches,
23
+ no_postal_address_duplication,
24
+ not_matching_pattern,
25
+ required_when_absent,
26
+ requires_if_present,
27
+ )
28
+
29
+ MT = "pacs.002"
30
+ YEAR = 2025
31
+ ROOT = "/Document/FIToFIPmtStsRpt"
32
+ TX = ROOT + "/TxInfAndSts"
33
+ ORGTR = TX + "/StsRsnInf/Orgtr"
34
+
35
+
36
+ def reg(number: str, name: str, description: str, check) -> None:
37
+ """Register a combinator-built check as a rule."""
38
+ rule(MT, YEAR, number, name, description)(check)
39
+
40
+
41
+ # ---------------------------------------------------------------------------
42
+ # Bespoke cross-field / cross-schema rules
43
+ # ---------------------------------------------------------------------------
44
+
45
+ def _values_match(msg, report, path_a, path_b, label):
46
+ a_nodes = msg.find(path_a)
47
+ if not a_nodes:
48
+ return
49
+ b_vals = {msg.text_of(n) for n in msg.find(path_b)}
50
+ if not b_vals:
51
+ return
52
+ a_vals = {msg.text_of(n) for n in a_nodes}
53
+ if a_vals != b_vals:
54
+ report(a_nodes[0], detail=label)
55
+
56
+
57
+ _BIC_PAIRS = [
58
+ ("/AppHdr/Fr/FIId/FinInstnId/BICFI", TX + "/InstgAgt/FinInstnId/BICFI", "From vs Instructing Agent"),
59
+ ("/AppHdr/To/FIId/FinInstnId/BICFI", TX + "/InstdAgt/FinInstnId/BICFI", "To vs Instructed Agent"),
60
+ ]
61
+
62
+
63
+ @rule(MT, YEAR, "R1", "CBPR_From_To_Instructing_Instructed_Agent_BIC_1_FormalRule",
64
+ 'BAH "From" BIC must match "Instructing Agent" BIC, except where BAH '
65
+ 'CopyDuplicate = COPY or = CODU. BAH "To" BIC must match "Instructed '
66
+ 'Agent" BIC, except where BAH CopyDuplicate = COPY or = CODU.')
67
+ def _r1(msg, report):
68
+ if any(v in {"COPY", "CODU"} for v in msg.values("/AppHdr/CpyDplct")):
69
+ return
70
+ for a, b, label in _BIC_PAIRS:
71
+ _values_match(msg, report, a, b, label)
72
+
73
+
74
+ @rule(MT, YEAR, "R2", "CBPR_From_To_Instructing_Instructed_Agent_BIC_2_FormalRule",
75
+ 'BAH "From" BIC must match "Instructing Agent" BIC if CopyDuplicate is '
76
+ 'absent. BAH "To" BIC must match "Instructed Agent" BIC if CopyDuplicate '
77
+ 'is absent.')
78
+ def _r2(msg, report):
79
+ if not msg.absent("/AppHdr/CpyDplct"):
80
+ return
81
+ for a, b, label in _BIC_PAIRS:
82
+ _values_match(msg, report, a, b, label)
83
+
84
+
85
+ @rule(MT, YEAR, "R11", "CBPR_Transaction_Status_Reject_Effective_Sett_Date_FormalRule",
86
+ "If TransactionStatus is “RJCT’ then Effective Interbank "
87
+ "Settlement Date is not allowed.")
88
+ def _r11(msg, report):
89
+ for tx in msg.each(TX):
90
+ sts = msg.values("TxSts", tx)
91
+ if sts and all(v == "RJCT" for v in sts) and msg.present("FctvIntrBkSttlmDt", tx):
92
+ report(tx, detail="EffectiveInterbankSettlementDate not allowed when TransactionStatus is RJCT")
93
+
94
+
95
+ @rule(MT, YEAR, "R12", "CBPR_Transaction_Status_Reject_Reason_FormalRule",
96
+ "If TransactionStatus/Code equals RJCT, then “Status Reason "
97
+ "Information/Reason” is mandatory.")
98
+ def _r12(msg, report):
99
+ for tx in msg.each(TX):
100
+ sts = msg.values("TxSts", tx)
101
+ if sts and all(v == "RJCT" for v in sts) and msg.absent("StsRsnInf/Rsn", tx):
102
+ report(tx, detail="StatusReasonInformation/Reason is mandatory when TransactionStatus is RJCT")
103
+
104
+
105
+ reg("R15", "CBPR_Original_Instruction_Identification_FormalRule",
106
+ "This field must not start or end with a slash '/' and must not contain "
107
+ "two consecutive slashes '//'.",
108
+ not_matching_pattern(TX + "/OrgnlInstrId", r"(/.*)|(.*/)|(.*//.*)"))
109
+
110
+
111
+ # ---------------------------------------------------------------------------
112
+ # Originator party: AnyBIC/Name, Name/PostalAddress, grace-period address rules
113
+ # ---------------------------------------------------------------------------
114
+ reg("R19", "CBPR_Party_Name_Any_BIC_FormalRule",
115
+ "If AnyBIC is absent, then Name is mandatory.",
116
+ required_when_absent(ORGTR, "Id/OrgId/AnyBIC", ["Nm"]))
117
+
118
+ reg("R20", "CBPR_Party_Name_Postal_Address_FormalRule",
119
+ "If Postal Address is present then Name is mandatory. Recommendation: If "
120
+ "present, the BIC (AnyBIC) will always take precedence in case of "
121
+ "conflicting information.",
122
+ requires_if_present(ORGTR, "PstlAdr", "Nm"))
123
+
124
+ reg("R22", "CBPR_GracePeriod_Structured_FormalRule",
125
+ "If Postal Address is used, and if Address Line is absent, then Town Name "
126
+ "and Country must be present.",
127
+ required_when_absent(ORGTR + "/PstlAdr", "AdrLine", ["TwnNm", "Ctry"]))
128
+
129
+ reg("R23", "CBPR_GracePeriod_Hybrid_FormalRule",
130
+ "If Address Line is present and any other Postal Address element(s) are "
131
+ "present, then Town Name and Country are mandatory in Postal Address and a "
132
+ "maximum of two occurrences of Address Line are allowed.",
133
+ address_hybrid(ORGTR + "/PstlAdr"))
134
+
135
+ reg("R25", "CBPR_GracePeriod_Unstructured_FormalRule",
136
+ "If Postal Address is present and if no other element than Address Line is "
137
+ "present then every occurrence of Address Line must not exceed 35 "
138
+ "characters.",
139
+ address_lines_max_length(ORGTR + "/PstlAdr", 35))
140
+
141
+
142
+ # ---------------------------------------------------------------------------
143
+ # Mechanizable textual rules
144
+ # ---------------------------------------------------------------------------
145
+ reg("R7", "CBPR_Business_Service_Usage_TextualRule",
146
+ 'The value "swift.cbprplus.03" must be used.',
147
+ code_in("/AppHdr/BizSvc", ["swift.cbprplus.03"]))
148
+
149
+ reg("R4", "CBPR_Business_Message_Identifier_TextualRule",
150
+ "The Business Message Identifier is the unique identifier of the Business "
151
+ "Message instance that is being transported with this header, as defined by "
152
+ "the sending application or system. Must contain the Message Identification "
153
+ "element from the Group Header of the underlying message, where available.",
154
+ business_msg_id_carries_group_id())
155
+
156
+ reg("R5", "CBPR_Message_Definition_Identifier_TextualRule",
157
+ "The Message Definition Identifier of the Business Message instance that is "
158
+ "being transported with this header. In general, it must be formatted exactly "
159
+ "as it appears in the namespace of the Business Message instance.",
160
+ header_msg_def_id_matches())
161
+
162
+ reg("R24", "CBPR_Duplication_Postal_Address_TextualRule",
163
+ "Data present in structured elements within the Postal Address must not, "
164
+ "under any circumstances be repeated in AddressLine.",
165
+ no_postal_address_duplication())
166
+
167
+
168
+ # ---------------------------------------------------------------------------
169
+ # Algorithmic field validation (only for fields present in pacs.002)
170
+ # ---------------------------------------------------------------------------
171
+ reg("VAL-BIC", "CBPR_Valid_Agent_BIC",
172
+ "Instructing/Instructed Agent BICFI must be a structurally valid BIC.",
173
+ each_value_valid(TX + "/InstgAgt/FinInstnId/BICFI", is_valid_bic, "BIC"))
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
+ reg("VAL-CTRY", "CBPR_Valid_Originator_Country",
180
+ "Originator Postal Address Country must be a valid ISO 3166 country code.",
181
+ each_value_valid(ORGTR + "/PstlAdr/Ctry", is_valid_country, "country"))
182
+
183
+
184
+ # ---------------------------------------------------------------------------
185
+ # Advisory textual rules (not mechanically enforceable - surfaced as guidance)
186
+ # ---------------------------------------------------------------------------
187
+ _ADVISORY = {
188
+ "R3": ("CBPR_Character_Set_Usage_TextualRule",
189
+ "For further description on the usage of the field, pls refer to the CBPR Plus UHB."),
190
+ "R6": ("CBPR_Business_Service_TextualRule",
191
+ "This field may be used by SWIFT to support differentiated processing on SWIFT-administered services such as FINplus. For a description of reserved values, please refer to the Service Description for your service."),
192
+ "R8": ("CBPR_Market_Practice_TextualRule",
193
+ "This field may be used by SWIFT on SWIFT-administered services. For a description of reserved values, please refer to the Service Description for your service."),
194
+ "R9": ("CBPR_Related_Business_Application_Header_TextualRule",
195
+ "If used, the Related BAH must transport the exact same information as in the BAH of the related message."),
196
+ "R10": ("CBPR_Related_BAH_Business_Service_TextualRule",
197
+ "If related BAH is present, it should transport the element Business Service."),
198
+ "R13": ("CBPR_Original_Message_Identification_TextualRule",
199
+ "Original Message Identification must transport the Message Identification of the underlying payment (eg. pacs.008/pacs.009/pacs.004)."),
200
+ "R14": ("CBPR_Original_Instruction_Identification_TextualRule",
201
+ "Should transport the Instruction Identification of the underlying payment message for example pacs.008/pacs.009 or the same Original Instruction Identification if present in pacs.004."),
202
+ "R16": ("CBPR_Original_End_To_End_Identification_TextualRule",
203
+ "Should transport the EndToEnd Identification of the underlying payment message for example pacs.008/pacs.009 or the same Original EndToEnd Identification as in the pacs.004."),
204
+ "R17": ("CBPR_Original_Transaction_Identification_TextualRule",
205
+ "Should transport the Transaction Identification of the underlying payment message for example pacs.008/pacs.009 when present, or the same Original Transaction Identification if present in pacs.004."),
206
+ "R18": ("CBPR_Original_UETR_TextualRule",
207
+ "Must transport the UETR of the underlying pacs.008/pacs.009."),
208
+ "R21": ("CBPR_Originator_Identification_TextualRule",
209
+ "If AnyBIC is present, in addition to any other optional elements, in case of conflicting information it will always take precedence."),
210
+ }
211
+ for _num, (_name, _desc) in _ADVISORY.items():
212
+ advisory(MT, YEAR, _num, _name, _desc)