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.

167 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
  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(_("Counter Party Account"), move[COUNTERPART_NUMBER])
  37. )
  38. notes.append("{}: {}".format(_("Communication"), move[COMMUNICATION]))
  39. return "\n".join(notes)
  40. def _get_move_value_crelan(self, move, sequence):
  41. move_data = {
  42. "name": move[TRANSACTION_TYPE] + ": " + move[COMMUNICATION],
  43. "note": self._generate_note_crelan(move),
  44. "date": self._to_iso_date(move[DATE]),
  45. "amount": float(move[AMOUNT]),
  46. "account_number": move[COUNTERPART_NUMBER], # Ok
  47. "partner_name": move[COUNTERPART_NAME], # Ok
  48. "ref": move[DATE]
  49. + "-"
  50. + move[AMOUNT]
  51. + "-"
  52. + move[COUNTERPART_NUMBER]
  53. + "-"
  54. + move[COUNTERPART_NAME],
  55. "sequence": sequence, # Ok
  56. "unique_import_id": move[DATE]
  57. + "-"
  58. + move[AMOUNT]
  59. + "-"
  60. + move[COUNTERPART_NUMBER]
  61. + "-"
  62. + move[COUNTERPART_NAME]
  63. + "-"
  64. + hashlib.new("md5", move[COMMUNICATION].encode()).hexdigest(),
  65. }
  66. return move_data
  67. def _get_statement_data_crelan(
  68. self, balance_start, balance_end, begin_date, end_date
  69. ):
  70. statement_data = {
  71. "name": _("Bank Statement from %s to %s") % (begin_date, end_date),
  72. "date": self._to_iso_date(end_date),
  73. "balance_start": balance_start, # Ok
  74. "balance_end_real": balance_end, # Ok
  75. "transactions": [],
  76. }
  77. return statement_data
  78. def _get_acc_number_crelan(self, acc_number):
  79. # Check if we match the exact acc_number or the end of an acc number
  80. journal = self.env["account.journal"].search(
  81. [("bank_acc_number", "=like", "%" + acc_number)]
  82. )
  83. if not journal or len(journal) > 1: # If not found or ambiguious
  84. return acc_number
  85. return journal.bank_acc_number
  86. def _get_acc_balance_crelan(self, acc_number):
  87. if not self.init_balance == None:
  88. return self.init_balance
  89. journal = self.env["account.journal"].search(
  90. [("bank_acc_number", "=like", "%" + acc_number)]
  91. )
  92. currency = journal.currency_id or journal.company_id.currency_id
  93. if not journal or len(journal) > 1: # If not found or ambiguious
  94. self.init_balance = 0.0
  95. else:
  96. lang = self._context.get("lang", "en_US")
  97. l = self.env["res.lang"].search([("code", "=", lang)])
  98. balance = journal.get_journal_dashboard_datas()["last_balance"][
  99. :-1
  100. ]
  101. self.init_balance = float(
  102. balance.replace(currency.symbol, "")
  103. .strip()
  104. .replace(l.thousands_sep, "")
  105. .replace(l.decimal_point, ".")
  106. )
  107. return self.init_balance
  108. def _to_iso_date(self, orig_date):
  109. date_obj = datetime.datetime.strptime(orig_date, self._date_format)
  110. return date_obj.strftime("%Y-%m-%d")
  111. def _parse_file(self, data_file):
  112. try:
  113. csv_file = StringIO(data_file.decode())
  114. data = csv.DictReader(
  115. csv_file,
  116. delimiter=self._csv_delimiter,
  117. quotechar=self._csv_quote,
  118. )
  119. if not data.fieldnames == self._header:
  120. raise ValueError()
  121. except ValueError:
  122. return super(CodaBankStatementImport, self)._parse_file(data_file)
  123. currency_code = False
  124. account_number = False
  125. self.init_balance = None
  126. begin_date = False
  127. end_date = False
  128. transactions = []
  129. i = 1
  130. sum_transaction = 0
  131. for statement in data:
  132. begin_date = begin_date or statement[DATE]
  133. end_date = statement[DATE]
  134. account_number = statement[ACCOUNT]
  135. balance = self._get_acc_balance_crelan(account_number)
  136. currency_code = statement[CURRENCY]
  137. transactions.append(self._get_move_value_crelan(statement, i))
  138. sum_transaction += float(statement[AMOUNT])
  139. i += 1
  140. stmt = self._get_statement_data_crelan(
  141. balance, balance + sum_transaction, begin_date, end_date
  142. )
  143. stmt["transactions"] = transactions
  144. return (
  145. currency_code,
  146. self._get_acc_number_crelan(account_number),
  147. [stmt],
  148. )