Turn into mbank-compatible script
This commit is contained in:
		
							parent
							
								
									e1defce133
								
							
						
					
					
						commit
						9fa7da54dc
					
				
							
								
								
									
										43
									
								
								main.py
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								main.py
									
									
									
									
									
								
							| @ -1,39 +1,44 @@ | ||||
| import argparse | ||||
| 
 | ||||
| from revolut import RevolutCsvReader | ||||
| from mbank import MbankCsvReader | ||||
| from mt940 import Mt940Writer | ||||
| 
 | ||||
| 
 | ||||
| def main(): | ||||
|     parser = argparse.ArgumentParser( | ||||
|         prog='oddity-revolut-to-mt940', | ||||
|         description='Convert Revolut CSV-files to MT940 format.') | ||||
|         prog="oddity-mbank-to-mt940", | ||||
|         description="Convert mBank CSV-files to MT940 format.", | ||||
|     ) | ||||
| 
 | ||||
|     parser.add_argument('--in', | ||||
|                         dest='input_file', | ||||
|                         help='path to Revolut csv-file', | ||||
|                         required=True) | ||||
|     parser.add_argument( | ||||
|         "--in", dest="input_file", help="path to Revolut csv-file", required=True | ||||
|     ) | ||||
| 
 | ||||
|     parser.add_argument('--account-iban', | ||||
|                         dest='account_iban', | ||||
|                         help='Revolut account IBAN', | ||||
|                         required=True) | ||||
| 
 | ||||
|     parser.add_argument('--out', | ||||
|                         dest='output_file', | ||||
|                         help='path to MT940 output path', | ||||
|                         required=True) | ||||
|     parser.add_argument( | ||||
|         "--out", dest="output_file", help="path to MT940 output path", required=True | ||||
|     ) | ||||
| 
 | ||||
|     args = parser.parse_args() | ||||
| 
 | ||||
|     reader = RevolutCsvReader(args.input_file) | ||||
|     reader = MbankCsvReader(args.input_file) | ||||
| 
 | ||||
|     with Mt940Writer(args.output_file, args.account_iban) as writer: | ||||
|     print(reader.range) | ||||
|     with Mt940Writer( | ||||
|         args.output_file, | ||||
|         reader.iban, | ||||
|         reader.range, | ||||
|         reader.starting_balance, | ||||
|         reader.date_start, | ||||
|     ) as writer: | ||||
|         transactions = reader.get_all_transactions() | ||||
|         for transaction in transactions: | ||||
|             writer.write_transaction(transaction) | ||||
| 
 | ||||
