# Copyright 2016-2020 Onestein () # 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 # Skip create new template when create move on spread lines if self.env.context.get("skip_create_template"): return 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()