[IMP] stock_account: remove the wizard which change the `standard_price`

Overwrite the method ``write`` of the model ``product.product``.

When we write on ``standard_price``, if
- the context key ``disable_auto_svl`` is not set
- the ``cost_method`` is not "fifo"
We automatically compute ``stock.valuation.layer``

(before we needed to manually call ``_change_standard_price``)

Task #2031422

closes odoo/odoo#41265

Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
This commit is contained in:
Debauche Stéphane
2019-12-06 10:58:03 +00:00
parent d6458e68df
commit 42d3a82a80
20 changed files with 69 additions and 225 deletions
+5 -15
View File
@@ -27,28 +27,18 @@ class ProductProduct(models.Model):
def button_bom_cost(self):
self.ensure_one()
price = self._get_price_from_bom()
if self.valuation == 'real_time':
action_rec = self.env.ref('stock_account.action_view_change_standard_price')
action = action_rec.read([])[0]
action['context'] = {'default_new_price': price}
return action
else:
self.standard_price = price
self._set_price_from_bom()
def action_bom_cost(self):
real_time_products = self.filtered(lambda p: p.valuation == 'real_time')
if real_time_products:
raise UserError(_('The inventory valuation of some products %s is automated. You can only update their cost from the product form.') % (real_time_products.mapped('display_name')))
boms_to_recompute = self.env['mrp.bom'].search(['|', ('product_id', 'in', self.ids), '&', ('product_id', '=', False), ('product_tmpl_id', 'in', self.mapped('product_tmpl_id').ids)])
for product in self:
product.standard_price = product._get_price_from_bom(boms_to_recompute)
product._set_price_from_bom(boms_to_recompute)
def _get_price_from_bom(self, boms_to_recompute=False):
def _set_price_from_bom(self, boms_to_recompute=False):
self.ensure_one()
bom = self.env['mrp.bom']._bom_find(product=self)
return self._compute_bom_price(bom, boms_to_recompute=boms_to_recompute)
if bom:
self.standard_price = self._compute_bom_price(bom, boms_to_recompute=boms_to_recompute)
def _compute_bom_price(self, bom, boms_to_recompute=False):
self.ensure_one()
@@ -182,9 +182,3 @@ class TestBom(common.TransactionCase):
self.Product.browse([self.dining_table.id, self.table_head.id]).action_bom_cost()
# Total cost of Dining Table = (718.75) + Total cost of all operations (125 + 10.42) = 854.17
self.assertEqual(float_compare(self.dining_table.standard_price, 854.17, precision_digits=2), 0, "After computing price from BoM price should be 786.46")
def test_01_compute_price_inventory_valuation(self):
"""Test update cost from bom in list view when inventory valuation is real time."""
self.glass.categ_id.property_valuation = 'real_time'
with self.assertRaises(UserError):
self.dining_table.with_context(button=False).action_bom_cost()
+19 -9
View File
@@ -7,7 +7,9 @@
<field name="inherit_id" ref="product.product_template_only_form_view" />
<field name="groups_id" eval="[(4, ref('mrp.group_mrp_user'))]"/>
<field name="arch" type="xml">
<xpath expr="//span[@name='update_cost_price']" position="inside">
<xpath expr="//div[@name='standard_price_uom']" position="inside">
<field name="cost_method" invisible="1"/>
<field name="valuation" invisible="1"/>
<button name="button_bom_cost"
string="Compute Price from BoM" type="object"
attrs="{'invisible': ['|', ('bom_count', '=', 0), '&amp;', ('valuation', '=', 'real_time'), ('cost_method', '=', 'fifo')]}"
@@ -24,7 +26,9 @@
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="groups_id" eval="[(4, ref('mrp.group_mrp_user'))]"/>
<field name="arch" type="xml">
<xpath expr="//span[@name='update_cost_price']" position="inside">
<xpath expr="//div[@name='standard_price_uom']" position="inside">
<field name="cost_method" invisible="1"/>
<field name="valuation" invisible="1"/>
<button name="button_bom_cost"
string="Compute Price from BoM" type="object"
attrs="{'invisible': ['|', ('bom_count', '=', 0), '&amp;', ('valuation', '=', 'real_time'), ('cost_method', '=', 'fifo')]}"
@@ -41,14 +45,20 @@
<field name="inherit_id" ref="product.product_variant_easy_edit_view"/>
<field name="arch" type="xml">
<data>
<xpath expr="//div[@name='update_cost_price']" position="inside">
<xpath expr="//field[@name='standard_price']" position="replace">
<field name="bom_count" invisible="1"/>
<button name="button_bom_cost"
string="Compute Price from BoM"
type="object"
attrs="{'invisible': ['|', ('bom_count', '=', 0), '&amp;', ('valuation', '=', 'real_time'), ('cost_method', '=', 'fifo')]}"
help="Compute the price of the product using products and operations of related bill of materials, for manufactured products only."
class="oe_link oe_read_only pt-0"/>
<field name="cost_method" invisible="1"/>
<field name="valuation" invisible="1"/>
<label for="standard_price"/>
<div>
<field name="standard_price" widget='monetary' options="{'currency_field': 'cost_currency_id'}"/>
<button name="button_bom_cost"
string="Compute Price from BoM"
type="object"
attrs="{'invisible': ['|', ('bom_count', '=', 0), '&amp;', ('valuation', '=', 'real_time'), ('cost_method', '=', 'fifo')]}"
help="Compute the price of the product using products and operations of related bill of materials, for manufactured products only."
class="oe_link oe_read_only pt-0"/>
</div>
</xpath>
</data>
</field>
+1 -1
View File
@@ -305,7 +305,7 @@
<field name="product_template_attribute_value_ids" widget="many2many_tags" groups="product.group_product_variant" readonly="1"/>
<field name="company_id" groups="base.group_multi_company" optional="hide" readonly="1"/>
<field name="lst_price" optional="show" string="Sales Price"/>
<field name="standard_price" optional="show" readonly="1"/>
<field name="standard_price" optional="show"/>
<field name="categ_id" optional="hide"/>
<field name="type" optional="hide" readonly="1"/>
<field name="price" invisible="not context.get('pricelist',False)"/>
@@ -40,7 +40,7 @@
<separator string="Purchases" colspan="4"/>
<field name="purchase_avg_price" string="Avg. Unit Price"/>
<field name="standard_price" string="Standard Price" readonly="1"/>
<field name="standard_price" string="Standard Price"/>
<field name="purchase_num_invoiced" />
<field name="purchase_gap" />
<field name="total_cost" />
@@ -39,9 +39,7 @@ class TestSaleMrpProcurement(TransactionCase):
product.route_ids.add(warehouse0.mto_pull_id.route_id)
product_template_slidermobile0 = product.save()
std_price_wiz = Form(self.env['stock.change.standard.price'].with_context(active_id=product_template_slidermobile0.id, active_model='product.template'))
std_price_wiz.new_price = 189
std_price_wiz.save()
product_template_slidermobile0.standard_price = 189
product_component = Form(self.env['product.product'])
product_component.name = 'Battery'
@@ -155,7 +155,7 @@ class TestAngloSaxonValuation(SavepointCase):
"""
self.product.categ_id.property_cost_method = 'standard'
self.product.invoice_policy = 'order'
self.product._change_standard_price(10.0, counterpart_account_id=self.counterpart_account.id)
self.product.standard_price = 10.0
# Put two items in stock.
self._inv_adj_two_units()
@@ -164,7 +164,7 @@ class TestAngloSaxonValuation(SavepointCase):
sale_order = self._so_and_confirm_two_units()
# standard price to 14
self.product._change_standard_price(14.0, counterpart_account_id=self.counterpart_account.id)
self.product.standard_price = 14.0
# Invoice the sale order.
invoice = sale_order._create_invoices()
@@ -192,7 +192,7 @@ class TestAngloSaxonValuation(SavepointCase):
The amounts used in Stock OUT and COGS should be 10 then 14."""
self.product.categ_id.property_cost_method = 'standard'
self.product.invoice_policy = 'order'
self.product._change_standard_price(10.0, counterpart_account_id=self.counterpart_account.id)
self.product.standard_price = 10.0
# Put two items in stock.
sale_order = self._so_and_confirm_two_units()
@@ -231,14 +231,14 @@ class TestAngloSaxonValuation(SavepointCase):
self.assertEqual(income_aml.credit, 12)
# change the standard price to 14
self.product._change_standard_price(14.0, counterpart_account_id=self.counterpart_account.id)
self.product.standard_price = 14.0
# deliver the backorder
sale_order.picking_ids[0].move_lines.quantity_done = 1
sale_order.picking_ids[0].button_validate()
# change the standard price to 16
self.product._change_standard_price(16.0, counterpart_account_id=self.counterpart_account.id)
self.product.standard_price = 16.0
# invoice 1
invoice2 = sale_order._create_invoices()
@@ -279,7 +279,7 @@ class TestAngloSaxonValuation(SavepointCase):
wiz.process()
# change the standard price to 14
self.product._change_standard_price(14.0, counterpart_account_id=self.counterpart_account.id)
self.product.standard_price = 14.0
# deliver the backorder
sale_order.picking_ids.filtered('backorder_id').move_lines.quantity_done = 1
@@ -370,14 +370,14 @@ class TestAngloSaxonValuation(SavepointCase):
self.assertEqual(income_aml.credit, 12)
# change the standard price to 14
self.product._change_standard_price(14.0, counterpart_account_id=self.counterpart_account.id)
self.product.standard_price = 14.0
# deliver the backorder
sale_order.picking_ids[0].move_lines.quantity_done = 1
sale_order.picking_ids[0].button_validate()
# change the standard price to 16
self.product._change_standard_price(16.0, counterpart_account_id=self.counterpart_account.id)
self.product.standard_price = 16.0
# invoice 1
invoice2 = sale_order._create_invoices()
@@ -418,7 +418,7 @@ class TestAngloSaxonValuation(SavepointCase):
wiz.process()
# change the standard price to 14
self.product._change_standard_price(14.0, counterpart_account_id=self.counterpart_account.id)
self.product.standard_price = 14.0
# deliver the backorder
sale_order.picking_ids.filtered('backorder_id').move_lines.quantity_done = 1
-1
View File
@@ -25,7 +25,6 @@ Dashboard / Reports for Warehouse Management includes:
'data': [
'security/stock_account_security.xml',
'security/ir.model.access.csv',
'wizard/stock_change_standard_price_views.xml',
'data/stock_account_data.xml',
'views/stock_account_views.xml',
'views/res_config_settings_views.xml',
+18 -5
View File
@@ -95,6 +95,16 @@ class ProductProduct(models.Model):
value_svl = fields.Float(compute='_compute_value_svl')
quantity_svl = fields.Float(compute='_compute_value_svl')
stock_valuation_layer_ids = fields.One2many('stock.valuation.layer', 'product_id')
valuation = fields.Selection(related="categ_id.property_valuation", readonly=True)
def write(self, vals):
if 'standard_price' in vals and not self.env.context.get('disable_auto_svl'):
for product_product in self:
if product_product.cost_method != 'fifo':
counterpart_account_id = product_product.property_account_expense_id.id or product_product.categ_id.property_account_expense_categ_id.id
product_product._change_standard_price(vals['standard_price'], counterpart_account_id)
return super(ProductProduct, self).write(vals)
@api.depends('stock_valuation_layer_ids')
@api.depends_context('to_date', 'company')
@@ -172,6 +182,10 @@ class ProductProduct(models.Model):
:param new_price: new standard price
"""
# Handle stock valuation layers.
if self.valuation == 'real_time' and not self.env['account.move'].check_access_rights('create', raise_exception=False):
raise UserError(_("You cannot update the cost of a product in automated valuation as it leads to the creation of a journal entry, for which you don't have the access rights."))
svl_vals_list = []
company_id = self.env.company
for product in self:
@@ -223,6 +237,7 @@ class ProductProduct(models.Model):
'company_id': company_id.id,
'ref': product.default_code,
'stock_valuation_layer_ids': [(6, None, [stock_valuation_layer.id])],
'type': 'entry',
'line_ids': [(0, 0, {
'name': _('%s changed cost from %s to %s - %s') % (self.env.user.name, product.standard_price, new_price, product.display_name),
'account_id': debit_account_id,
@@ -238,11 +253,9 @@ class ProductProduct(models.Model):
})],
}
am_vals_list.append(move_vals)
account_moves = self.env['account.move'].create(am_vals_list)
account_moves.post()
# Actually update the standard price.
self.with_company(company_id).sudo().write({'standard_price': new_price})
account_moves = self.env['account.move'].sudo().create(am_vals_list)
account_moves.post()
def _run_fifo(self, quantity, company):
self.ensure_one()
@@ -279,7 +292,7 @@ class ProductProduct(models.Model):
# Update the standard price with the price of the last used candidate, if any.
if new_standard_price and self.cost_method == 'fifo':
self.sudo().with_company(company.id).standard_price = new_standard_price
self.sudo().with_company(company.id).with_context(disable_auto_svl=True).standard_price = new_standard_price
# If there's still quantity to value but we're out of candidates, we fall in the
# negative stock use case. We chose to value the out move at the price of the
+1 -1
View File
@@ -325,7 +325,7 @@ class StockMove(models.Model):
tmpl_dict[move.product_id.id] += qty_done
# Write the standard price, as SUPERUSER_ID because a warehouse manager may not have the right to write on products
move.product_id.with_company(move.company_id.id).sudo().write({'standard_price': new_std_price})
move.product_id.with_company(move.company_id.id).with_context(disable_auto_svl=True).sudo().write({'standard_price': new_std_price})
std_price_update[move.company_id.id, move.product_id.id] = new_std_price
def _get_accounting_data_for_valuation(self):
@@ -108,7 +108,7 @@ class TestStockValuation(SavepointCase):
price change updates the stock value based on current stock level.
"""
# Enter 10 products while price is 5.0
self.product1._change_standard_price(5.0, self.expense_account.id)
self.product1.standard_price = 5.0
move1 = self.env['stock.move'].create({
'name': 'IN 10 units @ 10.00 per unit',
'location_id': self.supplier_location.id,
@@ -123,7 +123,7 @@ class TestStockValuation(SavepointCase):
move1._action_done()
# Set price to 6.0
self.product1._change_standard_price(6.0, self.expense_account.id)
self.product1.standard_price = 6.0
stock_aml, price_change_aml = self._get_stock_valuation_move_lines()
self.assertEqual(stock_aml.debit, 50)
self.assertEqual(price_change_aml.debit, 10)
@@ -2737,7 +2737,7 @@ class TestStockValuation(SavepointCase):
self.product1.categ_id.property_cost_method = 'standard'
self.product1.categ_id.property_valuation = 'manual_periodic'
self.product1.with_user(self.inventory_user)._change_standard_price(10)
self.product1.standard_price = 10.0
move1 = self.env['stock.move'].with_user(self.inventory_user).create({
'name': 'IN 10 units',
@@ -2752,12 +2752,12 @@ class TestStockValuation(SavepointCase):
move1.move_line_ids.qty_done = 10.0
move1._action_done()
def test_standard_perpetual_1(self):
def test_standard_perpetual_2(self):
"""Validate a receipt as a regular stock user."""
self.product1.categ_id.property_cost_method = 'standard'
self.product1.categ_id.property_valuation = 'real_time'
self.product1.with_user(self.inventory_user)._change_standard_price(10)
self.product1.standard_price = 10.0
move1 = self.env['stock.move'].with_user(self.inventory_user).create({
'name': 'IN 10 units',
@@ -3100,7 +3100,7 @@ class TestStockValuation(SavepointCase):
date8 = now - timedelta(days=1)
# set the standard price to 10
self.product1._change_standard_price(10, self.expense_account.id)
self.product1.standard_price = 10.0
# receive 10
move1 = self.env['stock.move'].create({
@@ -3160,7 +3160,7 @@ class TestStockValuation(SavepointCase):
self.assertEqual(self.product1.value_svl, 150)
# set the standard price to 5
self.product1._change_standard_price(5, self.expense_account.id)
self.product1.standard_price = 5
self.product1.stock_valuation_layer_ids.sorted()[-1]._write({'create_date': date5})
self.assertEqual(self.product1.quantity_svl, 15)
@@ -3186,7 +3186,7 @@ class TestStockValuation(SavepointCase):
self.assertEqual(self.product1.value_svl, -25)
# set the standard price to 7.5
self.product1._change_standard_price(7.5, self.expense_account.id)
self.product1.standard_price = 7.5
self.product1.stock_valuation_layer_ids.sorted()[-1]._write({'create_date': date7})
# receive 100
@@ -211,7 +211,7 @@ class TestStockValuationStandard(TestStockValuationCommon):
move3 = self._make_out_move(self.product1, 15)
# change cost from 10 to 15
self.product1._change_standard_price(15.0)
self.product1.standard_price = 15.0
self.assertEqual(self.product1.value_svl, 75)
self.assertEqual(self.product1.quantity_svl, 5)
@@ -35,78 +35,5 @@
</group>
</field>
</record>
<record id="view_template_property_form" model="ir.ui.view">
<field name="name">product.template.stock.property.form.inherit</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<data>
<field name="list_price" position="after">
<field name="valuation" invisible="1" readonly="1"/>
<field name="cost_method" invisible="1" readonly="1"/>
</field>
<field name="standard_price" position="replace">
<field name="standard_price"
attrs="{'readonly':[('cost_method', '!=', 'fifo')]}"
widget='monetary' options="{'currency_field': 'cost_currency_id', 'field_digits': True}"
class="oe_inline"/>
</field>
<xpath expr="//div[@name='standard_price_uom']" position="inside">
<span name="update_cost_price">
<button string="Update Cost" type="action"
name="%(action_view_change_standard_price)d"
attrs="{'invisible':['|', ('cost_method', '=', 'fifo'), ('product_variant_count', '>', 1)]}"
class="oe_link pt-0 oe_inline"/>
</span>
</xpath>
</data>
</field>
</record>
<record id="product_product_normal_form_view_inherit" model="ir.ui.view">
<field name="name">product.product.normal.form.view.inherit</field>
<field name="model">product.product</field>
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="arch" type="xml">
<data>
<field name="standard_price" position="replace">
<field name="standard_price"
attrs="{'readonly':[('cost_method', '!=', 'fifo')]}"
widget='monetary' options="{'currency_field': 'cost_currency_id', 'field_digits': True}"
class="oe_inline"/>
</field>
<xpath expr="//button[@name='%(action_view_change_standard_price)d']" position="attributes">
<attribute name="attrs">{'invisible': [('cost_method', '=', 'fifo')]}</attribute>
</xpath>
</data>
</field>
</record>
<record id="product_variant_easy_edit_view_inherit" model="ir.ui.view">
<field name="name">product.product.product.view.form.easy.inherit</field>
<field name="model">product.product</field>
<field name="inherit_id" ref="product.product_variant_easy_edit_view"/>
<field name="arch" type="xml">
<data>
<field name="standard_price" position="replace">
<field name="valuation" invisible="1" readonly="1"/>
<field name="cost_method" invisible="1" readonly="1"/>
<label for="standard_price"/>
<div class="o_row" name="update_cost_price">
<field name="standard_price"
attrs="{'readonly':[('cost_method', '!=', 'fifo')]}"
widget='monetary' options="{'currency_field': 'cost_currency_id', 'field_digits': True}"
class="oe_inline"/>
<button string="Update Cost" type="action"
name="%(action_view_change_standard_price)d"
attrs="{'invisible':[('cost_method', '=', 'fifo')]}"
class="oe_link oe_inline"/>
</div>
</field>
</data>
</field>
</record>
</data>
</odoo>
-1
View File
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import stock_change_standard_price
from . import stock_quantity_history
from . import stock_picking_return
@@ -1,43 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
class StockChangeStandardPrice(models.TransientModel):
_name = "stock.change.standard.price"
_description = "Change Standard Price"
new_price = fields.Float(
'Price', digits='Product Price', required=True,
help="If cost price is increased, stock variation account will be debited "
"and stock output account will be credited with the value = (difference of amount * quantity available).\n"
"If cost price is decreased, stock variation account will be creadited and stock input account will be debited.")
counterpart_account_id = fields.Many2one(
'account.account', string="Counter-Part Account",
domain=[('deprecated', '=', False)])
counterpart_account_id_required = fields.Boolean(string="Counter-Part Account Required")
@api.model
def default_get(self, fields):
res = super(StockChangeStandardPrice, self).default_get(fields)
if 'active_model' in self._context:
product_or_template = self.env[self._context['active_model']].browse(self._context['active_id'])
if 'new_price' in fields and 'new_price' not in res:
res['new_price'] = product_or_template.standard_price
if 'counterpart_account_id' in fields and 'counterpart_account_id' not in res:
res['counterpart_account_id'] = product_or_template.property_account_expense_id.id or product_or_template.categ_id.property_account_expense_categ_id.id
res['counterpart_account_id_required'] = bool(product_or_template.valuation == 'real_time')
return res
def change_price(self):
""" Changes the Standard Price of Product and creates an account move accordingly. """
self.ensure_one()
if self._context['active_model'] == 'product.template':
products = self.env['product.template'].browse(self._context['active_id']).product_variant_ids
else:
products = self.env['product.product'].browse(self._context['active_id'])
products._change_standard_price(self.new_price, counterpart_account_id=self.counterpart_account_id.id)
return {'type': 'ir.actions.act_window_close'}
@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_change_standard_price" model="ir.ui.view">
<field name="name">Change Standard Price</field>
<field name="model">stock.change.standard.price</field>
<field name="arch" type="xml">
<form string="Change Standard Price">
<separator string="Change Price"/>
<field name="counterpart_account_id_required" invisible="1"/>
<group>
<group>
<field name="new_price" string="Cost"/>
</group>
<group>
<field name="counterpart_account_id" options="{'no_create': True}"
attrs="{'invisible': [('counterpart_account_id_required', '=', False)], 'required': [('counterpart_account_id_required', '=', True)]}"/>
</group>
</group>
<footer>
<button name="change_price" string="_Apply" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-secondary" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="action_view_change_standard_price" model="ir.actions.act_window">
<field name="name">Change Standard Price</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">stock.change.standard.price</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_change_standard_price"/>
<field name="target">new</field>
</record>
</data>
</odoo>
@@ -34,9 +34,7 @@ class TestCrossdock(common.TransactionCase):
p_f.route_ids.add(wh_pps.crossdock_route_id)
cross_shop_product = p_f.save()
std_price_wiz = Form(self.env['stock.change.standard.price'].with_context(active_id=p_f.id, active_model='product.template'))
std_price_wiz.new_price = 70.0
std_price_wiz.save()
p_f.standard_price = 70.0
# Create a sales order with a line of 100 PCE incoming shipment with route_id crossdock shipping
so_form = Form(self.env['sale.order'])
@@ -38,9 +38,7 @@ class TestLifoPrice(StockAccountTestCommon):
product_form.categ_id.property_stock_account_output_categ_id = self.o_income
product_lifo_icecream = product_form.save()
std_price_wiz = Form(self.env['stock.change.standard.price'].with_context(active_id=product_lifo_icecream.id, active_model='product.product'))
std_price_wiz.new_price = 70.0
std_price_wiz.save()
product_lifo_icecream.standard_price = 70.0
# I create a draft Purchase Order for first in move for 10 pieces at 60 euro
order_form = Form(self.env['purchase.order'])
@@ -21,9 +21,8 @@ class TestProcurementException(common.TransactionCase):
product_form.categ_id = self.env.ref('product.product_category_1')
product_with_no_seller = product_form.save()
std_price_wiz = Form(self.env['stock.change.standard.price'].with_context(active_id=product_with_no_seller.id, active_model='product.product'))
std_price_wiz.new_price = 70.0
std_price_wiz.save()
product_with_no_seller.standard_price = 70.0
# I create a sales order with this product with route dropship.
so_form = Form(self.env['sale.order'])
so_form.partner_id = res_partner_2
@@ -144,7 +144,7 @@ class LandedCost(models.Model):
# Update the AVCO
product = line.move_id.product_id
if product.cost_method == 'average' and not float_is_zero(product.quantity_svl, precision_rounding=product.uom_id.rounding):
product.with_company(self.company_id).sudo().standard_price += cost_to_add / product.quantity_svl
product.with_company(self.company_id).sudo().with_context(disable_auto_svl=True).standard_price += cost_to_add / product.quantity_svl
# `remaining_qty` is negative if the move is out and delivered proudcts that were not
# in stock.
qty_out = 0