|         print('Wrote {} transactions to file: {}.'.format(len(transactions), args.output_file)) | ||||
|         print( | ||||
|             "Wrote {} transactions to file: {}.".format( | ||||
|                 len(transactions), args.output_file | ||||
|             ) | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|  | ||||
							
								
								
									
										155
									
								
								mbank.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								mbank.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,155 @@ | ||||
| import os | ||||
| import string | ||||
| import csv | ||||
| import math | ||||
| 
 | ||||
| from datetime import datetime, timedelta | ||||
| 
 | ||||
| from data import Transaction | ||||
| 
 | ||||
| EXPECT_HEADERS = [ | ||||
|     "#Data księgowania", | ||||
|     "#Data operacji", | ||||
|     "#Opis operacji", | ||||
|     "#Tytuł", | ||||
|     "#Nadawca/Odbiorca", | ||||
|     "#Numer konta", | ||||
|     "#Kwota", | ||||
|     "#Saldo po operacji", | ||||
| ] | ||||
| 
 | ||||
| NAME_REMOVE_PREFIXES = ["Payment from ", "To "] | ||||
| 
 | ||||
| DATE_FORMAT = "%Y-%m-%d" | ||||
| TIME_FORMAT = "%H:%M:%S" | ||||
| DATETIME_FORMAT = DATE_FORMAT + TIME_FORMAT | ||||
| 
 | ||||
| FEE_NAME = "Revolut" | ||||
| FEE_IBAN = "" | ||||
| FEE_DESCRIPTION_FORMAT = "Bank transaction fee {}" | ||||
| FEE_DATETIME_DELTA = timedelta(seconds=1) | ||||
| 
 | ||||
| 
 | ||||
| def parse_float(s: string): | ||||
|     return float(s.replace(",", ".").replace(" ", "")) | ||||
| 
 | ||||
| 
 | ||||
| class MbankCsvReader: | ||||
|     def __init__(self, file_path): | ||||
|         if not os.path.isfile(file_path): | ||||
|             raise ValueError("File does not exist: {}".format(file_path)) | ||||
| 
 | ||||
|         temp_file_path = file_path + ".tmp" | ||||
| 
 | ||||
|         # trimming metadata added my mbank export | ||||
|         with open(file_path, encoding="cp1250") as old, open( | ||||
|             temp_file_path, "w", encoding="utf-8" | ||||
|         ) as new: | ||||
|             lines = old.readlines() | ||||
|             (date_start, date_end, _3) = lines[14].split(";") | ||||
|             iban = "PL" + lines[20].split(";")[0].replace(" ", "") | ||||
|             starting_balance = parse_float(lines[35].split(";")[1].split(" ")[0]) | ||||
|             self.range = date_start + "-" + date_end | ||||
|             self.date_start = datetime.fromisoformat( | ||||
|                 "-".join(list(reversed(date_start.split(".")))) | ||||
|             ) | ||||
|             self.date_end = datetime.fromisoformat( | ||||
|                 "-".join(list(reversed(date_end.split(".")))) | ||||
|             ) | ||||
|             self.iban = iban | ||||
|             self.starting_balance = starting_balance | ||||
|             new.writelines(lines[37:-1]) | ||||
| 
 | ||||
|         self.filename = temp_file_path | ||||
| 
 | ||||
|         self.file = open(self.filename, "r", encoding="utf-8") | ||||
|         self.reader = csv.reader(self.file, delimiter=";") | ||||
| 
 | ||||
|         self._validate() | ||||
| 
 | ||||
|     def __del__(self): | ||||
|         if not self.file.closed: | ||||
|             self.file.close() | ||||
| 
 | ||||
|     def _validate(self): | ||||
|         headers = [h for h in next(self.reader) if h != ""] | ||||
|         print(headers) | ||||
|         print(EXPECT_HEADERS) | ||||
|         if headers != EXPECT_HEADERS: | ||||
|             raise ValueError("Headers do not match expected Revolut CSV format.") | ||||
| 
 | ||||
|     def get_all_transactions(self): | ||||
|         transactions = [] | ||||
|         for row in self.reader: | ||||
|             transactions = self._parse_transaction(row) + transactions | ||||
| 
 | ||||
|         return transactions | ||||
| 
 | ||||
|     def _parse_transaction(self, row): | ||||
|         def _santize_name(name_): | ||||
|             for remove_prefix in NAME_REMOVE_PREFIXES: | ||||
|                 if name_.startswith(remove_prefix): | ||||
|                     name_ = name_[len(remove_prefix) :] | ||||
| 
 | ||||
|             return name_ | ||||
| 
 | ||||
|         def _parse_datetime(date_str): | ||||
|             return datetime.strptime(date_str + "7:00:00", DATETIME_FORMAT) | ||||
| 
 | ||||
|         print(row) | ||||
|         if len(row) < 2 or row[2] == "OTWARCIE RACHUNKU" or row[0] == "": | ||||
|             print("skipping") | ||||
|             return [] | ||||
| 
 | ||||
|         ( | ||||
|             _0, | ||||
|             completed_date_str, | ||||
|             _1, | ||||
|             description, | ||||
|             name, | ||||
|             iban, | ||||
|             amount_str, | ||||
|             balance_str, | ||||
|             _9, | ||||
|         ) = row | ||||
| 
 | ||||
|         completed_datetime = _parse_datetime(completed_date_str) | ||||
|         amount, balance = parse_float(amount_str), parse_float(balance_str) | ||||
| 
 | ||||
|         print(amount, balance) | ||||
| 
 | ||||
|         transaction_without_fee = Transaction( | ||||
|             amount=amount, | ||||
|             name=_santize_name(name), | ||||
|             iban=iban, | ||||
|             description=description, | ||||
|             datetime=completed_datetime, | ||||
|             before_balance=balance - amount, | ||||
|             after_balance=balance, | ||||
|         ) | ||||
| 
 | ||||
|         batch = [transaction_without_fee] | ||||
| 
 | ||||
|         # no support for transaction fees | ||||
|         # if not math.isclose(fee, 0.00): | ||||
|         #     fee_transaction = self._make_fee_transaction( | ||||
|         #         completed_datetime, balance, fee | ||||
|         #     ) | ||||
|         #     batch.append(fee_transaction) | ||||
| 
 | ||||
|         return batch | ||||
| 
 | ||||
|     def _make_fee_transaction(self, completed_datetime, balance, fee): | ||||
|         return Transaction( | ||||
|             amount=fee, | ||||
|             name=FEE_NAME, | ||||
|             iban=FEE_IBAN, | ||||
|             # include timestamp of transaction to make sure that SnelStart | ||||
|             # does not detect similar transactions as the same one | ||||
|             description=FEE_DESCRIPTION_FORMAT.format( | ||||
|                 int(completed_datetime.timestamp()) | ||||
|             ), | ||||
|             datetime=completed_datetime + FEE_DATETIME_DELTA, | ||||
|             before_balance=balance - fee, | ||||
|             after_balance=balance, | ||||
|         ) | ||||
							
								
								
									
										136
									
								
								mt940.py
									
									
									
									
									
								
							
							
						
						
									
										136
									
								
								mt940.py
									
									
									
									
									
								
							| @ -1,16 +1,18 @@ | ||||
| from data import Transaction | ||||
| 
 | ||||
| BANK_NAME = 'Revolut' | ||||
| BANK_BIC = 'REVOLT21' | ||||
| BANK_NAME = "mBank" | ||||
| BANK_BIC = "BREXPLPWMBK" | ||||
| 
 | ||||
| DEFAULT_SEQUENCE_NO = 1 | ||||
| 
 | ||||
| 
 | ||||
| class Mt940Writer: | ||||
| 
 | ||||
|     def __init__(self, filename, account_iban): | ||||
|         self.file = open(filename, 'w') | ||||
|     def __init__(self, filename, account_iban, range, starting_balance, date_start): | ||||
|         self.file = open(filename, "w") | ||||
|         self.account_iban = account_iban | ||||
|         self.range = range | ||||
|         self.starting_balance = starting_balance | ||||
|         self.date_start = date_start | ||||
| 
 | ||||
|         self._write_header() | ||||
|         self._written_starting_balance = False | ||||
| @ -19,124 +21,106 @@ class Mt940Writer: | ||||
|         self._balance = None | ||||
|         self._date = None | ||||
| 
 | ||||
| 
 | ||||
|     def __enter__(self): | ||||
|         return self | ||||
| 
 | ||||
| 
 | ||||
|     def __exit__(self, exc_type, exc_val, exc_tb): | ||||
|         self.release() | ||||
| 
 | ||||
| 
 | ||||
|     def write_transaction(self, transaction : Transaction): | ||||
|     def write_transaction(self, transaction: Transaction): | ||||
|         if not self._written_starting_balance: | ||||
|             self._write_starting_balance(transaction.datetime, | ||||
|                                          transaction.before_balance) | ||||
|             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) | ||||
|         ]) | ||||
|         self.file.writelines( | ||||
|             [ | ||||
|                 Mt940.make_61(transaction.datetime, transaction.amount), | ||||
|                 Mt940.make_86( | ||||
|                     transaction.iban, transaction.name, transaction.description | ||||
|                 ), | ||||
|             ] | ||||
|         ) | ||||
| 
 | ||||
