[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:
@@ -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()
|
||||
|
||||
@@ -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), '&', ('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), '&', ('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), '&', ('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), '&', ('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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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
|
||||
|
||||
Reference in New Issue
Block a user