Skip to content

Commit

Permalink
[FIX] mrp_subcontracting_account: read price unit at validation
Browse files Browse the repository at this point in the history
In a subcontracting flow, the extra_cost on the subcontracted production
is read on the purchase line (via _get_price_unit() ) at the production
creation. In case the price unit on this purchase line change before the
validation, the stock valuation layer linked to the production will not
take this new value into account.

This commit ensures the price unit is the right one at validation

Note: the first version of the current fix broke a use case. The test
`test_tracked_compo_and_backorder` has been added to protect that use
case.

closes odoo#87792

Signed-off-by: William Henrotin (whe) <whe@odoo.com>
Signed-off-by: Adrien Widart <awt@odoo.com>
Co-authored-by: William Henrotin (whe) <whe@odoo.com>
Co-authored-by: Adrien Widart <awt@odoo.com>
  • Loading branch information
Whenrow and adwid committed Apr 8, 2022
1 parent 91a3a38 commit 511131c
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 7 deletions.
1 change: 1 addition & 0 deletions addons/mrp_subcontracting_account/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from . import mrp_production
from . import stock_picking
from . import product_product
from . import stock_move
16 changes: 16 additions & 0 deletions addons/mrp_subcontracting_account/models/mrp_production.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo import models


class MrpProduction(models.Model):
_inherit = 'mrp.production'

def _cal_price(self, consumed_moves):
finished_move = self.move_finished_ids.filtered(lambda x: x.product_id == self.product_id and x.state not in ('done', 'cancel') and x.quantity_done > 0)
# Take the price unit of the reception move
last_done_receipt = finished_move.move_dest_ids.filtered(lambda m: m.state == 'done')[-1:]
if last_done_receipt.is_subcontract:
self.extra_cost = last_done_receipt._get_price_unit()
return super()._cal_price(consumed_moves=consumed_moves)
6 changes: 0 additions & 6 deletions addons/mrp_subcontracting_account/models/stock_picking.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,3 @@ def action_view_stock_valuation_layers(self):
domain_subcontracting = [('id', 'in', (subcontracted_productions.move_raw_ids | subcontracted_productions.move_finished_ids).stock_valuation_layer_ids.ids)]
domain = OR([domain, domain_subcontracting])
return dict(action, domain=domain)

def _prepare_subcontract_mo_vals(self, subcontract_move, bom):
vals = super(StockPicking, self)._prepare_subcontract_mo_vals(subcontract_move, bom)
if bom.product_tmpl_id.cost_method in ('fifo', 'average'):
vals = dict(vals, extra_cost=subcontract_move._get_price_unit())
return vals
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,11 @@ def test_subcontracting_account_flow_1(self):
move.product_id = self.finished
move.product_uom_qty = 1
picking_receipt = picking_form.save()
picking_receipt.move_lines.price_unit = 30.0
picking_receipt.move_lines.price_unit = 15.0

picking_receipt.action_confirm()
# Suppose the additional cost changes:
picking_receipt.move_lines.price_unit = 30.0
picking_receipt.move_lines.quantity_done = 1.0
picking_receipt._action_done()

Expand Down Expand Up @@ -157,6 +159,59 @@ def test_subcontracting_account_backorder(self):
for layer in f_layers:
self.assertEqual(layer.value, 100 + 50)

def test_tracked_compo_and_backorder(self):
"""
Suppose a subcontracted product P with two tracked components, P is FIFO
Create a receipt for 10 x P, receive 5, then 3 and then 2
"""
self.env.ref('product.product_category_all').property_cost_method = 'fifo'
self.comp1.tracking = 'lot'
self.comp1.standard_price = 10
self.comp2.tracking = 'lot'
self.comp2.standard_price = 20

lot01, lot02 = self.env['stock.production.lot'].create([{
'name': "Lot of %s" % product.name,
'product_id': product.id,
'company_id': self.env.company.id,
} for product in (self.comp1, self.comp2)])

receipt_form = Form(self.env['stock.picking'])
receipt_form.picking_type_id = self.env.ref('stock.picking_type_in')
receipt_form.partner_id = self.subcontractor_partner1
with receipt_form.move_ids_without_package.new() as move:
move.product_id = self.finished
move.product_uom_qty = 10
receipt = receipt_form.save()
# add an extra cost
receipt.move_lines.price_unit = 50
receipt.action_confirm()

for qty_producing in (5, 3, 2):
action = receipt.action_record_components()
mo = self.env['mrp.production'].browse(action['res_id'])
mo_form = Form(mo.with_context(**action['context']), view=action['view_id'])
mo_form.qty_producing = qty_producing
with mo_form.move_line_raw_ids.edit(0) as ml:
ml.lot_id = lot01
with mo_form.move_line_raw_ids.edit(1) as ml:
ml.lot_id = lot02
mo = mo_form.save()
mo.subcontracting_record_component()

action = receipt.button_validate()
if isinstance(action, dict):
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
wizard.process()
receipt = receipt.backorder_ids

self.assertRecordValues(self.finished.stock_valuation_layer_ids, [
{'quantity': 5, 'value': 5 * (10 + 20 + 50)},
{'quantity': 3, 'value': 3 * (10 + 20 + 50)},
{'quantity': 2, 'value': 2 * (10 + 20 + 50)},
])


class TestBomPriceSubcontracting(TestBomPrice):

def test_01_compute_price_subcontracting_cost(self):
Expand Down

0 comments on commit 511131c

Please sign in to comment.