2
0

[IMP] account_move_template: black, isort, prettier

This commit is contained in:
Valentin Vinagre Urteaga 2020-04-24 17:27:55 +02:00 committed by Abraham Anes
parent 271fb301c8
commit f5b4892d24
7 changed files with 580 additions and 415 deletions

View File

@ -4,22 +4,20 @@
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
{ {
'name': "Account Move Template", "name": "Account Move Template",
'version': '12.0.1.0.0', "version": "12.0.1.0.0",
'category': 'Accounting', "category": "Accounting",
'summary': "Templates for recurring Journal Entries", "summary": "Templates for recurring Journal Entries",
'author': "Agile Business Group, Aurium Technologies, Vauxoo, Eficent, " "author": "Agile Business Group, Aurium Technologies, Vauxoo, Eficent, "
"Akretion, Odoo Community Association (OCA)", "Akretion, Odoo Community Association (OCA)",
'website': 'https://github.com/OCA/account-financial-tools', "website": "https://github.com/OCA/account-financial-tools",
'license': 'AGPL-3', "license": "AGPL-3",
'depends': [ "depends": ["account",],
'account', "data": [
"security/account_move_template_security.xml",
"security/ir.model.access.csv",
"wizard/account_move_template_run_view.xml",
"view/account_move_template.xml",
], ],
'data': [ "installable": True,
'security/account_move_template_security.xml',
'security/ir.model.access.csv',
'wizard/account_move_template_run_view.xml',
'view/account_move_template.xml',
],
'installable': True,
} }

View File

