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
169 lines
5.4 KiB
import csv
|
|
import datetime
|
|
import hashlib
|
|
from io import StringIO
|
|
|
|
from odoo import _, models
|
|
|
|
ACCOUNT = "Compte donneur d'ordre"
|
|
CURRENCY = "Devise"
|
|
DATE = "Date"
|
|
AMOUNT = "Montant"
|
|
COUNTERPART_NUMBER = "Compte contrepartie"
|
|
COUNTERPART_NAME = "Contrepartie"
|
|
COMMUNICATION = "Communication"
|
|
TRANSACTION_TYPE = "Type d'opération"
|
|
|
|
|
|
class CodaBankStatementImport(models.TransientModel):
|
|
_inherit = "account.bank.statement.import"
|
|
|
|
_date_format = "%d/%m/%Y"
|
|
|
|
_decimal_sep = "."
|
|
_csv_delimiter = ";"
|
|
_csv_quote = '"'
|
|
|
|
_header = [
|
|
"Date",
|
|
"Montant",
|
|
"Devise",
|
|
"Contrepartie",
|
|
"Compte contrepartie",
|
|
"Type d'opération",
|
|
"Communication",
|
|
"Compte donneur d'ordre",
|
|
]
|
|
|
|
def _generate_note_crelan(self, move):
|
|
notes = []
|
|
notes.append(
|
|
"{}: {}".format(_("Counter Party Name"), move[COUNTERPART_NAME])
|
|
)
|
|
notes.append(
|
|
"{}: {}".format(
|
|
_("Counter Party Account"), move[COUNTERPART_NUMBER]
|
|
)
|
|
)
|
|
notes.append("{}: {}".format(_("Communication"), move[COMMUNICATION]))
|
|
return "\n".join(notes)
|
|
|
|
def _get_move_value_crelan(self, move, sequence):
|
|
move_data = {
|
|
"name": move[TRANSACTION_TYPE] + ": " + move[COMMUNICATION],
|
|
"note": self._generate_note_crelan(move),
|
|
"date": self._to_iso_date(move[DATE]),
|
|
"amount": float(move[AMOUNT]),
|
|
"account_number": move[COUNTERPART_NUMBER], # Ok
|
|
"partner_name": move[COUNTERPART_NAME], # Ok
|
|
"ref": move[DATE]
|
|
+ "-"
|
|
+ move[AMOUNT]
|
|
+ "-"
|
|
+ move[COUNTERPART_NUMBER]
|
|
+ "-"
|
|
+ move[COUNTERPART_NAME],
|
|
"sequence": sequence, # Ok
|
|
"unique_import_id": move[DATE]
|
|
+ "-"
|
|
+ move[AMOUNT]
|
|
+ "-"
|
|
+ move[COUNTERPART_NUMBER]
|
|
+ "-"
|
|
+ move[COUNTERPART_NAME]
|
|
+ "-"
|
|
+ hashlib.new("md5", move[COMMUNICATION].encode()).hexdigest(),
|
|
}
|
|
return move_data
|
|
|
|
def _get_statement_data_crelan(
|
|
self, balance_start, balance_end, begin_date, end_date
|
|
):
|
|
statement_data = {
|
|
"name": _("Bank Statement from %s to %s") % (begin_date, end_date),
|
|
"date": self._to_iso_date(end_date),
|
|
"balance_start": balance_start, # Ok
|
|
"balance_end_real": balance_end, # Ok
|
|
"transactions": [],
|
|
}
|
|
return statement_data
|
|
|
|
def _get_acc_number_crelan(self, acc_number):
|
|
# Check if we match the exact acc_number or the end of an acc number
|
|
journal = self.env["account.journal"].search(
|
|
[("bank_acc_number", "=like", "%" + acc_number)]
|
|
)
|
|
if not journal or len(journal) > 1: # If not found or ambiguious
|
|
return acc_number
|
|
|
|
return journal.bank_acc_number
|
|
|
|
def _get_acc_balance_crelan(self, acc_number):
|
|
if self.init_balance is not None:
|
|
return self.init_balance
|
|
|
|
journal = self.env["account.journal"].search(
|
|
[("bank_acc_number", "=like", "%" + acc_number)]
|
|
)
|
|
currency = journal.currency_id or journal.company_id.currency_id
|
|
if not journal or len(journal) > 1: # If not found or ambiguious
|
|
self.init_balance = 0.0
|
|
else:
|
|
lang = self._context.get("lang", "en_US")
|
|
lang = self.env["res.lang"].search([("code", "=", lang)])
|
|
balance = journal.get_journal_dashboard_datas()["last_balance"][
|
|
:-1
|
|
]
|
|
self.init_balance = float(
|
|
balance.replace(currency.symbol, "")
|
|
.strip()
|
|
.replace(lang.thousands_sep, "")
|
|
.replace(lang.decimal_point, ".")
|
|
)
|
|
return self.init_balance
|
|
|
|
def _to_iso_date(self, orig_date):
|
|
date_obj = datetime.datetime.strptime(orig_date, self._date_format)
|
|
return date_obj.strftime("%Y-%m-%d")
|
|
|
|
def _parse_file(self, data_file):
|
|
|
|
try:
|
|
csv_file = StringIO(data_file.decode())
|
|
data = csv.DictReader(
|
|
csv_file,
|
|
delimiter=self._csv_delimiter,
|
|
quotechar=self._csv_quote,
|
|
)
|
|
if not data.fieldnames == self._header:
|
|
raise ValueError()
|
|
except ValueError:
|
|
return super(CodaBankStatementImport, self)._parse_file(data_file)
|
|
|
|
currency_code = False
|
|
account_number = False
|
|
self.init_balance = None
|
|
begin_date = False
|
|
end_date = False
|
|
|
|
transactions = []
|
|
i = 1
|
|
sum_transaction = 0
|
|
for statement in data:
|
|
begin_date = begin_date or statement[DATE]
|
|
end_date = statement[DATE]
|
|
account_number = statement[ACCOUNT]
|
|
balance = self._get_acc_balance_crelan(account_number)
|
|
currency_code = statement[CURRENCY]
|
|
transactions.append(self._get_move_value_crelan(statement, i))
|
|
sum_transaction += float(statement[AMOUNT])
|
|
i += 1
|
|
stmt = self._get_statement_data_crelan(
|
|
balance, balance + sum_transaction, begin_date, end_date
|
|
)
|
|
stmt["transactions"] = transactions
|
|
return (
|
|
currency_code,
|
|
self._get_acc_number_crelan(account_number),
|
|
[stmt],
|
|
)
|