|         self._balance = transaction.after_balance | ||||
|         self._date = transaction.datetime | ||||
| 
 | ||||
| 
 | ||||
|     def release(self): | ||||
|         if not self.file.closed \ | ||||
|            and self._written_starting_balance \ | ||||
|            and not self._written_ending_balance: | ||||
|         if ( | ||||
|             not self.file.closed | ||||
|             and self._written_starting_balance | ||||
|             and not self._written_ending_balance | ||||
|         ): | ||||
|             self._write_ending_balance() | ||||
| 
 | ||||
|         if not self.file.closed: | ||||
|             self.file.close() | ||||
| 
 | ||||
| 
 | ||||
|     def _write_header(self): | ||||
|         self.file.write( | ||||
|             Mt940.make_header(BANK_BIC)) | ||||
|         self.file.writelines([ | ||||
|             Mt940.make_20(BANK_NAME), | ||||
|             Mt940.make_25(self.account_iban, CURRENCY), | ||||
|             Mt940.make_28(DEFAULT_SEQUENCE_NO) | ||||
|         ]) | ||||
|         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, date, balance): | ||||
|         self.file.write( | ||||
|             Mt940.make_60f(date, balance, CURRENCY)) | ||||
|     def _write_starting_balance(self, balance): | ||||
|         self.file.write(Mt940.make_60f(self.date_start, balance, CURRENCY)) | ||||
|         self._written_starting_balance = True | ||||
| 
 | ||||
