You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

246 lines
7.4 KiB

  1. # -*- coding: utf-8 -*-
  2. """Classes and definitions used in parsing bank statements."""
  3. # © 2015-2016 Therp BV <http://therp.nl>
  4. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  5. class BankTransaction(dict):
  6. """Single transaction that is part of a bank statement."""
  7. @property
  8. def transaction_id(self):
  9. """property getter"""
  10. return self['transaction_id']
  11. @transaction_id.setter
  12. def transaction_id(self, transaction_id):
  13. """property setter"""
  14. self['transaction_id'] = transaction_id
  15. @property
  16. def value_date(self):
  17. """property getter"""
  18. return self['date']
  19. @value_date.setter
  20. def value_date(self, value_date):
  21. """property setter"""
  22. self['date'] = value_date
  23. @property
  24. def name(self):
  25. """property getter"""
  26. return self['name']
  27. @name.setter
  28. def name(self, name):
  29. """property setter"""
  30. self['name'] = name
  31. @property
  32. def transferred_amount(self):
  33. """property getter"""
  34. return self['amount']
  35. @transferred_amount.setter
  36. def transferred_amount(self, transferred_amount):
  37. """property setter"""
  38. self['amount'] = transferred_amount
  39. @property
  40. def eref(self):
  41. """property getter"""
  42. return self['ref']
  43. @eref.setter
  44. def eref(self, eref):
  45. """property setter"""
  46. self['ref'] = eref
  47. if not self.message:
  48. self.name = eref
  49. @property
  50. def message(self):
  51. """property getter"""
  52. return self._message
  53. @message.setter
  54. def message(self, message):
  55. """property setter"""
  56. self._message = message
  57. self.name = message
  58. @property
  59. def remote_owner(self):
  60. """property getter"""
  61. return self['partner_name']
  62. @remote_owner.setter
  63. def remote_owner(self, remote_owner):
  64. """property setter"""
  65. self['partner_name'] = remote_owner
  66. if not (self.message or self.eref):
  67. self.name = remote_owner
  68. @property
  69. def remote_account(self):
  70. """property getter"""
  71. return self['account_number']
  72. @remote_account.setter
  73. def remote_account(self, remote_account):
  74. """property setter"""
  75. self['account_number'] = remote_account
  76. @property
  77. def note(self):
  78. return self['note']
  79. @note.setter
  80. def note(self, note):
  81. self['note'] = note
  82. @property
  83. def data(self):
  84. return self['data']
  85. @data.setter
  86. def data(self, data):
  87. self['data'] = data
  88. def __init__(self):
  89. """Define and initialize attributes.
  90. Not all attributes are already used in the actual import.
  91. """
  92. super(BankTransaction, self).__init__()
  93. self.transaction_id = '' # Fill this only if unique for import
  94. self.transfer_type = False # Action type that initiated this message
  95. self.execution_date = False # The posted date of the action
  96. self.value_date = False # The value date of the action
  97. self.remote_account = False # The account of the other party
  98. self.remote_currency = False # The currency used by the other party
  99. self.exchange_rate = 0.0
  100. # The exchange rate used for conversion of local_currency and
  101. # remote_currency
  102. self.transferred_amount = 0.0 # actual amount transferred
  103. self.name = ''
  104. self._message = False # message from the remote party
  105. self.eref = False # end to end reference for transactions
  106. self.remote_owner = False # name of the other party
  107. self.remote_owner_address = [] # other parties address lines
  108. self.remote_owner_city = False # other parties city name
  109. self.remote_owner_postalcode = False # other parties zip code
  110. self.remote_owner_country_code = False # other parties country code
  111. self.remote_bank_bic = False # bic of other party's bank
  112. self.provision_costs = False # costs charged by bank for transaction
  113. self.provision_costs_currency = False
  114. self.provision_costs_description = False
  115. self.error_message = False # error message for interaction with user
  116. self.storno_retry = False
  117. # If True, make cancelled debit eligible for a next direct debit run
  118. self.data = '' # Raw data from which the transaction has been parsed
  119. class BankStatement(dict):
  120. """A bank statement groups data about several bank transactions."""
  121. @property
  122. def statement_id(self):
  123. """property getter"""
  124. return self['name']
  125. def _set_transaction_ids(self):
  126. """Set transaction ids to statement_id with sequence-number."""
  127. subno = 0
  128. for transaction in self['transactions']:
  129. subno += 1
  130. if transaction.transaction_id:
  131. transaction['unique_import_id'] = transaction.transaction_id
  132. else:
  133. # Cut local_account from prefix if applicable:
  134. if self.statement_id.startswith(self.local_account):
  135. prefix = self.statement_id[len(self.local_account):]
  136. else:
  137. prefix = self.statement_id
  138. transaction['unique_import_id'] = prefix + str(subno).zfill(4)
  139. @statement_id.setter
  140. def statement_id(self, statement_id):
  141. """property setter"""
  142. self['name'] = statement_id
  143. self._set_transaction_ids()
  144. @property
  145. def local_account(self):
  146. """property getter"""
  147. return self['account_number']
  148. @local_account.setter
  149. def local_account(self, local_account):
  150. """property setter"""
  151. self['account_number'] = local_account
  152. @property
  153. def local_currency(self):
  154. """property getter"""
  155. return self['currency_code']
  156. @local_currency.setter
  157. def local_currency(self, local_currency):
  158. """property setter"""
  159. self['currency_code'] = local_currency
  160. @property
  161. def start_balance(self):
  162. """property getter"""
  163. return self['balance_start']
  164. @start_balance.setter
  165. def start_balance(self, start_balance):
  166. """property setter"""
  167. self['balance_start'] = start_balance
  168. @property
  169. def end_balance(self):
  170. """property getter"""
  171. return self['balance_end']
  172. @end_balance.setter
  173. def end_balance(self, end_balance):
  174. """property setter"""
  175. self['balance_end'] = end_balance
  176. self['balance_end_real'] = end_balance
  177. @property
  178. def date(self):
  179. """property getter"""
  180. return self['date']
  181. @date.setter
  182. def date(self, date):
  183. """property setter"""
  184. self['date'] = date
  185. def create_transaction(self):
  186. """Create and append transaction.
  187. This should only be called after statement_id has been set, because
  188. statement_id will become part of the unique transaction_id.
  189. """
  190. transaction = BankTransaction()
  191. self['transactions'].append(transaction)
  192. # Fill default id, but might be overruled
  193. transaction['unique_import_id'] = (
  194. self.statement_id + str(len(self['transactions'])).zfill(4))
  195. return transaction
  196. def __init__(self):
  197. super(BankStatement, self).__init__()
  198. self['transactions'] = []
  199. self.statement_id = ''
  200. self.local_account = ''
  201. self.local_currency = ''
  202. self.date = ''
  203. self.start_balance = 0.0
  204. self.end_balance = 0.0