Skip to content

Commit

Permalink
Added better docs and more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
phoughton committed Aug 12, 2024
1 parent 60af6fc commit 4b7113d
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 10 deletions.
130 changes: 125 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
<iMG SRC="https://github.com/phoughton/pyiso20022/raw/main/docs/logo_pyiso20022.png?raw=true" WIDTH=400>

# PYISO20022 - an ISO 20022 Message Generator

1. [PYISO20022 - an ISO 20022 Message Generator and Parser](#pyiso20022-an-iso-20022-message-generator-and-parser)
1. [Parse an ISO 20022 PAIN.001 message](#parse-an-iso-20022-pain001-message)
1. [Create a ISO 20022 PAIN.001 message](#create-a-iso-20022-pain001-message)
1. [Create a ISO 20022 PACS.008 message](#create-a-iso-20022-pacs008-message)


# PYISO20022 an ISO 20022 Message Generator and Parser

A package of classes to support payment, financial, securities & accounting message generation (for ISO 20022 messages).

Expand All @@ -12,7 +19,8 @@ See a full list of types and versions [here](https://github.com/phoughton/pyiso2

(Raise an issue in github if find a version or msg type is missing! We are constantly expanding the scope of messages we support.)

## Using pyiso20022 package

## Parse an ISO 20022 PAIN.001 message

Install this package and some others...
```bash
Expand Down Expand Up @@ -41,13 +49,125 @@ print(doc.cstmr_cdt_trf_initn.pmt_inf[0].dbtr.pstl_adr.pst_cd)

or...

## Create a MX (ISO20022) payment message programatically:
## Create a ISO 20022 PAIN.001 message

Uee this code to create a PAyment INitiation message. We've used PAIN.001.001.08 but other versions are available.

It will create a file called: `my_pain_001_001_08_from_code.xml`

```python
from pyiso20022.pain.pain_001_001_08 import *
from xsdata.formats.dataclass.serializers import XmlSerializer
from xsdata.formats.dataclass.serializers.config import SerializerConfig
from xsdata.models.datatype import XmlDate


initg_pty__id = Party11Choice(
org_id=OrganisationIdentification8(
othr=GenericOrganisationIdentification1(
id="uktestdda")
))

initg_pty = PartyIdentification43(nm="TXB Test Account",
id=initg_pty__id)


grp_hdr = GroupHeader48(msg_id="test-160620",
cre_dt_tm="2019-12-03T13:01:00+00:00",
nb_of_txs=1,
ctrl_sum=10,
initg_pty=initg_pty)

dbtr__pstl_adr = PostalAddress6(strt_nm="DBTR LUEZOF",
bldg_nb="88",
pst_cd="052",
twn_nm="VVR MBDB",
ctry="QA")

dbtr = PartyIdentification43(nm="UFXQHBE",
pstl_adr=dbtr__pstl_adr)


dbtr_acct = CashAccount24(id=AccountIdentification4Choice(
othr=GenericAccountIdentification1(id="50000970")),
ccy="GBP")

dbtr_agt = BranchAndFinancialInstitutionIdentification5(
fin_instn_id=FinancialInstitutionIdentification8(
bicfi="GSLDGB20"))

amt = AmountType4Choice(instd_amt=ActiveOrHistoricCurrencyAndAmount(value=10,
ccy="GBP"))

cdtr_agt = BranchAndFinancialInstitutionIdentification5(
fin_instn_id=FinancialInstitutionIdentification8(
bicfi="BARCGB22"))

cdtr__pstl_adr = PostalAddress6(strt_nm="CDTR LUEZOF",
bldg_nb="99",
pst_cd="052",
twn_nm="VVR MBDB",
ctry="QA")

cdtr = PartyIdentification43(nm="Creditor account name",
pstl_adr=cdtr__pstl_adr)

cdtr_acct = CashAccount24(id=AccountIdentification4Choice(
othr=GenericAccountIdentification1(id="12345678")))

rmt_inf = RemittanceInformation11(ustrd="USD Payment from USD account")

cdt_trf_tx_inf = CreditTransferTransaction26(
pmt_id=PaymentIdentification1(end_to_end_id="test-160620"),
pmt_tp_inf=PaymentTypeInformation19(
ctgy_purp=CategoryPurpose1Choice(prtry="Tax Payment")),
amt=amt,
cdtr_agt=cdtr_agt,
cdtr=cdtr,
cdtr_acct=cdtr_acct,
purp=Purpose2Choice(prtry="Purpose of payment"),
rmt_inf=rmt_inf)

pmt_inf = PaymentInstruction22(pmt_inf_id="test-160620",
pmt_mtd=PaymentMethod3Code("TRF"),
reqd_exctn_dt=DateAndDateTimeChoice(
dt=XmlDate.from_string("2020-06-16")),
dbtr=dbtr,
dbtr_acct=dbtr_acct,
dbtr_agt=dbtr_agt,
cdt_trf_tx_inf=cdt_trf_tx_inf)

cstmr_cdt_trf_initn = CustomerCreditTransferInitiationV08(grp_hdr=grp_hdr,
pmt_inf=pmt_inf)

doc = Document(cstmr_cdt_trf_initn=cstmr_cdt_trf_initn)

ns_map_doc: dict[None, str] = {
None: "urn:iso:std:iso:20022:tech:xsd:pain.001.001.08"
}

config = SerializerConfig(pretty_print=True,
xml_declaration=True,
encoding='UTF-8'
)
serializer = XmlSerializer(config=config)

xml_content = serializer.render(doc, ns_map=ns_map_doc)

with open("my_pain_001_001_08_from_code.xml", "w") as xml_file:
xml_file.write(xml_content)

```

or...

## Create a ISO 20022 PACS.008 message

This is an example of how to create a realistic PACS.008 MX payment message.

(it should write out a file called: `my_pacs_008_from_code.xml`)

Depending on your setup you may need a different or even no wrapper element (I've used &lt;MSGRoot&gt; here, but yours might be called something different etc)
Depending on your setup you may need a different or even no wrapper element (We've used &lt;MSGRoot&gt; here, but yours might be called something different etc)

```python
from pyiso20022.pacs.pacs_008_001_08 import *
Expand Down Expand Up @@ -176,7 +296,7 @@ with open("my_pacs_008_from_code.xml", "w") as xml_file:
```

### Message types?
Currently supports PACS, PAIN and CAMT messages as well as HEAD (header documents for the PACS).
Currently supports PACS, PAIN and CAMT messages as well as HEAD (header documents for the messages).


### Source of truth?
Expand Down
8 changes: 4 additions & 4 deletions example_files/gs_pain/pain001_001_08.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<Dbtr>
<Nm>UFXQHBE</Nm>
<PstlAdr>
<StrtNm>LCPM LUEZOF</StrtNm>
<StrtNm>DBTR LUEZOF</StrtNm>
<BldgNb>88</BldgNb>
<PstCd>052</PstCd>
<TwnNm>VVR MBDB</TwnNm>
Expand Down Expand Up @@ -66,9 +66,9 @@
<Cdtr>
<Nm>Creditor account name</Nm>
<PstlAdr>
<StrtNm>LCPM LUEZOF</StrtNm>
<BldgNb>88</BldgNb>
<PstCd>052</PstCd>
<StrtNm>CDTR LUEZOF</StrtNm>
<BldgNb>99</BldgNb>
<PstCd>E1 9TY</PstCd>
<TwnNm>VVR MBDB</TwnNm>
<Ctry>QA</Ctry>
</PstlAdr>
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="pyiso20022",
version="0.6.5",
version="0.6.6",
author="Peter Houghton",
author_email="[email protected]",
description="pyiso20022 is a library for generating ISO20022 messages in Python.",
Expand Down
122 changes: 122 additions & 0 deletions tests/create_pain_msgs_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import tempfile
import pytest
from pyiso20022.pain.pain_001_001_08 import *
from xsdata.formats.dataclass.serializers import XmlSerializer
from xsdata.formats.dataclass.serializers.config import SerializerConfig
from xsdata.models.datatype import XmlDate
from xsdata.formats.dataclass.parsers import XmlParser


def create_pain001_001_008():
initg_pty__id = Party11Choice(
org_id=OrganisationIdentification8(
othr=GenericOrganisationIdentification1(
id="uktestdda")
))

initg_pty = PartyIdentification43(nm="TXB Test Account",
id=initg_pty__id)


grp_hdr = GroupHeader48(msg_id="test-160620",
cre_dt_tm="2019-12-03T13:01:00+00:00",
nb_of_txs=1,
ctrl_sum=10,
initg_pty=initg_pty)

dbtr__pstl_adr = PostalAddress6(strt_nm="DBTR LUEZOF",
bldg_nb="88",
pst_cd="052",
twn_nm="VVR MBDB",
ctry="QA")

dbtr = PartyIdentification43(nm="UFXQHBE",
pstl_adr=dbtr__pstl_adr)

dbtr_acct = CashAccount24(id=AccountIdentification4Choice(
othr=GenericAccountIdentification1(id="50000970")),
ccy="GBP")

dbtr_agt = BranchAndFinancialInstitutionIdentification5(
fin_instn_id=FinancialInstitutionIdentification8(
bicfi="GSLDGB20"))

amt = AmountType4Choice(instd_amt=ActiveOrHistoricCurrencyAndAmount(
value=10,
ccy="GBP"))

cdtr_agt = BranchAndFinancialInstitutionIdentification5(
fin_instn_id=FinancialInstitutionIdentification8(
bicfi="BARCGB22"))

cdtr__pstl_adr = PostalAddress6(strt_nm="CDTR LUEZOF",
bldg_nb="99",
pst_cd="E1 9TY",
twn_nm="VVR MBDB",
ctry="QA")

cdtr = PartyIdentification43(nm="Creditor account name",
pstl_adr=cdtr__pstl_adr)

cdtr_acct = CashAccount24(id=AccountIdentification4Choice(
othr=GenericAccountIdentification1(id="12345678")))

rmt_inf = RemittanceInformation11(ustrd="USD Payment from USD account")

cdt_trf_tx_inf = CreditTransferTransaction26(
pmt_id=PaymentIdentification1(end_to_end_id="test-160620"),
pmt_tp_inf=PaymentTypeInformation19(
ctgy_purp=CategoryPurpose1Choice(prtry="Tax Payment")),
amt=amt,
cdtr_agt=cdtr_agt,
cdtr=cdtr,
cdtr_acct=cdtr_acct,
purp=Purpose2Choice(prtry="Purpose of payment"),
rmt_inf=rmt_inf)

pmt_inf = PaymentInstruction22(pmt_inf_id="test-160620",
pmt_mtd=PaymentMethod3Code("TRF"),
reqd_exctn_dt=DateAndDateTimeChoice(
dt=XmlDate.from_string("2020-06-16")),
dbtr=dbtr,
dbtr_acct=dbtr_acct,
dbtr_agt=dbtr_agt,
cdt_trf_tx_inf=cdt_trf_tx_inf)

cstmr_cdt_trf_initn = CustomerCreditTransferInitiationV08(grp_hdr=grp_hdr,
pmt_inf=pmt_inf)

doc = Document(cstmr_cdt_trf_initn=cstmr_cdt_trf_initn)

ns_map_doc: dict[None, str] = {
None: "urn:iso:std:iso:20022:tech:xsd:pain.001.001.08"
}

config = SerializerConfig(xml_declaration=True,
encoding='UTF-8'
)
serializer = XmlSerializer(config=config)

xml_content = serializer.render(doc, ns_map=ns_map_doc)

return xml_content


@pytest.mark.parametrize("expected_dbtr_postcode, expected_cdtr_postcode", [
("052", "E1 9TY")
])
def test_parse_pain001_001_008(expected_dbtr_postcode, expected_cdtr_postcode):
xml = create_pain001_001_008()

with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(bytes(xml, 'utf-8'))
temp_file.seek(0)
parser = XmlParser()

doc: Document = parser.parse(temp_file, Document, )

dbtr_post_code = doc.cstmr_cdt_trf_initn.pmt_inf[0].dbtr.pstl_adr.pst_cd
cdtr_post_code = doc.cstmr_cdt_trf_initn.pmt_inf[0].cdt_trf_tx_inf[0].cdtr.pstl_adr.pst_cd

assert dbtr_post_code == expected_dbtr_postcode
assert cdtr_post_code == expected_cdtr_postcode

0 comments on commit 4b7113d

Please sign in to comment.