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,377 @@
1
+ """CBPR+ SR2026 usage rules for pacs.008.001.08 (FIToFICustomerCreditTransfer).
2
+
3
+ Rules, numbers, names and descriptions are taken from the published SR2026 usage
4
+ guideline's Rules sheet. Formal rules are implemented with shared combinators
5
+ from ``helpers`` where they match a known shape, or a bespoke ``fn(msg, report)``
6
+ for cross-field / cross-schema logic. Non-mechanizable textual rules are
7
+ registered as advisories.
8
+ """
9
+ from __future__ import annotations
10
+
11
+ from ...registry import advisory, rule
12
+ from ...validators import is_valid_bic, is_valid_country, is_valid_currency, is_valid_lei
13
+ from ...helpers import (
14
+ bic_presence_exclusive,
15
+ business_msg_id_carries_group_id,
16
+ charges_required_when_amounts_differ,
17
+ code_in,
18
+ each_value_valid,
19
+ header_msg_def_id_matches,
20
+ mutually_exclusive,
21
+ no_postal_address_duplication,
22
+ not_matching_pattern,
23
+ presence_together,
24
+ required_when_absent,
25
+ requires_if_present,
26
+ structured_remittance_max_total,
27
+ )
28
+
29
+ MT = "pacs.008"
30
+ YEAR = 2026
31
+ ROOT = "/Document/FIToFICstmrCdtTrf"
32
+ TX = ROOT + "/CdtTrfTxInf"
33
+
34
+ # Repeated rule descriptions (identical across the locations they apply to).
35
+ D_AGENT_NAME_ADR = "Name and Address must always be present together."
36
+ D_PARTY_NAME_ADR = "If Postal Address is present then Name is mandatory."
37
+ D_PARTY_ANY_BIC = (
38
+ "If AnyBIC is absent then Name is mandatory and it is recommended to also "
39
+ "provide the Postal Address."
40
+ )
41
+
42
+
43
+ def reg(number: str, name: str, description: str, check) -> None:
44
+ """Register a combinator-built check as a rule."""
45
+ rule(MT, YEAR, number, name, description)(check)
46
+
47
+
48
+ # ---------------------------------------------------------------------------
49
+ # Bespoke cross-field / cross-schema rules
50
+ # ---------------------------------------------------------------------------
51
+
52
+ def _values_match(msg, report, path_a, path_b, label):
53
+ a_nodes = msg.find(path_a)
54
+ if not a_nodes:
55
+ return
56
+ b_vals = {msg.text_of(n) for n in msg.find(path_b)}
57
+ if not b_vals:
58
+ return
59
+ a_vals = {msg.text_of(n) for n in a_nodes}
60
+ if a_vals != b_vals:
61
+ report(a_nodes[0], detail=label)
62
+
63
+
64
+ @rule(MT, YEAR, "R1", "CBPR_BusinessMessageIdentifier_FormalRule",
65
+ "The Business Message Identifier must match the Message Identification in "
66
+ "the Group Header.")
67
+ def _r1(msg, report):
68
+ _values_match(msg, report, "/AppHdr/BizMsgIdr", ROOT + "/GrpHdr/MsgId",
69
+ "BusinessMessageIdentifier must equal GroupHeader MessageIdentification")
70
+
71
+
72
+ @rule(MT, YEAR, "R2", "CBPR_To_Instructed_Agent_BIC_1_FormalRule",
73
+ 'BAH "To" BIC must match "Instructed Agent" BIC, except where BAH '
74
+ "CopyDuplicate = COPY or = CODU")
75
+ def _r2(msg, report):
76
+ if any(v in {"COPY", "CODU"} for v in msg.values("/AppHdr/CpyDplct")):
77
+ return
78
+ _values_match(msg, report, "/AppHdr/To/FIId/FinInstnId/BICFI",
79
+ TX + "/InstdAgt/FinInstnId/BICFI", "To BIC must equal Instructed Agent BIC")
80
+
81
+
82
+ @rule(MT, YEAR, "R3", "CBPR_To_Instructed_Agent_BIC_2_FormalRule",
83
+ 'BAH "To" BIC must match "Instructed Agent" BIC if CopyDuplicate is absent.')
84
+ def _r3(msg, report):
85
+ if not msg.absent("/AppHdr/CpyDplct"):
86
+ return
87
+ _values_match(msg, report, "/AppHdr/To/FIId/FinInstnId/BICFI",
88
+ TX + "/InstdAgt/FinInstnId/BICFI", "To BIC must equal Instructed Agent BIC")
89
+
90
+
91
+ @rule(MT, YEAR, "R4", "CBPR_Priority_Instruction_Priority_FormalRule",
92
+ 'If "Priority" is used in the BAH for pacs messages, the value should be '
93
+ 'identical to the one in the "Payment Type Information/InstructionPriority" '
94
+ "if present.")
95
+ def _r4(msg, report):
96
+ if msg.present("/AppHdr/Prty") and msg.present(TX + "/PmtTpInf/InstrPrty"):
97
+ _values_match(msg, report, "/AppHdr/Prty", TX + "/PmtTpInf/InstrPrty",
98
+ "BAH Priority must equal InstructionPriority")
99
+
100
+
101
+ @rule(MT, YEAR, "R5", "CBPR_From_Instructing_Agent_BIC_FormalRule",
102
+ 'BAH "From" BIC must match "Instructing Agent" BIC')
103
+ def _r5(msg, report):
104
+ _values_match(msg, report, "/AppHdr/Fr/FIId/FinInstnId/BICFI",
105
+ TX + "/InstgAgt/FinInstnId/BICFI", "From BIC must equal Instructing Agent BIC")
106
+
107
+
108
+ @rule(MT, YEAR, "R10", "CBPR_Instruction_for_Creditor_Agent2_FormalRule",
109
+ 'The code "TELB" is not allowed if the code "PHOB" is present.')
110
+ def _r10(msg, report):
111
+ for tx in msg.each(TX):
112
+ codes = set(msg.values("InstrForCdtrAgt/Cd", tx))
113
+ if "PHOB" in codes and "TELB" in codes:
114
+ report(tx, detail="TELB not allowed when PHOB present")
115
+
116
+
117
+ @rule(MT, YEAR, "R11", "CBPR_Instruction_for_Creditor_Agent1_FormalRule",
118
+ 'The code "HOLD" is not allowed if the code "CHQB" is present.')
119
+ def _r11(msg, report):
120
+ for tx in msg.each(TX):
121
+ codes = set(msg.values("InstrForCdtrAgt/Cd", tx))
122
+ if "CHQB" in codes and "HOLD" in codes:
123
+ report(tx, detail="HOLD not allowed when CHQB present")
124
+
125
+
126
+ # R12: agent name/address on each ChargesInformation/Agent
127
+ reg("R12", "CBPR_Agent_Name_Postal_Address_FormalRule", D_AGENT_NAME_ADR,
128
+ presence_together(TX + "/ChrgsInf/Agt/FinInstnId", "Nm", "PstlAdr"))
129
+
130
+
131
+ reg("R13", "CBPR_GPI_ServiceLevel_Code_FormalRule",
132
+ "The GPI ServiceLevel Code in pacs.008 must be 'G001'.",
133
+ not_matching_pattern(TX + "/PmtTpInf/SvcLvl/Cd",
134
+ r"(G002|G003|G004|G005|G006|G007|G009)"))
135
+
136
+
137
+ # Reimbursement agents (Group Header / Settlement Information)
138
+ reg("R19", "CBPR_Agent_Name_Postal_Address_FormalRule", D_AGENT_NAME_ADR,
139
+ presence_together(ROOT + "/GrpHdr/SttlmInf/InstgRmbrsmntAgt/FinInstnId", "Nm", "PstlAdr"))
140
+ reg("R21", "CBPR_Agent_Name_Postal_Address_FormalRule", D_AGENT_NAME_ADR,
141
+ presence_together(ROOT + "/GrpHdr/SttlmInf/InstdRmbrsmntAgt/FinInstnId", "Nm", "PstlAdr"))
142
+ reg("R22", "CBPR_Agent_Name_Postal_Address_FormalRule", D_AGENT_NAME_ADR,
143
+ presence_together(ROOT + "/GrpHdr/SttlmInf/ThrdRmbrsmntAgt/FinInstnId", "Nm", "PstlAdr"))
144
+
145
+
146
+ @rule(MT, YEAR, "R23", "CBPR_DEBT_FormalRule",
147
+ 'If "Charge Bearer/DEBT" is present, then only one occurrence of '
148
+ '"Charge Information" is allowed.')
149
+ def _r23(msg, report):
150
+ for tx in msg.each(TX):
151
+ if "DEBT" in msg.values("ChrgBr", tx) and len(msg.find("ChrgsInf", tx)) > 1:
152
+ report(tx, detail="only one ChargesInformation allowed when ChargeBearer is DEBT")
153
+
154
+
155
+ reg("R24", "CBPR_Remittance_Mutually_Exclusive_FormalRule",
156
+ "Either Structured or Unstructured Remittance can be present.",
157
+ mutually_exclusive(TX, ["RmtInf/Ustrd", "RmtInf/Strd"]))
158
+
159
+
160
+ @rule(MT, YEAR, "R25", "CBPR_Instruction_For_Creditor_Presence_Code_FormalRule",
161
+ "Each code can only be used once for element Instruction For Creditor Agent.")
162
+ def _r25(msg, report):
163
+ for tx in msg.each(TX):
164
+ codes = msg.values("InstrForCdtrAgt/Cd", tx)
165
+ if len(codes) != len(set(codes)):
166
+ report(tx, detail="duplicate InstructionForCreditorAgent code")
167
+
168
+
169
+ @rule(MT, YEAR, "R26", "CBPR_CRED_FormalRule",
170
+ "Charge information is mandatory if CRED is present – if no charges are "
171
+ 'taken, Zero must be used in "Amount" (any agent in the payment chain).')
172
+ def _r26(msg, report):
173
+ for tx in msg.each(TX):
174
+ cb = msg.values("ChrgBr", tx)
175
+ if cb and all(v == "CRED" for v in cb) and msg.absent("ChrgsInf", tx):
176
+ report(tx, detail="ChargesInformation required when ChargeBearer is CRED")
177
+
178
+
179
+ reg("R27", "CBPR_Related_Remit_Info_Remit_Info_Mutually_Exclusive_FormalRule",
180
+ "In the interbank space, Related Remittance Information and Remittance "
181
+ "Information are mutually exclusive and all may be absent.",
182
+ mutually_exclusive(TX, ["RltdRmtInf", "RmtInf"]))
183
+
184
+
185
+ reg("R28", "CBPR_Instruction_Identification_FormalRule",
186
+ "This element must not start or end with a slash '/' and must not contain "
187
+ "two consecutive slashes '//'.",
188
+ not_matching_pattern(TX + "/PmtId/InstrId", r"(/.*)|(.*/)|(.*//.*)"))
189
+
190
+
191
+ @rule(MT, YEAR, "R31", "CBPR_Interbank_Settlement_Currency_FormalRule",
192
+ "The codes XAU, XAG, XPD and XPT are not allowed, as these are codes are "
193
+ "only used for commodities.")
194
+ def _r31(msg, report):
195
+ for el, ccy in msg.attr_nodes(TX + "/IntrBkSttlmAmt", "Ccy"):
196
+ if ccy in {"XAU", "XAG", "XPD", "XPT"}:
197
+ report(el, detail=f"commodity currency '{ccy}' not allowed")
198
+
199
+
200
+ # Transaction-chain agents (each: Name and PostalAddress present together)
201
+ reg("R35", "CBPR_Agent_Name_Postal_Address_FormalRule", D_AGENT_NAME_ADR,
202
+ presence_together(TX + "/PrvsInstgAgt1/FinInstnId", "Nm", "PstlAdr"))
203
+ reg("R36", "CBPR_Agent_Name_Postal_Address_FormalRule", D_AGENT_NAME_ADR,
204
+ presence_together(TX + "/PrvsInstgAgt2/FinInstnId", "Nm", "PstlAdr"))
205
+ reg("R37", "CBPR_Agent_Name_Postal_Address_FormalRule", D_AGENT_NAME_ADR,
206
+ presence_together(TX + "/PrvsInstgAgt3/FinInstnId", "Nm", "PstlAdr"))
207
+ reg("R38", "CBPR_Agent_Name_Postal_Address_FormalRule", D_AGENT_NAME_ADR,
208
+ presence_together(TX + "/IntrmyAgt1/FinInstnId", "Nm", "PstlAdr"))
209
+ reg("R39", "CBPR_Agent_Name_Postal_Address_FormalRule", D_AGENT_NAME_ADR,
210
+ presence_together(TX + "/IntrmyAgt2/FinInstnId", "Nm", "PstlAdr"))
211
+ reg("R40", "CBPR_Agent_Name_Postal_Address_FormalRule", D_AGENT_NAME_ADR,
212
+ presence_together(TX + "/IntrmyAgt3/FinInstnId", "Nm", "PstlAdr"))
213
+ reg("R52", "CBPR_Agent_Name_Postal_Address_FormalRule", D_AGENT_NAME_ADR,
214
+ presence_together(TX + "/DbtrAgt/FinInstnId", "Nm", "PstlAdr"))
215
+ reg("R53", "CBPR_Agent_Name_Postal_Address_FormalRule", D_AGENT_NAME_ADR,
216
+ presence_together(TX + "/CdtrAgt/FinInstnId", "Nm", "PstlAdr"))
217
+
218
+ # Parties: if PostalAddress present then Name mandatory
219
+ reg("R44", "CBPR_Party_Name_Postal_Address_FormalRule", D_PARTY_NAME_ADR,
220
+ requires_if_present(TX + "/UltmtDbtr", "PstlAdr", "Nm"))
221
+ reg("R45", "CBPR_Party_Name_Postal_Address_FormalRule", D_PARTY_NAME_ADR,
222
+ requires_if_present(TX + "/InitgPty", "PstlAdr", "Nm"))
223
+ reg("R48", "CBPR_Party_Name_Postal_Address_FormalRule", D_PARTY_NAME_ADR,
224
+ requires_if_present(TX + "/Dbtr", "PstlAdr", "Nm"))
225
+ reg("R56", "CBPR_Party_Name_Postal_Address_FormalRule", D_PARTY_NAME_ADR,
226
+ requires_if_present(TX + "/Cdtr", "PstlAdr", "Nm"))
227
+ reg("R60", "CBPR_Party_Name_Postal_Address_FormalRule", D_PARTY_NAME_ADR,
228
+ requires_if_present(TX + "/UltmtCdtr", "PstlAdr", "Nm"))
229
+
230
+ # Parties: if AnyBIC absent then Name mandatory
231
+ reg("R50", "CBPR_Party_Name_Any_BIC_FormalRule", D_PARTY_ANY_BIC,
232
+ required_when_absent(TX + "/Dbtr", "Id/OrgId/AnyBIC", ["Nm"]))
233
+ reg("R55", "CBPR_Party_Name_Any_BIC_FormalRule", D_PARTY_ANY_BIC,
234
+ required_when_absent(TX + "/Cdtr", "Id/OrgId/AnyBIC", ["Nm"]))
235
+
236
+
237
+ # ---------------------------------------------------------------------------
238
+ # Mechanizable textual rules
239
+ # ---------------------------------------------------------------------------
240
+ reg("R8", "CBPR_Message_Definition_Identifier_TextualRule",
241
+ "The Message Definition Identifier of the Business Message instance that is "
242
+ "being transported with this header. In general, it must be formatted exactly "
243
+ "as it appears in the namespace of the Business Message instance.",
244
+ header_msg_def_id_matches())
245
+
246
+
247
+ # R7: Business Message Identifier must carry the Group Header MsgId (promoted).
248
+ reg("R7", "CBPR_Business_Message_Identifier_TextualRule",
249
+ "The Business Message Identifier is the unique identifier of the Business "
250
+ "Message instance that is being transported with this header, as defined by "
251
+ "the sending application or system. Must contain the Message Identification "
252
+ "element from the Group Header of the underlying message, where available.",
253
+ business_msg_id_carries_group_id())
254
+
255
+
256
+ # R20: structured Postal Address data must not be repeated in AddressLine (promoted).
257
+ reg("R20", "CBPR_Duplication_Postal_Address_TextualRule",
258
+ "Data present in structured elements within the Postal Address must not, "
259
+ "under any circumstances be repeated in AddressLine.",
260
+ no_postal_address_duplication())
261
+
262
+
263
+ # R47/R54: if AnyBIC present, Name and Postal Address are not allowed (promoted).
264
+ reg("R47", "CBPR_Debtor_BIC_Presence_TextualRule",
265
+ "If Any BIC is present, then (Name and Postal Address) is NOT allowed (other "
266
+ "elements remain optional) - However, in case of conflicting information, "
267
+ "AnyBIC will always take precedence.",
268
+ bic_presence_exclusive(TX + "/Dbtr"))
269
+ reg("R54", "CBPR_Creditor_BIC_Presence_TextualRule",
270
+ "If Any BIC is present, then (Name and Postal Address) is NOT allowed (other "
271
+ "elements remain optional) - However, in case of conflicting information, "
272
+ "AnyBIC will always take precedence.",
273
+ bic_presence_exclusive(TX + "/Cdtr"))
274
+
275
+
276
+ # R30/R33: charges mandatory when same-currency instructed/settlement amounts
277
+ # differ (DEBT_Rule_1) (promoted).
278
+ _D_DEBT_RULE_1 = (
279
+ "If Instructed amount and Interbank Settlement amount are expressed in the "
280
+ "same currency: if Charge Bearer/DEBT is used then charge information is only "
281
+ "mandatory in case of prepaid charges (that is if interbank settlement amount "
282
+ "is higher than instructed amount) and in that case zero amount is not "
283
+ "allowed. This rule only applies when Interbank Settlement Amount and "
284
+ "Instructed amount are expressed in the same currency.")
285
+ reg("R30", "CBPR_DEBT_Rule_1_TextualRule", _D_DEBT_RULE_1,
286
+ charges_required_when_amounts_differ(TX, "InstdAmt", "IntrBkSttlmAmt", "ChrgsInf"))
287
+ reg("R33", "CBPR_DEBT_Rule_1_TextualRule", _D_DEBT_RULE_1,
288
+ charges_required_when_amounts_differ(TX, "InstdAmt", "IntrBkSttlmAmt", "ChrgsInf"))
289
+
290
+
291
+ # R29: EndToEndIdentification, if present, must be non-empty (NOTPROVIDED ok) (promoted).
292
+ @rule(MT, YEAR, "R29", "CBPR_EndToEndIdentification_TextualRule",
293
+ 'If no EndToEndIdentification is provided by the Debtor, then the element '
294
+ 'must be populated with "NOTPROVIDED".')
295
+ def _r29(msg, report):
296
+ for node in msg.find(TX + "/PmtId/EndToEndId"):
297
+ if not msg.text_of(node):
298
+ report(node, detail='EndToEndIdentification must not be empty (use "NOTPROVIDED" when not provided)')
299
+
300
+
301
+ reg("R63", "CBPR_Structured_RemittanceInformation_TextualRule",
302
+ "Structured can be repeated, however the total business data for all "
303
+ "occurrences (excluding tags) must not exceed 9,000 characters.",
304
+ structured_remittance_max_total(TX + "/RmtInf/Strd", 9000))
305
+
306
+
307
+ # ---------------------------------------------------------------------------
308
+ # Algorithmic field validation required by the project brief
309
+ # ---------------------------------------------------------------------------
310
+ reg("VAL-CCY", "CBPR_Valid_Settlement_Currency",
311
+ "Interbank Settlement Amount currency must be a valid ISO 4217 code.",
312
+ lambda msg, report: [
313
+ report(el, detail=f"invalid currency '{ccy}'")
314
+ for el, ccy in msg.attr_nodes(TX + "/IntrBkSttlmAmt", "Ccy")
315
+ if ccy and not is_valid_currency(ccy)
316
+ ])
317
+
318
+ reg("VAL-BIC", "CBPR_Valid_Agent_BIC",
319
+ "Every BICFI in the message must be a structurally valid BIC.",
320
+ each_value_valid(TX + "/InstgAgt/FinInstnId/BICFI", is_valid_bic, "BIC"))
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
+ reg("VAL-CTRY", "CBPR_Valid_Country",
327
+ "Every Country code must be a valid ISO 3166 code.",
328
+ each_value_valid(TX + "/Dbtr/PstlAdr/Ctry", is_valid_country, "Country"))
329
+
330
+
331
+ # ---------------------------------------------------------------------------
332
+ # Advisory textual rules (not mechanically enforceable - surfaced as guidance)
333
+ # ---------------------------------------------------------------------------
334
+ _ADVISORY = {
335
+ "R6": ("CBPR_Related_Business_Application_Header_TextualRule",
336
+ "If used, the Related BAH must transport the exact same information as in the BAH of the related message."),
337
+ "R9": ("CBPR_Related_BAH_Business_Service_TextualRule",
338
+ "If related BAH is present, it should transport the element Business Service."),
339
+ "R14": ("CBPR_Agent_Option_3_TextualRule",
340
+ "Name AND ([Structured postal address with minimum Town Name and Country] OR [Hybrid postal address with minimum Town Name and Country]). It is recommended to also add the post code when available."),
341
+ "R15": ("CBPR_Agent_Point_To_Point_On_SWIFT_TextualRule",
342
+ "If the transaction is exchanged on the SWIFT network (i.e. if the sender and receiver of the message are on SWIFT), then BIC is mandatory and other elements are optional, e.g. LEI."),
343
+ "R16": ("CBPR_Agent_Option_1_TextualRule",
344
+ "BICFI, complemented optionally with a LEI (preferred option)"),
345
+ "R17": ("CBPR_Agent_National_only_TextualRule",
346
+ "Whenever Debtor Agent, Creditor Agent and all agents in between are located within the same country, the clearing code only may be used."),
347
+ "R18": ("CBPR_Agent_Option_2_TextualRule",
348
+ "(Clearing Code OR LEI) AND (Name AND ([Structured postal address with minimum Town Name and Country] OR [Hybrid postal address with minimum Town Name and Country]). It is recommended to also add the post code when available."),
349
+ "R32": ("CBPR_DEBT_Rule_2_TextualRule",
350
+ "If Instructed amount and Interbank Settlement amount are not expressed in the same currency: If Charge Bearer/DEBT is used then charge information is only mandatory in case of prepaid charges (that is if interbank settlement amount is higher than instructed amount WHEN converted in the same currency) and in that case zero amount is not allowed. Otherwise Charge information is optional (both Agent and currency always need to be provided)."),
351
+ "R34": ("CBPR_SHAR_TextualRule",
352
+ "If deduct taken then Charge Information is mandatory. It is optional for initiator (not taking deduct)."),
353
+ "R41": ("CBPR_UltimateDebtor_Option_3_Jurisdictions_only_TextualRule",
354
+ "For Jurisdictional transactions, Name and/or Identification (Private or Organisation) (that is within a country or for regions under same legislations). The jurisdictional rules apply only when all agents in the payment chain underly the same jurisdiction."),
355
+ "R42": ("CBPR_Ultimate_Debtor_Option_1_TextualRule",
356
+ "Name AND [(Structured Postal Address) OR (Hybrid Postal Address) with minimum Town Name & Country - it is recommended to add Post code when available)]"),
357
+ "R43": ("CBPR_Ultimate_Debtor_Option_2_TextualRule",
358
+ "Name AND [(Structured Postal Address) OR (Hybrid Postal Address) with minimum Town Name & Country- it is recommended to add Post code when available] AND (Identification: Private or Organisation)"),
359
+ "R46": ("CBPR_Debtor_Option_3_Jurisdictions_only_TextualRule",
360
+ "For Jurisdictional transactions, Debtor/ Name is mandatory with either Debtor Account OR Debtor Identification. The jurisdictional rules apply only when all agents in the payment chain underly the same jurisdiction."),
361
+ "R49": ("CBPR_Debtor_Option_1_TextualRule",
362
+ "Organisation Identification/AnyBIC AND (Account Number OR Organisation Identification/Other)"),
363
+ "R51": ("CBPR_Debtor_Option_2_TextualRule",
364
+ "Name AND ([Structured Address with minimum Town Name & Country (+ recommended to add Post code when available)] OR [Hybrid postal address with minimum Town Name and Country (+ recommended to add Post code when available)] AND (Account Number OR Identification: Private or Organisation)"),
365
+ "R57": ("CBPR_Creditor_Option_1_TextualRule",
366
+ "Organisation Identification/AnyBIC AND (Account Number OR Organisation Identification/Other)"),
367
+ "R58": ("CBPR_Creditor_Option_3_Jurisdictions_only_TextualRule",
368
+ "For Jurisdictional transactions, Creditor/Name is mandatory with either Creditor Account OR Creditor Identification. The jurisdictional rules apply only when all agents in the payment chain underly the same jurisdiction."),
369
+ "R59": ("CBPR_Creditor_Option_2_TextualRule",
370
+ "Name AND ([Structured Address with minimum Town Name & Country (+ recommended to add Post code when available)] OR [Hybrid postal address with minimum Town Name and Country (+ recommended to add Post code when available)) AND (Account Number OR Identification: Private or Organisation)"),
371
+ "R61": ("CBPR_UltimateCreditor_Option_2_Jurisdictions_only_TextualRule",
372
+ "For Jurisdictional transactions, Name and/or Identification (Private or Organisation) (that is within a country or for regions under same legislations). The jurisdictional rules apply only when all agents in the payment chain underly the same jurisdiction."),
373
+ "R62": ("CBPR_Ultimate_Creditor_Option_1_TextualRule",
374
+ "Name AND [(Structured Postal Address) OR (Hybrid Postal Address) with minimum Town Name & Country - it is recommended to add Post code when available)]. Other elements are optional, eg Identification: Private or Organisation)"),
375
+ }
376
+ for _num, (_name, _desc) in _ADVISORY.items():
377
+ advisory(MT, YEAR, _num, _name, _desc)