# Copyright 2015-2019 Akretion France (http://www.akretion.com) # @author Alexis de Lattre # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import api, fields, models import odoo.addons.decimal_precision as dp class AccountInvoiceLine(models.Model): _inherit = "account.invoice.line" standard_price_company_currency = fields.Float( string="Cost Price in Company Currency", readonly=True, digits=dp.get_precision("Product Price"), help="Cost price in company currency in the unit of measure " "of the invoice line (which may be different from the unit " "of measure of the product).", ) standard_price_invoice_currency = fields.Float( string="Cost Price in Invoice Currency", readonly=True, compute="_compute_margin", store=True, digits=dp.get_precision("Product Price"), help="Cost price in invoice currency in the unit of measure " "of the invoice line", ) margin_invoice_currency = fields.Monetary( string="Margin in Invoice Currency", readonly=True, store=True, compute="_compute_margin", currency_field="currency_id", ) margin_company_currency = fields.Monetary( string="Margin in Company Currency", readonly=True, store=True, compute="_compute_margin", currency_field="company_currency_id", ) margin_rate = fields.Float( string="Margin Rate", readonly=True, store=True, compute="_compute_margin", digits=(16, 2), help="Margin rate in percentage of the sale price", ) @api.depends( "standard_price_company_currency", "invoice_id.currency_id", "invoice_id.type", "invoice_id.company_id", "invoice_id.date_invoice", "quantity", "price_subtotal", ) def _compute_margin(self): for il in self: standard_price_inv_cur = 0.0 margin_inv_cur = 0.0 margin_comp_cur = 0.0 margin_rate = 0.0 inv = il.invoice_id if inv and inv.type in ("out_invoice", "out_refund"): # it works in _get_current_rate # even if we set date = False in context # standard_price_inv_cur is in the UoM of the invoice line date = inv._get_currency_rate_date() or fields.Date.context_today(self) company = inv.company_id company_currency = company.currency_id standard_price_inv_cur = company_currency._convert( il.standard_price_company_currency, inv.currency_id, company, date ) margin_inv_cur = ( il.price_subtotal - il.quantity * standard_price_inv_cur ) margin_comp_cur = inv.currency_id._convert( margin_inv_cur, company_currency, company, date ) if il.price_subtotal: margin_rate = 100 * margin_inv_cur / il.price_subtotal # for a refund, margin should be negative # but margin rate should stay positive if inv.type == "out_refund": margin_inv_cur *= -1 margin_comp_cur *= -1 il.standard_price_invoice_currency = standard_price_inv_cur il.margin_invoice_currency = margin_inv_cur il.margin_company_currency = margin_comp_cur il.margin_rate = margin_rate # We want to copy standard_price on invoice line for customer # invoice/refunds. We can't do that via on_change of product_id, # because it is not always played when invoice is created from code # => we inherit write/create # We write standard_price_company_currency even on supplier invoice/refunds # because we don't have access to the 'type' of the invoice @api.model def create(self, vals): if vals.get("product_id"): pp = self.env["product.product"].browse(vals["product_id"]) std_price = pp.standard_price inv_uom_id = vals.get("uom_id") if inv_uom_id and inv_uom_id != pp.uom_id.id: inv_uom = self.env["uom.uom"].browse(inv_uom_id) std_price = pp.uom_id._compute_price(std_price, inv_uom) vals["standard_price_company_currency"] = std_price return super(AccountInvoiceLine, self).create(vals) def write(self, vals): if not vals: vals = {} if "product_id" in vals or "uom_id" in vals: for il in self: if "product_id" in vals: if vals.get("product_id"): pp = self.env["product.product"].browse(vals["product_id"]) else: pp = False else: pp = il.product_id or False # uom_id is NOT a required field if "uom_id" in vals: if vals.get("uom_id"): inv_uom = self.env["uom.uom"].browse(vals["uom_id"]) else: inv_uom = False else: inv_uom = il.uom_id or False std_price = 0.0 if pp: std_price = pp.standard_price if inv_uom and inv_uom != pp.uom_id: std_price = pp.uom_id._compute_price(std_price, inv_uom) il.write({"standard_price_company_currency": std_price}) return super(AccountInvoiceLine, self).write(vals) class AccountInvoice(models.Model): _inherit = "account.invoice" margin_invoice_currency = fields.Monetary( string="Margin in Invoice Currency", compute="_compute_margin", store=True, readonly=True, currency_field="currency_id", ) margin_company_currency = fields.Monetary( string="Margin in Company Currency", compute="_compute_margin", store=True, readonly=True, currency_field="company_currency_id", ) @api.depends( "type", "invoice_line_ids.margin_invoice_currency", "invoice_line_ids.margin_company_currency", ) def _compute_margin(self): res = self.env["account.invoice.line"].read_group( [("invoice_id", "in", self.ids)], ["invoice_id", "margin_invoice_currency", "margin_company_currency"], ["invoice_id"], ) for re in res: if re["invoice_id"]: inv = self.browse(re["invoice_id"][0]) if inv.type in ("out_invoice", "out_refund"): inv.margin_invoice_currency = re["margin_invoice_currency"] inv.margin_company_currency = re["margin_company_currency"]