Initial commit: Odoo 18.0-20251222 extra-addons
This commit is contained in:
1
account_move_template/models/__init__.py
Executable file
1
account_move_template/models/__init__.py
Executable file
@@ -0,0 +1 @@
|
||||
from . import account_move_template
|
||||
230
account_move_template/models/account_move_template.py
Executable file
230
account_move_template/models/account_move_template.py
Executable file
@@ -0,0 +1,230 @@
|
||||
# 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.exceptions import UserError, ValidationError
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
|
||||
class AccountMoveTemplate(models.Model):
|
||||
_name = "account.move.template"
|
||||
_description = "Journal Entry Template"
|
||||
_check_company_auto = True
|
||||
|
||||
name = fields.Char(required=True)
|
||||
company_id = fields.Many2one(
|
||||
"res.company",
|
||||
string="Company",
|
||||
required=True,
|
||||
ondelete="cascade",
|
||||
default=lambda self: self.env.company,
|
||||
)
|
||||
journal_id = fields.Many2one(
|
||||
"account.journal",
|
||||
string="Journal",
|
||||
required=True,
|
||||
check_company=True,
|
||||
domain="[('company_id', '=', company_id)]",
|
||||
)
|
||||
ref = fields.Char(string="Reference", copy=False)
|
||||
line_ids = fields.One2many(
|
||||
"account.move.template.line", inverse_name="template_id", string="Lines"
|
||||
)
|
||||
active = fields.Boolean(default=True)
|
||||
|
||||
_sql_constraints = [
|
||||
(
|
||||
"name_company_unique",
|
||||
"unique(name, company_id)",
|
||||
"This name is already used by another template!",
|
||||
)
|
||||
]
|
||||
|
||||
def copy(self, default=None):
|
||||
self.ensure_one()
|
||||
default = dict(default or {}, name=_("%s (copy)") % self.name)
|
||||
return super().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
|
||||
try:
|
||||
val = safe_eval(line.python_code, safe_eval_dict)
|
||||
sequence2amount[line.sequence] = val
|
||||
except ValueError as err:
|
||||
raise UserError(
|
||||
_(
|
||||
"Impossible to compute the formula of line with sequence "
|
||||
"%(sequence)s (formula: %(code)s). Check that the lines used in "
|
||||
"the formula really exists and have a lower sequence than "
|
||||
"the current line.",
|
||||
sequence=line.sequence,
|
||||
code=line.python_code,
|
||||
)
|
||||
) from err
|
||||
except SyntaxError as err:
|
||||
raise UserError(
|
||||
_(
|
||||
"Impossible to compute the formula of line with sequence "
|
||||
"%(sequence)s (formula: %(code)s): the syntax of the formula "
|
||||
"is wrong.",
|
||||
sequence=line.sequence,
|
||||
code=line.python_code,
|
||||
)
|
||||
) from err
|
||||
|
||||
def compute_lines(self, sequence2amount):
|
||||
company_cur = self.company_id.currency_id
|
||||
input_sequence2amount = sequence2amount.copy()
|
||||
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."
|
||||
)
|
||||
)
|
||||
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"):
|
||||
self.eval_computed_line(line, sequence2amount)
|
||||
sequence2amount[line.sequence] = company_cur.round(
|
||||
sequence2amount[line.sequence]
|
||||
)
|
||||
return sequence2amount
|
||||
|
||||
def generate_journal_entry(self):
|
||||
"""Called by the button on the form view"""
|
||||
self.ensure_one()
|
||||
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"
|
||||
_inherit = "analytic.mixin"
|
||||
_check_company_auto = True
|
||||
|
||||
template_id = fields.Many2one(
|
||||
"account.move.template", string="Move Template", ondelete="cascade"
|
||||
)
|
||||
name = fields.Char(string="Label")
|
||||
sequence = fields.Integer(required=True)
|
||||
account_id = fields.Many2one(
|
||||
"account.account",
|
||||
string="Account",
|
||||
required=True,
|
||||
domain="[('company_ids', 'in', company_id), ('deprecated', '=', False)]",
|
||||
check_company=True,
|
||||
)
|
||||
partner_id = fields.Many2one(
|
||||
"res.partner",
|
||||
string="Partner",
|
||||
domain=["|", ("parent_id", "=", False), ("is_company", "=", True)],
|
||||
)
|
||||
tax_ids = fields.Many2many("account.tax", string="Taxes", check_company=True)
|
||||
tax_line_id = fields.Many2one(
|
||||
"account.tax", string="Originator Tax", ondelete="restrict", check_company=True
|
||||
)
|
||||
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,
|
||||
)
|
||||
note = fields.Char()
|
||||
type = fields.Selection(
|
||||
[
|
||||
("input", "User input"),
|
||||
("computed", "Computed"),
|
||||
],
|
||||
required=True,
|
||||
default="input",
|
||||
)
|
||||
python_code = fields.Text(string="Formula")
|
||||
move_line_type = fields.Selection(
|
||||
[("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.",
|
||||
check_company=True,
|
||||
)
|
||||
is_refund = fields.Boolean(
|
||||
default=False,
|
||||
string="Is a refund?",
|
||||
)
|
||||
tax_repartition_line_id = fields.Many2one(
|
||||
"account.tax.repartition.line",
|
||||
string="Tax Repartition Line",
|
||||
compute="_compute_tax_repartition_line_id",
|
||||
store=True,
|
||||
)
|
||||
opt_account_id = fields.Many2one(
|
||||
"account.account",
|
||||
string="Account if Negative",
|
||||
domain="[('company_ids', 'in', company_id), ('deprecated', '=', False)]",
|
||||
check_company=True,
|
||||
help="When amount is negative, use this account instead",
|
||||
)
|
||||
|
||||
@api.depends("is_refund", "account_id", "tax_line_id")
|
||||
def _compute_tax_repartition_line_id(self):
|
||||
for record in self.filtered(lambda x: x.account_id and x.tax_line_id):
|
||||
tax_repartition = "tax_id"
|
||||
record.tax_repartition_line_id = self.env[
|
||||
"account.tax.repartition.line"
|
||||
].search(
|
||||
[
|
||||
("account_id", "=", record.account_id.id),
|
||||
(tax_repartition, "=", record.tax_line_id.id),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
|
||||
@api.depends("account_id", "partner_id")
|
||||
def _compute_analytic_distribution(self):
|
||||
for line in self:
|
||||
distribution = self.env[
|
||||
"account.analytic.distribution.model"
|
||||
]._get_distribution(
|
||||
{
|
||||
"partner_id": line.partner_id.id,
|
||||
"partner_category_id": line.partner_id.category_id.ids,
|
||||
"product_id": False,
|
||||
"product_categ_id": False,
|
||||
"account_prefix": line.account_id.code,
|
||||
"company_id": line.template_id.company_id.id,
|
||||
}
|
||||
)
|
||||
line.analytic_distribution = distribution or line.analytic_distribution
|
||||
|
||||
_sql_constraints = [
|
||||
(
|
||||
"sequence_template_uniq",
|
||||
"unique(template_id, sequence)",
|
||||
"The sequence of the line must be unique per template!",
|
||||
)
|
||||
]
|
||||
|
||||
@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
|
||||
)
|
||||
Reference in New Issue
Block a user