[REF] stock_account: valuation layer and not admin user
Carefully sudo when necessary. task-2034044 closes odoo/odoo#34802 Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
This commit is contained in:
@@ -169,10 +169,11 @@ class ProductProduct(models.Model):
|
||||
for product in self:
|
||||
if product.cost_method not in ('standard', 'average'):
|
||||
continue
|
||||
if float_is_zero(product.quantity_svl, precision_rounding=product.uom_id.rounding):
|
||||
quantity_svl = product.sudo().quantity_svl
|
||||
if float_is_zero(quantity_svl, precision_rounding=product.uom_id.rounding):
|
||||
continue
|
||||
diff = new_price - product.standard_price
|
||||
value = company_id.currency_id.round(product.quantity_svl * diff)
|
||||
value = company_id.currency_id.round(quantity_svl * diff)
|
||||
if company_id.currency_id.is_zero(value):
|
||||
continue
|
||||
|
||||
@@ -184,7 +185,7 @@ class ProductProduct(models.Model):
|
||||
'quantity': 0,
|
||||
}
|
||||
svl_vals_list.append(svl_vals)
|
||||
stock_valuation_layers = self.env['stock.valuation.layer'].create(svl_vals_list)
|
||||
stock_valuation_layers = self.env['stock.valuation.layer'].sudo().create(svl_vals_list)
|
||||
|
||||
# Handle account moves.
|
||||
product_accounts = {product.id: product.product_tmpl_id.get_product_accounts() for product in self}
|
||||
@@ -233,7 +234,7 @@ class ProductProduct(models.Model):
|
||||
account_moves.post()
|
||||
|
||||
# Actually update the standard price.
|
||||
self.write({'standard_price': new_price})
|
||||
self.with_context(force_company=company_id.id).sudo().write({'standard_price': new_price})
|
||||
|
||||
def _run_fifo(self, quantity, company):
|
||||
self.ensure_one()
|
||||
@@ -291,16 +292,21 @@ class ProductProduct(models.Model):
|
||||
}
|
||||
return vals
|
||||
|
||||
def _run_fifo_vacuum(self):
|
||||
def _run_fifo_vacuum(self, company=None):
|
||||
"""Compensate layer valued at an estimated price with the price of future receipts
|
||||
if any. If the estimated price is equals to the real price, no layer is created but
|
||||
the original layer is marked as compensated.
|
||||
|
||||
:param company: recordset of `res.company` to limit the execution of the vacuum
|
||||
"""
|
||||
self.ensure_one()
|
||||
svls_to_vacuum = self.env['stock.valuation.layer'].search([
|
||||
if company is None:
|
||||
company = self.env.company
|
||||
svls_to_vacuum = self.env['stock.valuation.layer'].sudo().search([
|
||||
('product_id', '=', self.id),
|
||||
('remaining_qty', '<', 0),
|
||||
('stock_move_id', '!=', False),
|
||||
('company_id', '=', company.id),
|
||||
])
|
||||
for svl_to_vacuum in svls_to_vacuum:
|
||||
domain = [
|
||||
@@ -313,7 +319,7 @@ class ProductProduct(models.Model):
|
||||
('create_date', '=', svl_to_vacuum.create_date),
|
||||
('id', '>', svl_to_vacuum.id)
|
||||
]
|
||||
candidates = self.env['stock.valuation.layer'].search(domain)
|
||||
candidates = self.env['stock.valuation.layer'].sudo().search(domain)
|
||||
if not candidates:
|
||||
continue
|
||||
qty_to_take_on_candidates = abs(svl_to_vacuum.remaining_qty)
|
||||
@@ -359,7 +365,7 @@ class ProductProduct(models.Model):
|
||||
'company_id': move.company_id.id,
|
||||
'description': 'Revaluation of %s (negative inventory)' % move.picking_id.name or move.name,
|
||||
}
|
||||
vacuum_svl = self.env['stock.valuation.layer'].create(vals)
|
||||
vacuum_svl = self.env['stock.valuation.layer'].sudo().create(vals)
|
||||
|
||||
# Create the account move.
|
||||
if self.valuation != 'real_time':
|
||||
@@ -683,7 +689,7 @@ class ProductCategory(models.Model):
|
||||
% (self.display_name, self.property_valuation, new_valuation)
|
||||
out_svl_vals_list, products_orig_quantity_svl, products = Product\
|
||||
._svl_empty_stock(description, product_category=product_category)
|
||||
out_stock_valuation_layers = SVL.create(out_svl_vals_list)
|
||||
out_stock_valuation_layers = SVL.sudo().create(out_svl_vals_list)
|
||||
if product_category.property_valuation == 'real_time':
|
||||
move_vals_list += Product._svl_empty_stock_am(out_stock_valuation_layers)
|
||||
impacted_categories[product_category] = (products, description, products_orig_quantity_svl)
|
||||
@@ -693,7 +699,7 @@ class ProductCategory(models.Model):
|
||||
for product_category, (products, description, products_orig_quantity_svl) in impacted_categories.items():
|
||||
# Replenish the stock with the new cost method.
|
||||
in_svl_vals_list = products._svl_replenish_stock(description, products_orig_quantity_svl)
|
||||
in_stock_valuation_layers = SVL.create(in_svl_vals_list)
|
||||
in_stock_valuation_layers = SVL.sudo().create(in_svl_vals_list)
|
||||
if product_category.property_valuation == 'real_time':
|
||||
move_vals_list += Product._svl_replenish_stock_am(in_stock_valuation_layers)
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ class StockMove(models.Model):
|
||||
if forced_quantity:
|
||||
svl_vals['description'] = 'Correction of %s (modification of past move)' % move.picking_id.name or move.name
|
||||
svl_vals_list.append(svl_vals)
|
||||
return self.env['stock.valuation.layer'].create(svl_vals_list)
|
||||
return self.env['stock.valuation.layer'].sudo().create(svl_vals_list)
|
||||
|
||||
def _create_out_svl(self, forced_quantity=None):
|
||||
"""Create a `stock.valuation.layer` from `self`.
|
||||
@@ -179,7 +179,7 @@ class StockMove(models.Model):
|
||||
if forced_quantity:
|
||||
svl_vals['description'] = 'Correction of %s (modification of past move)' % move.picking_id.name or move.name
|
||||
svl_vals_list.append(svl_vals)
|
||||
return self.env['stock.valuation.layer'].create(svl_vals_list)
|
||||
return self.env['stock.valuation.layer'].sudo().create(svl_vals_list)
|
||||
|
||||
def _create_dropshipped_svl(self, forced_quantity=None):
|
||||
"""Create a `stock.valuation.layer` from `self`.
|
||||
@@ -218,7 +218,7 @@ class StockMove(models.Model):
|
||||
}
|
||||
out_vals.update(common_vals)
|
||||
svl_vals_list.append(out_vals)
|
||||
return self.env['stock.valuation.layer'].create(svl_vals_list)
|
||||
return self.env['stock.valuation.layer'].sudo().create(svl_vals_list)
|
||||
|
||||
def _create_dropshipped_returned_svl(self, forced_quantity=None):
|
||||
"""Create a `stock.valuation.layer` from `self`.
|
||||
@@ -242,7 +242,7 @@ class StockMove(models.Model):
|
||||
|
||||
res = super(StockMove, self)._action_done(cancel_backorder=cancel_backorder)
|
||||
|
||||
stock_valuation_layers = self.env['stock.valuation.layer']
|
||||
stock_valuation_layers = self.env['stock.valuation.layer'].sudo()
|
||||
# Create the valuation layers in batch by calling `moves._create_valued_type_svl`.
|
||||
for valued_type in self._get_valued_types():
|
||||
todo_valued_moves = valued_moves[valued_type]
|
||||
@@ -260,8 +260,9 @@ class StockMove(models.Model):
|
||||
|
||||
# For every in move, run the vacuum for the linked product.
|
||||
products_to_vacuum = valued_moves['in'].mapped('product_id')
|
||||
company = valued_moves['in'].mapped('company_id') and valued_moves['in'].mapped('company_id')[0] or self.env.company
|
||||
for product_to_vacuum in products_to_vacuum:
|
||||
product_to_vacuum._run_fifo_vacuum()
|
||||
product_to_vacuum._run_fifo_vacuum(company)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
@@ -29,6 +29,13 @@ class TestStockValuation(SavepointCase):
|
||||
'type': 'product',
|
||||
'categ_id': cls.env.ref('product.product_category_all').id,
|
||||
})
|
||||
cls.inventory_user = cls.env['res.users'].create({
|
||||
'name': 'Pauline Poivraisselle',
|
||||
'login': 'pauline',
|
||||
'email': 'p.p@example.com',
|
||||
'notification_type': 'inbox',
|
||||
'groups_id': [(6, 0, [cls.env.ref('stock.group_stock_user').id])]
|
||||
})
|
||||
|
||||
cls.product1.categ_id.property_valuation = 'real_time'
|
||||
cls.product2.categ_id.property_valuation = 'real_time'
|
||||
@@ -2674,6 +2681,46 @@ class TestStockValuation(SavepointCase):
|
||||
self.assertAlmostEqual(self.product1.quantity_svl, 0.0)
|
||||
self.assertAlmostEqual(self.product1.value_svl, 0.0)
|
||||
|
||||
def test_standard_manual_2(self):
|
||||
"""Validate a receipt as a regular stock user."""
|
||||
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)
|
||||
|
||||
move1 = self.env['stock.move'].with_user(self.inventory_user).create({
|
||||
'name': 'IN 10 units',
|
||||
'location_id': self.supplier_location.id,
|
||||
'location_dest_id': self.stock_location.id,
|
||||
'product_id': self.product1.id,
|
||||
'product_uom': self.uom_unit.id,
|
||||
'product_uom_qty': 10.0,
|
||||
})
|
||||
move1._action_confirm()
|
||||
move1._action_assign()
|
||||
move1.move_line_ids.qty_done = 10.0
|
||||
move1._action_done()
|
||||
|
||||
def test_standard_perpetual_1(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)
|
||||
|
||||
move1 = self.env['stock.move'].with_user(self.inventory_user).create({
|
||||
'name': 'IN 10 units',
|
||||
'location_id': self.supplier_location.id,
|
||||
'location_dest_id': self.stock_location.id,
|
||||
'product_id': self.product1.id,
|
||||
'product_uom': self.uom_unit.id,
|
||||
'product_uom_qty': 10.0,
|
||||
})
|
||||
move1._action_confirm()
|
||||
move1._action_assign()
|
||||
move1.move_line_ids.qty_done = 10.0
|
||||
move1._action_done()
|
||||
|
||||
def test_change_cost_method_1(self):
|
||||
""" Change the cost method from FIFO to AVCO.
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user