[IMP] account_move_base_import: black, isort, prettier

This commit is contained in:
Damien Crier
2020-07-15 11:43:01 +02:00
committed by Florian da Costa
parent e81b55d0a8
commit 68fc7849f3
16 changed files with 653 additions and 571 deletions

View File

@@ -4,13 +4,13 @@
# Copyright 2014 ACSONE SA/NV # Copyright 2014 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
{ {
'name': "Journal Entry base import", "name": "Journal Entry base import",
'version': '12.0.2.0.0', "version": "13.0.1.0.0",
'author': "Akretion,Camptocamp,Odoo Community Association (OCA)", "author": "Akretion,Camptocamp,Odoo Community Association (OCA)",
'category': 'Finance', "category": "Finance",
'depends': ['account'], "depends": ["account"],
'website': 'http://www.camptocamp.com', "website": "http://www.camptocamp.com",
'data': [ "data": [
"security/ir.model.access.csv", "security/ir.model.access.csv",
"data/completion_rule_data.xml", "data/completion_rule_data.xml",
"wizard/import_statement_view.xml", "wizard/import_statement_view.xml",
@@ -18,9 +18,7 @@
"views/journal_view.xml", "views/journal_view.xml",
"views/partner_view.xml", "views/partner_view.xml",
], ],
'external_dependencies': { "external_dependencies": {"python": ["xlrd"]},
'python': ['xlrd'], "installable": True,
}, "license": "AGPL-3",
'installable': True,
'license': 'AGPL-3',
} }

View File

@@ -1,28 +1,27 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1"> <odoo noupdate="1">
<record id="bank_statement_completion_rule_2" model="account.move.completion.rule">
<record id="bank_statement_completion_rule_2" model="account.move.completion.rule"> <field
<field name="name">Match from line label (based on partner field 'Bank Statement Label')</field> name="name"
<field name="sequence">60</field> >Match from line label (based on partner field 'Bank Statement Label')</field>
<field name="function_to_call">get_from_name_and_partner_field</field> <field name="sequence">60</field>
</record> <field name="function_to_call">get_from_name_and_partner_field</field>
</record>
<record id="bank_statement_completion_rule_3" model="account.move.completion.rule"> <record id="bank_statement_completion_rule_3" model="account.move.completion.rule">
<field name="name">Match from line label (based on partner name)</field> <field name="name">Match from line label (based on partner name)</field>
<field name="sequence">70</field> <field name="sequence">70</field>
<field name="function_to_call">get_from_name_and_partner_name</field> <field name="function_to_call">get_from_name_and_partner_name</field>
</record> </record>
<record id="bank_statement_completion_rule_4" model="account.move.completion.rule">
<record id="bank_statement_completion_rule_4" model="account.move.completion.rule"> <field name="name">Match from line label (based on Invoice number)</field>
<field name="name">Match from line label (based on Invoice number)</field> <field name="sequence">40</field>
<field name="sequence">40</field> <field name="function_to_call">get_from_name_and_invoice</field>
<field name="function_to_call">get_from_name_and_invoice</field> </record>
</record> <record id="bank_statement_completion_rule_5" model="account.move.completion.rule">
<field
<record id="bank_statement_completion_rule_5" model="account.move.completion.rule"> name="name"
<field name="name">Match from line label (based on Invoice Supplier number)</field> >Match from line label (based on Invoice Supplier number)</field>
<field name="sequence">45</field> <field name="sequence">45</field>
<field name="function_to_call">get_from_name_and_supplier_invoice</field> <field name="function_to_call">get_from_name_and_supplier_invoice</field>
</record> </record>
</odoo> </odoo>

View File

