mbank-to-mt940/mt940.py

178 lines
4.5 KiB
Python
Raw Normal View History

2020-02-17 09:54:00 +01:00
from data import Transaction
2023-09-03 15:31:36 +02:00
BANK_NAME = "mBank"
BANK_BIC = "BREXPLPWMBK"
2020-02-17 09:54:00 +01:00
DEFAULT_SEQUENCE_NO = 1
class Mt940Writer:
2023-09-03 15:31:36 +02:00
def __init__(self, filename, account_iban, range, starting_balance, date_start):
self.file = open(filename, "w")
2020-02-17 09:54:00 +01:00
self.account_iban = account_iban
2023-09-03 15:31:36 +02:00
self.range = range
self.starting_balance = starting_balance
self.date_start = date_start
2020-02-17 09:54:00 +01:00
self._write_header()
self._written_starting_balance = False
self._written_ending_balance = False
self._balance = None
self._date = None
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.release()
2023-09-03 15:31:36 +02:00
def write_transaction(self, transaction: Transaction):
2020-02-17 09:54:00 +01:00
if not self._written_starting_balance:
2023-09-03 15:31:36 +02:00
self._write_starting_balance(self.starting_balance)
self.file.writelines(
[
Mt940.make_61(transaction.datetime, transaction.amount),
Mt940.make_86(
transaction.iban, transaction.name, transaction.description
),
]
)
2020-02-17 09:54:00 +01:00
self._balance = transaction.after_balance
self._date = transaction.datetime
def release(self):
2023-09-03 15:31:36 +02:00
if (
not self.file.closed
and self._written_starting_balance
and not self._written_ending_balance
):
2020-02-17 09:54:00 +01:00
self._write_ending_balance()
if not self.file.closed:
self.file.close()
def _write_header(self):
2023-09-03 15:31:36 +02:00
self.file.write(Mt940.make_header(BANK_BIC))
self.file.writelines(
[
Mt940.make_20(BANK_NAME, self.range),
Mt940.make_25(self.account_iban, CURRENCY),
Mt940.make_28(self.range),
]
)
def _write_starting_balance(self, balance):
self.file.write(Mt940.make_60f(self.date_start, balance, CURRENCY))
2020-02-17 09:54:00 +01:00
self._written_starting_balance = True
def _write_ending_balance(self):
2023-09-03 15:31:36 +02:00
self.file.write(Mt940.make_62f(self._date, self._balance, CURRENCY))
2020-02-17 09:54:00 +01:00
self._written_ending_balance = True
2023-09-03 15:31:36 +02:00
CURRENCY = "PLN"
2020-02-17 09:54:00 +01:00
# format identifier
2023-09-03 15:31:36 +02:00
TAG_940 = "940"
2020-02-17 09:54:00 +01:00
# header
2023-09-03 15:31:36 +02:00
FORMAT_HEADER = "{bic}\n" + TAG_940 + "\n" + "{bic}\n"
2020-02-17 09:54:00 +01:00
# transaction ref
2023-09-03 15:31:36 +02:00
FORMAT_20 = ":20:{bank}{range}\n"
2020-02-17 09:54:00 +01:00
# account id
2023-09-03 15:31:36 +02:00
FORMAT_25 = ":25:{iban} {currency}\n"
2020-02-17 09:54:00 +01:00
# sequence no
2023-09-03 15:31:36 +02:00
FORMAT_28 = ":28:{seqno}\n"
2020-02-17 09:54:00 +01:00
# opening balance
2023-09-03 15:31:36 +02:00
FORMAT_60F = ":60F:{sign}{date}{currency}{amount}\n"
2020-02-17 09:54:00 +01:00
# closing balance
2023-09-03 15:31:36 +02:00
FORMAT_62F = ":62F:{sign}{date}{currency}{amount}\n"
2020-02-17 09:54:00 +01:00
# transaction
2023-09-03 15:31:36 +02:00
FORMAT_61 = ":61:{date}{date2}{amount}{magic}\n"
2020-02-17 09:54:00 +01:00
# transaction 2
2023-09-03 15:31:36 +02:00
FORMAT_86 = ":86:/IBAN/{iban}/NAME/{name}/REMI/{description}\n"
2020-02-17 09:54:00 +01:00
2023-09-03 15:31:36 +02:00
MAGIC = "NTRFNONREF"
2020-02-17 09:54:00 +01:00
class Mt940:
@staticmethod
def make_header(bic):
2023-09-03 15:31:36 +02:00
return FORMAT_HEADER.format(bic=bic)
2020-02-17 09:54:00 +01:00
@staticmethod
2023-09-03 15:31:36 +02:00
def make_20(bank, range):
return FORMAT_20.format(bank=bank, range=range)
2020-02-17 09:54:00 +01:00
@staticmethod
def make_25(iban, currency):
2023-09-03 15:31:36 +02:00
return FORMAT_25.format(iban=iban, currency=currency)
2020-02-17 09:54:00 +01:00
@staticmethod
def make_28(seqno):
2023-09-03 15:31:36 +02:00
return FORMAT_28.format(seqno=Mt940.pad_5(seqno))
2020-02-17 09:54:00 +01:00
@staticmethod
def make_60f(datetime, balance, currency):
return FORMAT_60F.format(
sign=Mt940.amount_sign(balance),
date=Mt940.date(datetime),
currency=currency,
2023-09-03 15:31:36 +02:00
amount=Mt940.amount_val(balance),
)
2020-02-17 09:54:00 +01:00
@staticmethod
def make_62f(datetime, balance, currency):
return FORMAT_62F.format(
sign=Mt940.amount_sign(balance),
date=Mt940.date(datetime),
currency=currency,
2023-09-03 15:31:36 +02:00
amount=Mt940.amount_val(balance),
)
2020-02-17 09:54:00 +01:00
@staticmethod
def make_61(datetime, amount):
return FORMAT_61.format(
date=Mt940.date(datetime),
date2=Mt940.date(datetime, with_year=False),
amount=Mt940.amount(amount),
2023-09-03 15:31:36 +02:00
magic=MAGIC,
)
2020-02-17 09:54:00 +01:00
@staticmethod
def make_86(iban, name, description):
2023-09-03 15:31:36 +02:00
return FORMAT_86.format(iban=iban, name=name, description=description)
2020-02-17 09:54:00 +01:00
@staticmethod
def pad_5(val):
return str(val).zfill(5)
@staticmethod
def amount_sign(val):
2023-09-03 15:31:36 +02:00
return "C" if val > 0 else "D"
2020-02-17 09:54:00 +01:00
@staticmethod
def amount_val(val):
2023-09-03 15:31:36 +02:00
return "{0:.2f}".format(abs(val)).replace(".", ",")
2020-02-17 09:54:00 +01:00
@staticmethod
def amount(val):
return Mt940.amount_sign(val) + Mt940.amount_val(val)
@staticmethod
def date(val, with_year=True):
if with_year:
2023-09-03 15:31:36 +02:00
return val.strftime("%y%m%d")
2020-02-17 09:54:00 +01:00
else:
2023-09-03 15:31:36 +02:00
return val.strftime("%m%d")