From 67e575e6fd9be54637fc036b72b0a00e6e3225e1 Mon Sep 17 00:00:00 2001 From: William Henrotin Date: Tue, 13 Apr 2021 15:45:37 +0000 Subject: [PATCH] [FIX] mrp_account: copy extra_cost to backorder In a subcontracting flow, a production order is created to reflect the subcontractor work. An extra cost is set on this production order corresponding to the purchase order line price unit. If the subcontracting product is tracked, we may create some backorder to save all the lot/serial numbers. As the extra_cost is not copied, the first lot/serial number will have the corresponding stock valuation layer with the correct quantity. The following ones will only have the cost of the components as value. closes odoo/odoo#69245 Opw: 2487450 X-original-commit: 262c2ba8773c698ccde499b095794ab0fc780699 Signed-off-by: Arnold Moyaux Signed-off-by: William Henrotin --- addons/mrp_account/models/mrp_production.py | 5 ++ .../tests/test_subcontracting_account.py | 69 +++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/addons/mrp_account/models/mrp_production.py b/addons/mrp_account/models/mrp_production.py index d193a98eecd..74b10914178 100644 --- a/addons/mrp_account/models/mrp_production.py +++ b/addons/mrp_account/models/mrp_production.py @@ -70,6 +70,11 @@ class MrpProduction(models.Model): # able to produce orders AccountAnalyticLine.create(vals) + def _get_backorder_mo_vals(self): + res = super()._get_backorder_mo_vals() + res['extra_cost'] = self.extra_cost + return res + def button_mark_done(self): res = super(MrpProduction, self).button_mark_done() for order in self: diff --git a/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py b/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py index c144e3ed250..60e13d9e10f 100644 --- a/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py +++ b/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py @@ -63,3 +63,72 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon): self.assertEqual(mo.move_finished_ids.stock_valuation_layer_ids.value, 60) self.assertEqual(picking_receipt.move_lines.stock_valuation_layer_ids.value, 0) self.assertEqual(picking_receipt.move_lines.product_id.value_svl, 60) + + def test_subcontracting_account_backorder(self): + """ This test uses tracked (serial and lot) component and tracked (serial) finished product + The original subcontracting production order will be split into 4 backorders. This test + ensure the extra cost asked from the subcontractor is added correctly on all the finished + product valuation layer. Not only the first one. """ + todo_nb = 4 + self.comp2.tracking = 'lot' + self.comp1.tracking = 'serial' + self.comp2.standard_price = 100 + self.finished.tracking = 'serial' + self.env.ref('product.product_category_all').property_cost_method = 'fifo' + + # Create a receipt picking from the subcontractor + picking_form = Form(self.env['stock.picking']) + picking_form.picking_type_id = self.env.ref('stock.picking_type_in') + picking_form.partner_id = self.subcontractor_partner1 + with picking_form.move_ids_without_package.new() as move: + move.product_id = self.finished + move.product_uom_qty = todo_nb + picking_receipt = picking_form.save() + # Mimic the extra cost on the po line + picking_receipt.move_lines.price_unit = 50 + picking_receipt.action_confirm() + + # We should be able to call the 'record_components' button + self.assertTrue(picking_receipt.display_action_record_components) + + lot_comp2 = self.env['stock.production.lot'].create({ + 'name': 'lot_comp2', + 'product_id': self.comp2.id, + 'company_id': self.env.company.id, + }) + serials_finished = [] + serials_comp1 = [] + for i in range(todo_nb): + serials_finished.append(self.env['stock.production.lot'].create({ + 'name': 'serial_fin_%s' % i, + 'product_id': self.finished.id, + 'company_id': self.env.company.id, + })) + serials_comp1.append(self.env['stock.production.lot'].create({ + 'name': 'serials_comp1_%s' % i, + 'product_id': self.comp1.id, + 'company_id': self.env.company.id, + })) + + for i in range(todo_nb): + action = picking_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.lot_producing_id = serials_finished[i] + with mo_form.move_line_raw_ids.edit(0) as ml: + self.assertEqual(ml.product_id, self.comp1) + ml.lot_id = serials_comp1[i] + with mo_form.move_line_raw_ids.edit(1) as ml: + self.assertEqual(ml.product_id, self.comp2) + ml.lot_id = lot_comp2 + mo = mo_form.save() + mo.subcontracting_record_component() + + # We should not be able to call the 'record_components' button + + picking_receipt.button_validate() + + f_layers = self.finished.stock_valuation_layer_ids + self.assertEqual(len(f_layers), 4) + for layer in f_layers: + self.assertEqual(layer.value, 100 + 50)