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.

153 lines
5.5 KiB

  1. # Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
  2. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
  3. from odoo import api, fields, models
  4. from dateutil.relativedelta import relativedelta, MO
  5. from decimal import Decimal
  6. class AccountBankStatementImport(models.TransientModel):
  7. _inherit = 'account.bank.statement.import'
  8. import_mode = fields.Selection(
  9. selection=[
  10. ('single', 'Single statement'),
  11. ('daily', 'Daily statements'),
  12. ('weekly', 'Weekly statements'),
  13. ('monthly', 'Monthly statements'),
  14. ],
  15. default='single',
  16. )
  17. def _complete_stmts_vals(self, stmts_vals, journal, account_number):
  18. stmts_vals = super()._complete_stmts_vals(
  19. stmts_vals,
  20. journal,
  21. account_number
  22. )
  23. if not self.import_mode or self.import_mode == 'single':
  24. return stmts_vals
  25. statements = []
  26. for st_vals in stmts_vals:
  27. transactions = list(sorted(
  28. map(
  29. lambda transaction: self._prepare_transaction(
  30. transaction
  31. ),
  32. st_vals['transactions']
  33. ),
  34. key=lambda transaction: transaction['date']
  35. ))
  36. if not transactions:
  37. continue
  38. del st_vals['transactions']
  39. balance_start = Decimal(st_vals['balance_start']) \
  40. if 'balance_start' in st_vals else None
  41. balance_end = Decimal(st_vals['balance_end_real']) \
  42. if 'balance_end_real' in st_vals else None
  43. statement_date_since = self._get_statement_date_since(
  44. transactions[0]['date']
  45. )
  46. while transactions:
  47. statement_date_until = (
  48. statement_date_since + self._get_statement_date_step()
  49. )
  50. last_transaction_index = None
  51. for index, transaction in enumerate(transactions):
  52. if transaction['date'] >= statement_date_until:
  53. break
  54. last_transaction_index = index
  55. if last_transaction_index is None:
  56. # NOTE: No transactions for current period
  57. statement_date_since = statement_date_until
  58. continue
  59. statement_transactions = \
  60. transactions[0:last_transaction_index + 1]
  61. transactions = transactions[last_transaction_index + 1:]
  62. statement_values = dict(st_vals)
  63. statement_values.update({
  64. 'name': self._get_statement_name(
  65. journal,
  66. statement_date_since,
  67. statement_date_until,
  68. ),
  69. 'date': self._get_statement_date(
  70. statement_date_since,
  71. statement_date_until,
  72. ),
  73. 'transactions': statement_transactions,
  74. })
  75. if balance_start is not None:
  76. statement_values.update({
  77. 'balance_start': float(balance_start),
  78. })
  79. for transaction in statement_transactions:
  80. balance_start += Decimal(transaction['amount'])
  81. if balance_end is not None:
  82. statement_balance_end = balance_end
  83. for transaction in transactions:
  84. statement_balance_end -= Decimal(transaction['amount'])
  85. statement_values.update({
  86. 'balance_end_real': float(statement_balance_end),
  87. })
  88. statements.append(statement_values)
  89. statement_date_since = statement_date_until
  90. return statements
  91. @api.multi
  92. def _prepare_transaction(self, transaction):
  93. transaction.update({
  94. 'date': fields.Date.from_string(transaction['date']),
  95. })
  96. return transaction
  97. @api.multi
  98. def _get_statement_date_since(self, date):
  99. self.ensure_one()
  100. if self.import_mode == 'daily':
  101. return date
  102. elif self.import_mode == 'weekly':
  103. return date + relativedelta(weekday=MO(-1))
  104. elif self.import_mode == 'monthly':
  105. return date.replace(
  106. day=1,
  107. )
  108. @api.multi
  109. def _get_statement_date_step(self):
  110. self.ensure_one()
  111. if self.import_mode == 'daily':
  112. return relativedelta(
  113. days=1,
  114. )
  115. elif self.import_mode == 'weekly':
  116. return relativedelta(
  117. weeks=1,
  118. weekday=MO,
  119. )
  120. elif self.import_mode == 'monthly':
  121. return relativedelta(
  122. months=1,
  123. day=1,
  124. )
  125. @api.multi
  126. def _get_statement_date(self, date_since, date_until):
  127. self.ensure_one()
  128. # NOTE: Statement date is treated by Odoo as start of period. Details
  129. # - addons/account/models/account_journal_dashboard.py
  130. # - def get_line_graph_datas()
  131. return date_since
  132. @api.multi
  133. def _get_statement_name(self, journal, date_since, date_until):
  134. self.ensure_one()
  135. return journal.sequence_id.with_context(
  136. ir_sequence_date=self._get_statement_date(date_since, date_until)
  137. ).next_by_id()