This is a python implementation to generate SEPA XML files.
Supported standards:
- SEPA PAIN.001.001.03
- SEPA PAIN.001.001.09
- SEPA PAIN.001.001.10
- SEPA PAIN.001.001.11
- SEPA PAIN.008.001.02
- SEPA PAIN.008.001.08
- SEPA PAIN.008.001.09
- SEPA PAIN.008.001.10
Example:
from sepaxml import SepaDD
import datetime, uuid
config = {
# "msg_id": "", # If your bank require a specific format for MsgId, you can optionnaly set it up here. Default will be randomly generated with timestamp followed by a random value.
"name": "Test von Testenstein",
"IBAN": "NL50BANK1234567890",
"BIC": "BANKNL2A",
"batch": True,
"creditor_id": "DE26ZZZ00000000000", # supplied by your bank or financial authority
"currency": "EUR", # ISO 4217
# "instrument": "B2B", # - default is CORE (B2C)
"address": {
# The address and all of its fields are optional but in some countries they are required
"address_type": "ADDR", # valid: ADDR, PBOX, HOME, BIZZ, MLTO, DLVY
"department": "Head Office",
"subdepartment": None,
"street_name": "Musterstr.",
"building_number": "1",
"postcode": "12345",
"town": "Berlin",
"country": "DE",
"country_subdivision": None,
"lines": ["Line 1", "Line 2"],
},
# "initiating_party": "John Doe", # optional name of the initiator of the payment, required by some banks. default to ''name'
# "initiating_party_id": "DE26ZZZ00000000002", # optional, supplied by your bank or financial authority. default to 'creditor_id'
"ultimate_creditor": {
# The ultimate_creditor and all of its fields are optional but in some financial institution they are required
"name": "Real Creditor",
"BIC_or_BEI": "REALNL2A",
"id": "12345678900001", # can be a local official id or the creditor_id
"id_scheme_name": "SIRET", # proprietary scheme of the id provided (i.e. SEPA, SIRET...)
},
}
sepa = SepaDD(config, schema="pain.008.001.02", clean=True)
payment = {
"name": "Test von Testenstein",
"IBAN": "NL50BANK1234567890",
"BIC": "BANKNL2A",
"amount": 5000, # in cents
"type": "RCUR", # FRST,RCUR,OOFF,FNAL
"collection_date": datetime.date.today(),
"mandate_id": "1234",
"mandate_date": datetime.date.today(),
"description": "Test transaction",
# "endtoend_id": str(uuid.uuid1()).replace("-", ""), # autogenerated if obmitted
"address": {
# The address and all of its fields are optional but in some countries they are required
"address_type": "ADDR", # valid: ADDR, PBOX, HOME, BIZZ, MLTO, DLVY
"department": "Head Office",
"subdepartment": None,
"street_name": "Musterstr.",
"building_number": "1",
"postcode": "12345",
"town": "Berlin",
"country": "DE",
"country_subdivision": None,
"lines": ["Line 1", "Line 2"],
},
# "initiating_party": "John Doe", # optional name of the initiator of the payment, required by some banks. default to ''name'
# "initiating_party_id": "DE26ZZZ00000000002", # optional, supplied by your bank or financial authority. default to 'creditor_id'
}
sepa.add_payment(payment)
print(sepa.export(validate=True))Example:
from sepaxml import SepaTransfer
import datetime, uuid
config = {
# "msg_id": "", # If your bank require a specific message_id format, you can set it up here. Default will be randomly generated with timestamp followed by a random value.
"name": "Test von Testenstein",
"IBAN": "NL50BANK1234567890",
"BIC": "BANKNL2A",
"batch": True,
# For non-SEPA transfers, set "domestic" to True, necessary e.g. for CH/LI
"currency": "EUR", # ISO 4217
"address": {
# The address and all of its fields are optional but in some countries they are required
"address_type": "ADDR", # valid: ADDR, PBOX, HOME, BIZZ, MLTO, DLVY
"department": "Head Office",
"subdepartment": None,
"street_name": "Musterstr.",
"building_number": "1",
"postcode": "12345",
"town": "Berlin",
"country": "DE",
"country_subdivision": None,
"lines": ["Line 1", "Line 2"],
},
}
sepa = SepaTransfer(config, clean=True)
payment = {
"name": "Test von Testenstein",
"IBAN": "NL50BANK1234567890",
"BIC": "BANKNL2A",
"amount": 5000, # in cents
"execution_date": datetime.date.today() + datetime.timedelta(days=2),
"description": "Test transaction",
# "endtoend_id": str(uuid.uuid1()).replace("-", ""), # optional
"address": {
# The address and all of its fields are optional but in some countries they are required
"address_type": "ADDR", # valid: ADDR, PBOX, HOME, BIZZ, MLTO, DLVY
"department": "Head Office",
"subdepartment": None,
"street_name": "Musterstr.",
"building_number": "1",
"postcode": "12345",
"town": "Berlin",
"country": "DE",
"country_subdivision": None,
"lines": ["Line 1", "Line 2"],
},
}
sepa.add_payment(payment)
print(sepa.export(validate=True))To run the included tests:
pip install -r requirements_dev.txt py.test tests
To automatically sort your Imports as required by CI:
pip install isort isort -rc .
If you discover a security issue, please contact us at security@pretix.eu and see our Responsible Disclosure Policy further information.
Maintainer: Raphael Michel <mail@raphaelmichel.de>
This basically started as a properly packaged, python 3 tested version of the PySepaDD implementation that was released by The Congressus under the MIT license. Thanks for your work!
The source code is released under MIT license.
Not part of the MIT-licensed project are the XML schemas in the sepaxml/schemas/
folder which are copyrighted by the ISO 20022 organization but allowed to be reproduced
freely.