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.

169 lines
5.4 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. import csv
  2. import datetime
  3. import hashlib
  4. from io import StringIO
  5. from odoo import _, models
  6. ACCOUNT = "Compte donneur d'ordre"
  7. CURRENCY = "Devise"
  8. DATE = "Date"
  9. AMOUNT = "Montant"
  10. COUNTERPART_NUMBER = "Compte contrepartie"
  11. COUNTERPART_NAME = "Contrepartie"
  12. COMMUNICATION = "Communication"
  13. TRANSACTION_TYPE = "Type d'opération"
  14. class CodaBankStatementImport(models.TransientModel):
  15. _inherit = "account.bank.statement.import"
  16. _date_format = "%d/%m/%Y"
  17. _decimal_sep = "."
  18. _csv_delimiter = ";"
  19. _csv_quote = '"'
  20. _header = [
  21. "Date",
  22. "Montant",
  23. "Devise",
  24. "Contrepartie",
  25. "Compte contrepartie",
  26. "Type d'opération",
  27. "Communication",
  28. "Compte donneur d'ordre",
  29. ]
  30. def _generate_note_crelan(self, move):
  31. notes = []
  32. notes.append(
  33. "{}: {}".format(_("Counter Party Name"), move[COUNTERPART_NAME])
  34. )
  35. notes.append(
  36. "{}: {}".format(
  37. _("Counter Party Account"), move[COUNTERPART_NUMBER]
  38. )
  39. )
  40. notes.append("{}: {}".format(_("Communication"), move[COMMUNICATION]))
  41. return "\n".join(notes)
  42. def _get_move_value_crelan(self, move, sequence):
  43. move_data = {
  44. "name": move[TRANSACTION_TYPE] + ": " + move[COMMUNICATION],
  45. "note": self._generate_note_crelan(move),
  46. "date": self._to_iso_date(move[DATE]),
  47. "amount": float(move[AMOUNT]),
  48. "account_number": move[COUNTERPART_NUMBER], # Ok
  49. "partner_name": move[COUNTERPART_NAME], # Ok
  50. "ref": move[DATE]
  51. + "-"
  52. + move[AMOUNT]
  53. + "-"
  54. + move[COUNTERPART_NUMBER]
  55. + "-"
  56. + move[COUNTERPART_NAME],
  57. "sequence": sequence, # Ok
  58. "unique_import_id": move[DATE]
  59. + "-"
  60. + move[AMOUNT]
  61. + "-"
  62. + move[COUNTERPART_NUMBER]
  63. + "-"
  64. + move[COUNTERPART_NAME]
  65. + "-"
  66. + hashlib.new("md5", move[COMMUNICATION].encode()).hexdigest(),
  67. }
  68. return move_data
  69. def _get_statement_data_crelan(
  70. self, balance_start, balance_end, begin_date, end_date
  71. ):
  72. statement_data = {
  73. "name": _("Bank Statement from %s to %s") % (begin_date, end_date),
  74. "date": self._to_iso_date(end_date),
  75. "balance_start": balance_start, # Ok
  76. "balance_end_real": balance_end, # Ok
  77. "transactions": [],
  78. }
  79. return statement_data
  80. def _get_acc_number_crelan(self, acc_number):
  81. # Check if we match the exact acc_number or the end of an acc number
  82. journal = self.env["account.journal"].search(
  83. [("bank_acc_number", "=like", "%" + acc_number)]
  84. )
  85. if not journal or len(journal) > 1: # If not found or ambiguious
  86. return acc_number
  87. return journal.bank_acc_number
  88. def _get_acc_balance_crelan(self, acc_number):
  89. if self.init_balance is not None:
  90. return self.init_balance
  91. journal = self.env["account.journal"].search(
  92. [("bank_acc_number", "=like", "%" + acc_number)]
  93. )
  94. currency = journal.currency_id or journal.company_id.currency_id
  95. if not journal or len(journal) > 1: # If not found or ambiguious
  96. self.init_balance = 0.0
  97. else:
  98. lang = self._context.get("lang", "en_US")
  99. lang = self.env["res.lang"].search([("code", "=", lang)])
  100. balance = journal.get_journal_dashboard_datas()["last_balance"][
  101. :-1
  102. ]
  103. self.init_balance = float(
  104. balance.replace(currency.symbol, "")
  105. .strip()
  106. .replace(lang.thousands_sep, "")
  107. .replace(lang.decimal_point, ".")
  108. )
  109. return self.init_balance
  110. def _to_iso_date(self, orig_date):
  111. date_obj = datetime.datetime.strptime(orig_date, self._date_format)
  112. return date_obj.strftime("%Y-%m-%d")
  113. def _parse_file(self, data_file):
  114. try:
  115. csv_file = StringIO(data_file.decode())
  116. data = csv.DictReader(
  117. csv_file,
  118. delimiter=self._csv_delimiter,
  119. quotechar=self._csv_quote,
  120. )
  121. if not data.fieldnames == self._header:
  122. raise ValueError()
  123. except ValueError:
  124. return super(CodaBankStatementImport, self)._parse_file(data_file)
  125. currency_code = False
  126. account_number = False
  127. self.init_balance = None
  128. begin_date = False
  129. end_date = False
  130. transactions = []
  131. i = 1
  132. sum_transaction = 0
  133. for statement in data:
  134. begin_date = begin_date or statement[DATE]
  135. end_date = statement[DATE]
  136. account_number = statement[ACCOUNT]
  137. balance = self._get_acc_balance_crelan(account_number)
  138. currency_code = statement[CURRENCY]
  139. transactions.append(self._get_move_value_crelan(statement, i))
  140. sum_transaction += float(statement[AMOUNT])
  141. i += 1
  142. stmt = self._get_statement_data_crelan(
  143. balance, balance + sum_transaction, begin_date, end_date
  144. )
  145. stmt["transactions"] = transactions
  146. return (
  147. currency_code,
  148. self._get_acc_number_crelan(account_number),
  149. [stmt],
  150. )