@@ -3,13 +3,15 @@
# Copyright 2013 Savoir-faire Linux # Copyright 2013 Savoir-faire Linux
# Copyright 2014 ACSONE SA/NV # Copyright 2014 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import os
import sys import sys
import traceback import traceback
import os
from odoo import _, api, fields, models from odoo import _, api, fields, models
from ..parser.parser import new_move_parser
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
from ..parser.parser import new_move_parser
class AccountJournal(models.Model): class AccountJournal(models.Model):
_name = "account.journal" _name = "account.journal"
@@ -118,21 +120,17 @@ class AccountJournal(models.Model):
total_amount = refund + payment total_amount = refund + payment
if total_amount: if total_amount:
transfer_lines.append(total_amount) transfer_lines.append(total_amount)
counterpart_date = ( counterpart_date = parser.get_move_vals().get("date") or fields.Date.today()
parser.get_move_vals().get("date") or fields.Date.today()
)
transfer_line_count = len(transfer_lines) transfer_line_count = len(transfer_lines)
check_move_validity = False check_move_validity = False
for amount in transfer_lines: for amount in transfer_lines:
transfer_line_count -= 1 transfer_line_count -= 1
if not transfer_line_count: if not transfer_line_count:
check_move_validity = True check_move_validity = True
vals = self._prepare_counterpart_line( vals = self._prepare_counterpart_line(move, amount, counterpart_date)
move, amount, counterpart_date move_line_obj.with_context(check_move_validity=check_move_validity).create(
vals
) )
move_line_obj.with_context(
check_move_validity=check_move_validity
).create(vals)
@api.multi @api.multi
def _write_extra_move_lines(self, parser, move): def _write_extra_move_lines(self, parser, move):
@@ -151,25 +149,20 @@ class AccountJournal(models.Model):
move_line_obj = self.env["account.move.line"] move_line_obj = self.env["account.move.line"]
global_commission_amount = 0 global_commission_amount = 0
for row in parser.result_row_list: for row in parser.result_row_list:
global_commission_amount += float( global_commission_amount += float(row.get("commission_amount", "0.0"))
row.get("commission_amount", "0.0")
)
partner_id = self.partner_id.id partner_id = self.partner_id.id
# Commission line # Commission line
if global_commission_amount > 0.0: if global_commission_amount > 0.0:
raise UserError(_("Commission amount should not be positive.")) raise UserError(_("Commission amount should not be positive."))
elif global_commission_amount < 0.0: elif global_commission_amount < 0.0:
if not self.commission_account_id: if not self.commission_account_id:
raise UserError( raise UserError(_("No commission account is set on the journal."))
_("No commission account is set on the journal.")
)
else: else:
commission_account_id = self.commission_account_id.id commission_account_id = self.commission_account_id.id
comm_values = { comm_values = {
"name": _("Commission line"), "name": _("Commission line"),
"date_maturity": ( "date_maturity": (
parser.get_move_vals().get("date") parser.get_move_vals().get("date") or fields.Date.today()
or fields.Date.today()
), ),
"debit": -global_commission_amount, "debit": -global_commission_amount,
"partner_id": partner_id, "partner_id": partner_id,
@@ -177,10 +170,7 @@ class AccountJournal(models.Model):
"account_id": commission_account_id, "account_id": commission_account_id,
"already_completed": True, "already_completed": True,
} }
if ( if self.currency_id and self.currency_id != self.company_id.currency_id:
self.currency_id
and self.currency_id != self.company_id.currency_id
):
# the commission we are reading is in the currency of the # the commission we are reading is in the currency of the
# journal: use the amount in the amount_currency field, and # journal: use the amount in the amount_currency field, and
# set credit / debit to the value in company currency at # set credit / debit to the value in company currency at
@@ -228,10 +218,7 @@ class AccountJournal(models.Model):
if not values.get("account_id", False): if not values.get("account_id", False):
values["account_id"] = self.receivable_account_id.id values["account_id"] = self.receivable_account_id.id
account = self.env["account.account"].browse(values["account_id"]) account = self.env["account.account"].browse(values["account_id"])
if ( if self.currency_id and self.currency_id != self.company_id.currency_id:
self.currency_id
and self.currency_id != self.company_id.currency_id
):
# the debit and credit we are reading are in the currency of the # the debit and credit we are reading are in the currency of the
# journal: use the amount in the amount_currency field, and set # journal: use the amount in the amount_currency field, and set
# credit / debit to the value in company currency at the date of # credit / debit to the value in company currency at the date of
@@ -239,12 +226,8 @@ class AccountJournal(models.Model):
currency = self.currency_id.with_context(date=move.date) currency = self.currency_id.with_context(date=move.date)
company_currency = self.company_id.currency_id company_currency = self.company_id.currency_id
values["amount_currency"] = values["debit"] - values["credit"] values["amount_currency"] = values["debit"] - values["credit"]
values["debit"] = currency.compute( values["debit"] = currency.compute(values["debit"], company_currency)
values["debit"], company_currency values["credit"] = currency.compute(values["credit"], company_currency)
)
values["credit"] = currency.compute(
values["credit"], company_currency
)
if account.reconcile: if account.reconcile:
values["amount_residual"] = values["debit"] - values["credit"] values["amount_residual"] = values["debit"] - values["credit"]
else: else:
@@ -294,16 +277,12 @@ class AccountJournal(models.Model):
res = self.env["account.move"] res = self.env["account.move"]
for result_row_list in parser.parse(file_stream): for result_row_list in parser.parse(file_stream):
move = self._move_import( move = self._move_import(
parser, parser, file_stream, result_row_list=result_row_list, ftype=ftype,
file_stream,
result_row_list=result_row_list,
ftype=ftype,
) )
res |= move res |= move
return res return res
def _move_import( def _move_import(self, parser, file_stream, result_row_list=None, ftype="csv"):
self, parser, file_stream, result_row_list=None, ftype="csv"):
"""Create a bank statement with the given profile and parser. It will """Create a bank statement with the given profile and parser. It will
fulfill the bank statement with the values of the file provided, but fulfill the bank statement with the values of the file provided, but
will not complete data (like finding the partner, or the right will not complete data (like finding the partner, or the right
@@ -323,9 +302,7 @@ class AccountJournal(models.Model):
# Check all key are present in account.bank.statement.line!! # Check all key are present in account.bank.statement.line!!
if not result_row_list: if not result_row_list:
raise UserError(_("Nothing to import: " "The file is empty")) raise UserError(_("Nothing to import: " "The file is empty"))
parsed_cols = list( parsed_cols = list(parser.get_move_line_vals(result_row_list[0]).keys())
parser.get_move_line_vals(result_row_list[0]).keys()
)
for col in parsed_cols: for col in parsed_cols:
if col not in move_line_obj._fields: if col not in move_line_obj._fields:
raise UserError( raise UserError(
@@ -344,9 +321,7 @@ class AccountJournal(models.Model):
parser_vals = parser.get_move_line_vals(line) parser_vals = parser.get_move_line_vals(line)
values = self.prepare_move_line_vals(parser_vals, move) values = self.prepare_move_line_vals(parser_vals, move)
move_store.append(values) move_store.append(values)
move_line_obj.with_context(check_move_validity=False).create( move_line_obj.with_context(check_move_validity=False).create(move_store)
move_store
)
self._write_extra_move_lines(parser, move) self._write_extra_move_lines(parser, move)
if self.create_counterpart: if self.create_counterpart:
self._create_counterpart(parser, move) self._create_counterpart(parser, move)
@@ -358,7 +333,7 @@ class AccountJournal(models.Model):
attachment_data = { attachment_data = {
"name": "statement file", "name": "statement file",
"datas": file_stream, "datas": file_stream,
"datas_fname": "%s.%s" % (fields.Date.today(), ftype), "datas_fname": "{}.{}".format(fields.Date.today(), ftype),
"res_model": "account.move", "res_model": "account.move",
"res_id": move.id, "res_id": move.id,
} }
@@ -373,16 +348,11 @@ class AccountJournal(models.Model):
raise raise
except Exception: except Exception:
error_type, error_value, trbk = sys.exc_info() error_type, error_value, trbk = sys.exc_info()
st = "Error: %s\nDescription: %s\nTraceback:" % ( st = "Error: {}\nDescription: {}\nTraceback:".format(
error_type.__name__, error_type.__name__, error_value,
error_value,
) )
st += "".join(traceback.format_tb(trbk, 30)) st += "".join(traceback.format_tb(trbk, 30))
raise ValidationError( raise ValidationError(
_( _("Statement import error " "The statement cannot be created: %s") % st
"Statement import error "
"The statement cannot be created: %s"
)
% st
) )
return move return move

View File

@@ -3,14 +3,13 @@
# Copyright 2013 Savoir-faire Linux # Copyright 2013 Savoir-faire Linux
# Copyright 2014 ACSONE SA/NV # Copyright 2014 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import traceback
import sys
import logging import logging
import sys
import traceback
from odoo import _, api, fields, models from odoo import _, api, fields, models
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -38,68 +37,81 @@ class AccountMoveCompletionRule(models.Model):
process. The reference should contain the invoice number or the SO number process. The reference should contain the invoice number or the SO number
or any reference that will be matched by the invoice accounting move. or any reference that will be matched by the invoice accounting move.
""" """
_name = "account.move.completion.rule" _name = "account.move.completion.rule"
_order = "sequence asc" _order = "sequence asc"
_description = "Account move completion method" _description = "Account move completion method"
sequence = fields.Integer( sequence = fields.Integer(string="Sequence", help="Lower means parsed first.")
string='Sequence', name = fields.Char(string="Name")
help="Lower means parsed first.")
name = fields.Char(
string='Name')
journal_ids = fields.Many2many( journal_ids = fields.Many2many(
comodel_name='account.journal', comodel_name="account.journal",
relation='account_journal_completion_rule_rel', relation="account_journal_completion_rule_rel",
string='Related journals') string="Related journals",
function_to_call = fields.Selection([ )
('get_from_name_and_invoice', function_to_call = fields.Selection(
'From line name (based on customer invoice number)'), [
('get_from_name_and_supplier_invoice', (
'From line name (based on supplier invoice number)'), "get_from_name_and_invoice",
('get_from_name_and_partner_field', "From line name (based on customer invoice number)",
'From line name (based on partner field)'), ),
('get_from_name_and_partner_name', (
'From line name (based on partner name)') "get_from_name_and_supplier_invoice",
], string='Method' "From line name (based on supplier invoice number)",
),
(
"get_from_name_and_partner_field",
"From line name (based on partner field)",
),
(
"get_from_name_and_partner_name",
"From line name (based on partner name)",
),
],
string="Method",
) )
def _find_invoice(self, line, inv_type): def _find_invoice(self, line, inv_type):
"""Find invoice related to statement line""" """Find invoice related to statement line"""
inv_obj = self.env['account.invoice'] inv_obj = self.env["account.invoice"]
if inv_type == 'supplier': if inv_type == "supplier":
type_domain = ('in_invoice', 'in_refund') type_domain = ("in_invoice", "in_refund")
number_field = 'reference' number_field = "reference"
elif inv_type == 'customer': elif inv_type == "customer":
type_domain = ('out_invoice', 'out_refund') type_domain = ("out_invoice", "out_refund")
number_field = 'number' number_field = "number"
else: else:
raise ValidationError( raise ValidationError(
_('Invalid invoice type for completion: %s') % inv_type) _("Invalid invoice type for completion: %s") % inv_type
)
invoices = inv_obj.search([(number_field, '=', line.name.strip()), invoices = inv_obj.search(
('type', 'in', type_domain)]) [(number_field, "=", line.name.strip()), ("type", "in", type_domain)]
)
if invoices: if invoices:
if len(invoices) == 1: if len(invoices) == 1:
return invoices return invoices
else: else:
raise ErrorTooManyPartner( raise ErrorTooManyPartner(
_('Line named "%s" was matched by more than one ' _(
'partner while looking on %s invoices') % 'Line named "%s" was matched by more than one '
(line.name, inv_type)) "partner while looking on %s invoices"
)
% (line.name, inv_type)
)
return False return False
def _from_invoice(self, line, inv_type): def _from_invoice(self, line, inv_type):
"""Populate statement line values""" """Populate statement line values"""
if inv_type not in ('supplier', 'customer'): if inv_type not in ("supplier", "customer"):
raise ValidationError( raise ValidationError(
_('Invalid invoice type for completion: %s') % _("Invalid invoice type for completion: %s") % inv_type
inv_type) )
res = {} res = {}
invoice = self._find_invoice(line, inv_type) invoice = self._find_invoice(line, inv_type)
if invoice: if invoice:
partner_id = invoice.commercial_partner_id.id partner_id = invoice.commercial_partner_id.id
res = {'partner_id': partner_id, res = {"partner_id": partner_id, "account_id": invoice.account_id.id}
'account_id': invoice.account_id.id}
return res return res
# Should be private but data are initialised with no update XML # Should be private but data are initialised with no update XML
@@ -117,7 +129,7 @@ class AccountMoveCompletionRule(models.Model):
'account_id': value, 'account_id': value,
...} ...}
""" """
return self._from_invoice(line, 'supplier') return self._from_invoice(line, "supplier")
# Should be private but data are initialised with no update XML # Should be private but data are initialised with no update XML
def get_from_name_and_invoice(self, line): def get_from_name_and_invoice(self, line):
@@ -134,7 +146,7 @@ class AccountMoveCompletionRule(models.Model):
'account_id': value, 'account_id': value,
...} ...}
""" """
return self._from_invoice(line, 'customer') return self._from_invoice(line, "customer")
# Should be private but data are initialised with no update XML # Should be private but data are initialised with no update XML
def get_from_name_and_partner_field(self, line): def get_from_name_and_partner_field(self, line):
@@ -155,21 +167,20 @@ class AccountMoveCompletionRule(models.Model):
...} ...}
""" """
res = {} res = {}
partner_obj = self.env['res.partner'] partner_obj = self.env["res.partner"]
or_regex = ".*;? *%s *;?.*" % line.name or_regex = ".*;? *%s *;?.*" % line.name
sql = ("SELECT id from res_partner" sql = "SELECT id from res_partner" " WHERE bank_statement_label ~* %s"
" WHERE bank_statement_label ~* %s") self.env.cr.execute(sql, (or_regex,))
self.env.cr.execute(sql, (or_regex, ))
partner_ids = self.env.cr.fetchall() partner_ids = self.env.cr.fetchall()
partners = partner_obj.browse([x[0] for x in partner_ids]) partners = partner_obj.browse([x[0] for x in partner_ids])
if partners: if partners:
if len(partners) > 1: if len(partners) > 1:
msg = (_('Line named "%s" was matched by more than ' msg = _(
'one partner while looking on partner label: %s') % 'Line named "%s" was matched by more than '
(line.name, "one partner while looking on partner label: %s"
','.join([x.name for x in partners]))) ) % (line.name, ",".join([x.name for x in partners]))
raise ErrorTooManyPartner(msg) raise ErrorTooManyPartner(msg)
res['partner_id'] = partners[0].id res["partner_id"] = partners[0].id
return res return res
def get_from_name_and_partner_name(self, line): def get_from_name_and_partner_name(self, line):
@@ -210,10 +221,13 @@ class AccountMoveCompletionRule(models.Model):
if result: if result:
if len(result) > 1: if len(result) > 1:
raise ErrorTooManyPartner( raise ErrorTooManyPartner(
_('Line named "%s" was matched by more than one ' _(
'partner while looking on partner by name') % 'Line named "%s" was matched by more than one '
line.name) "partner while looking on partner by name"
res['partner_id'] = result[0][0] )
% line.name
)
res["partner_id"] = result[0][0]
return res return res
@@ -227,6 +241,7 @@ class AccountMoveLine(models.Model):
Have a look in account_move_base_import module to see how we've done Have a look in account_move_base_import module to see how we've done
it. it.
""" """
_inherit = "account.move.line" _inherit = "account.move.line"
_order = "already_completed desc, date asc" _order = "already_completed desc, date asc"
@@ -234,7 +249,8 @@ class AccountMoveLine(models.Model):
string="Auto-Completed", string="Auto-Completed",
default=False, default=False,
help="When this checkbox is ticked, the auto-completion " help="When this checkbox is ticked, the auto-completion "
"process/button will ignore this line.") "process/button will ignore this line.",
)
def _get_line_values_from_rules(self): def _get_line_values_from_rules(self):
"""We'll try to find out the values related to the line based on rules """We'll try to find out the values related to the line based on rules
@@ -268,12 +284,11 @@ class AccountMoveLine(models.Model):
rules = self.journal_id.rule_ids rules = self.journal_id.rule_ids
for rule in rules: for rule in rules:
method_to_call = getattr( method_to_call = getattr(
self.env['account.move.completion.rule'], self.env["account.move.completion.rule"], rule.function_to_call
rule.function_to_call
) )
result = method_to_call(self) result = method_to_call(self)
if result: if result:
result['already_completed'] = True result["already_completed"] = True
return result return result
return None return None
@@ -282,17 +297,17 @@ class AccountMove(models.Model):
"""We add a basic button and stuff to support the auto-completion """We add a basic button and stuff to support the auto-completion
of the bank statement once line have been imported or manually fulfill. of the bank statement once line have been imported or manually fulfill.
""" """
_name = 'account.move'
_inherit = ['account.move', 'mail.thread'] _name = "account.move"
_inherit = ["account.move", "mail.thread"]
used_for_completion = fields.Boolean( used_for_completion = fields.Boolean(
related='journal_id.used_for_completion', related="journal_id.used_for_completion", readonly=True
readonly=True) )
completion_logs = fields.Text(string='Completion Log', readonly=True) completion_logs = fields.Text(string="Completion Log", readonly=True)
import_partner_id = fields.Many2one('res.partner', import_partner_id = fields.Many2one("res.partner", string="Partner from import")
string="Partner from import")
@api.depends('line_ids.partner_id', 'import_partner_id') @api.depends("line_ids.partner_id", "import_partner_id")
def _compute_partner_id(self): def _compute_partner_id(self):
for move in self: for move in self:
if move.import_partner_id: if move.import_partner_id:
@@ -314,14 +329,25 @@ class AccountMove(models.Model):
number_line = len(self.line_ids) number_line = len(self.line_ids)
log = self.completion_logs or "" log = self.completion_logs or ""
completion_date = fields.Datetime.now() completion_date = fields.Datetime.now()
message = (_("%s Account Move %s has %s/%s lines completed by " message = _(
"%s \n%s\n%s\n") % (completion_date, self.name, "%s Account Move %s has %s/%s lines completed by " "%s \n%s\n%s\n"
number_imported, number_line, ) % (
user_name, error_msg, log)) completion_date,
self.write({'completion_logs': message}) self.name,
number_imported,
number_line,
user_name,
error_msg,
log,
)
self.write({"completion_logs": message})
body = (_('Statement ID %s auto-completed for %s/%s lines completed') % body = (
(self.name, number_imported, number_line)), (
_("Statement ID %s auto-completed for %s/%s lines completed")
% (self.name, number_imported, number_line)
),
)
self.message_post(body=body) self.message_post(body=body)
return True return True
@@ -345,9 +371,10 @@ class AccountMove(models.Model):
except Exception as exc: except Exception as exc:
msg_lines.append(repr(exc)) msg_lines.append(repr(exc))
error_type, error_value, trbk = sys.exc_info() error_type, error_value, trbk = sys.exc_info()
st = "Error: %s\nDescription: %s\nTraceback:" % ( st = "Error: {}\nDescription: {}\nTraceback:".format(
error_type.__name__, error_value) error_type.__name__, error_value,
st += ''.join(traceback.format_tb(trbk, 30)) )
st += "".join(traceback.format_tb(trbk, 30))
_logger.error(st) _logger.error(st)
if res: if res:
try: try:
@@ -355,10 +382,11 @@ class AccountMove(models.Model):
except Exception as exc: except Exception as exc:
msg_lines.append(repr(exc)) msg_lines.append(repr(exc))
error_type, error_value, trbk = sys.exc_info() error_type, error_value, trbk = sys.exc_info()
st = "Error: %s\nDescription: %s\nTraceback:" % ( st = "Error: {}\nDescription: {}\nTraceback:".format(
error_type.__name__, error_value) error_type.__name__, error_value,
st += ''.join(traceback.format_tb(trbk, 30)) )
st += "".join(traceback.format_tb(trbk, 30))
_logger.error(st) _logger.error(st)
msg = '\n'.join(msg_lines) msg = "\n".join(msg_lines)
self.write_completion_log(msg, compl_lines) self.write_completion_log(msg, compl_lines)
return True return True