| 
 | ||||
|     def _write_ending_balance(self): | ||||
|         self.file.write( | ||||
|             Mt940.make_62f(self._date, self._balance, CURRENCY)) | ||||
|         self.file.write(Mt940.make_62f(self._date, self._balance, CURRENCY)) | ||||
|         self._written_ending_balance = True | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| CURRENCY = 'EUR' | ||||
| CURRENCY = "PLN" | ||||
| 
 | ||||
| # format identifier | ||||
| TAG_940 = '940' | ||||
| TAG_940 = "940" | ||||
| 
 | ||||
| # header | ||||
| FORMAT_HEADER = \ | ||||
|     '{bic}\n' + \ | ||||
|     TAG_940 + '\n' + \ | ||||
|     '{bic}\n' | ||||
| FORMAT_HEADER = "{bic}\n" + TAG_940 + "\n" + "{bic}\n" | ||||
| 
 | ||||
| # transaction ref | ||||
| FORMAT_20 = ':20:{bank}\n' | ||||
| FORMAT_20 = ":20:{bank}{range}\n" | ||||
| 
 | ||||
| # account id | ||||
| FORMAT_25 = ':25:{iban} {currency}\n' | ||||
| FORMAT_25 = ":25:{iban} {currency}\n" | ||||
| 
 | ||||
| # sequence no | ||||
| FORMAT_28 = ':28:{seqno}\n' | ||||
| FORMAT_28 = ":28:{seqno}\n" | ||||
| 
 | ||||
| # opening balance | ||||
| FORMAT_60F = ':60F:{sign}{date}{currency}{amount}\n' | ||||
| FORMAT_60F = ":60F:{sign}{date}{currency}{amount}\n" | ||||
| 
 | ||||
| # closing balance | ||||
| FORMAT_62F = ':62F:{sign}{date}{currency}{amount}\n' | ||||
| FORMAT_62F = ":62F:{sign}{date}{currency}{amount}\n" | ||||
| 
 | ||||
| # transaction | ||||
| FORMAT_61 = ':61:{date}{date2}{amount}{magic}\n' | ||||
| FORMAT_61 = ":61:{date}{date2}{amount}{magic}\n" | ||||
| 
 | ||||
| # transaction 2 | ||||
| FORMAT_86 = ':86:/IBAN/{iban}/NAME/{name}/REMI/{description}\n' | ||||
| FORMAT_86 = ":86:/IBAN/{iban}/NAME/{name}/REMI/{description}\n" | ||||
| 
 | ||||
| MAGIC = 'NTRFNONREF' | ||||
| MAGIC = "NTRFNONREF" | ||||
| 
 | ||||
| 
 | ||||
