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
{
'name': "Account Move Template",
'version': '12.0.1.0.0',
'category': 'Accounting',
'summary': "Templates for recurring Journal Entries",
'author': "Agile Business Group, Aurium Technologies, Vauxoo, Eficent, "
"Akretion, Odoo Community Association (OCA)",
'website': 'https://github.com/OCA/account-financial-tools',
'license': 'AGPL-3',
'depends': [
'account',
"name": "Account Move Template",
"version": "12.0.1.0.0",
"category": "Accounting",
"summary": "Templates for recurring Journal Entries",
"author": "Agile Business Group, Aurium Technologies, Vauxoo, Eficent, "
"Akretion, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/account-financial-tools",
"license": "AGPL-3",
"depends": ["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': [
'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,
"installable": True,
}

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
# Copyright 2015-2019 See manifest
# 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.tools import float_is_zero
@ -10,71 +10,82 @@ class AccountMoveTemplateRun(models.TransientModel):
_name = "account.move.template.run"
_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(
'res.company', required=True, readonly=True,
default=lambda self: self.env['res.company']._company_default_get())
"res.company",
required=True,
readonly=True,
default=lambda self: self.env["res.company"]._company_default_get(),
)
partner_id = fields.Many2one(
'res.partner', 'Override Partner',
domain=['|', ('parent_id', '=', False), ('is_company', '=', True)])
"res.partner",
"Override Partner",
domain=["|", ("parent_id", "=", False), ("is_company", "=", True)],
)
date = fields.Date(required=True, default=fields.Date.context_today)
journal_id = fields.Many2one(
'account.journal', string='Journal', readonly=True)
ref = fields.Char(string='Reference')
journal_id = fields.Many2one("account.journal", string="Journal", readonly=True)
ref = fields.Char(string="Reference")
line_ids = fields.One2many(
'account.move.template.line.run', 'wizard_id', string="Lines")
state = fields.Selection([
('select_template', 'Select Template'),
('set_lines', 'Set Lines'),
], readonly=True, default='select_template')
"account.move.template.line.run", "wizard_id", string="Lines"
)
state = fields.Selection(
[("select_template", "Select Template"), ("set_lines", "Set Lines"),],
readonly=True,
default="select_template",
)
def _prepare_wizard_line(self, tmpl_line):
vals = {
'wizard_id': self.id,
'sequence': tmpl_line.sequence,
'name': tmpl_line.name,
'amount': 0.0,
'account_id': tmpl_line.account_id.id,
'partner_id': tmpl_line.partner_id.id or False,
'move_line_type': tmpl_line.move_line_type,
'tax_ids': [(6, 0, tmpl_line.tax_ids.ids)],
'tax_line_id': tmpl_line.tax_line_id.id,
'analytic_account_id': tmpl_line.analytic_account_id.id,
'analytic_tag_ids': [(6, 0, tmpl_line.analytic_tag_ids.ids)],
'note': tmpl_line.note,
'payment_term_id': tmpl_line.payment_term_id.id or False,
}
"wizard_id": self.id,
"sequence": tmpl_line.sequence,
"name": tmpl_line.name,
"amount": 0.0,
"account_id": tmpl_line.account_id.id,
"partner_id": tmpl_line.partner_id.id or False,
"move_line_type": tmpl_line.move_line_type,
"tax_ids": [(6, 0, tmpl_line.tax_ids.ids)],
"tax_line_id": tmpl_line.tax_line_id.id,
"analytic_account_id": tmpl_line.analytic_account_id.id,
"analytic_tag_ids": [(6, 0, tmpl_line.analytic_tag_ids.ids)],
"note": tmpl_line.note,
"payment_term_id": tmpl_line.payment_term_id.id or False,
}
return vals
# STEP 1
def load_lines(self):
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:
raise UserError(_(
"The selected template (%s) is not in the same company (%s) "
"as the current user (%s).") % (
raise UserError(
_(
"The selected template (%s) is not in the same company (%s) "
"as the current user (%s)."
)
% (
self.template_id.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
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)
amtlro.create(vals)
self.write({
'journal_id': self.template_id.journal_id.id,
'ref': self.template_id.ref,
'state': 'set_lines',
})
self.write(
{
"journal_id": self.template_id.journal_id.id,
"ref": self.template_id.ref,
"state": "set_lines",
}
)
if not self.line_ids:
return self.generate_move()
action = self.env.ref(
'account_move_template.account_move_template_run_action')
action = self.env.ref("account_move_template.account_move_template_run_action")
result = action.read()[0]
result.update({
'res_id': self.id,
'context': self.env.context,
})
result.update(
{"res_id": self.id, "context": self.env.context,}
)
return result
# STEP 2
@ -84,93 +95,100 @@ class AccountMoveTemplateRun(models.TransientModel):
for wizard_line in self.line_ids:
sequence2amount[wizard_line.sequence] = wizard_line.amount
prec = self.company_id.currency_id.rounding
if all([
if all(
[
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."))
self.template_id.compute_lines(sequence2amount)
move_vals = self._prepare_move()
for line in self.template_id.line_ids:
amount = sequence2amount[line.sequence]
if not float_is_zero(amount, precision_rounding=prec):
move_vals['line_ids'].append(
(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_vals["line_ids"].append(
(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")
result = action.read()[0]
result.update({
'name': _('Entry from template %s') % self.template_id.name,
'res_id': move.id,
'views': False,
'view_id': False,
'view_mode': 'form,tree,kanban',
'context': self.env.context,
})
result.update(
{
"name": _("Entry from template %s") % self.template_id.name,
"res_id": move.id,
"views": False,
"view_id": False,
"view_mode": "form,tree,kanban",
"context": self.env.context,
}
)
return result
def _prepare_move(self):
move_vals = {
'ref': self.ref,
'journal_id': self.journal_id.id,
'date': self.date,
'company_id': self.company_id.id,
'line_ids': [],
"ref": self.ref,
"journal_id": self.journal_id.id,
"date": self.date,
"company_id": self.company_id.id,
"line_ids": [],
}
return move_vals
def _prepare_move_line(self, line, amount):
date_maturity = False
if line.payment_term_id:
pterm_list = line.payment_term_id.compute(
value=1, date_ref=self.date)[0]
pterm_list = line.payment_term_id.compute(value=1, date_ref=self.date)[0]
date_maturity = max(l[0] for l in pterm_list)
debit = line.move_line_type == 'dr'
debit = line.move_line_type == "dr"
values = {
'name': line.name,
'analytic_account_id': line.analytic_account_id.id,
'account_id': line.account_id.id,
'credit': not debit and amount or 0.0,
'debit': debit and amount or 0.0,
'partner_id': self.partner_id.id or line.partner_id.id,
'tax_line_id': line.tax_line_id.id,
'date_maturity': date_maturity or self.date,
"name": line.name,
"analytic_account_id": line.analytic_account_id.id,
"account_id": line.account_id.id,
"credit": not debit and amount or 0.0,
"debit": debit and amount or 0.0,
"partner_id": self.partner_id.id or line.partner_id.id,
"tax_line_id": line.tax_line_id.id,
"date_maturity": date_maturity or self.date,
}
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:
values['tax_ids'] = [(6, 0, line.tax_ids.ids)]
values["tax_ids"] = [(6, 0, line.tax_ids.ids)]
return values
class AccountMoveTemplateLineRun(models.TransientModel):
_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(
'account.move.template.run', ondelete='cascade')
company_id = fields.Many2one(
related='wizard_id.company_id')
wizard_id = fields.Many2one("account.move.template.run", ondelete="cascade")
company_id = fields.Many2one(related="wizard_id.company_id")
company_currency_id = fields.Many2one(
related='wizard_id.company_id.currency_id', string='Company Currency')
sequence = fields.Integer('Sequence', required=True)
name = fields.Char('Name', readonly=True)
account_id = fields.Many2one(
'account.account', required=True, readonly=True)
analytic_account_id = fields.Many2one(
'account.analytic.account', readonly=True)
related="wizard_id.company_id.currency_id", string="Company Currency"
)
sequence = fields.Integer("Sequence", required=True)
name = fields.Char("Name", readonly=True)
account_id = fields.Many2one("account.account", required=True, readonly=True)
analytic_account_id = fields.Many2one("account.analytic.account", readonly=True)
analytic_tag_ids = fields.Many2many(
'account.analytic.tag', string='Analytic Tags', readonly=True)
tax_ids = fields.Many2many('account.tax', string='Taxes', readonly=True)
"account.analytic.tag", string="Analytic Tags", readonly=True
)
tax_ids = fields.Many2many("account.tax", string="Taxes", readonly=True)
tax_line_id = fields.Many2one(
'account.tax', string='Originator Tax',
ondelete='restrict', readonly=True)
partner_id = fields.Many2one(
'res.partner', readonly=True, string='Partner')
"account.tax", string="Originator Tax", ondelete="restrict", readonly=True
)
partner_id = fields.Many2one("res.partner", readonly=True, string="Partner")
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(
[('cr', 'Credit'), ('dr', 'Debit')],
required=True, readonly=True, string='Direction')
[("cr", "Credit"), ("dr", "Debit")],
required=True,
readonly=True,
string="Direction",
)
amount = fields.Monetary(
'Amount', required=True, currency_field='company_currency_id')
"Amount", required=True, currency_field="company_currency_id"
)
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>
<record id="account_move_template_run_form" model="ir.ui.view">
<field name="model">account.move.template.run</field>
<field name="arch" type="xml">
<form string="Journal Entry Template" >
<form string="Journal Entry Template">
<group name="main">
<field name="state" invisible="1"/>
<field name="template_id" widget="selection"
<field name="state" invisible="1" />
<field
name="template_id"
widget="selection"
domain="[('company_id', '=', company_id)]"
attrs="{'readonly': [('state', '=', 'set_lines')]}" />
<field name="company_id" groups="base.group_multi_company"/>
<field name="date" states="set_lines"/>
<field name="journal_id" states="set_lines"/>
<field name="ref" states="set_lines"/>
<field name="partner_id" states="set_lines"/>
attrs="{'readonly': [('state', '=', 'set_lines')]}"
/>
<field name="company_id" groups="base.group_multi_company" />
<field name="date" states="set_lines" />
<field name="journal_id" states="set_lines" />
<field name="ref" states="set_lines" />
<field name="partner_id" states="set_lines" />
</group>
<group name="lines" states="set_lines">
<field name="line_ids" nolabel="1">
<tree editable="bottom">
<field name="sequence" invisible="1"/>
<field name="name"/>
<field name="account_id" domain="[('company_id','=',company_id)]"/>
<field name="partner_id"/>
<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="sequence" invisible="1" />
<field name="name" />
<field
name="account_id"
domain="[('company_id','=',company_id)]"
/>
<field name="partner_id" />
<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="amount" />
<field name="note"/>
<field name="payment_term_id"/>
<field name="company_id" invisible="1"/>
<field name="company_currency_id" invisible="1"/>
<field name="note" />
<field name="payment_term_id" />
<field name="company_id" invisible="1" />
<field name="company_currency_id" invisible="1" />
</tree>
</field>
</group>
<footer>
<button name="load_lines" 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"/>
<button
name="load_lines"
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>
</form>
</field>
</record>
<record id="account_move_template_run_action" model="ir.actions.act_window">
<field name="name">Create Entry from Template</field>
<field name="res_model">account.move.template.run</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<menuitem id="account_move_template_run_menu"
parent="account.menu_finance_entries_accounting_entries"
action="account_move_template_run_action"
sequence="10"/>
<menuitem
id="account_move_template_run_menu"
parent="account.menu_finance_entries_accounting_entries"
action="account_move_template_run_action"
sequence="10"
/>
</odoo>