@ -1,138 +1,172 @@
# Copyright 2015-2019 See manifest # Copyright 2015-2019 See manifest
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from odoo import api, fields, models, _ from odoo import _, api, fields, models
from odoo.tools.safe_eval import safe_eval
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
from odoo.tools import float_round from odoo.tools import float_round
from odoo.tools.safe_eval import safe_eval
class AccountMoveTemplate(models.Model): class AccountMoveTemplate(models.Model):
_name = 'account.move.template' _name = "account.move.template"
_description = 'Journal Entry Template' _description = "Journal Entry Template"
name = fields.Char(required=True) name = fields.Char(required=True)
company_id = fields.Many2one( company_id = fields.Many2one(
'res.company', string='Company', required=True, ondelete='cascade', "res.company",
default=lambda self: self.env['res.company']._company_default_get()) string="Company",
journal_id = fields.Many2one( required=True,
'account.journal', string='Journal', required=True) ondelete="cascade",
ref = fields.Char(string='Reference', copy=False) default=lambda self: self.env["res.company"]._company_default_get(),
)
journal_id = fields.Many2one("account.journal", string="Journal", required=True)
ref = fields.Char(string="Reference", copy=False)
line_ids = fields.One2many( line_ids = fields.One2many(
'account.move.template.line', inverse_name='template_id', "account.move.template.line", inverse_name="template_id", string="Lines"
string='Lines') )
_sql_constraints = [( _sql_constraints = [
'name_company_unique', (
'unique(name, company_id)', "name_company_unique",
'This name is already used by another template!' "unique(name, company_id)",
)] "This name is already used by another template!",
)
]
@api.multi @api.multi
@api.returns('self', lambda value: value.id) @api.returns("self", lambda value: value.id)
def copy(self, default=None): def copy(self, default=None):
self.ensure_one() self.ensure_one()
default = dict(default or {}, name=_('%s (copy)') % self.name) default = dict(default or {}, name=_("%s (copy)") % self.name)
return super(AccountMoveTemplate, self).copy(default) return super(AccountMoveTemplate, self).copy(default)
def eval_computed_line(self, line, sequence2amount): def eval_computed_line(self, line, sequence2amount):
safe_eval_dict = {} safe_eval_dict = {}
for seq, amount in sequence2amount.items(): for seq, amount in sequence2amount.items():
safe_eval_dict['L%d' % seq] = amount safe_eval_dict["L%d" % seq] = amount
try: try:
val = safe_eval(line.python_code, safe_eval_dict) val = safe_eval(line.python_code, safe_eval_dict)
sequence2amount[line.sequence] = val sequence2amount[line.sequence] = val
except ValueError: except ValueError:
raise UserError(_( raise UserError(
"Impossible to compute the formula of line with sequence %s " _(
"(formula: %s). Check that the lines used in the formula " "Impossible to compute the formula of line with sequence %s "
"really exists and have a lower sequence than the current " "(formula: %s). Check that the lines used in the formula "
"line.") % (line.sequence, line.python_code)) "really exists and have a lower sequence than the current "
"line."
)
% (line.sequence, line.python_code)
)
except SyntaxError: except SyntaxError:
raise UserError(_( raise UserError(
"Impossible to compute the formula of line with sequence %s " _(
"(formula: %s): the syntax of the formula is wrong.") "Impossible to compute the formula of line with sequence %s "
% (line.sequence, line.python_code)) "(formula: %s): the syntax of the formula is wrong."
)
% (line.sequence, line.python_code)
)
def compute_lines(self, sequence2amount): def compute_lines(self, sequence2amount):
prec = self.company_id.currency_id.rounding prec = self.company_id.currency_id.rounding
input_sequence2amount = sequence2amount.copy() input_sequence2amount = sequence2amount.copy()
for line in self.line_ids.filtered(lambda x: x.type == 'input'): for line in self.line_ids.filtered(lambda x: x.type == "input"):
if line.sequence not in sequence2amount: if line.sequence not in sequence2amount:
raise UserError(_( raise UserError(
"You deleted a line in the wizard. This is not allowed: " _(
"you should either update the template or modify the " "You deleted a line in the wizard. This is not allowed: "
"journal entry that will be generated by this wizard.")) "you should either update the template or modify the "
"journal entry that will be generated by this wizard."
)
)
input_sequence2amount.pop(line.sequence) input_sequence2amount.pop(line.sequence)
if input_sequence2amount: if input_sequence2amount:
raise UserError(_( raise UserError(
"You added a line in the wizard. This is not allowed: " _(
"you should either update the template or modify " "You added a line in the wizard. This is not allowed: "
"the journal entry that will be generated by this wizard.")) "you should either update the template or modify "
for line in self.line_ids.filtered(lambda x: x.type == 'computed'): "the journal entry that will be generated by this wizard."
)
)
for line in self.line_ids.filtered(lambda x: x.type == "computed"):
self.eval_computed_line(line, sequence2amount) self.eval_computed_line(line, sequence2amount)
sequence2amount[line.sequence] = float_round( sequence2amount[line.sequence] = float_round(
sequence2amount[line.sequence], precision_rounding=prec) sequence2amount[line.sequence], precision_rounding=prec
)
return sequence2amount return sequence2amount
def generate_journal_entry(self): def generate_journal_entry(self):
'''Called by the button on the form view''' """Called by the button on the form view"""
self.ensure_one() self.ensure_one()
wiz = self.env['account.move.template.run'].create({ wiz = self.env["account.move.template.run"].create({"template_id": self.id})
'template_id': self.id})
action = wiz.load_lines() action = wiz.load_lines()
return action return action
class AccountMoveTemplateLine(models.Model): class AccountMoveTemplateLine(models.Model):
_name = 'account.move.template.line' _name = "account.move.template.line"
_description = 'Journal Item Template' _description = "Journal Item Template"
_order = 'sequence, id' _order = "sequence, id"
template_id = fields.Many2one( template_id = fields.Many2one(
'account.move.template', string='Move Template', ondelete='cascade') "account.move.template", string="Move Template", ondelete="cascade"
name = fields.Char(string='Label', required=True) )
sequence = fields.Integer('Sequence', required=True) name = fields.Char(string="Label", required=True)
sequence = fields.Integer("Sequence", required=True)
account_id = fields.Many2one( account_id = fields.Many2one(
'account.account', string='Account', "account.account",
required=True, domain=[('deprecated', '=', False)]) string="Account",
required=True,
domain=[("deprecated", "=", False)],
)
partner_id = fields.Many2one( partner_id = fields.Many2one(
'res.partner', string='Partner', "res.partner",
domain=['|', ('parent_id', '=', False), ('is_company', '=', True)]) string="Partner",
domain=["|", ("parent_id", "=", False), ("is_company", "=", True)],
)
analytic_account_id = fields.Many2one( analytic_account_id = fields.Many2one(
'account.analytic.account', string='Analytic Account') "account.analytic.account", string="Analytic Account"
analytic_tag_ids = fields.Many2many( )
'account.analytic.tag', string='Analytic Tags') analytic_tag_ids = fields.Many2many("account.analytic.tag", string="Analytic Tags")
tax_ids = fields.Many2many('account.tax', string='Taxes') tax_ids = fields.Many2many("account.tax", string="Taxes")
tax_line_id = fields.Many2one( tax_line_id = fields.Many2one(
'account.tax', string='Originator Tax', ondelete='restrict') "account.tax", string="Originator Tax", ondelete="restrict"
company_id = fields.Many2one( )
related='template_id.company_id', store=True) company_id = fields.Many2one(related="template_id.company_id", store=True)
company_currency_id = fields.Many2one( company_currency_id = fields.Many2one(
related='template_id.company_id.currency_id', related="template_id.company_id.currency_id",
string='Company Currency', store=True) string="Company Currency",
store=True,
)
note = fields.Char() note = fields.Char()
type = fields.Selection([ type = fields.Selection(
('computed', 'Computed'), [("computed", "Computed"), ("input", "User input"),],
('input', 'User input'), string="Type",
], string='Type', required=True, default='input') required=True,
python_code = fields.Text('Python Code') default="input",
)
python_code = fields.Text("Python Code")
move_line_type = fields.Selection( move_line_type = fields.Selection(
[('cr', 'Credit'), ('dr', 'Debit')], required=True, string='Direction') [("cr", "Credit"), ("dr", "Debit")], required=True, string="Direction"
)
payment_term_id = fields.Many2one( payment_term_id = fields.Many2one(
'account.payment.term', string='Payment Terms', "account.payment.term",
help="Used to compute the due date of the journal item.") string="Payment Terms",
help="Used to compute the due date of the journal item.",
)
_sql_constraints = [( _sql_constraints = [
'sequence_template_uniq', (
'unique(template_id, sequence)', "sequence_template_uniq",
'The sequence of the line must be unique per template!' "unique(template_id, sequence)",
)] "The sequence of the line must be unique per template!",
)
]
@api.constrains('type', 'python_code') @api.constrains("type", "python_code")
def check_python_code(self): def check_python_code(self):
for line in self: for line in self:
if line.type == 'computed' and not line.python_code: if line.type == "computed" and not line.python_code:
raise ValidationError(_( raise ValidationError(
"Python Code must be set for computed line with " _("Python Code must be set for computed line with " "sequence %d.")
"sequence %d.") % line.sequence) % line.sequence
)

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1"> <odoo noupdate="1">
<record id="account_move_template_comp_rule" model="ir.rule"> <record id="account_move_template_comp_rule" model="ir.rule">
<field name="name">Move Template multi-company rule</field> <field name="name">Move Template multi-company rule</field>
<field name="model_id" ref="model_account_move_template"/> <field name="model_id" ref="model_account_move_template" />
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field> <field
name="domain_force"
>['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record> </record>
</odoo> </odoo>

View File

@ -1,92 +1,105 @@
# Copyright 2018-2019 Eficent Business and IT Consulting Services, S.L. # Copyright 2018-2019 Eficent Business and IT Consulting Services, S.L.
# 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 logging import logging
from psycopg2 import IntegrityError from psycopg2 import IntegrityError
from odoo import fields
from odoo.tests.common import TransactionCase from odoo.tests.common import TransactionCase
from odoo.tools import mute_logger from odoo.tools import mute_logger
from odoo import fields
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class TestAccountMoveTemplate(TransactionCase): class TestAccountMoveTemplate(TransactionCase):
def with_context(self, *args, **kwargs): def with_context(self, *args, **kwargs):
context = dict(args[0] if args else self.env.context, **kwargs) context = dict(args[0] if args else self.env.context, **kwargs)
self.env = self.env(context=context) self.env = self.env(context=context)
return self return self
def _chart_of_accounts_create(self, company, chart): def _chart_of_accounts_create(self, company, chart):
_logger.debug('Creating chart of account') _logger.debug("Creating chart of account")
self.env.user.write({ self.env.user.write(
'company_ids': [(4, company.id)], {"company_ids": [(4, company.id)], "company_id": company.id,}
'company_id': company.id, )
}) self.with_context(company_id=company.id, force_company=company.id)
self.with_context( wizard = self.env["wizard.multi.charts.accounts"].create(
company_id=company.id, force_company=company.id) {
wizard = self.env['wizard.multi.charts.accounts'].create({ "company_id": company.id,
'company_id': company.id, "chart_template_id": chart.id,
'chart_template_id': chart.id, "code_digits": 6,
'code_digits': 6, "currency_id": self.env.ref("base.EUR").id,
'currency_id': self.env.ref('base.EUR').id, "transfer_account_id": chart.transfer_account_id.id,
'transfer_account_id': chart.transfer_account_id.id, }
}) )
wizard.onchange_chart_template_id() wizard.onchange_chart_template_id()
wizard.execute() wizard.execute()
return True return True
def setUp(self): def setUp(self):
super(TestAccountMoveTemplate, self).setUp() super(TestAccountMoveTemplate, self).setUp()
employees_group = self.env.ref('base.group_user') employees_group = self.env.ref("base.group_user")
multi_company_group = self.env.ref('base.group_multi_company') multi_company_group = self.env.ref("base.group_multi_company")
account_user_group = self.env.ref('account.group_account_user') account_user_group = self.env.ref("account.group_account_user")
account_manager_group = self.env.ref('account.group_account_manager') account_manager_group = self.env.ref("account.group_account_manager")
self.company = self.env['res.company'].create({ self.company = self.env["res.company"].create({"name": "Test company",})
'name': 'Test company', self.company_2 = self.env["res.company"].create(
}) {"name": "Test company 2", "parent_id": self.company.id,}
self.company_2 = self.env['res.company'].create({ )
'name': 'Test company 2',
'parent_id': self.company.id,
})
self.env.user.company_ids += self.company self.env.user.company_ids += self.company
self.env.user.company_ids += self.company_2 self.env.user.company_ids += self.company_2
self.user = self.env['res.users'].sudo(self.env.user).with_context( self.user = (
no_reset_password=True).create( self.env["res.users"]
{'name': 'Test User', .sudo(self.env.user)
'login': 'test_user', .with_context(no_reset_password=True)
'email': 'test@oca.com', .create(
'groups_id': [(6, 0, [employees_group.id, {
account_user_group.id, "name": "Test User",
account_manager_group.id, "login": "test_user",
multi_company_group.id, "email": "test@oca.com",
])], "groups_id": [
'company_id': self.company.id, (
'company_ids': [(4, self.company.id)], 6,
}) 0,
[
employees_group.id,
account_user_group.id,
account_manager_group.id,
multi_company_group.id,
],
)
],
"company_id": self.company.id,
"company_ids": [(4, self.company.id)],
}
)
)
self.user_type = self.env.ref('account.data_account_type_liquidity') self.user_type = self.env.ref("account.data_account_type_liquidity")
self.chart = self.env['account.chart.template'].search([], limit=1) self.chart = self.env["account.chart.template"].search([], limit=1)
self._chart_of_accounts_create(self.company, self.chart) self._chart_of_accounts_create(self.company, self.chart)
account_template = self.env['account.account.template'].create({ account_template = self.env["account.account.template"].create(
'name': 'Test 1', {"name": "Test 1", "code": "Code_test", "user_type_id": self.user_type.id,}
'code': 'Code_test', )
'user_type_id': self.user_type.id, self.env["ir.model.data"].create(
}) {
self.env['ir.model.data'].create({ "name": account_template.name,
'name': account_template.name, "module": "account",
'module': 'account', "model": "account.account.template",
'model': 'account.account.template', "res_id": account_template.id,
'res_id': account_template.id, "noupdate": 0,
'noupdate': 0, }
}) )
self.chart_2 = self.env['account.chart.template'].create({ self.chart_2 = self.env["account.chart.template"].create(
'name': 'Test Chart', {
'currency_id': self.env.ref('base.EUR').id, "name": "Test Chart",
'transfer_account_id': account_template.id, "currency_id": self.env.ref("base.EUR").id,
}) "transfer_account_id": account_template.id,
}
)
account_template.chart_template_id = self.chart_2 account_template.chart_template_id = self.chart_2
self.chart_2.tax_template_ids |= self.chart.tax_template_ids self.chart_2.tax_template_ids |= self.chart.tax_template_ids
@ -96,88 +109,113 @@ class TestAccountMoveTemplate(TransactionCase):
self.chart.company_id = self.company self.chart.company_id = self.company
self.chart_2.company_id = self.company_2 self.chart_2.company_id = self.company_2
self.account_company_1 = self.env['account.account'].search( self.account_company_1 = self.env["account.account"].search(
[('company_id', '=', self.company.id)], limit=1) [("company_id", "=", self.company.id)], limit=1
self.account_journal_1 = self.env['account.journal'].create({ )
'name': 'Journal Company 1', self.account_journal_1 = self.env["account.journal"].create(
'company_id': self.company.id, {
'code': 'TST', "name": "Journal Company 1",
'type': 'general', "company_id": self.company.id,
}) "code": "TST",
self.partner = self.env['res.partner'].create({ "type": "general",
'name': 'Test partner', }
'company_id': False, )
}) self.partner = self.env["res.partner"].create(
self.partner2 = self.env['res.partner'].create({ {"name": "Test partner", "company_id": False,}
'name': 'Test partner 2', )
'company_id': False, self.partner2 = self.env["res.partner"].create(
}) {"name": "Test partner 2", "company_id": False,}
self.account_type = self.env['account.account.type'].create({ )
'name': 'Test Tax Account Type'}) self.account_type = self.env["account.account.type"].create(
{"name": "Test Tax Account Type"}
)
self.tax_account_id = self.env['account.account'].create({ self.tax_account_id = self.env["account.account"].create(
'name': 'tax account', {
'code': 'TAX', "name": "tax account",
'user_type_id': self.account_type.id, "code": "TAX",
'company_id': self.company.id, "user_type_id": self.account_type.id,
}) "company_id": self.company.id,
self.tax = self.env['account.tax'].create({ }
'name': 'Tax 10.0%', )
'amount': 10.0, self.tax = self.env["account.tax"].create(
'amount_type': 'percent', {
'account_id': self.tax_account_id.id, "name": "Tax 10.0%",
}) "amount": 10.0,
"amount_type": "percent",
"account_id": self.tax_account_id.id,
}
)
def test_create_template(self): def test_create_template(self):
"""Test that I can create a template """Test that I can create a template
""" """
template = self.env['account.move.template'].sudo(self.user).create({ template = (
'name': 'Test Move Template', self.env["account.move.template"]
'company_id': self.company.id, .sudo(self.user)
'journal_id': self.account_journal_1.id, .create(
'template_line_ids': [ {
(0, 0, { "name": "Test Move Template",
'name': 'L1', "company_id": self.company.id,
'sequence': 1, "journal_id": self.account_journal_1.id,
'account_id': self.account_company_1.id, "template_line_ids": [
'partner_id': self.partner.id, (
'tax_line_id': self.tax.id, 0,
'move_line_type': 'dr', 0,
'type': 'input' {
}), "name": "L1",
(0, 0, { "sequence": 1,
'name': 'L2', "account_id": self.account_company_1.id,
'sequence': 2, "partner_id": self.partner.id,
'account_id': self.account_company_1.id, "tax_line_id": self.tax.id,
'move_line_type': 'cr', "move_line_type": "dr",
'tax_ids': [(4, self.tax.id)], "type": "input",
'type': 'input', },
}) ),
] (
}) 0,
0,
{
"name": "L2",
"sequence": 2,
"account_id": self.account_company_1.id,
"move_line_type": "cr",
"tax_ids": [(4, self.tax.id)],
"type": "input",
},
),
],
}
)
)
self.assertEquals(template.company_id, self.user.company_id) self.assertEquals(template.company_id, self.user.company_id)
template_2 = template.copy() template_2 = template.copy()
self.assertEquals(template_2.name, '%s (copy)' % template.name) self.assertEquals(template_2.name, "%s (copy)" % template.name)
wiz = self.env['wizard.select.move.template'].sudo(self.user).create({ wiz = (
'company_id': self.company.id, self.env["wizard.select.move.template"]
'template_id': template.id, .sudo(self.user)
'partner_id': self.partner2.id, .create(
'date': fields.Date.today(), {
}) "company_id": self.company.id,
"template_id": template.id,
"partner_id": self.partner2.id,
"date": fields.Date.today(),
}
)
)
wiz.load_lines() wiz.load_lines()
res = wiz.load_template() res = wiz.load_template()
aml = self.env['account.move.line'].search( aml = self.env["account.move.line"].search(
[('account_id', '=', self.account_company_1.id)], limit=1) [("account_id", "=", self.account_company_1.id)], limit=1
self.assertEquals(res['domain'], ([('id', 'in', aml.move_id.ids)])) )
aml = self.env['account.move.line'].search( self.assertEquals(res["domain"], ([("id", "in", aml.move_id.ids)]))
[('name', '=', 'L1')], limit=1) aml = self.env["account.move.line"].search([("name", "=", "L1")], limit=1)
self.assertEquals(aml.tax_line_id, self.tax) self.assertEquals(aml.tax_line_id, self.tax)
self.assertEquals(aml.partner_id, self.partner) self.assertEquals(aml.partner_id, self.partner)
aml = self.env['account.move.line'].search( aml = self.env["account.move.line"].search([("name", "=", "L2")], limit=1)
[('name', '=', 'L2')], limit=1)
self.assertEquals(aml.tax_ids[0], self.tax) self.assertEquals(aml.tax_ids[0], self.tax)
with self.assertRaises(IntegrityError), mute_logger('odoo.sql_db'): with self.assertRaises(IntegrityError), mute_logger("odoo.sql_db"):
template_2.name = template.name template_2.name = template.name

View File

@ -1,28 +1,38 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="account_move_template_line_tree" model="ir.ui.view"> <record id="account_move_template_line_tree" model="ir.ui.view">
<field name="name">account.move.template.line.tree</field> <field name="name">account.move.template.line.tree</field>
<field name="model">account.move.template.line</field> <field name="model">account.move.template.line</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree> <tree>
<field name="sequence"/> <field name="sequence" />
<field name="account_id" domain="[('company_id', '=', company_id)]"/> <field name="account_id" domain="[('company_id', '=', company_id)]" />
<field name="partner_id"/> <field name="partner_id" />
<field name="name"/> <field name="name" />
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"/> <field
<field name="analytic_tag_ids" widget="many2many_tags" groups="analytic.group_analytic_accounting"/> name="analytic_account_id"
<field name="move_line_type"/> groups="analytic.group_analytic_accounting"
<field name="type"/> />
<field name="note"/> <field
<field name="tax_line_id" invisible="1"/> name="analytic_tag_ids"
<field name="tax_ids" widget="many2many_tags" options="{'no_create': True}"/> widget="many2many_tags"
<field name="payment_term_id"/> groups="analytic.group_analytic_accounting"
<field name="company_id" invisible="1"/> />
<field name="company_currency_id" invisible="1"/> <field name="move_line_type" />
<field name="type" />
<field name="note" />
<field name="tax_line_id" invisible="1" />
<field
name="tax_ids"
widget="many2many_tags"
options="{'no_create': True}"
/>
<field name="payment_term_id" />
<field name="company_id" invisible="1" />
<field name="company_currency_id" invisible="1" />
</tree> </tree>
</field> </field>
</record> </record>
<record id="account_move_template_line_form" model="ir.ui.view"> <record id="account_move_template_line_form" model="ir.ui.view">
<field name="name">account.move.template.line.form</field> <field name="name">account.move.template.line.form</field>
<field name="model">account.move.template.line</field> <field name="model">account.move.template.line</field>
@ -31,30 +41,47 @@
<sheet> <sheet>
<group name="main"> <group name="main">
<group name="account"> <group name="account">
<field name="sequence"/> <field name="sequence" />
<field name="name"/> <field name="name" />
<field name="account_id" domain="[('company_id', '=', company_id)]"/> <field
<field name="partner_id"/> name="account_id"
<field name="payment_term_id"/> domain="[('company_id', '=', company_id)]"
<field name="company_id" invisible="1"/> />
<field name="partner_id" />
<field name="payment_term_id" />
<field name="company_id" invisible="1" />
</group> </group>
<group groups="analytic.group_analytic_accounting" string="Analytic" name="analytic"> <group
<field name="analytic_account_id" domain="[('company_id','=',company_id)]"/> groups="analytic.group_analytic_accounting"
<field name="analytic_tag_ids" widget="many2many_tags"/> string="Analytic"
name="analytic"
>
<field
name="analytic_account_id"
domain="[('company_id','=',company_id)]"
/>
<field name="analytic_tag_ids" widget="many2many_tags" />
</group> </group>
<group name="amount" string="Amount"> <group name="amount" string="Amount">
<field name="move_line_type"/> <field name="move_line_type" />
<field name="type"/> <field name="type" />
<field name="note"/> <field name="note" />
</group> </group>
<group string="Taxes" name="tax"> <group string="Taxes" name="tax">
<field name="tax_line_id"/> <field name="tax_line_id" />
<field name="tax_ids" widget="many2many_tags"/> <field name="tax_ids" widget="many2many_tags" />
</group> </group>
</group> </group>
<group name="python_code" attrs="{'invisible': [('type', '!=', 'computed')]}" col="1" string="Compute Formula"> <group
name="python_code"
attrs="{'invisible': [('type', '!=', 'computed')]}"
col="1"
string="Compute Formula"
>
<div class="oe_account_help"> <div class="oe_account_help">
<p>You can refer to other lines using their sequence number e.g. <i>L1</i> for line with sequence = 1. Examples:</p> <p
>You can refer to other lines using their sequence number e.g. <i
>L1</i> for line with sequence = 1. Examples:</p>
<ul> <ul>
<li>L1 * 0.2</li> <li>L1 * 0.2</li>
<li>L2 - L1</li> <li>L2 - L1</li>
@ -62,82 +89,99 @@
<li>1250</li> <li>1250</li>
</ul> </ul>
</div> </div>
<field
<field name="python_code" nolabel="1" attrs="{'required': [('type', '=', 'computed')]}"/> name="python_code"
nolabel="1"
attrs="{'required': [('type', '=', 'computed')]}"
/>
</group> </group>
</sheet> </sheet>
</form> </form>
</field> </field>
</record> </record>
<record id="account_move_template_form" model="ir.ui.view"> <record id="account_move_template_form" model="ir.ui.view">
<field name="name">account.move.template.form</field> <field name="name">account.move.template.form</field>
<field name="model">account.move.template</field> <field name="model">account.move.template</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Journal Entry Template"> <form string="Journal Entry Template">
<header> <header>
<button string="Generate Journal Entry" <button
name="generate_journal_entry" string="Generate Journal Entry"
class="btn-primary" name="generate_journal_entry"
type="object"/> class="btn-primary"
type="object"
/>
</header> </header>
<sheet> <sheet>
<div class="oe_title"> <div class="oe_title">
<label for="name" class="oe_edit_only"/> <label for="name" class="oe_edit_only" />
<h1><field name="name"/></h1> <h1>
<field name="name" />
</h1>
</div> </div>
<group name="main"> <group name="main">
<group name="main-left"> <group name="main-left">
<field name="company_id" widget="selection" groups="base.group_multi_company"/> <field
<field name="journal_id" options="{'no_open': True, 'no_create': True}"/> name="company_id"
widget="selection"
groups="base.group_multi_company"
/>
<field
name="journal_id"
options="{'no_open': True, 'no_create': True}"
/>
</group> </group>
<group name="main-right"> <group name="main-right">
<field name="ref"/> <field name="ref" />
</group> </group>
</group> </group>
<group name="lines"> <group name="lines">
<field name="line_ids" nolabel="1" context="{'default_company_id': company_id}"/> <field
name="line_ids"
nolabel="1"
context="{'default_company_id': company_id}"
/>
</group> </group>
</sheet> </sheet>
</form> </form>
</field> </field>
</record> </record>
<record id="account_move_template_tree" model="ir.ui.view"> <record id="account_move_template_tree" model="ir.ui.view">
<field name="name">account.move.template.tree</field> <field name="name">account.move.template.tree</field>
<field name="model">account.move.template</field> <field name="model">account.move.template</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree> <tree>
<field name="name"/> <field name="name" />
<field name="journal_id"/> <field name="journal_id" />
<field name="company_id" groups="base.group_multi_company"/> <field name="company_id" groups="base.group_multi_company" />
</tree> </tree>
</field> </field>
</record> </record>
<record id="account_move_template_search" model="ir.ui.view"> <record id="account_move_template_search" model="ir.ui.view">
<field name="name">account.move.template.search</field> <field name="name">account.move.template.search</field>
<field name="model">account.move.template</field> <field name="model">account.move.template</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Journal Entry Template"> <search string="Journal Entry Template">
<field name="name"/> <field name="name" />
<group name="groupby"> <group name="groupby">
<filter name="journal_groupby" string="Journal" context="{'group_by': 'journal_id'}"/> <filter
name="journal_groupby"
string="Journal"
context="{'group_by': 'journal_id'}"
/>
</group> </group>
</search> </search>
</field> </field>
</record> </record>
<record id="account_move_template_action" model="ir.actions.act_window"> <record id="account_move_template_action" model="ir.actions.act_window">
<field name="name">Journal Entry Templates</field> <field name="name">Journal Entry Templates</field>
<field name="res_model">account.move.template</field> <field name="res_model">account.move.template</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
</record> </record>
<menuitem <menuitem
id="account_move_template_menu" id="account_move_template_menu"
action="account_move_template_action" action="account_move_template_action"
parent="account.account_account_menu" parent="account.account_account_menu"
sequence="300"/> sequence="300"
/>
</odoo> </odoo>

View File

@ -1,7 +1,7 @@
# Copyright 2015-2019 See manifest # Copyright 2015-2019 See manifest
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from odoo import fields, models, _ from odoo import _, fields, models
from odoo.exceptions import UserError from odoo.exceptions import UserError
from odoo.tools import float_is_zero from odoo.tools import float_is_zero
@ -10,71 +10,82 @@ class AccountMoveTemplateRun(models.TransientModel):
_name = "account.move.template.run" _name = "account.move.template.run"
_description = "Wizard to generate move from template" _description = "Wizard to generate move from template"
template_id = fields.Many2one('account.move.template', required=True) template_id = fields.Many2one("account.move.template", required=True)
company_id = fields.Many2one( company_id = fields.Many2one(
'res.company', required=True, readonly=True, "res.company",
default=lambda self: self.env['res.company']._company_default_get()) required=True,
readonly=True,
default=lambda self: self.env["res.company"]._company_default_get(),
)
partner_id = fields.Many2one( partner_id = fields.Many2one(
'res.partner', 'Override Partner', "res.partner",
domain=['|', ('parent_id', '=', False), ('is_company', '=', True)]) "Override Partner",
domain=["|", ("parent_id", "=", False), ("is_company", "=", True)],
)
date = fields.Date(required=True, default=fields.Date.context_today) date = fields.Date(required=True, default=fields.Date.context_today)
journal_id = fields.Many2one( journal_id = fields.Many2one("account.journal", string="Journal", readonly=True)
'account.journal', string='Journal', readonly=True) ref = fields.Char(string="Reference")
ref = fields.Char(string='Reference')
line_ids = fields.One2many( line_ids = fields.One2many(
'account.move.template.line.run', 'wizard_id', string="Lines") "account.move.template.line.run", "wizard_id", string="Lines"
state = fields.Selection([ )
('select_template', 'Select Template'), state = fields.Selection(
('set_lines', 'Set Lines'), [("select_template", "Select Template"), ("set_lines", "Set Lines"),],
], readonly=True, default='select_template') readonly=True,
default="select_template",
)
def _prepare_wizard_line(self, tmpl_line): def _prepare_wizard_line(self, tmpl_line):
vals = { vals = {
'wizard_id': self.id, "wizard_id": self.id,
'sequence': tmpl_line.sequence, "sequence": tmpl_line.sequence,
'name': tmpl_line.name, "name": tmpl_line.name,
'amount': 0.0, "amount": 0.0,
'account_id': tmpl_line.account_id.id, "account_id": tmpl_line.account_id.id,
'partner_id': tmpl_line.partner_id.id or False, "partner_id": tmpl_line.partner_id.id or False,
'move_line_type': tmpl_line.move_line_type, "move_line_type": tmpl_line.move_line_type,
'tax_ids': [(6, 0, tmpl_line.tax_ids.ids)], "tax_ids": [(6, 0, tmpl_line.tax_ids.ids)],
'tax_line_id': tmpl_line.tax_line_id.id, "tax_line_id": tmpl_line.tax_line_id.id,
'analytic_account_id': tmpl_line.analytic_account_id.id, "analytic_account_id": tmpl_line.analytic_account_id.id,
'analytic_tag_ids': [(6, 0, tmpl_line.analytic_tag_ids.ids)], "analytic_tag_ids": [(6, 0, tmpl_line.analytic_tag_ids.ids)],
'note': tmpl_line.note, "note": tmpl_line.note,
'payment_term_id': tmpl_line.payment_term_id.id or False, "payment_term_id": tmpl_line.payment_term_id.id or False,
} }
return vals return vals
# STEP 1 # STEP 1
def load_lines(self): def load_lines(self):
self.ensure_one() self.ensure_one()
amtlro = self.env['account.move.template.line.run'] amtlro = self.env["account.move.template.line.run"]
if self.company_id != self.template_id.company_id: if self.company_id != self.template_id.company_id:
raise UserError(_( raise UserError(
"The selected template (%s) is not in the same company (%s) " _(
"as the current user (%s).") % ( "The selected template (%s) is not in the same company (%s) "
"as the current user (%s)."
)
% (
self.template_id.name, self.template_id.name,
self.template_id.company_id.display_name, self.template_id.company_id.display_name,
self.company_id.display_name)) self.company_id.display_name,
)
)
tmpl_lines = self.template_id.line_ids tmpl_lines = self.template_id.line_ids
for tmpl_line in tmpl_lines.filtered(lambda l: l.type == 'input'): for tmpl_line in tmpl_lines.filtered(lambda l: l.type == "input"):
vals = self._prepare_wizard_line(tmpl_line) vals = self._prepare_wizard_line(tmpl_line)
amtlro.create(vals) amtlro.create(vals)
self.write({ self.write(
'journal_id': self.template_id.journal_id.id, {
'ref': self.template_id.ref, "journal_id": self.template_id.journal_id.id,
'state': 'set_lines', "ref": self.template_id.ref,
}) "state": "set_lines",
}
)
if not self.line_ids: if not self.line_ids:
return self.generate_move() return self.generate_move()
action = self.env.ref( action = self.env.ref("account_move_template.account_move_template_run_action")
'account_move_template.account_move_template_run_action')
result = action.read()[0] result = action.read()[0]
result.update({ result.update(
'res_id': self.id, {"res_id": self.id, "context": self.env.context,}
'context': self.env.context, )
})
return result return result
# STEP 2 # STEP 2
@ -84,93 +95,100 @@ class AccountMoveTemplateRun(models.TransientModel):
for wizard_line in self.line_ids: for wizard_line in self.line_ids:
sequence2amount[wizard_line.sequence] = wizard_line.amount sequence2amount[wizard_line.sequence] = wizard_line.amount
prec = self.company_id.currency_id.rounding prec = self.company_id.currency_id.rounding
if all([ if all(
[
float_is_zero(x, precision_rounding=prec) float_is_zero(x, precision_rounding=prec)
for x in sequence2amount.values()]): for x in sequence2amount.values()
]
):
raise UserError(_("Debit and credit of all lines are null.")) raise UserError(_("Debit and credit of all lines are null."))
self.template_id.compute_lines(sequence2amount) self.template_id.compute_lines(sequence2amount)
move_vals = self._prepare_move() move_vals = self._prepare_move()
for line in self.template_id.line_ids: for line in self.template_id.line_ids:
amount = sequence2amount[line.sequence] amount = sequence2amount[line.sequence]
if not float_is_zero(amount, precision_rounding=prec): if not float_is_zero(amount, precision_rounding=prec):
move_vals['line_ids'].append( move_vals["line_ids"].append(
(0, 0, self._prepare_move_line(line, amount))) (0, 0, self._prepare_move_line(line, amount))
move = self.env['account.move'].create(move_vals) )
action = self.env.ref('account.action_move_journal_line') move = self.env["account.move"].create(move_vals)
action = self.env.ref("account.action_move_journal_line")
result = action.read()[0] result = action.read()[0]
result.update({ result.update(
'name': _('Entry from template %s') % self.template_id.name, {
'res_id': move.id, "name": _("Entry from template %s") % self.template_id.name,
'views': False, "res_id": move.id,
'view_id': False, "views": False,
'view_mode': 'form,tree,kanban', "view_id": False,
'context': self.env.context, "view_mode": "form,tree,kanban",
}) "context": self.env.context,
}
)
return result return result
def _prepare_move(self): def _prepare_move(self):
move_vals = { move_vals = {
'ref': self.ref, "ref": self.ref,
'journal_id': self.journal_id.id, "journal_id": self.journal_id.id,
'date': self.date, "date": self.date,
'company_id': self.company_id.id, "company_id": self.company_id.id,
'line_ids': [], "line_ids": [],
} }
return move_vals return move_vals
def _prepare_move_line(self, line, amount): def _prepare_move_line(self, line, amount):
date_maturity = False date_maturity = False
if line.payment_term_id: if line.payment_term_id:
pterm_list = line.payment_term_id.compute( pterm_list = line.payment_term_id.compute(value=1, date_ref=self.date)[0]
value=1, date_ref=self.date)[0]
date_maturity = max(l[0] for l in pterm_list) date_maturity = max(l[0] for l in pterm_list)
debit = line.move_line_type == 'dr' debit = line.move_line_type == "dr"
values = { values = {
'name': line.name, "name": line.name,
'analytic_account_id': line.analytic_account_id.id, "analytic_account_id": line.analytic_account_id.id,
'account_id': line.account_id.id, "account_id": line.account_id.id,
'credit': not debit and amount or 0.0, "credit": not debit and amount or 0.0,
'debit': debit and amount or 0.0, "debit": debit and amount or 0.0,
'partner_id': self.partner_id.id or line.partner_id.id, "partner_id": self.partner_id.id or line.partner_id.id,
'tax_line_id': line.tax_line_id.id, "tax_line_id": line.tax_line_id.id,
'date_maturity': date_maturity or self.date, "date_maturity": date_maturity or self.date,
} }
if line.analytic_tag_ids: if line.analytic_tag_ids:
values['analytic_tag_ids'] = [(6, 0, line.analytic_tag_ids.ids)] values["analytic_tag_ids"] = [(6, 0, line.analytic_tag_ids.ids)]
if line.tax_ids: if line.tax_ids:
values['tax_ids'] = [(6, 0, line.tax_ids.ids)] values["tax_ids"] = [(6, 0, line.tax_ids.ids)]
return values return values
class AccountMoveTemplateLineRun(models.TransientModel): class AccountMoveTemplateLineRun(models.TransientModel):
_name = "account.move.template.line.run" _name = "account.move.template.line.run"
_description = 'Wizard Lines to generate move from template' _description = "Wizard Lines to generate move from template"
wizard_id = fields.Many2one( wizard_id = fields.Many2one("account.move.template.run", ondelete="cascade")
'account.move.template.run', ondelete='cascade') company_id = fields.Many2one(related="wizard_id.company_id")
company_id = fields.Many2one(
related='wizard_id.company_id')
company_currency_id = fields.Many2one( company_currency_id = fields.Many2one(
related='wizard_id.company_id.currency_id', string='Company Currency') related="wizard_id.company_id.currency_id", string="Company Currency"
sequence = fields.Integer('Sequence', required=True) )
name = fields.Char('Name', readonly=True) sequence = fields.Integer("Sequence", required=True)
account_id = fields.Many2one( name = fields.Char("Name", readonly=True)
'account.account', required=True, readonly=True) account_id = fields.Many2one("account.account", required=True, readonly=True)
analytic_account_id = fields.Many2one( analytic_account_id = fields.Many2one("account.analytic.account", readonly=True)
'account.analytic.account', readonly=True)
analytic_tag_ids = fields.Many2many( analytic_tag_ids = fields.Many2many(
'account.analytic.tag', string='Analytic Tags', readonly=True) "account.analytic.tag", string="Analytic Tags", readonly=True
tax_ids = fields.Many2many('account.tax', string='Taxes', readonly=True) )
tax_ids = fields.Many2many("account.tax", string="Taxes", readonly=True)
tax_line_id = fields.Many2one( tax_line_id = fields.Many2one(
'account.tax', string='Originator Tax', "account.tax", string="Originator Tax", ondelete="restrict", readonly=True
ondelete='restrict', readonly=True) )
partner_id = fields.Many2one( partner_id = fields.Many2one("res.partner", readonly=True, string="Partner")
'res.partner', readonly=True, string='Partner')
payment_term_id = fields.Many2one( payment_term_id = fields.Many2one(
'account.payment.term', string='Payment Terms', readonly=True) "account.payment.term", string="Payment Terms", readonly=True
)
move_line_type = fields.Selection( move_line_type = fields.Selection(
[('cr', 'Credit'), ('dr', 'Debit')], [("cr", "Credit"), ("dr", "Debit")],
required=True, readonly=True, string='Direction') required=True,
readonly=True,
string="Direction",
)
amount = fields.Monetary( amount = fields.Monetary(
'Amount', required=True, currency_field='company_currency_id') "Amount", required=True, currency_field="company_currency_id"
)
note = fields.Char(readonly=True) note = fields.Char(readonly=True)

View File

@ -1,58 +1,91 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="account_move_template_run_form" model="ir.ui.view"> <record id="account_move_template_run_form" model="ir.ui.view">
<field name="model">account.move.template.run</field> <field name="model">account.move.template.run</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Journal Entry Template" > <form string="Journal Entry Template">
<group name="main"> <group name="main">
<field name="state" invisible="1"/> <field name="state" invisible="1" />
<field name="template_id" widget="selection" <field
name="template_id"
widget="selection"
domain="[('company_id', '=', company_id)]" domain="[('company_id', '=', company_id)]"
attrs="{'readonly': [('state', '=', 'set_lines')]}" /> attrs="{'readonly': [('state', '=', 'set_lines')]}"
<field name="company_id" groups="base.group_multi_company"/> />
<field name="date" states="set_lines"/> <field name="company_id" groups="base.group_multi_company" />
<field name="journal_id" states="set_lines"/> <field name="date" states="set_lines" />
<field name="ref" states="set_lines"/> <field name="journal_id" states="set_lines" />
<field name="partner_id" states="set_lines"/> <field name="ref" states="set_lines" />
<field name="partner_id" states="set_lines" />
</group> </group>
<group name="lines" states="set_lines"> <group name="lines" states="set_lines">
<field name="line_ids" nolabel="1"> <field name="line_ids" nolabel="1">
<tree editable="bottom"> <tree editable="bottom">
<field name="sequence" invisible="1"/> <field name="sequence" invisible="1" />
<field name="name"/> <field name="name" />
<field name="account_id" domain="[('company_id','=',company_id)]"/> <field
<field name="partner_id"/> name="account_id"
<field name="analytic_account_id" domain="[('company_id','=',company_id)]" groups="analytic.group_analytic_accounting"/> domain="[('company_id','=',company_id)]"
<field name="analytic_tag_ids" widget="many2many_tags" groups="analytic.group_analytic_accounting"/> />
<field name="tax_line_id" attrs="{'invisible': [('tax_line_id','=',False)]}"/> <field name="partner_id" />
<field name="tax_ids" widget="many2many_tags" attrs="{'invisible': [('tax_ids','=',[])]}"/> <field
name="analytic_account_id"
domain="[('company_id','=',company_id)]"
groups="analytic.group_analytic_accounting"
/>
<field
name="analytic_tag_ids"
widget="many2many_tags"
groups="analytic.group_analytic_accounting"
/>
<field
name="tax_line_id"
attrs="{'invisible': [('tax_line_id','=',False)]}"
/>
<field
name="tax_ids"
widget="many2many_tags"
attrs="{'invisible': [('tax_ids','=',[])]}"
/>
<field name="move_line_type" /> <field name="move_line_type" />
<field name="amount" /> <field name="amount" />
<field name="note"/> <field name="note" />
<field name="payment_term_id"/> <field name="payment_term_id" />
<field name="company_id" invisible="1"/> <field name="company_id" invisible="1" />
<field name="company_currency_id" invisible="1"/> <field name="company_currency_id" invisible="1" />
</tree> </tree>
</field> </field>
</group> </group>
<footer> <footer>
<button name="load_lines" class="btn-primary" string="Next" type="object" states="select_template" /> <button
<button name="generate_move" class="btn-primary" string="Create Journal Entry" type="object" states="set_lines" /> name="load_lines"
<button special="cancel" string="Cancel" class="btn-default"/> class="btn-primary"
string="Next"
type="object"
states="select_template"
/>
<button
name="generate_move"
class="btn-primary"
string="Create Journal Entry"
type="object"
states="set_lines"
/>
<button special="cancel" string="Cancel" class="btn-default" />
</footer> </footer>
</form> </form>
</field> </field>
</record> </record>
<record id="account_move_template_run_action" model="ir.actions.act_window"> <record id="account_move_template_run_action" model="ir.actions.act_window">
<field name="name">Create Entry from Template</field> <field name="name">Create Entry from Template</field>
<field name="res_model">account.move.template.run</field> <field name="res_model">account.move.template.run</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="account_move_template_run_menu" id="account_move_template_run_menu"
parent="account.menu_finance_entries_accounting_entries" parent="account.menu_finance_entries_accounting_entries"
action="account_move_template_run_action" action="account_move_template_run_action"
sequence="10"/> sequence="10"
/>
</odoo> </odoo>