| class Mt940: | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def make_header(bic): | ||||
|         return FORMAT_HEADER.format( | ||||
|             bic=bic) | ||||
|         return FORMAT_HEADER.format(bic=bic) | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def make_20(bank): | ||||
|         return FORMAT_20.format( | ||||
|             bank=bank) | ||||
|     def make_20(bank, range): | ||||
|         return FORMAT_20.format(bank=bank, range=range) | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def make_25(iban, currency): | ||||
|         return FORMAT_25.format( | ||||
|             iban=iban, | ||||
|             currency=currency) | ||||
|         return FORMAT_25.format(iban=iban, currency=currency) | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def make_28(seqno): | ||||
|         return FORMAT_28.format( | ||||
|             seqno=Mt940.pad_5(seqno)) | ||||
|         return FORMAT_28.format(seqno=Mt940.pad_5(seqno)) | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def make_60f(datetime, balance, currency): | ||||
| @ -144,7 +128,8 @@ class Mt940: | ||||
|             sign=Mt940.amount_sign(balance), | ||||
|             date=Mt940.date(datetime), | ||||
|             currency=currency, | ||||
|             amount= Mt940.amount_val(balance)) | ||||
|             amount=Mt940.amount_val(balance), | ||||
|         ) | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def make_62f(datetime, balance, currency): | ||||
| @ -152,7 +137,8 @@ class Mt940: | ||||
|             sign=Mt940.amount_sign(balance), | ||||
|             date=Mt940.date(datetime), | ||||
|             currency=currency, | ||||
|             amount= Mt940.amount_val(balance)) | ||||
|             amount=Mt940.amount_val(balance), | ||||
|         ) | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def make_61(datetime, amount): | ||||
| @ -160,14 +146,12 @@ class Mt940: | ||||
|             date=Mt940.date(datetime), | ||||
|             date2=Mt940.date(datetime, with_year=False), | ||||
|             amount=Mt940.amount(amount), | ||||
|             magic=MAGIC) | ||||
|             magic=MAGIC, | ||||
|         ) | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def make_86(iban, name, description): | ||||
|         return FORMAT_86.format( | ||||
|             iban=iban, | ||||
|             name=name, | ||||
|             description=description) | ||||
|         return FORMAT_86.format(iban=iban, name=name, description=description) | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def pad_5(val): | ||||
| @ -175,11 +159,11 @@ class Mt940: | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def amount_sign(val): | ||||
|         return 'C' if val > 0 else 'D' | ||||
|         return "C" if val > 0 else "D" | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def amount_val(val): | ||||
|         return '{0:.2f}'.format(abs(val)).replace('.', ',') | ||||
|         return "{0:.2f}".format(abs(val)).replace(".", ",") | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def amount(val): | ||||
| @ -188,6 +172,6 @@ class Mt940: | ||||
|     @staticmethod | ||||
|     def date(val, with_year=True): | ||||
|         if with_year: | ||||
|             return val.strftime('%y%m%d') | ||||
|             return val.strftime("%y%m%d") | ||||
|         else: | ||||
|             return val.strftime('%m%d') | ||||
|             return val.strftime("%m%d") | ||||
|  | ||||
							
								
								
									
										127
									
								
								revolut.py
									
									
									
									
									
								
							
							
						
						
									
										127
									
								
								revolut.py
									
									
									
									
									
								
							| @ -1,127 +0,0 @@ | ||||
| import os | ||||
| import string | ||||
| import csv | ||||
| import math | ||||
| 
 | ||||
| from datetime import datetime, timedelta | ||||
| 
 | ||||
| from data import Transaction | ||||
| 
 | ||||
| EXCPECT_HEADERS = [ | ||||
|     'Date started (UTC)', 'Time started (UTC)', 'Date completed (UTC)', | ||||
|     'Time completed (UTC)', 'State', 'Type', 'Description', 'Reference', | ||||
|     'Payer', 'Card name', 'Card number', 'Orig currency', 'Orig amount', | ||||
|     'Payment currency', 'Amount', 'Fee', 'Balance', 'Account', | ||||
|     'Beneficiary account number', 'Beneficiary sort code or routing number', | ||||
|     'Beneficiary IBAN', 'Beneficiary BIC' | ||||
| ] | ||||
| 
 | ||||
| NAME_REMOVE_PREFIXES = [ | ||||
|     'Payment from ', | ||||
|     'To ' | ||||
| ] | ||||
| 
 | ||||
| DATE_FORMAT = '%Y-%m-%d' | ||||
| TIME_FORMAT = '%H:%M:%S' | ||||
| DATETIME_FORMAT = DATE_FORMAT + TIME_FORMAT | ||||
| 
 | ||||
| FEE_NAME = 'Revolut' | ||||
| FEE_IBAN = '' | ||||
| FEE_DESCRIPTION_FORMAT = 'Bank transaction fee {}' | ||||
| FEE_DATETIME_DELTA = timedelta(seconds=1) | ||||
| 
 | ||||
