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.

236 lines
7.3 KiB

  1. # -*- encoding: utf-8 -*-
  2. """Classes and definitions used in parsing bank statements."""
  3. ##############################################################################
  4. #
  5. # Copyright (C) 2015 Therp BV <http://therp.nl>.
  6. #
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU Affero General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU Affero General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Affero General Public License
  18. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. #
  20. ##############################################################################
  21. class BankTransaction(dict):
  22. """Single transaction that is part of a bank statement."""
  23. @property
  24. def value_date(self):
  25. """property getter"""
  26. return self['date']
  27. @value_date.setter
  28. def value_date(self, value_date):
  29. """property setter"""
  30. self['date'] = value_date
  31. @property
  32. def name(self):
  33. """property getter"""
  34. return self['name']
  35. @name.setter
  36. def name(self, name):
  37. """property setter"""
  38. self['name'] = name
  39. @property
  40. def transferred_amount(self):
  41. """property getter"""
  42. return self['amount']
  43. @transferred_amount.setter
  44. def transferred_amount(self, transferred_amount):
  45. """property setter"""
  46. self['amount'] = transferred_amount
  47. @property
  48. def eref(self):
  49. """property getter"""
  50. return self['ref']
  51. @eref.setter
  52. def eref(self, eref):
  53. """property setter"""
  54. self['ref'] = eref
  55. if not self.message:
  56. self.name = eref
  57. @property
  58. def message(self):
  59. """property getter"""
  60. return self._message
  61. @message.setter
  62. def message(self, message):
  63. """property setter"""
  64. self._message = message
  65. self.name = message
  66. @property
  67. def remote_owner(self):
  68. """property getter"""
  69. return self['partner_name']
  70. @remote_owner.setter
  71. def remote_owner(self, remote_owner):
  72. """property setter"""
  73. self['partner_name'] = remote_owner
  74. if not (self.message or self.eref):
  75. self.name = remote_owner
  76. @property
  77. def remote_account(self):
  78. """property getter"""
  79. return self['account_number']
  80. @remote_account.setter
  81. def remote_account(self, remote_account):
  82. """property setter"""
  83. self['account_number'] = remote_account
  84. @property
  85. def note(self):
  86. return self['note']
  87. @note.setter
  88. def note(self, note):
  89. self['note'] = note
  90. def __init__(self):
  91. """Define and initialize attributes.
  92. Not all attributes are already used in the actual import.
  93. """
  94. super(BankTransaction, self).__init__()
  95. self.transfer_type = False # Action type that initiated this message
  96. self.execution_date = False # The posted date of the action
  97. self.value_date = False # The value date of the action
  98. self.remote_account = False # The account of the other party
  99. self.remote_currency = False # The currency used by the other party
  100. self.exchange_rate = 0.0
  101. # The exchange rate used for conversion of local_currency and
  102. # remote_currency
  103. self.transferred_amount = 0.0 # actual amount transferred
  104. self.name = ''
  105. self._message = False # message from the remote party
  106. self.eref = False # end to end reference for transactions
  107. self.remote_owner = False # name of the other party
  108. self.remote_owner_address = [] # other parties address lines
  109. self.remote_owner_city = False # other parties city name
  110. self.remote_owner_postalcode = False # other parties zip code
  111. self.remote_owner_country_code = False # other parties country code
  112. self.remote_bank_bic = False # bic of other party's bank
  113. self.provision_costs = False # costs charged by bank for transaction
  114. self.provision_costs_currency = False
  115. self.provision_costs_description = False
  116. self.error_message = False # error message for interaction with user
  117. self.storno_retry = False
  118. # If True, make cancelled debit eligible for a next direct debit run
  119. self.data = '' # Raw data from which the transaction has been parsed
  120. class BankStatement(dict):
  121. """A bank statement groups data about several bank transactions."""
  122. @property
  123. def statement_id(self):
  124. """property getter"""
  125. return self['name']
  126. def _set_transaction_ids(self):
  127. """Set transaction ids to statement_id with sequence-number."""
  128. subno = 0
  129. for transaction in self['transactions']:
  130. subno += 1
  131. transaction['unique_import_id'] = (
  132. self.statement_id + 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