174 lines
6.7 KiB
Python
174 lines
6.7 KiB
Python
# Copyright 2016-2020 Onestein (<https://www.onestein.eu>)
|
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
|
|
|
from odoo import _, api, fields, models
|
|
from odoo.exceptions import UserError, ValidationError
|
|
|
|
|
|
class AccountMoveLine(models.Model):
|
|
_inherit = "account.move.line"
|
|
|
|
spread_id = fields.Many2one("account.spread", string="Spread Board", copy=False)
|
|
spread_check = fields.Selection(
|
|
[
|
|
("linked", "Linked"),
|
|
("unlinked", "Unlinked"),
|
|
("unavailable", "Unavailable"),
|
|
],
|
|
compute="_compute_spread_check",
|
|
)
|
|
|
|
@api.depends("spread_id", "move_id.state")
|
|
def _compute_spread_check(self):
|
|
for line in self:
|
|
if line.spread_id:
|
|
line.spread_check = "linked"
|
|
elif line.move_id.state == "draft":
|
|
line.spread_check = "unlinked"
|
|
else:
|
|
line.spread_check = "unavailable"
|
|
|
|
def spread_details(self):
|
|
"""Button on the invoice lines tree view of the invoice
|
|
form to show the spread form view."""
|
|
if not self:
|
|
# In case the widget clicked before the creation of the line
|
|
return
|
|
|
|
if self.spread_id:
|
|
return {
|
|
"name": _("Spread Details"),
|
|
"view_mode": "form",
|
|
"res_model": "account.spread",
|
|
"type": "ir.actions.act_window",
|
|
"target": "current",
|
|
"readonly": False,
|
|
"res_id": self.spread_id.id,
|
|
}
|
|
|
|
# In case no spread board is linked to the invoice line
|
|
# open the wizard to link them
|
|
ctx = dict(
|
|
self.env.context,
|
|
default_invoice_line_id=self.id,
|
|
default_company_id=self.move_id.company_id.id,
|
|
allow_spread_planning=self.move_id.company_id.allow_spread_planning,
|
|
)
|
|
return {
|
|
"name": _("Link Invoice Line with Spread Board"),
|
|
"view_mode": "form",
|
|
"res_model": "account.spread.invoice.line.link.wizard",
|
|
"type": "ir.actions.act_window",
|
|
"target": "new",
|
|
"context": ctx,
|
|
}
|
|
|
|
@api.constrains("spread_id", "account_id")
|
|
def _check_spread_account_balance_sheet(self):
|
|
for line in self:
|
|
if not line.spread_id:
|
|
pass
|
|
elif line.move_id.move_type in ("out_invoice", "in_refund"):
|
|
if line.account_id != line.spread_id.debit_account_id:
|
|
raise ValidationError(
|
|
_(
|
|
"The account of the invoice line does not correspond "
|
|
"to the Balance Sheet (debit account) of the spread"
|
|
)
|
|
)
|
|
elif line.move_id.move_type in ("in_invoice", "out_refund"):
|
|
if line.account_id != line.spread_id.credit_account_id:
|
|
raise ValidationError(
|
|
_(
|
|
"The account of the invoice line does not correspond "
|
|
"to the Balance Sheet (credit account) of the spread"
|
|
)
|
|
)
|
|
|
|
def write(self, vals):
|
|
if vals.get("spread_id"):
|
|
spread = self.env["account.spread"].browse(vals.get("spread_id"))
|
|
if spread.invoice_type in ["out_invoice", "in_refund"]:
|
|
vals["account_id"] = spread.debit_account_id.id
|
|
else:
|
|
vals["account_id"] = spread.credit_account_id.id
|
|
return super().write(vals)
|
|
|
|
def _check_spread_reconcile_validity(self):
|
|
# Improve error messages of standard Odoo
|
|
reconciled_lines = self.filtered(lambda l: l.reconciled)
|
|
msg_line = _(
|
|
"Move line: %(line_id)s (%(line_name)s), account code: %(account_code)s\n"
|
|
)
|
|
if reconciled_lines:
|
|
msg = _("Cannot reconcile entries that are already reconciled:\n")
|
|
for line in reconciled_lines:
|
|
msg += msg_line % {
|
|
"line_id": line.id,
|
|
"line_name": line.name,
|
|
"account_code": line.account_id.code,
|
|
}
|
|
raise ValidationError(msg)
|
|
if len(self.mapped("account_id").ids) > 1:
|
|
msg = _("Some entries are not from the same account:\n")
|
|
for line in self:
|
|
msg += msg_line % {
|
|
"line_id": line.id,
|
|
"line_name": line.name,
|
|
"account_code": line.account_id.code,
|
|
}
|
|
raise ValidationError(msg)
|
|
|
|
def create_auto_spread(self):
|
|
"""Create auto spread table for each invoice line, when needed"""
|
|
|
|
def _filter_line(aline, iline):
|
|
"""Find matching template auto line with invoice line"""
|
|
if aline.product_id and iline.product_id != aline.product_id:
|
|
return False
|
|
if aline.account_id and iline.account_id != aline.account_id:
|
|
return False
|
|
if (
|
|
aline.analytic_distribution
|
|
and iline.analytic_distribution != aline.analytic_distribution
|
|
):
|
|
return False
|
|
return True
|
|
|
|
for line in self:
|
|
if line.spread_check == "linked":
|
|
continue
|
|
spread_type = (
|
|
"sale"
|
|
if line.move_id.move_type in ["out_invoice", "out_refund"]
|
|
else "purchase"
|
|
)
|
|
spread_auto = self.env["account.spread.template.auto"].search(
|
|
[
|
|
("template_id.auto_spread", "=", True),
|
|
("template_id.spread_type", "=", spread_type),
|
|
]
|
|
)
|
|
matched = spread_auto.filtered(lambda a, i=line: _filter_line(a, i))
|
|
template = matched.mapped("template_id")
|
|
if not template:
|
|
continue
|
|
elif len(template) > 1:
|
|
raise UserError(
|
|
_(
|
|
"Too many auto spread templates (%(len_template)s) matched with the "
|
|
"invoice line, %(line_name)s"
|
|
)
|
|
% {"len_template": len(template), "line_name": line.display_name}
|
|
)
|
|
# Found auto spread template for this invoice line, create it
|
|
wizard = self.env["account.spread.invoice.line.link.wizard"].new(
|
|
{
|
|
"invoice_line_id": line.id,
|
|
"company_id": line.company_id.id,
|
|
"spread_action_type": "template",
|
|
"template_id": template.id,
|
|
}
|
|
)
|
|
wizard.confirm()
|