| 
 | ||||
| class RevolutCsvReader: | ||||
| 
 | ||||
|     def __init__(self, filename): | ||||
|         if not os.path.isfile(filename): | ||||
|             raise ValueError('File does not exist: {}'.format(filename)) | ||||
| 
 | ||||
|         self.filename = filename | ||||
| 
 | ||||
|         self.file = open(self.filename, 'r') | ||||
|         self.reader = csv.reader(self.file) | ||||
| 
 | ||||
|         self._validate() | ||||
| 
 | ||||
| 
 | ||||
|     def __del__(self): | ||||
|         if not self.file.closed: | ||||
|             self.file.close() | ||||
| 
 | ||||
| 
 | ||||
|     def _validate(self): | ||||
|         def _santize_header(header): | ||||
|             header = ''.join([c for c in header | ||||
|                               if c in string.printable]) | ||||
|             header = header.strip() | ||||
|             return header | ||||
| 
 | ||||
|         headers = [_santize_header(h) for h in next(self.reader)] | ||||
|         if headers != EXCPECT_HEADERS: | ||||
|             raise ValueError('Headers do not match expected Revolut CSV format.') | ||||
| 
 | ||||
| 
 | ||||
|     def get_all_transactions(self): | ||||
|         transactions = [] | ||||
|         for row in self.reader: | ||||
|             transactions = self._parse_transaction(row) + transactions | ||||
| 
 | ||||
|         return transactions | ||||
| 
 | ||||
| 
 | ||||
|     def _parse_transaction(self, row): | ||||
| 
 | ||||
|         def _santize_name(name_): | ||||
|             for remove_prefix in NAME_REMOVE_PREFIXES: | ||||
|                 if name_.startswith(remove_prefix): | ||||
|                     name_ = name_[len(remove_prefix):] | ||||
| 
 | ||||
|             return name_ | ||||
| 
 | ||||
|         def _parse_datetime(date_str, time_str): | ||||
|             return datetime.strptime(date_str + time_str, DATETIME_FORMAT) | ||||
| 
 | ||||
| 
 | ||||
|         _0, _1, completed_date_str, completed_time_str, _4, _5, name, description, _8, _9, _10, \ | ||||
|         _11, _12, _13, amount_str, fee_str, balance_str, _17, _18, _19, iban, _21 \ | ||||
|             = row | ||||
| 
 | ||||
|         completed_datetime = _parse_datetime(completed_date_str, completed_time_str) | ||||
|         amount, fee, balance = \ | ||||
|             float(amount_str), float(fee_str), float(balance_str) | ||||
| 
 | ||||
|         transaction_without_fee = Transaction( | ||||
|             amount=amount, | ||||
|             name=_santize_name(name), | ||||
|             iban=iban, | ||||
|             description=description, | ||||
|             datetime=completed_datetime, | ||||
|             before_balance=balance - amount - fee, | ||||
|             after_balance=balance - fee) | ||||
| 
 | ||||
|         batch = [transaction_without_fee] | ||||
| 
 | ||||
|         if not math.isclose(fee, 0.00): | ||||
|             fee_transaction = self._make_fee_transaction( | ||||
|                 completed_datetime, | ||||
|                 balance, | ||||
|                 fee) | ||||
| 
 | ||||
|             batch.append(fee_transaction) | ||||
| 
 | ||||
|         return batch | ||||
| 
 | ||||
| 
 | ||||
|     def _make_fee_transaction(self, completed_datetime, balance, fee): | ||||
|         return Transaction( | ||||
|             amount=fee, | ||||
|             name=FEE_NAME, | ||||
|             iban=FEE_IBAN, | ||||
|             # include timestamp of transaction to make sure that SnelStart | ||||
|             # does not detect similar transactions as the same one | ||||
|             description=FEE_DESCRIPTION_FORMAT.format(int(completed_datetime.timestamp())), | ||||
|             datetime=completed_datetime + FEE_DATETIME_DELTA, | ||||
|             before_balance=balance - fee, | ||||
|             after_balance=balance) | ||||
| 
 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user