[MIG] account_bank_statement_import_txt_xlsx: Migration to 13.0

This commit is contained in:
mreficent
2020-02-10 16:24:02 +01:00
committed by Sergio Zanchetta
parent 51e4044692
commit 1e0efc397a
13 changed files with 182 additions and 262 deletions

View File

@@ -14,13 +14,13 @@ Account Bank Statement Import TXT XLSX
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fbank--statement--import-lightgray.png?logo=github
:target: https://github.com/OCA/bank-statement-import/tree/12.0/account_bank_statement_import_txt_xlsx
:target: https://github.com/OCA/bank-statement-import/tree/13.0/account_bank_statement_import_txt_xlsx
:alt: OCA/bank-statement-import
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/bank-statement-import-12-0/bank-statement-import-12-0-account_bank_statement_import_txt_xlsx
:target: https://translation.odoo-community.org/projects/bank-statement-import-13.0/bank-statement-import-13.0-account_bank_statement_import_txt_xlsx
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/174/12.0
:target: https://runbot.odoo-community.org/runbot/174/13.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
@@ -62,7 +62,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/OCA/bank-statement-import/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/bank-statement-import/issues/new?body=module:%20account_bank_statement_import_txt_xlsx%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
`feedback <https://github.com/OCA/bank-statement-import/issues/new?body=module:%20account_bank_statement_import_txt_xlsx%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
@@ -72,7 +72,7 @@ Credits
Authors
~~~~~~~
* Eficent
* ForgeFlow
Contributors
~~~~~~~~~~~~
@@ -82,8 +82,8 @@ Contributors
* Tecnativa (https://www.tecnativa.com)
* Vicent Cubells <vicent.cubells@tecnativa.com>
* Victor M.M. Torres <victor.martin@tecnativa.com>
* Eficent (https://www.eficent.com)
* Jordi Ballester Alomar <jordi.ballester@eficent.com>
* ForgeFlow (https://www.forgeflow.com)
* Jordi Ballester Alomar <jordi.ballester@forgeflow.com>
Maintainers
~~~~~~~~~~~
@@ -98,6 +98,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
This module is part of the `OCA/bank-statement-import <https://github.com/OCA/bank-statement-import/tree/12.0/account_bank_statement_import_txt_xlsx>`_ project on GitHub.
This module is part of the `OCA/bank-statement-import <https://github.com/OCA/bank-statement-import/tree/13.0/account_bank_statement_import_txt_xlsx>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@@ -5,10 +5,10 @@
{
"name": "Account Bank Statement Import TXT XLSX",
"summary": "Import TXT/CSV or XLSX files as Bank Statements in Odoo",
"version": "12.0.2.0.0",
"version": "13.0.1.0.0",
"category": "Accounting",
"website": "https://github.com/OCA/bank-statement-import",
"author": "ForgeFlow, " "Brainbean Apps, " "Odoo Community Association (OCA)",
"author": "ForgeFlow, Brainbean Apps, Odoo Community Association (OCA)",
"license": "AGPL-3",
"installable": True,
"depends": [
@@ -16,7 +16,7 @@
"multi_step_wizard",
"web_widget_dropdown_dynamic",
],
"external_dependencies": {"python": ["csv", "xlrd",]},
"external_dependencies": {"python": ["csv", "xlrd"]},
"data": [
"security/ir.model.access.csv",
"data/map_data.xml",

View File

@@ -4,7 +4,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: <>\n"
"Language-Team: \n"

View File

@@ -1,98 +0,0 @@
# Copyright 2020 Brainbean Apps (https://brainbeanapps.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from openupgradelib import openupgrade
@openupgrade.migrate()
def migrate(env, version):
openupgrade.logged_query(
env.cr,
"""
WITH _mappings AS (
SELECT
m.id,
l.field_to_assign,
l.name,
l.date_format
FROM
account_bank_statement_import_map AS m
RIGHT OUTER JOIN (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY map_parent_id, field_to_assign
ORDER BY id ASC
) AS row_number
FROM account_bank_statement_import_map_line
WHERE field_to_assign IS NOT NULL
) AS l ON m.id = l.map_parent_id AND l.row_number = 1
)
INSERT INTO account_bank_statement_import_sheet_mapping (
name,
float_thousands_sep,
float_decimal_sep,
file_encoding,
delimiter,
quotechar,
timestamp_format,
timestamp_column,
amount_column,
original_currency_column,
original_amount_column,
description_column,
reference_column,
notes_column,
partner_name_column,
bank_account_column
)
SELECT
m.name,
m.float_thousands_sep,
m.float_decimal_sep,
m.file_encoding,
(
CASE
WHEN m.delimiter='.' THEN 'dot'
WHEN m.delimiter=',' THEN 'comma'
WHEN m.delimiter=';' THEN 'semicolon'
WHEN m.delimiter='' THEN 'n/a'
WHEN m.delimiter='\t' THEN 'tab'
WHEN m.delimiter=' ' THEN 'space'
ELSE 'n/a'
END
) AS delimiter,
m.quotechar,
COALESCE(_date.date_format, '%m/%d/%Y') AS timestamp_format,
COALESCE(_date.name, 'Date') AS timestamp_column,
COALESCE(_amount.name, 'Amount') AS amount_column,
_o_currency.name AS original_currency_column,
_o_amount.name AS original_amount_column,
_description.name AS description_column,
_ref.name AS reference_column,
_notes.name AS notes_column,
_p_name.name AS partner_name_column,
_bank_acc.name AS bank_account_column
FROM
account_bank_statement_import_map AS m
LEFT JOIN _mappings AS _date
ON m.id = _date.id AND _date.field_to_assign = 'date'
LEFT JOIN _mappings AS _description
ON m.id = _description.id AND _description.field_to_assign = 'name'
LEFT JOIN _mappings AS _o_currency
ON m.id = _o_currency.id AND _o_currency.field_to_assign = 'currency'
LEFT JOIN _mappings AS _amount
ON m.id = _amount.id AND _amount.field_to_assign = 'amount'
LEFT JOIN _mappings AS _o_amount
ON m.id = _o_amount.id AND _o_amount.field_to_assign = 'amount_currency'
LEFT JOIN _mappings AS _ref
ON m.id = _ref.id AND _ref.field_to_assign = 'ref'
LEFT JOIN _mappings AS _notes
ON m.id = _notes.id AND _notes.field_to_assign = 'note'
LEFT JOIN _mappings AS _p_name
ON m.id = _p_name.id AND _p_name.field_to_assign = 'partner_name'
LEFT JOIN _mappings AS _bank_acc
ON m.id = _bank_acc.id AND _bank_acc.field_to_assign = 'account_number';
""",
)

View File

@@ -3,7 +3,7 @@
import logging
from odoo import api, fields, models
from odoo import fields, models
_logger = logging.getLogger(__name__)
@@ -24,13 +24,12 @@ class AccountBankStatementImport(models.TransientModel):
default=_get_default_mapping_id,
)
@api.multi
def _parse_file(self, data_file):
self.ensure_one()
try:
Parser = self.env["account.bank.statement.import.sheet.parser"]
return Parser.parse(self.sheet_mapping_id, data_file, self.filename)
except:
return Parser.parse(data_file, self.sheet_mapping_id)
except BaseException:
if self.env.context.get("account_bank_statement_import_txt_xlsx_test"):
raise
_logger.warning("Sheet parser error", exc_info=True)

View File

@@ -12,12 +12,12 @@ class AccountBankStatementImportSheetMapping(models.Model):
name = fields.Char(required=True,)
float_thousands_sep = fields.Selection(
string="Thousands Separator",
selection=[("dot", "dot (.)"), ("comma", "comma (,)"), ("none", "none"),],
selection=[("dot", "dot (.)"), ("comma", "comma (,)"), ("none", "none")],
default="dot",
)
float_decimal_sep = fields.Selection(
string="Decimals Separator",
selection=[("dot", "dot (.)"), ("comma", "comma (,)"), ("none", "none"),],
selection=[("dot", "dot (.)"), ("comma", "comma (,)"), ("none", "none")],
default="comma",
)
file_encoding = fields.Selection(
@@ -52,9 +52,9 @@ class AccountBankStatementImportSheetMapping(models.Model):
],
default="comma",
)
quotechar = fields.Char(string="Text qualifier", size=1, default='"',)
timestamp_format = fields.Char(string="Timestamp Format", required=True,)
timestamp_column = fields.Char(string="Timestamp column", required=True,)
quotechar = fields.Char(string="Text qualifier", size=1, default='"')
timestamp_format = fields.Char(string="Timestamp Format", required=True)
timestamp_column = fields.Char(string="Timestamp column", required=True)
currency_column = fields.Char(
string="Currency column",
help=(
@@ -127,7 +127,6 @@ class AccountBankStatementImportSheetMapping(models.Model):
elif "comma" == self.float_thousands_sep == self.float_decimal_sep:
self.float_thousands_sep = "dot"
@api.multi
def _get_float_separators(self):
self.ensure_one()
separators = {
@@ -143,9 +142,8 @@ class AccountBankStatementImportSheetMapping(models.Model):
@api.model
def _decode_column_delimiter_character(self, delimiter):
return (
{"dot": ".", "comma": ",", "semicolon": ";", "tab": "\t", "space": " ",}
{"dot": ".", "comma": ",", "semicolon": ";", "tab": "\t", "space": " "}
).get(delimiter)
@api.multi
def _get_column_delimiter_character(self):
return self._decode_column_delimiter_character(self.delimiter)

View File

@@ -7,7 +7,6 @@ import logging
from datetime import datetime
from decimal import Decimal
from io import StringIO
from os import path
from odoo import _, api, models
@@ -43,21 +42,19 @@ class AccountBankStatementImportSheetParser(models.TransientModel):
return list(next(csv_data))
@api.model
def parse(self, mapping, data_file, filename):
def parse(self, data_file, mapping):
journal = self.env["account.journal"].browse(self.env.context.get("journal_id"))
currency_code = (journal.currency_id or journal.company_id.currency_id).name
account_number = journal.bank_account_id.acc_number
name = _("%s: %s") % (journal.code, path.basename(filename),)
lines = self._parse_lines(mapping, data_file, currency_code)
if not lines:
return currency_code, account_number, [{"name": name, "transactions": [],}]
return currency_code, account_number, [{"transactions": []}]
lines = list(sorted(lines, key=lambda line: line["timestamp"]))
first_line = lines[0]
last_line = lines[-1]
data = {
"name": name,
"date": first_line["timestamp"].date(),
}
@@ -77,13 +74,12 @@ class AccountBankStatementImportSheetParser(models.TransientModel):
map(lambda line: self._convert_line_to_transactions(line), lines)
)
)
data.update(
{"transactions": transactions,}
)
data.update({"transactions": transactions})
return currency_code, account_number, [data]
def _parse_lines(self, mapping, data_file, currency_code):
columns = dict()
try:
workbook = xlrd.open_workbook(
file_contents=data_file,
@@ -111,59 +107,61 @@ class AccountBankStatementImportSheetParser(models.TransientModel):
header = [str(value) for value in csv_or_xlsx[1].row_values(0)]
else:
header = [value.strip() for value in next(csv_or_xlsx)]
timestamp_column = header.index(mapping.timestamp_column)
currency_column = (
columns["timestamp_column"] = header.index(mapping.timestamp_column)
columns["currency_column"] = (
header.index(mapping.currency_column) if mapping.currency_column else None
)
amount_column = header.index(mapping.amount_column)
balance_column = (
columns["amount_column"] = header.index(mapping.amount_column)
columns["balance_column"] = (
header.index(mapping.balance_column) if mapping.balance_column else None
)
original_currency_column = (
columns["original_currency_column"] = (
header.index(mapping.original_currency_column)
if mapping.original_currency_column
else None
)
original_amount_column = (
columns["original_amount_column"] = (
header.index(mapping.original_amount_column)
if mapping.original_amount_column
else None
)
debit_credit_column = (
columns["debit_credit_column"] = (
header.index(mapping.debit_credit_column)
if mapping.debit_credit_column
else None
)
transaction_id_column = (
columns["transaction_id_column"] = (
header.index(mapping.transaction_id_column)
if mapping.transaction_id_column
else None
)
description_column = (
columns["description_column"] = (
header.index(mapping.description_column)
if mapping.description_column
else None
)
notes_column = (
columns["notes_column"] = (
header.index(mapping.notes_column) if mapping.notes_column else None
)
reference_column = (
columns["reference_column"] = (
header.index(mapping.reference_column) if mapping.reference_column else None
)
partner_name_column = (
columns["partner_name_column"] = (
header.index(mapping.partner_name_column)
if mapping.partner_name_column
else None
)
bank_name_column = (
columns["bank_name_column"] = (
header.index(mapping.bank_name_column) if mapping.bank_name_column else None
)
bank_account_column = (
columns["bank_account_column"] = (
header.index(mapping.bank_account_column)
if mapping.bank_account_column
else None
)
return self._parse_rows(mapping, currency_code, csv_or_xlsx, columns)
def _parse_rows(self, mapping, currency_code, csv_or_xlsx, columns): # noqa: C901
if isinstance(csv_or_xlsx, tuple):
rows = range(1, csv_or_xlsx[1].nrows)
else:
@@ -184,47 +182,67 @@ class AccountBankStatementImportSheetParser(models.TransientModel):
else:
values = list(row)
timestamp = values[timestamp_column]
timestamp = values[columns["timestamp_column"]]
currency = (
values[currency_column]
if currency_column is not None
values[columns["currency_column"]]
if columns["currency_column"] is not None
else currency_code
)
amount = values[amount_column]
balance = values[balance_column] if balance_column is not None else None
amount = values[columns["amount_column"]]
balance = (
values[columns["balance_column"]]
if columns["balance_column"] is not None
else None
)
original_currency = (
values[original_currency_column]
if original_currency_column is not None
values[columns["original_currency_column"]]
if columns["original_currency_column"] is not None
else None
)
original_amount = (
values[original_amount_column]
if original_amount_column is not None
values[columns["original_amount_column"]]
if columns["original_amount_column"] is not None
else None
)
debit_credit = (
values[debit_credit_column] if debit_credit_column is not None else None
values[columns["debit_credit_column"]]
if columns["debit_credit_column"] is not None
else None
)
transaction_id = (
values[transaction_id_column]
if transaction_id_column is not None
values[columns["transaction_id_column"]]
if columns["transaction_id_column"] is not None
else None
)
description = (
values[description_column] if description_column is not None else None
values[columns["description_column"]]
if columns["description_column"] is not None
else None
)
notes = (
values[columns["notes_column"]]
if columns["notes_column"] is not None
else None
)
notes = values[notes_column] if notes_column is not None else None
reference = (
values[reference_column] if reference_column is not None else None
values[columns["reference_column"]]
if columns["reference_column"] is not None
else None
)
partner_name = (
values[partner_name_column] if partner_name_column is not None else None
values[columns["partner_name_column"]]
if columns["partner_name_column"] is not None
else None
)
bank_name = (
values[bank_name_column] if bank_name_column is not None else None
values[columns["bank_name_column"]]
if columns["bank_name_column"] is not None
else None
)
bank_account = (
values[bank_account_column] if bank_account_column is not None else None
values[columns["bank_account_column"]]
if columns["bank_account_column"] is not None
else None
)
if currency != currency_code:
@@ -310,8 +328,7 @@ class AccountBankStatementImportSheetParser(models.TransientModel):
if transaction_id:
transaction["unique_import_id"] = "{}-{}".format(
transaction_id,
int(timestamp.timestamp()),
transaction_id, int(timestamp.timestamp()),
)
transaction["name"] = description or _("N/A")

View File

@@ -3,6 +3,7 @@
* Tecnativa (https://www.tecnativa.com)
* Vicent Cubells <vicent.cubells@tecnativa.com>
* Victor M.M. Torres <victor.martin@tecnativa.com>
* Eficent (https://www.eficent.com)
* Jordi Ballester Alomar <jordi.ballester@eficent.com>
* ForgeFlow (https://www.forgeflow.com)
* Jordi Ballester Alomar <jordi.ballester@forgeflow.com>
* Miquel Raïch Regué <miquel.raich@forgeflow.com>
* Alexey Pelykh <alexey.pelykh@brainbeanapps.com>

View File

@@ -367,7 +367,7 @@ ul.auto-toc {
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/bank-statement-import/tree/12.0/account_bank_statement_import_txt_xlsx"><img alt="OCA/bank-statement-import" src="https://img.shields.io/badge/github-OCA%2Fbank--statement--import-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/bank-statement-import-12-0/bank-statement-import-12-0-account_bank_statement_import_txt_xlsx"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/174/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/bank-statement-import/tree/13.0/account_bank_statement_import_txt_xlsx"><img alt="OCA/bank-statement-import" src="https://img.shields.io/badge/github-OCA%2Fbank--statement--import-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/bank-statement-import-13.0/bank-statement-import-13.0-account_bank_statement_import_txt_xlsx"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/174/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module allows you to import the any TXT/CSV or XLSX file in Odoo as bank
statements.</p>
<p><strong>Table of contents</strong></p>
@@ -410,7 +410,7 @@ Lines</strong> and set every line with which field of statement have to match.</
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/bank-statement-import/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/bank-statement-import/issues/new?body=module:%20account_bank_statement_import_txt_xlsx%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<a class="reference external" href="https://github.com/OCA/bank-statement-import/issues/new?body=module:%20account_bank_statement_import_txt_xlsx%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
@@ -418,7 +418,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id5">Authors</a></h2>
<ul class="simple">
<li>Eficent</li>
<li>ForgeFlow</li>
</ul>
</div>
<div class="section" id="contributors">
@@ -429,8 +429,8 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<li>Tecnativa (<a class="reference external" href="https://www.tecnativa.com">https://www.tecnativa.com</a>)
* Vicent Cubells &lt;<a class="reference external" href="mailto:vicent.cubells&#64;tecnativa.com">vicent.cubells&#64;tecnativa.com</a>&gt;
* Victor M.M. Torres &lt;<a class="reference external" href="mailto:victor.martin&#64;tecnativa.com">victor.martin&#64;tecnativa.com</a>&gt;</li>
<li>Eficent (<a class="reference external" href="https://www.eficent.com">https://www.eficent.com</a>)
* Jordi Ballester Alomar &lt;<a class="reference external" href="mailto:jordi.ballester&#64;eficent.com">jordi.ballester&#64;eficent.com</a>&gt;</li>
<li>ForgeFlow (<a class="reference external" href="https://www.forgeflow.com">https://www.forgeflow.com</a>)
* Jordi Ballester Alomar &lt;<a class="reference external" href="mailto:jordi.ballester&#64;forgeflow.com">jordi.ballester&#64;forgeflow.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
@@ -440,7 +440,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/bank-statement-import/tree/12.0/account_bank_statement_import_txt_xlsx">OCA/bank-statement-import</a> project on GitHub.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/bank-statement-import/tree/13.0/account_bank_statement_import_txt_xlsx">OCA/bank-statement-import</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>

View File

@@ -47,24 +47,21 @@ class TestAccountBankStatementImportTxtXlsx(common.TransactionCase):
"currency_id": self.currency_usd.id,
}
)
data = self._data_file("fixtures/sample_statement_en.csv", "utf-8")
wizard = self.AccountBankStatementImport.with_context(
{"journal_id": journal.id,}
journal_id=journal.id
).create(
{
"filename": "fixtures/sample_statement_en.csv",
"data_file": self._data_file(
"fixtures/sample_statement_en.csv", "utf-8"
),
"attachment_ids": [
(0, 0, {"name": "fixtures/sample_statement_en.csv", "datas": data})
],
"sheet_mapping_id": self.sample_statement_map.id,
}
)
wizard.with_context(
{
"journal_id": journal.id,
"account_bank_statement_import_txt_xlsx_test": True,
}
account_bank_statement_import_txt_xlsx_test=True
).import_file()
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id),])
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 1)
self.assertEqual(len(statement.line_ids), 2)
@@ -77,25 +74,22 @@ class TestAccountBankStatementImportTxtXlsx(common.TransactionCase):
"currency_id": self.currency_usd.id,
}
)
data = self._data_file("fixtures/empty_statement_en.csv", "utf-8")
wizard = self.AccountBankStatementImport.with_context(
{"journal_id": journal.id,}
journal_id=journal.id
).create(
{
"filename": "fixtures/empty_statement_en.csv",
"data_file": self._data_file(
"fixtures/empty_statement_en.csv", "utf-8"
),
"attachment_ids": [
(0, 0, {"name": "fixtures/empty_statement_en.csv", "datas": data})
],
"sheet_mapping_id": self.sample_statement_map.id,
}
)
with self.assertRaises(UserError):
wizard.with_context(
{
"journal_id": journal.id,
"account_bank_statement_import_txt_xlsx_test": True,
}
account_bank_statement_import_txt_xlsx_test=True
).import_file()
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id),])
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 0)
def test_import_xlsx_file(self):
@@ -107,22 +101,21 @@ class TestAccountBankStatementImportTxtXlsx(common.TransactionCase):
"currency_id": self.currency_usd.id,
}
)
data = self._data_file("fixtures/sample_statement_en.xlsx")
wizard = self.AccountBankStatementImport.with_context(
{"journal_id": journal.id,}
journal_id=journal.id
).create(
{
"filename": "fixtures/sample_statement_en.xlsx",
"data_file": self._data_file("fixtures/sample_statement_en.xlsx"),
"attachment_ids": [
(0, 0, {"name": "fixtures/sample_statement_en.xlsx", "datas": data})
],
"sheet_mapping_id": self.sample_statement_map.id,
}
)
wizard.with_context(
{
"journal_id": journal.id,
"account_bank_statement_import_txt_xlsx_test": True,
}
account_bank_statement_import_txt_xlsx_test=True
).import_file()
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id),])
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 1)
self.assertEqual(len(statement.line_ids), 2)
@@ -135,29 +128,33 @@ class TestAccountBankStatementImportTxtXlsx(common.TransactionCase):
"currency_id": self.currency_usd.id,
}
)
data = self._data_file("fixtures/empty_statement_en.xlsx")
wizard = self.AccountBankStatementImport.with_context(
{"journal_id": journal.id,}
journal_id=journal.id
).create(
{
"filename": "fixtures/empty_statement_en.xlsx",
"data_file": self._data_file("fixtures/empty_statement_en.xlsx"),
"attachment_ids": [
(0, 0, {"name": "fixtures/empty_statement_en.xlsx", "datas": data})
],
"sheet_mapping_id": self.sample_statement_map.id,
}
)
with self.assertRaises(UserError):
wizard.with_context(
{
"journal_id": journal.id,
"account_bank_statement_import_txt_xlsx_test": True,
}
account_bank_statement_import_txt_xlsx_test=True
).import_file()
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id),])
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 0)
def test_mapping_import_wizard_xlsx(self):
with common.Form(self.AccountBankStatementImportSheetMappingWizard) as form:
form.filename = "fixtures/empty_statement_en.xlsx"
form.data_file = self._data_file("fixtures/empty_statement_en.xlsx")
attachment = self.env["ir.attachment"].create(
{
"name": "fixtures/empty_statement_en.xlsx",
"datas": self._data_file("fixtures/empty_statement_en.xlsx"),
}
)
form.attachment_ids.add(attachment)
self.assertEqual(len(form.header), 90)
self.assertEqual(
len(
@@ -174,8 +171,13 @@ class TestAccountBankStatementImportTxtXlsx(common.TransactionCase):
def test_mapping_import_wizard_csv(self):
with common.Form(self.AccountBankStatementImportSheetMappingWizard) as form:
form.filename = "fixtures/empty_statement_en.csv"
form.data_file = self._data_file("fixtures/empty_statement_en.csv")
attachment = self.env["ir.attachment"].create(
{
"name": "fixtures/empty_statement_en.csv",
"datas": self._data_file("fixtures/empty_statement_en.csv"),
}
)
form.attachment_ids.add(attachment)
self.assertEqual(len(form.header), 90)
self.assertEqual(
len(
@@ -199,22 +201,21 @@ class TestAccountBankStatementImportTxtXlsx(common.TransactionCase):
"currency_id": self.currency_usd.id,
}
)
data = self._data_file("fixtures/original_currency.csv", "utf-8")
wizard = self.AccountBankStatementImport.with_context(
{"journal_id": journal.id,}
journal_id=journal.id
).create(
{
"filename": "fixtures/original_currency.csv",
"data_file": self._data_file("fixtures/original_currency.csv", "utf-8"),
"attachment_ids": [
(0, 0, {"name": "fixtures/original_currency.csv", "datas": data})
],
"sheet_mapping_id": self.sample_statement_map.id,
}
)
wizard.with_context(
{
"journal_id": journal.id,
"account_bank_statement_import_txt_xlsx_test": True,
}
account_bank_statement_import_txt_xlsx_test=True
).import_file()
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id),])
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 1)
self.assertEqual(len(statement.line_ids), 1)
@@ -238,22 +239,21 @@ class TestAccountBankStatementImportTxtXlsx(common.TransactionCase):
"original_amount_column": None,
}
)
data = self._data_file("fixtures/multi_currency.csv", "utf-8")
wizard = self.AccountBankStatementImport.with_context(
{"journal_id": journal.id,}
journal_id=journal.id
).create(
{
"filename": "fixtures/multi_currency.csv",
"data_file": self._data_file("fixtures/multi_currency.csv", "utf-8"),
"attachment_ids": [
(0, 0, {"name": "fixtures/multi_currency.csv", "datas": data})
],
"sheet_mapping_id": statement_map.id,
}
)
wizard.with_context(
{
"journal_id": journal.id,
"account_bank_statement_import_txt_xlsx_test": True,
}
account_bank_statement_import_txt_xlsx_test=True
).import_file()
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id),])
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 1)
self.assertEqual(len(statement.line_ids), 1)
@@ -277,22 +277,21 @@ class TestAccountBankStatementImportTxtXlsx(common.TransactionCase):
"original_amount_column": None,
}
)
data = self._data_file("fixtures/balance.csv", "utf-8")
wizard = self.AccountBankStatementImport.with_context(
{"journal_id": journal.id,}
journal_id=journal.id
).create(
{
"filename": "fixtures/balance.csv",
"data_file": self._data_file("fixtures/balance.csv", "utf-8"),
"attachment_ids": [
(0, 0, {"name": "fixtures/balance.csv", "datas": data})
],
"sheet_mapping_id": statement_map.id,
}
)
wizard.with_context(
{
"journal_id": journal.id,
"account_bank_statement_import_txt_xlsx_test": True,
}
account_bank_statement_import_txt_xlsx_test=True
).import_file()
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id),])
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 1)
self.assertEqual(len(statement.line_ids), 2)
self.assertEqual(statement.balance_start, 10.0)
@@ -318,22 +317,21 @@ class TestAccountBankStatementImportTxtXlsx(common.TransactionCase):
"credit_value": "C",
}
)
data = self._data_file("fixtures/debit_credit.csv", "utf-8")
wizard = self.AccountBankStatementImport.with_context(
{"journal_id": journal.id,}
journal_id=journal.id
).create(
{
"filename": "fixtures/debit_credit.csv",
"data_file": self._data_file("fixtures/debit_credit.csv", "utf-8"),
"attachment_ids": [
(0, 0, {"name": "fixtures/debit_credit.csv", "datas": data})
],
"sheet_mapping_id": statement_map.id,
}
)
wizard.with_context(
{
"journal_id": journal.id,
"account_bank_statement_import_txt_xlsx_test": True,
}
account_bank_statement_import_txt_xlsx_test=True
).import_file()
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id),])
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 1)
self.assertEqual(len(statement.line_ids), 2)
self.assertEqual(statement.balance_start, 10.0)

View File

@@ -78,7 +78,6 @@
>
<field name="name">Statement Sheet Mappings</field>
<field name="res_model">account.bank.statement.import.sheet.mapping</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem

View File

@@ -14,8 +14,12 @@ class AccountBankStatementImportSheetMappingWizard(models.TransientModel):
_description = "Account Bank Statement Import Sheet Mapping Wizard"
_inherit = ["multi.step.wizard.mixin"]
data_file = fields.Binary(string="Bank Statement File", required=True,)
filename = fields.Char()
attachment_ids = fields.Many2many(
comodel_name="ir.attachment",
string="Files",
required=True,
relation="account_bank_statement_import_sheet_mapping_wiz_attachment_rel",
)
header = fields.Char()
file_encoding = fields.Selection(
string="Encoding", selection=lambda self: self._selection_file_encoding(),
@@ -97,11 +101,11 @@ class AccountBankStatementImportSheetMappingWizard(models.TransientModel):
.selection
)
@api.onchange("data_file")
def _onchange_data_file(self):
@api.onchange("attachment_ids")
def _onchange_attachment_ids(self):
Parser = self.env["account.bank.statement.import.sheet.parser"]
Mapping = self.env["account.bank.statement.import.sheet.mapping"]
if not self.data_file:
if not self.attachment_ids:
return
csv_options = {}
if self.delimiter:
@@ -110,9 +114,12 @@ class AccountBankStatementImportSheetMappingWizard(models.TransientModel):
)
if self.quotechar:
csv_options["quotechar"] = self.quotechar
header = Parser.parse_header(
b64decode(self.data_file), self.file_encoding, csv_options
)
header = []
for data_file in self.attachment_ids:
header += Parser.parse_header(
b64decode(data_file.datas), self.file_encoding, csv_options
)
header = list(set(header))
self.header = json.dumps(header)
@api.model
@@ -122,12 +129,12 @@ class AccountBankStatementImportSheetMappingWizard(models.TransientModel):
return []
return [(x, x) for x in json.loads(header)]
@api.multi
def _get_mapping_values(self):
"""Hook for extension"""
self.ensure_one()
filename = "& ".join(self.attachment_ids.mapped("name"))
return {
"name": _("Mapping from %s") % path.basename(self.filename),
"name": _("Mapping from %s") % path.basename(filename),
"float_thousands_sep": "comma",
"float_decimal_sep": "dot",
"file_encoding": self.file_encoding,
@@ -152,7 +159,6 @@ class AccountBankStatementImportSheetMappingWizard(models.TransientModel):
"bank_account_column": self.bank_account_column,
}
@api.multi
def import_mapping(self):
self.ensure_one()
mapping = self.env["account.bank.statement.import.sheet.mapping"].create(

View File

@@ -21,11 +21,12 @@
<group name="start" attrs="{'invisible': [('state', '!=', 'start')]}">
<group colspan="2">
<field
name="data_file"
filename="filename"
placeholder="Choose a file to import..."
name="attachment_ids"
widget="many2many_binary"
colspan="2"
string="Upload Files"
nolabel="1"
/>
<field name="filename" invisible="1" />
</group>
<group string="Options" colspan="2">
<field name="file_encoding" />
@@ -157,9 +158,8 @@
id="action_account_bank_statement_import_sheet_mapping_wizard"
name="Import Mapping"
res_model="account.bank.statement.import.sheet.mapping.wizard"
src_model="account.bank.statement.import.sheet.mapping"
binding_model="account.bank.statement.import.sheet.mapping"
view_mode="form"
target="new"
key2="client_action_multi"
/>
</odoo>