View File

@@ -10,12 +10,14 @@ class ResPartner(models.Model):
"""Add a bank label on the partner so that we can use it to match """Add a bank label on the partner so that we can use it to match
this partner when we found this in a statement line. this partner when we found this in a statement line.
""" """
_inherit = 'res.partner'
_inherit = "res.partner"
bank_statement_label = fields.Char( bank_statement_label = fields.Char(
string='Bank Statement Label', string="Bank Statement Label",
help="Enter the various label found on your bank statement " help="Enter the various label found on your bank statement "
"separated by a ; If one of this label is include in the " "separated by a ; If one of this label is include in the "
"bank statement line, the partner will be automatically " "bank statement line, the partner will be automatically "
"filled (as long as you use this method/rules in your " "filled (as long as you use this method/rules in your "
"statement profile).") "statement profile).",
)

View File

@@ -4,8 +4,8 @@
# Copyright 2014 ACSONE SA/NV # Copyright 2014 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import datetime import datetime
import tempfile
import logging import logging
import tempfile
from odoo import _ from odoo import _
from odoo.exceptions import UserError from odoo.exceptions import UserError
@@ -33,14 +33,15 @@ class FileParser(AccountMoveImportParser):
""" """
def __init__( def __init__(
self, self,
journal, journal,
ftype="csv", ftype="csv",
extra_fields=None, extra_fields=None,
header=None, header=None,
dialect=None, dialect=None,
move_ref=None, move_ref=None,
**kwargs): **kwargs
):
""" """
:param char: parse_name: The name of the parser :param char: parse_name: The name of the parser
:param char: ftype: extension of the file (could be csv, xls or :param char: ftype: extension of the file (could be csv, xls or
@@ -90,7 +91,7 @@ class FileParser(AccountMoveImportParser):
return False return False
else: else:
self.result_row_list = self.parsed_file[ self.result_row_list = self.parsed_file[
self.current_line: self.current_line + 1 self.current_line : self.current_line + 1
] ]
self.current_line += 1 self.current_line += 1
return True return True
@@ -152,9 +153,7 @@ class FileParser(AccountMoveImportParser):
if conversion_rules[rule] == datetime.datetime: if conversion_rules[rule] == datetime.datetime:
try: try:
date_string = line[rule].split(" ")[0] date_string = line[rule].split(" ")[0]
line[rule] = datetime.datetime.strptime( line[rule] = datetime.datetime.strptime(date_string, "%Y-%m-%d")
date_string, "%Y-%m-%d"
)
except ValueError as err: except ValueError as err:
raise UserError( raise UserError(
_( _(
@@ -196,9 +195,7 @@ class FileParser(AccountMoveImportParser):
for rule in conversion_rules: for rule in conversion_rules:
if conversion_rules[rule] == datetime.datetime: if conversion_rules[rule] == datetime.datetime:
try: try:
t_tuple = xlrd.xldate_as_tuple( t_tuple = xlrd.xldate_as_tuple(line[rule], self._datemode)
line[rule], self._datemode
)
line[rule] = datetime.datetime(*t_tuple) line[rule] = datetime.datetime(*t_tuple)
except Exception as err: except Exception as err:
raise UserError( raise UserError(

View File

@@ -4,9 +4,11 @@
# Copyright 2014 ACSONE SA/NV # Copyright 2014 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import datetime import datetime
from .file_parser import FileParser, float_or_zero
from odoo.tools import ustr from odoo.tools import ustr
from .file_parser import FileParser, float_or_zero
class GenericFileParser(FileParser): class GenericFileParser(FileParser):
"""Standard parser that use a define format in csv or xls to import into a """Standard parser that use a define format in csv or xls to import into a
@@ -15,25 +17,22 @@ class GenericFileParser(FileParser):
file. file.
""" """
def __init__(self, journal, ftype='csv', **kwargs): def __init__(self, journal, ftype="csv", **kwargs):
conversion_dict = { conversion_dict = {
'label': ustr, "label": ustr,
'date': datetime.datetime, "date": datetime.datetime,
'amount': float_or_zero, "amount": float_or_zero,
} }
# set self.env for later ORM searches # set self.env for later ORM searches
self.env = journal.env self.env = journal.env
super().__init__( super().__init__(journal, ftype=ftype, extra_fields=conversion_dict, **kwargs)
journal, ftype=ftype,
extra_fields=conversion_dict,
**kwargs)
@classmethod @classmethod
def parser_for(cls, parser_name): def parser_for(cls, parser_name):
"""Used by the new_bank_statement_parser class factory. Return true if """Used by the new_bank_statement_parser class factory. Return true if
the providen name is generic_csvxls_so the providen name is generic_csvxls_so
""" """
return parser_name == 'generic_csvxls_so' return parser_name == "generic_csvxls_so"
def get_move_line_vals(self, line, *args, **kwargs): def get_move_line_vals(self, line, *args, **kwargs):
""" """
@@ -52,27 +51,27 @@ class GenericFileParser(FileParser):
'debit':value 'debit':value
} }
""" """
account_obj = self.env['account.account'] account_obj = self.env["account.account"]
partner_obj = self.env['res.partner'] partner_obj = self.env["res.partner"]
account_id = False account_id = False
partner_id = False partner_id = False
if line.get('account'): if line.get("account"):
accounts = account_obj.search([('code', '=', line['account'])]) accounts = account_obj.search([("code", "=", line["account"])])
if len(accounts) == 1: if len(accounts) == 1:
account_id = accounts[0].id account_id = accounts[0].id
if line.get('partner'): if line.get("partner"):
partners = partner_obj.search([('name', '=', line['partner'])]) partners = partner_obj.search([("name", "=", line["partner"])])
if len(partners) == 1: if len(partners) == 1:
partner_id = partners[0].id partner_id = partners[0].id
amount = line.get('amount', 0.0) amount = line.get("amount", 0.0)
return { return {
'name': line.get('label', '/'), "name": line.get("label", "/"),
'date_maturity': line.get('date', datetime.datetime.now().date()), "date_maturity": line.get("date", datetime.datetime.now().date()),
'credit': amount > 0.0 and amount or 0.0, "credit": amount > 0.0 and amount or 0.0,
'debit': amount < 0.0 and -amount or 0.0, "debit": amount < 0.0 and -amount or 0.0,
'account_id': account_id, "account_id": account_id,
'partner_id': partner_id, "partner_id": partner_id,
} }

View File

@@ -5,6 +5,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import base64 import base64
import csv import csv
from openerp import _, fields from openerp import _, fields
@@ -13,16 +14,14 @@ def UnicodeDictReader(utf8_data, **kwargs):
pos = utf8_data.tell() pos = utf8_data.tell()
sample_data = utf8_data.read(2048) sample_data = utf8_data.read(2048)
utf8_data.seek(pos) utf8_data.seek(pos)
if not kwargs.get('dialect'): if not kwargs.get("dialect"):
dialect = sniffer.sniff(sample_data, delimiters=',;\t') dialect = sniffer.sniff(sample_data, delimiters=",;\t")
del kwargs['dialect'] del kwargs["dialect"]
else: else:
dialect = kwargs.pop('dialect') dialect = kwargs.pop("dialect")
csv_reader = csv.DictReader(utf8_data, dialect=dialect, **kwargs) csv_reader = csv.DictReader(utf8_data, dialect=dialect, **kwargs)
for row in csv_reader: for row in csv_reader:
yield dict([(str(key or ''), yield {str(key or ""): str(value or "") for key, value in row.items()}
str(value or ''))
for key, value in row.items()])
class AccountMoveImportParser(object): class AccountMoveImportParser(object):
@@ -108,9 +107,9 @@ class AccountMoveImportParser(object):
:return: dict of vals that represent additional infos for the statement :return: dict of vals that represent additional infos for the statement
""" """
return { return {
'name': self.move_name or '/', "name": self.move_name or "/",
'date': self.move_date or fields.Datetime.now(), "date": self.move_date or fields.Datetime.now(),
'ref': self.move_ref or '/' "ref": self.move_ref or "/",
} }
def get_move_line_vals(self, line, *args, **kwargs): def get_move_line_vals(self, line, *args, **kwargs):
@@ -144,7 +143,7 @@ class AccountMoveImportParser(object):
if filebuffer: if filebuffer:
self.filebuffer = filebuffer self.filebuffer = filebuffer
else: else:
raise Exception(_('No buffer file given.')) raise Exception(_("No buffer file given."))
self._format(*args, **kwargs) self._format(*args, **kwargs)
self._pre(*args, **kwargs) self._pre(*args, **kwargs)
if self.support_multi_moves: if self.support_multi_moves:
@@ -184,8 +183,9 @@ def itersubclasses(cls, _seen=None):
['type', ...'tuple', ...] ['type', ...'tuple', ...]
""" """
if not isinstance(cls, type): if not isinstance(cls, type):
raise TypeError('itersubclasses must be called with ' raise TypeError(
'new-style classes, not %.100r' % cls) "itersubclasses must be called with " "new-style classes, not %.100r" % cls
)
if _seen is None: if _seen is None:
_seen = set() _seen = set()
try: try:

View File

@@ -3,13 +3,15 @@
# Copyright 2013 Savoir-faire Linux # Copyright 2013 Savoir-faire Linux
# Copyright 2014 ACSONE SA/NV # Copyright 2014 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
from collections import namedtuple
from odoo import fields, tools from odoo import fields, tools
from odoo.modules import get_resource_path from odoo.modules import get_resource_path
from odoo.tests import common from odoo.tests import common
from collections import namedtuple
name_completion_case = namedtuple( name_completion_case = namedtuple(
"name_completion_case", ["partner_name", "line_label", "should_match"]) "name_completion_case", ["partner_name", "line_label", "should_match"]
)
NAMES_COMPLETION_CASES = [ NAMES_COMPLETION_CASES = [
name_completion_case("Acsone", "Line for Acsone SA", True), name_completion_case("Acsone", "Line for Acsone SA", True),
name_completion_case("Acsone", "Line for Acsone", True), name_completion_case("Acsone", "Line for Acsone", True),
@@ -21,29 +23,37 @@ NAMES_COMPLETION_CASES = [
name_completion_case("Acsone", "A..one for line", False), name_completion_case("Acsone", "A..one for line", False),
name_completion_case("A.one SA", "A.one SA for line", True), name_completion_case("A.one SA", "A.one SA for line", True),
name_completion_case( name_completion_case(
"Acsone SA", "Line for Acsone ([^a-zA-Z0-9 -]) SA test", False), "Acsone SA", "Line for Acsone ([^a-zA-Z0-9 -]) SA test", False
),
name_completion_case( name_completion_case(
"Acsone ([^a-zA-Z0-9 -]) SA", "Line for Acsone ([^a-zA-Z0-9 -]) SA " "Acsone ([^a-zA-Z0-9 -]) SA",
"test", True), "Line for Acsone ([^a-zA-Z0-9 -]) SA " "test",
True,
),
name_completion_case( name_completion_case(
r"Acsone (.^$*+?()[{\| -]\) SA", r"Line for Acsone (.^$*+?()[{\| -]\) " r"Acsone (.^$*+?()[{\| -]\) SA",
r"SA test", True), r"Line for Acsone (.^$*+?()[{\| -]\) " r"SA test",
True,
),
name_completion_case("Acšone SA", "Line for Acšone SA test", True), name_completion_case("Acšone SA", "Line for Acšone SA test", True),
] ]
class BaseCompletion(common.TransactionCase): class BaseCompletion(common.TransactionCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
tools.convert_file(self.cr, 'account', tools.convert_file(
get_resource_path('account', 'test', self.cr,
'account_minimal_test.xml'), "account",
{}, 'init', False, 'test') get_resource_path("account", "test", "account_minimal_test.xml"),
{},
"init",
False,
"test",
)
self.account_move_obj = self.env["account.move"] self.account_move_obj = self.env["account.move"]
self.account_move_line_obj = \ self.account_move_line_obj = self.env["account.move.line"]
self.env["account.move.line"] self.company_a = self.browse_ref("base.main_company")
self.company_a = self.browse_ref('base.main_company')
self.journal = self.browse_ref("account.bank_journal") self.journal = self.browse_ref("account.bank_journal")
self.partner = self.browse_ref("base.res_partner_12") self.partner = self.browse_ref("base.res_partner_12")
self.account_id = self.ref("account.a_recv") self.account_id = self.ref("account.a_recv")
@@ -54,41 +64,49 @@ class BaseCompletion(common.TransactionCase):
the partner appears in the statement line label the partner appears in the statement line label
""" """
self.completion_rule_id = self.ref( self.completion_rule_id = self.ref(
'account_move_base_import.bank_statement_completion_rule_3') "account_move_base_import.bank_statement_completion_rule_3"
)
# Create the profile # Create the profile
self.journal.write({ self.journal.write(
'used_for_completion': True, {
'rule_ids': [(6, 0, [self.completion_rule_id])] "used_for_completion": True,
}) "rule_ids": [(6, 0, [self.completion_rule_id])],
}
)
# Create a bank statement # Create a bank statement
self.move = self.account_move_obj.create({ self.move = self.account_move_obj.create(
"date": fields.Date.today(), {"date": fields.Date.today(), "journal_id": self.journal.id}
"journal_id": self.journal.id )
})
for case in NAMES_COMPLETION_CASES: for case in NAMES_COMPLETION_CASES:
self.partner.write({'name': case.partner_name}) self.partner.write({"name": case.partner_name})
self.move_line = self.account_move_line_obj.with_context( self.move_line = self.account_move_line_obj.with_context(
check_move_validity=False check_move_validity=False
).create({ ).create(
'account_id': self.account_id, {
'credit': 1000.0, "account_id": self.account_id,
'name': case.line_label, "credit": 1000.0,
'move_id': self.move.id, "name": case.line_label,
}) "move_id": self.move.id,
}
)
self.assertFalse( self.assertFalse(
self.move_line.partner_id, self.move_line.partner_id, "Partner_id must be blank before completion"
"Partner_id must be blank before completion") )
self.move.button_auto_completion() self.move.button_auto_completion()
if case.should_match: if case.should_match:
self.assertEqual( self.assertEqual(
self.partner, self.move_line.partner_id, self.partner,
self.move_line.partner_id,
"Missing expected partner id after completion " "Missing expected partner id after completion "
"(partner_name: %s, line_name: %s)" % "(partner_name: %s, line_name: %s)"
(case.partner_name, case.line_label)) % (case.partner_name, case.line_label),
)
else: else:
self.assertNotEqual( self.assertNotEqual(
self.partner, self.move_line.partner_id, self.partner,
self.move_line.partner_id,
"Partner id should be empty after completion " "Partner id should be empty after completion "
"(partner_name: %s, line_name: %s)" "(partner_name: %s, line_name: %s)"
% (case.partner_name, case.line_label)) % (case.partner_name, case.line_label),
)

View File

@@ -6,57 +6,63 @@
import base64 import base64
import os import os
from operator import attrgetter from operator import attrgetter
from odoo.tests import common
from odoo import tools, fields from odoo import fields, tools
from odoo.modules import get_resource_path from odoo.modules import get_resource_path
from odoo.tests import common
class TestCodaImport(common.TransactionCase): class TestCodaImport(common.TransactionCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.company_a = self.browse_ref('base.main_company') self.company_a = self.browse_ref("base.main_company")
tools.convert_file(self.cr, 'account', tools.convert_file(
get_resource_path('account', 'test', self.cr,
'account_minimal_test.xml'), "account",
{}, 'init', False, 'test') get_resource_path("account", "test", "account_minimal_test.xml"),
{},
"init",
False,
"test",
)
self.account_move_obj = self.env["account.move"] self.account_move_obj = self.env["account.move"]
self.account_move_line_obj = self.env["account.move.line"] self.account_move_line_obj = self.env["account.move.line"]
self.account_id = self.ref("account.a_recv") self.account_id = self.ref("account.a_recv")
self.journal = self.browse_ref("account.bank_journal") self.journal = self.browse_ref("account.bank_journal")
self.import_wizard_obj = self.env['credit.statement.import'] self.import_wizard_obj = self.env["credit.statement.import"]
self.partner = self.browse_ref("base.res_partner_12") self.partner = self.browse_ref("base.res_partner_12")
self.journal.write({ self.journal.write(
'used_for_import': True, {
"import_type": "generic_csvxls_so", "used_for_import": True,
'partner_id': self.partner.id, "import_type": "generic_csvxls_so",
'commission_account_id': self.account_id, "partner_id": self.partner.id,
'receivable_account_id': self.account_id, "commission_account_id": self.account_id,
'create_counterpart': True, "receivable_account_id": self.account_id,
}) "create_counterpart": True,
}
)
def _import_file(self, file_name): def _import_file(self, file_name):
""" import a file using the wizard """ import a file using the wizard
return the create account.bank.statement object return the create account.bank.statement object
""" """
with open(file_name, 'rb') as f: with open(file_name, "rb") as f:
content = f.read() content = f.read()
self.wizard = self.import_wizard_obj.create({ self.wizard = self.import_wizard_obj.create(
"journal_id": self.journal.id, {
'input_statement': base64.b64encode(content), "journal_id": self.journal.id,
'file_name': os.path.basename(file_name), "input_statement": base64.b64encode(content),
}) "file_name": os.path.basename(file_name),
}
)
res = self.wizard.import_statement() res = self.wizard.import_statement()
return self.account_move_obj.browse(res['res_id']) return self.account_move_obj.browse(res["res_id"])
def test_simple_xls(self): def test_simple_xls(self):
"""Test import from xls """Test import from xls
""" """
file_name = get_resource_path( file_name = get_resource_path(
'account_move_base_import', "account_move_base_import", "tests", "data", "statement.xls"
'tests',
'data',
'statement.xls'
) )
move = self._import_file(file_name) move = self._import_file(file_name)
self._validate_imported_move(move) self._validate_imported_move(move)
@@ -65,10 +71,7 @@ class TestCodaImport(common.TransactionCase):
"""Test import from csv """Test import from csv
""" """
file_name = get_resource_path( file_name = get_resource_path(
'account_move_base_import', "account_move_base_import", "tests", "data", "statement.csv"
'tests',
'data',
'statement.csv'
) )
move = self._import_file(file_name) move = self._import_file(file_name)
self._validate_imported_move(move) self._validate_imported_move(move)
@@ -76,11 +79,8 @@ class TestCodaImport(common.TransactionCase):
def _validate_imported_move(self, move): def _validate_imported_move(self, move):
self.assertEqual("/", move.name) self.assertEqual("/", move.name)
self.assertEqual(5, len(move.line_ids)) self.assertEqual(5, len(move.line_ids))
move_line = sorted(move.line_ids, move_line = sorted(move.line_ids, key=attrgetter("date_maturity"))[2]
key=attrgetter('date_maturity'))[2]
# common infos # common infos
self.assertEqual( self.assertEqual(move_line.date_maturity, fields.Date.from_string("2011-03-07"))
move_line.date_maturity, fields.Date.from_string('2011-03-07')
)
self.assertEqual(move_line.credit, 118.4) self.assertEqual(move_line.credit, 118.4)
self.assertEqual(move_line.name, "label a") self.assertEqual(move_line.name, "label a")

View File

@@ -7,143 +7,168 @@ from odoo.tools import convert_file
class TestInvoice(SingleTransactionCase): class TestInvoice(SingleTransactionCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.account_move_obj = self.env["account.move"] self.account_move_obj = self.env["account.move"]
self.account_move_line_obj = \ self.account_move_line_obj = self.env["account.move.line"]
self.env["account.move.line"] self.company_a = self.env.ref("base.main_company")
self.company_a = self.env.ref('base.main_company')
self.partner = self.env.ref("base.res_partner_12") self.partner = self.env.ref("base.res_partner_12")
def test_01_partner(self): def test_01_partner(self):
# I fill in the field Bank Statement Label in a Partner # I fill in the field Bank Statement Label in a Partner
self.partner_4 = self.env.ref('base.res_partner_4') self.partner_4 = self.env.ref("base.res_partner_4")
self.partner_4.bank_statement_label = 'XXX66Z' self.partner_4.bank_statement_label = "XXX66Z"
self.assertEqual(self.partner_4.bank_statement_label, 'XXX66Z') self.assertEqual(self.partner_4.bank_statement_label, "XXX66Z")
def test_02_invoice(self): def test_02_invoice(self):
convert_file( convert_file(
self.cr, 'account', get_resource_path( self.cr,
'account', 'test', 'account_minimal_test.xml' "account",
), {}, 'init', False, 'test' get_resource_path("account", "test", "account_minimal_test.xml"),
{},
"init",
False,
"test",
) )
self.journal = self.env.ref("account.bank_journal") self.journal = self.env.ref("account.bank_journal")
self.account_id = self.env.ref("account.a_recv") self.account_id = self.env.ref("account.a_recv")
# I create a customer Invoice to be found by the completion. # I create a customer Invoice to be found by the completion.
product_3 = self.env.ref('product.product_product_3') product_3 = self.env.ref("product.product_product_3")
self.invoice_for_completion_1 = self.env['account.invoice'].create({ self.invoice_for_completion_1 = self.env["account.invoice"].create(
'currency_id': self.env.ref('base.EUR').id, {
'invoice_line_ids': [(0, 0, { "currency_id": self.env.ref("base.EUR").id,
'name': '[PCSC234] PC Assemble SC234', "invoice_line_ids": [
'product_id': product_3.id, (
'price_unit': 210.0, 0,
'quantity': 1.0, 0,
'uom_id': self.env.ref('uom.product_uom_unit').id, {
'account_id': self.env.ref('account.a_sale').id, "name": "[PCSC234] PC Assemble SC234",
})], "product_id": product_3.id,
'journal_id': self.journal.id, "price_unit": 210.0,
'partner_id': self.partner.id, "quantity": 1.0,
'account_id': self.env.ref('account.a_recv').id, "uom_id": self.env.ref("uom.product_uom_unit").id,
}) "account_id": self.env.ref("account.a_sale").id,
},
)
],
"journal_id": self.journal.id,
"partner_id": self.partner.id,
"account_id": self.env.ref("account.a_recv").id,
}
)
# I confirm the Invoice # I confirm the Invoice
self.invoice_for_completion_1.action_invoice_open() self.invoice_for_completion_1.action_invoice_open()
# I check that the invoice state is "Open" # I check that the invoice state is "Open"
self.assertEqual(self.invoice_for_completion_1.state, 'open') self.assertEqual(self.invoice_for_completion_1.state, "open")
# I check that it is given the number "TBNK/%Y/0001" # I check that it is given the number "TBNK/%Y/0001"
self.assertEqual( self.assertEqual(
self.invoice_for_completion_1.number, self.invoice_for_completion_1.number,
fields.Date.today().strftime('TBNK/%Y/0001') fields.Date.today().strftime("TBNK/%Y/0001"),
) )
def test_03_supplier_invoice(self): def test_03_supplier_invoice(self):
# I create a demo invoice # I create a demo invoice
product_delivery = self.env.ref('product.product_delivery_01') product_delivery = self.env.ref("product.product_delivery_01")
product_order = self.env.ref('product.product_order_01') product_order = self.env.ref("product.product_order_01")
exp_account = self.env.ref('account.a_expense') exp_account = self.env.ref("account.a_expense")
rec_account = self.env.ref('account.a_recv') rec_account = self.env.ref("account.a_recv")
demo_invoice_0 = self.env['account.invoice'].create({ demo_invoice_0 = self.env["account.invoice"].create(
'partner_id': self.partner.id, {
'payment_term_id': self.env.ref('account.account_payment_term').id, "partner_id": self.partner.id,
'type': 'in_invoice', "payment_term_id": self.env.ref("account.account_payment_term").id,
'date_invoice': fields.Date.today().replace(day=1), "type": "in_invoice",
'account_id': rec_account.id, "date_invoice": fields.Date.today().replace(day=1),
'invoice_line_ids': [ "account_id": rec_account.id,
(0, 0, { "invoice_line_ids": [
'price_unit': 10.0, (
'quantity': 1.0, 0,
'product_id': product_delivery.id, 0,
'name': product_delivery.name, {
'uom_id': self.env.ref('uom.product_uom_unit').id, "price_unit": 10.0,
'account_id': exp_account.id, "quantity": 1.0,
}), (0, 0, { "product_id": product_delivery.id,
'price_unit': 4.0, "name": product_delivery.name,
'quantity': 1.0, "uom_id": self.env.ref("uom.product_uom_unit").id,
'product_id': product_order.id, "account_id": exp_account.id,
'name': product_order.name, },
'uom_id': self.env.ref('uom.product_uom_unit').id, ),
'account_id': exp_account.id, (
}) 0,
], 0,
}) {
"price_unit": 4.0,
"quantity": 1.0,
"product_id": product_order.id,
"name": product_order.name,
"uom_id": self.env.ref("uom.product_uom_unit").id,
"account_id": exp_account.id,
},
),
],
}
)
# I check that my invoice is a supplier invoice # I check that my invoice is a supplier invoice
self.assertEqual( self.assertEqual(demo_invoice_0.type, "in_invoice", msg="Check invoice type")
demo_invoice_0.type, 'in_invoice', msg="Check invoice type"
)
# I add a reference to an existing supplier invoice # I add a reference to an existing supplier invoice
demo_invoice_0.write({'reference': 'T2S12345'}) demo_invoice_0.write({"reference": "T2S12345"})
# I check a second time that my invoice is still a supplier invoice # I check a second time that my invoice is still a supplier invoice
self.assertEqual( self.assertEqual(demo_invoice_0.type, "in_invoice", msg="Check invoice type 2")
demo_invoice_0.type, 'in_invoice', msg="Check invoice type 2"
)
# Now I confirm it # Now I confirm it
demo_invoice_0.action_invoice_open() demo_invoice_0.action_invoice_open()
# I check that the supplier number is there # I check that the supplier number is there
self.assertEqual( self.assertEqual(
demo_invoice_0.reference, 'T2S12345', msg="Check supplier number" demo_invoice_0.reference, "T2S12345", msg="Check supplier number"
) )
# I check a third time that my invoice is still a supplier invoice # I check a third time that my invoice is still a supplier invoice
self.assertEqual( self.assertEqual(demo_invoice_0.type, "in_invoice", msg="Check invoice type 3")
demo_invoice_0.type, 'in_invoice', msg="Check invoice type 3"
)
def test_04_refund(self): def test_04_refund(self):
# I create a "child" partner, to use in the invoice # I create a "child" partner, to use in the invoice
# (and have a different commercial_partner_id than itself) # (and have a different commercial_partner_id than itself)
res_partner_12_child = self.env['res.partner'].create({ res_partner_12_child = self.env["res.partner"].create(
'name': 'Child Partner', {
'supplier': False, "name": "Child Partner",
'customer': True, "supplier": False,
'is_company': False, "customer": True,
'parent_id': self.partner.id, "is_company": False,
}) "parent_id": self.partner.id,
}
)
# I create a customer refund to be found by the completion. # I create a customer refund to be found by the completion.
product_3 = self.env.ref('product.product_product_3') product_3 = self.env.ref("product.product_product_3")
self.refund_for_completion_1 = self.env['account.invoice'].create({ self.refund_for_completion_1 = self.env["account.invoice"].create(
'currency_id': self.env.ref('base.EUR').id, {
'invoice_line_ids': [(0, 0, { "currency_id": self.env.ref("base.EUR").id,
'name': '[PCSC234] PC Assemble SC234', "invoice_line_ids": [
'product_id': product_3.id, (
'price_unit': 210.0, 0,
'quantity': 1.0, 0,
'uom_id': self.env.ref('uom.product_uom_unit').id, {
'account_id': self.env.ref('account.a_sale').id, "name": "[PCSC234] PC Assemble SC234",
})], "product_id": product_3.id,
'journal_id': self.env.ref('account.expenses_journal').id, "price_unit": 210.0,
'partner_id': res_partner_12_child.id, "quantity": 1.0,
'type': 'out_refund', "uom_id": self.env.ref("uom.product_uom_unit").id,
'account_id': self.env.ref('account.a_recv').id, "account_id": self.env.ref("account.a_sale").id,
}) },
)
],
"journal_id": self.env.ref("account.expenses_journal").id,
"partner_id": res_partner_12_child.id,
"type": "out_refund",
"account_id": self.env.ref("account.a_recv").id,
}
)
# I confirm the refund # I confirm the refund
self.refund_for_completion_1.action_invoice_open() self.refund_for_completion_1.action_invoice_open()
# I check that the refund state is "Open" # I check that the refund state is "Open"
self.assertEqual(self.refund_for_completion_1.state, 'open') self.assertEqual(self.refund_for_completion_1.state, "open")
# I check that it is given the number "RTEXJ/%Y/0001" # I check that it is given the number "RTEXJ/%Y/0001"
self.assertEqual( self.assertEqual(
self.refund_for_completion_1.number, self.refund_for_completion_1.number,
fields.Date.today().strftime('RTEXJ/%Y/0001') fields.Date.today().strftime("RTEXJ/%Y/0001"),
) )
def test_05_completion(self): def test_05_completion(self):
@@ -151,92 +176,102 @@ class TestInvoice(SingleTransactionCase):
# journal # journal
self.journal = self.env.ref("account.bank_journal") self.journal = self.env.ref("account.bank_journal")
completion_rule_4 = self.env.ref( completion_rule_4 = self.env.ref(
'account_move_base_import.bank_statement_completion_rule_4' "account_move_base_import.bank_statement_completion_rule_4"
) )
completion_rule_2 = self.env.ref( completion_rule_2 = self.env.ref(
'account_move_base_import.bank_statement_completion_rule_2' "account_move_base_import.bank_statement_completion_rule_2"
) )
completion_rule_3 = self.env.ref( completion_rule_3 = self.env.ref(
'account_move_base_import.bank_statement_completion_rule_3' "account_move_base_import.bank_statement_completion_rule_3"
) )
completion_rule_5 = self.env.ref( completion_rule_5 = self.env.ref(
'account_move_base_import.bank_statement_completion_rule_5' "account_move_base_import.bank_statement_completion_rule_5"
) )
completion_rules = ( completion_rules = (
completion_rule_2 | completion_rule_3 | completion_rule_4 completion_rule_2
| completion_rule_3
| completion_rule_4
| completion_rule_5 | completion_rule_5
) )
self.journal.write({ self.journal.write(
'used_for_completion': True, {
'rule_ids': [ "used_for_completion": True,
(4, comp_rule.id, False) for comp_rule in completion_rules "rule_ids": [
] (4, comp_rule.id, False) for comp_rule in completion_rules
}) ],
}
)
# Now I create a statement. I create statment lines separately because # Now I create a statement. I create statment lines separately because
# I need to find each one by XML id # I need to find each one by XML id
move_test1 = self.env['account.move'].create({ move_test1 = self.env["account.move"].create(
'name': 'Move 2', {"name": "Move 2", "journal_id": self.journal.id}
'journal_id': self.journal.id, )
})
# I create a move line for a CI # I create a move line for a CI
move_line_ci = self.env['account.move.line'].create({ move_line_ci = self.env["account.move.line"].create(
'name': '\\', {
'account_id': self.env.ref('account.a_sale').id, "name": "\\",
'move_id': move_test1.id, "account_id": self.env.ref("account.a_sale").id,
'date_maturity': fields.Date.from_string('2013-12-20'), "move_id": move_test1.id,
'credit': 0.0, "date_maturity": fields.Date.from_string("2013-12-20"),
}) "credit": 0.0,
}
)
# I create a move line for a SI # I create a move line for a SI
move_line_si = self.env['account.move.line'].create({ move_line_si = self.env["account.move.line"].create(
'name': '\\', {
'account_id': self.env.ref('account.a_expense').id, "name": "\\",
'move_id': move_test1.id, "account_id": self.env.ref("account.a_expense").id,
'date_maturity': fields.Date.from_string('2013-12-19'), "move_id": move_test1.id,
'debit': 0.0, "date_maturity": fields.Date.from_string("2013-12-19"),
}) "debit": 0.0,
}
)
# I create a move line for a CR # I create a move line for a CR
move_line_cr = self.env['account.move.line'].create({ move_line_cr = self.env["account.move.line"].create(
'name': '\\', {
'account_id': self.env.ref('account.a_expense').id, "name": "\\",
'move_id': move_test1.id, "account_id": self.env.ref("account.a_expense").id,
'date_maturity': fields.Date.from_string('2013-12-19'), "move_id": move_test1.id,
'debit': 0.0, "date_maturity": fields.Date.from_string("2013-12-19"),
}) "debit": 0.0,
}
)
# I create a move line for the Partner Name # I create a move line for the Partner Name
move_line_partner_name = self.env['account.move.line'].create({ move_line_partner_name = self.env["account.move.line"].create(
'name': 'Test autocompletion based on Partner Name Azure Interior', {
'account_id': self.env.ref('account.a_sale').id, "name": "Test autocompletion based on Partner Name Azure Interior",
'move_id': move_test1.id, "account_id": self.env.ref("account.a_sale").id,
'date_maturity': fields.Date.from_string('2013-12-17'), "move_id": move_test1.id,
'credit': 0.0, "date_maturity": fields.Date.from_string("2013-12-17"),
}) "credit": 0.0,
}
)
# I create a move line for the Partner Label # I create a move line for the Partner Label
move_line_partner_label = self.env['account.move.line'].create({ move_line_partner_label = self.env["account.move.line"].create(
'name': 'XXX66Z', {
'account_id': self.env.ref('account.a_sale').id, "name": "XXX66Z",
'move_id': move_test1.id, "account_id": self.env.ref("account.a_sale").id,
'date_maturity': '2013-12-24', "move_id": move_test1.id,
'debit': 0.0, "date_maturity": "2013-12-24",
}) "debit": 0.0,
}
)
# and add the correct name # and add the correct name
move_line_ci.with_context(check_move_validity=False).write({ move_line_ci.with_context(check_move_validity=False).write(
'name': fields.Date.today().strftime('TBNK/%Y/0001'), {"name": fields.Date.today().strftime("TBNK/%Y/0001"), "credit": 210.0}
'credit': 210.0, )
}) move_line_si.with_context(check_move_validity=False).write(
move_line_si.with_context(check_move_validity=False).write({ {"name": "T2S12345", "debit": 65.0}
'name': 'T2S12345', )
'debit': 65.0, move_line_cr.with_context(check_move_validity=False).write(
}) {"name": fields.Date.today().strftime("RTEXJ/%Y/0001"), "debit": 210.0}
move_line_cr.with_context(check_move_validity=False).write({ )
'name': fields.Date.today().strftime('RTEXJ/%Y/0001'), move_line_partner_name.with_context(check_move_validity=False).write(
'debit': 210.0, {"credit": 600.0}
}) )
move_line_partner_name.with_context(check_move_validity=False).write({ move_line_partner_label.with_context(check_move_validity=False).write(
'credit': 600.0, {"debit": 932.4}
}) )
move_line_partner_label.with_context(check_move_validity=False).write({
'debit': 932.4,
})
# I run the auto complete # I run the auto complete
move_test1.button_auto_completion() move_test1.button_auto_completion()
# Now I can check that all is nice and shiny, line 1. I expect the # Now I can check that all is nice and shiny, line 1. I expect the
@@ -244,31 +279,31 @@ class TestInvoice(SingleTransactionCase):
# I Use _ref, because ref conflicts with the field ref of the # I Use _ref, because ref conflicts with the field ref of the
# statement line # statement line
self.assertEqual( self.assertEqual(
move_line_ci.partner_id, self.partner, move_line_ci.partner_id, self.partner, msg="Check completion by CI number"
msg="Check completion by CI number"
) )
# Line 2. I expect the Supplier invoice number to be recognised. The # Line 2. I expect the Supplier invoice number to be recognised. The
# supplier invoice was created by the account module demo data, and we # supplier invoice was created by the account module demo data, and we
# confirmed it here. # confirmed it here.
self.assertEqual( self.assertEqual(
move_line_si.partner_id, self.partner, move_line_si.partner_id, self.partner, msg="Check completion by SI number"
msg="Check completion by SI number"
) )
# Line 3. I expect the Customer refund number to be recognised. It # Line 3. I expect the Customer refund number to be recognised. It
# should be the commercial partner, and not the regular partner. # should be the commercial partner, and not the regular partner.
self.assertEqual( self.assertEqual(
move_line_cr.partner_id, self.partner, move_line_cr.partner_id,
msg="Check completion by CR number and commercial partner" self.partner,
msg="Check completion by CR number and commercial partner",
) )
# Line 4. I check that the partner name has been recognised. # Line 4. I check that the partner name has been recognised.
self.assertEqual( self.assertEqual(
move_line_partner_name.partner_id.name, 'Azure Interior', move_line_partner_name.partner_id.name,
msg="Check completion by partner name" "Azure Interior",
msg="Check completion by partner name",
) )
# Line 5. I check that the partner special label has been recognised. # Line 5. I check that the partner special label has been recognised.
self.partner_4 = self.env.ref('base.res_partner_4') self.partner_4 = self.env.ref("base.res_partner_4")
self.assertEqual( self.assertEqual(
move_line_partner_label.partner_id, move_line_partner_label.partner_id,
self.partner_4, self.partner_4,
msg="Check completion by partner label" msg="Check completion by partner label",
) )

View File

@@ -1,85 +1,93 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="view_move_importer_form" model="ir.ui.view"> <record id="view_move_importer_form" model="ir.ui.view">
<field name="name">account.move.view</field> <field name="name">account.move.view</field>
<field name="model">account.move</field> <field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/> <field name="inherit_id" ref="account.view_move_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="journal_id" position="after"> <field name="journal_id" position="after">
<field name="used_for_completion" invisible="1"/> <field name="used_for_completion" invisible="1" />
</field> </field>
<button name="action_duplicate" position="after"> <button name="action_duplicate" position="after">
<button name="button_auto_completion" <button
string="Auto Completion" name="button_auto_completion"
type="object" string="Auto Completion"
class="oe_highlight" type="object"
groups="account.group_account_invoice" class="oe_highlight"
attrs="{'invisible': ['|', ('used_for_completion','=',False), ('state','not in', ['draft'])]}"/> groups="account.group_account_invoice"
attrs="{'invisible': ['|', ('used_for_completion','=',False), ('state','not in', ['draft'])]}"
/>
</button> </button>
<xpath expr="//field[@name='line_ids']/tree/field[@name='credit']" position="after"> <xpath
<field name="already_completed"/> expr="//field[@name='line_ids']/tree/field[@name='credit']"
position="after"
>
<field name="already_completed" />
</xpath> </xpath>
<xpath expr="/form/sheet/notebook" position="inside"> <xpath expr="/form/sheet/notebook" position="inside">
<page string="Completion Logs" attrs="{'invisible':[('completion_logs','=',False)]}"> <page
<field name="completion_logs" colspan="4" nolabel="1"/> string="Completion Logs"
attrs="{'invisible':[('completion_logs','=',False)]}"
>
<field name="completion_logs" colspan="4" nolabel="1" />
</page> </page>
</xpath> </xpath>
</field> </field>
</record> </record>
<record id="move_completion_rule_view_form" model="ir.ui.view"> <record id="move_completion_rule_view_form" model="ir.ui.view">
<field name="name">account.move.completion.rule.view</field> <field name="name">account.move.completion.rule.view</field>
<field name="model">account.move.completion.rule</field> <field name="model">account.move.completion.rule</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Move Completion Rule"> <form string="Move Completion Rule">
<group> <group>
<field name="sequence"/> <field name="sequence" />
<field name="name" select="1" /> <field name="name" select="1" />
<field name="function_to_call"/> <field name="function_to_call" />
</group> </group>
<separator colspan="4" string="Related Profiles"/> <separator colspan="4" string="Related Profiles" />
<field name="journal_ids" nolabel="1" colspan="4"/> <field name="journal_ids" nolabel="1" colspan="4" />
</form> </form>
</field> </field>
</record> </record>
<record id="move_completion_rule_view_tree" model="ir.ui.view"> <record id="move_completion_rule_view_tree" model="ir.ui.view">
<field name="name">account.move.completion.rule.view</field> <field name="name">account.move.completion.rule.view</field>
<field name="model">account.move.completion.rule</field> <field name="model">account.move.completion.rule</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Move Completion Rule"> <tree string="Move Completion Rule">
<field name="sequence"/> <field name="sequence" />
<field name="name" select="1" /> <field name="name" select="1" />
<field name="journal_ids" /> <field name="journal_ids" />
<field name="function_to_call"/> <field name="function_to_call" />
</tree> </tree>
</field> </field>
</record> </record>
<record id="action_move_completion_rule_tree" model="ir.actions.act_window"> <record id="action_move_completion_rule_tree" model="ir.actions.act_window">
<field name="name">Move Completion Rules</field> <field name="name">Move Completion Rules</field>
<field name="res_model">account.move.completion.rule</field> <field name="res_model">account.move.completion.rule</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
</record> </record>
<menuitem
<menuitem string="Move Completion Rule" action="action_move_completion_rule_tree" string="Move Completion Rule"
id="menu_action_move_completion_rule_tree_menu" parent="account.account_management_menu"/> action="action_move_completion_rule_tree"
id="menu_action_move_completion_rule_tree_menu"
parent="account.account_management_menu"
/>
<record id="view_account_move_filter" model="ir.ui.view"> <record id="view_account_move_filter" model="ir.ui.view">
<field name="model">account.move</field> <field name="model">account.move</field>
<field name="inherit_id" ref="account.view_account_move_filter"/> <field name="inherit_id" ref="account.view_account_move_filter" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<separator position="after"> <separator position="after">
<filter name="to_complete" <filter
name="to_complete"
string="To Complete" string="To Complete"
domain="[ domain="[
('state','!=','posted'), ('state','!=','posted'),
('journal_id.used_for_completion', '=', True), ('journal_id.used_for_completion', '=', True),
('line_ids.already_completed', '=', False)]" ('line_ids.already_completed', '=', False)]"
help="Account move that should be completed manually"/> help="Account move that should be completed manually"
<separator/> />
<separator />
</separator> </separator>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,40 +1,60 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="journal_importer_view_form" model="ir.ui.view"> <record id="journal_importer_view_form" model="ir.ui.view">
<field name="name">account.journal.view</field> <field name="name">account.journal.view</field>
<field name="model">account.journal</field> <field name="model">account.journal</field>
<field name="inherit_id" ref="account.view_account_journal_form"/> <field name="inherit_id" ref="account.view_account_journal_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="loss_account_id" position="after"> <field name="loss_account_id" position="after">
<field name="used_for_import"/> <field name="used_for_import" />
<field name="used_for_completion"/> <field name="used_for_completion" />
</field> </field>
<notebook position="inside"> <notebook position="inside">
<page string="Import related infos" attrs="{'invisible': [('used_for_import', '=', False)]}"> <page
string="Import related infos"
attrs="{'invisible': [('used_for_import', '=', False)]}"
>
<group> <group>
<field name="launch_import_completion" attrs="{'invisible': ['|', <field
name="launch_import_completion"
attrs="{'invisible': ['|',
('used_for_import', '=', False), ('used_for_import', '=', False),
('used_for_completion', '=', False)]}"/> ('used_for_completion', '=', False)]}"
<field name="last_import_date" readonly="1"/> />
<field name="import_type" attrs="{'required': [('used_for_import', '=', True)]}"/> <field name="last_import_date" readonly="1" />
<field
name="import_type"
attrs="{'required': [('used_for_import', '=', True)]}"
/>
</group> </group>
<group> <group>
<field name="commission_account_id"/> <field name="commission_account_id" />
<field name="receivable_account_id" attrs="{'required': [('used_for_import', '=', True)]}"/> <field
<field name="partner_id"/> name="receivable_account_id"
<field name="create_counterpart"/> attrs="{'required': [('used_for_import', '=', True)]}"
<field name="split_counterpart" attrs="{'invisible': [('create_counterpart', '=', False)]}"/> />
<field name="partner_id" />
<field name="create_counterpart" />
<field
name="split_counterpart"
attrs="{'invisible': [('create_counterpart', '=', False)]}"
/>
</group> </group>
<group> <group>
<button name="%(account_move_base_import.move_importer_action)d" <button
string="Import batch file" name="%(account_move_base_import.move_importer_action)d"
type="action" string="Import batch file"
colspan = "2"/> type="action"
colspan="2"
/>
</group> </group>
</page> </page>
<page string="Auto-Completion related infos" attrs="{'invisible': [('used_for_completion', '=', False)]}"> <page
string="Auto-Completion related infos"
attrs="{'invisible': [('used_for_completion', '=', False)]}"
>
<group string="Auto-Completion Rules" name="completion_rules"> <group string="Auto-Completion Rules" name="completion_rules">
<field name="rule_ids" colspan="2" nolabel="1"/> <field name="rule_ids" colspan="2" nolabel="1" />
</group> </group>
</page> </page>
</notebook> </notebook>

View File

@@ -1,15 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="bk_view_partner_form" model="ir.ui.view"> <record id="bk_view_partner_form" model="ir.ui.view">
<field name="name">account_bank_statement_import.view.partner.form</field> <field name="name">account_bank_statement_import.view.partner.form</field>
<field name="model">res.partner</field> <field name="model">res.partner</field>
<field name="inherit_id" ref="account.view_partner_property_form"/> <field name="inherit_id" ref="account.view_partner_property_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="property_account_payable_id" position="after"> <field name="property_account_payable_id" position="after">
<field name="bank_statement_label"/> <field name="bank_statement_label" />
</field> </field>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -7,72 +7,71 @@
Wizard to import financial institute date in bank statement Wizard to import financial institute date in bank statement
""" """
import os
from odoo import _, api, fields, models from odoo import _, api, fields, models
from odoo.exceptions import UserError from odoo.exceptions import UserError
import os
class CreditPartnerStatementImporter(models.TransientModel): class CreditPartnerStatementImporter(models.TransientModel):
_name = "credit.statement.import" _name = "credit.statement.import"
_description = 'Import Batch File wizard' _description = "Import Batch File wizard"
@api.model @api.model
def default_get(self, fields): def default_get(self, fields):
res = super().default_get(fields) res = super().default_get(fields)
ctx = self.env.context ctx = self.env.context
if ( if ctx.get("active_model") == "account.journal" and ctx.get("active_ids"):
ctx.get('active_model') == 'account.journal' and ids = ctx["active_ids"]
ctx.get('active_ids')): assert len(ids) == 1, "You cannot use this on more than one journal !"
ids = ctx['active_ids'] res["journal_id"] = ids[0]
assert len(ids) == 1, \
'You cannot use this on more than one journal !'
res['journal_id'] = ids[0]
return res return res
journal_id = fields.Many2one( journal_id = fields.Many2one(
comodel_name='account.journal', comodel_name="account.journal",
string='Import configuration parameter', string="Import configuration parameter",
required=True) required=True,
input_statement = fields.Binary( )
string='Statement file', input_statement = fields.Binary(string="Statement file", required=True)
required=True)
partner_id = fields.Many2one( partner_id = fields.Many2one(
comodel_name='res.partner', comodel_name="res.partner", related="journal_id.partner_id", readonly=True
related='journal_id.partner_id', readonly=True) )
file_name = fields.Char() file_name = fields.Char()
receivable_account_id = fields.Many2one( receivable_account_id = fields.Many2one(
comodel_name='account.account', comodel_name="account.account",
related='journal_id.receivable_account_id', readonly=True) related="journal_id.receivable_account_id",
readonly=True,
)
commission_account_id = fields.Many2one( commission_account_id = fields.Many2one(
comodel_name='account.account', comodel_name="account.account",
related='journal_id.commission_account_id', readonly=True) related="journal_id.commission_account_id",
readonly=True,
)
@api.multi @api.multi
def _check_extension(self): def _check_extension(self):
self.ensure_one() self.ensure_one()
(__, ftype) = os.path.splitext(self.file_name) (__, ftype) = os.path.splitext(self.file_name)
if not ftype: if not ftype:
raise UserError(_('Please use a file with an extension')) raise UserError(_("Please use a file with an extension"))
return ftype return ftype
@api.multi @api.multi
def import_statement(self): def import_statement(self):
"""This Function import credit card agency statement""" """This Function import credit card agency statement"""
moves = self.env['account.move'] moves = self.env["account.move"]
for importer in self: for importer in self:
journal = importer.journal_id journal = importer.journal_id
ftype = importer._check_extension() ftype = importer._check_extension()
moves |= journal.with_context( moves |= journal.with_context(
file_name=importer.file_name).multi_move_import( file_name=importer.file_name
importer.input_statement, ).multi_move_import(importer.input_statement, ftype.replace(".", ""))
ftype.replace('.', '') xmlid = ("account", "action_move_journal_line")
) action = self.env["ir.actions.act_window"].for_xml_id(*xmlid)
xmlid = ('account', 'action_move_journal_line')
action = self.env['ir.actions.act_window'].for_xml_id(*xmlid)
if len(moves) > 1: if len(moves) > 1:
action['domain'] = [('id', 'in', moves.ids)] action["domain"] = [("id", "in", moves.ids)]
else: else:
ref = self.env.ref('account.view_move_form') ref = self.env.ref("account.view_move_form")
action['views'] = [(ref.id, 'form')] action["views"] = [(ref.id, "form")]
action['res_id'] = moves.id if moves else False action["res_id"] = moves.id if moves else False
return action return action

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="move_importer_view" model="ir.ui.view"> <record id="move_importer_view" model="ir.ui.view">
<field name="name">credit.statement.import.config.view</field> <field name="name">credit.statement.import.config.view</field>
@@ -6,29 +6,40 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Import move"> <form string="Import move">
<group name="main"> <group name="main">
<field name="journal_id" domain="[('used_for_import', '=', True)]"/> <field
<field name="input_statement" filename="file_name"/> name="journal_id"
<field name="file_name" invisible="1"/> domain="[('used_for_import', '=', True)]"
/>
<field name="input_statement" filename="file_name" />
<field name="file_name" invisible="1" />
</group> </group>
<group string="Import Parameters Summary" name="params"> <group string="Import Parameters Summary" name="params">
<field name="partner_id"/> <field name="partner_id" />
<field name="receivable_account_id"/> <field name="receivable_account_id" />
<field name="commission_account_id"/> <field name="commission_account_id" />
</group> </group>
<footer> <footer>
<button name="import_statement" string="Import file" type="object" class="oe_highlight"/> <button
<button special="cancel" string="Cancel" class="oe_link"/> name="import_statement"
string="Import file"
type="object"
class="oe_highlight"
/>
<button special="cancel" string="Cancel" class="oe_link" />
</footer> </footer>
</form> </form>
</field> </field>
</record> </record>
<record id="move_importer_action" model="ir.actions.act_window"> <record id="move_importer_action" model="ir.actions.act_window">
<field name="name">Import Batch File</field> <field name="name">Import Batch File</field>
<field name="res_model">credit.statement.import</field> <field name="res_model">credit.statement.import</field>
<field name="view_mode">form</field> <field name="view_mode">form</field>
<field name="target">new</field> <field name="target">new</field>
</record> </record>
<menuitem
<menuitem id="move_importer_menu" name="Import Batch File" action="move_importer_action" parent="account.menu_finance_entries"/> id="move_importer_menu"
name="Import Batch File"
action="move_importer_action"
parent="account.menu_finance_entries"
/>
</odoo> </odoo>