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.

238 lines
7.3 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. def __init__(self):
  83. """Define and initialize attributes.
  84. Not all attributes are already used in the actual import.
  85. """
  86. super(BankTransaction, self).__init__()
  87. self.transaction_id = '' # Fill this only if unique for import
  88. self.transfer_type = False # Action type that initiated this message
  89. self.execution_date = False # The posted date of the action
  90. self.value_date = False # The value date of the action
  91. self.remote_account = False # The account of the other party
  92. self.remote_currency = False # The currency used by the other party
  93. self.exchange_rate = 0.0
  94. # The exchange rate used for conversion of local_currency and
  95. # remote_currency
  96. self.transferred_amount = 0.0 # actual amount transferred
  97. self.name = ''
  98. self._message = False # message from the remote party
  99. self.eref = False # end to end reference for transactions
  100. self.remote_owner = False # name of the other party
  101. self.remote_owner_address = [] # other parties address lines
  102. self.remote_owner_city = False # other parties city name
  103. self.remote_owner_postalcode = False # other parties zip code
  104. self.remote_owner_country_code = False # other parties country code
  105. self.remote_bank_bic = False # bic of other party's bank
  106. self.provision_costs = False # costs charged by bank for transaction
  107. self.provision_costs_currency = False
  108. self.provision_costs_description = False
  109. self.error_message = False # error message for interaction with user
  110. self.storno_retry = False
  111. # If True, make cancelled debit eligible for a next direct debit run
  112. self.data = '' # Raw data from which the transaction has been parsed
  113. class BankStatement(dict):
  114. """A bank statement groups data about several bank transactions."""
  115. @property
  116. def statement_id(self):
  117. """property getter"""
  118. return self['name']
  119. def _set_transaction_ids(self):
  120. """Set transaction ids to statement_id with sequence-number."""
  121. subno = 0
  122. for transaction in self['transactions']:
  123. subno += 1
  124. if transaction.transaction_id:
  125. transaction['unique_import_id'] = transaction.transaction_id
  126. else:
  127. # Cut local_account from prefix if applicable:
  128. if self.statement_id.startswith(self.local_account):
  129. prefix = self.statement_id[len(self.local_account):]
  130. else:
  131. prefix = self.statement_id
  132. transaction['unique_import_id'] = prefix + str(subno).zfill(4)
  133. @statement_id.setter
  134. def statement_id(self, statement_id):
  135. """property setter"""
  136. self['name'] = statement_id
  137. self._set_transaction_ids()
  138. @property
  139. def local_account(self):
  140. """property getter"""
  141. return self['account_number']
  142. @local_account.setter
  143. def local_account(self, local_account):
  144. """property setter"""
  145. self['account_number'] = local_account
  146. @property
  147. def local_currency(self):
  148. """property getter"""
  149. return self['currency_code']
  150. @local_currency.setter
  151. def local_currency(self, local_currency):
  152. """property setter"""
  153. self['currency_code'] = local_currency
  154. @property
  155. def start_balance(self):
  156. """property getter"""
  157. return self['balance_start']
  158. @start_balance.setter
  159. def start_balance(self, start_balance):
  160. """property setter"""
  161. self['balance_start'] = start_balance
  162. @property
  163. def end_balance(self):
  164. """property getter"""
  165. return self['balance_end']
  166. @end_balance.setter
  167. def end_balance(self, end_balance):
  168. """property setter"""
  169. self['balance_end'] = end_balance
  170. self['balance_end_real'] = end_balance
  171. @property
  172. def date(self):
  173. """property getter"""
  174. return self['date']
  175. @date.setter
  176. def date(self, date):
  177. """property setter"""
  178. self['date'] = date
  179. def create_transaction(self):
  180. """Create and append transaction.
  181. This should only be called after statement_id has been set, because
  182. statement_id will become part of the unique transaction_id.
  183. """
  184. transaction = BankTransaction()
  185. self['transactions'].append(transaction)
  186. # Fill default id, but might be overruled
  187. transaction['unique_import_id'] = (
  188. self.statement_id + str(len(self['transactions'])).zfill(4))
  189. return transaction
  190. def __init__(self):
  191. super(BankStatement, self).__init__()
  192. self['transactions'] = []
  193. self.statement_id = ''
  194. self.local_account = ''
  195. self.local_currency = ''
  196. self.date = ''
  197. self.start_balance = 0.0
  198. self.end_balance = 0.0