From 77a8616263ae2e1120cfbde4cd96c4fd6a23c1c1 Mon Sep 17 00:00:00 2001 From: yhu-odoo Date: Wed, 5 Apr 2023 11:11:12 +0000 Subject: [PATCH] [FIX] mrp_subcontracting_account: subcontract cost don't match the price When doing subcontracting with standard price product. If Final procut cost != Components cost + subcontracting cost When posting account entries for final product, the amount of componets entry is adjusted for the difference of the two costs. After this commit, we will post components cost according to it's price so that it can match the value change of the stock. We adjust the amount on subcontracting cost for the cost difference. NOTE: the remaining of subcontracting cost will be post in price difference account when create vendor bill. Task-3223451 X-original-commit: 514f5b51ad30cce0048abb4cf343e830f0288b36 Part-of: odoo/odoo#132282 --- .../models/stock_move.py | 13 +++-- .../tests/test_subcontracting_account.py | 52 +++++++++++++++++++ 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/addons/mrp_subcontracting_account/models/stock_move.py b/addons/mrp_subcontracting_account/models/stock_move.py index d964651b601..744f3f993ca 100644 --- a/addons/mrp_subcontracting_account/models/stock_move.py +++ b/addons/mrp_subcontracting_account/models/stock_move.py @@ -19,10 +19,17 @@ class StockMove(models.Model): return rslt # split the credit line to two, one for component cost, one for subcontracting service cost currency = self.company_id.currency_id - subcontract_service_cost = currency.round(subcontract_production.extra_cost * qty) + if self.product_id.cost_method == 'standard': + # In case of standard price, the component cost is the cost of the product + # the subcontracting service cost may not represent the real cost of the subcontracting service + # the difference should be posted in price difference account in the end + component_cost = currency.round(sum(m.price_unit * m.product_uom_qty for m in subcontract_production.move_raw_ids)) + subcontract_service_cost = credit_value - component_cost + else: + subcontract_service_cost = currency.round(subcontract_production.extra_cost * qty) + component_cost = credit_value - subcontract_service_cost if not currency.is_zero(subcontract_service_cost): del rslt['credit_line_vals'] - component_cost = -credit_value + subcontract_service_cost service_cost_account = self.product_id.product_tmpl_id.get_product_accounts()['stock_input'] rslt['subcontract_credit_line_vals'] = { 'name': description, @@ -41,7 +48,7 @@ class StockMove(models.Model): 'product_uom_id': self.product_id.uom_id.id, 'ref': description, 'partner_id': partner_id, - 'balance': component_cost, + 'balance': -component_cost, 'account_id': credit_account_id, } return rslt diff --git a/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py b/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py index 1e5a75864b1..f6223ac50d2 100644 --- a/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py +++ b/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py @@ -336,6 +336,58 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon): {'quantity': 2, 'value': 2 * (10 + 20 + 50)}, ]) + def test_subcontract_cost_different_when_standard_price(self): + """Test when subcontracting with standard price when + Final product cost != Components cost + Subcontracting cost + When posting the account entries for receiving final product, the + subcontracting cost will be adjusted based on the difference of the cost. + """ + # pylint: disable=bad-whitespace + self.stock_location = self.env.ref('stock.stock_location_stock') + self.customer_location = self.env.ref('stock.stock_location_customers') + self.supplier_location = self.env.ref('stock.stock_location_suppliers') + self.uom_unit = self.env.ref('uom.product_uom_unit') + product_category_all = self.env.ref('product.product_category_all') + product_category_all.property_cost_method = 'standard' + product_category_all.property_valuation = 'real_time' + stock_in_acc_id = product_category_all.property_stock_account_input_categ_id.id + stock_valu_acc_id = product_category_all.property_stock_valuation_account_id.id + stock_cop_acc_id = product_category_all.property_stock_account_production_cost_id.id + + self.comp1.standard_price = 10 + self.comp2.standard_price = 20 + self.finished.standard_price = 40 + + all_amls_ids = self.env['account.move.line'].search([]).ids + + 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 = 1 + picking_receipt = picking_form.save() + # subcontracting cost is 15 + picking_receipt.move_ids.price_unit = 15.0 + picking_receipt.action_confirm() + + picking_receipt.move_ids.quantity_done = 1.0 + picking_receipt._action_done() + + amls = self.env['account.move.line'].search([('id', 'not in', all_amls_ids)]) + self.assertRecordValues(amls, [ + # Receipt from subcontractor + {'account_id': stock_valu_acc_id, 'product_id': self.finished.id, 'debit': 40.0, 'credit': 0.0}, + {'account_id': stock_in_acc_id, 'product_id': self.finished.id, 'debit': 0.0, 'credit': 10.0}, # adjust according to the difference + {'account_id': stock_cop_acc_id, 'product_id': self.finished.id, 'debit': 0.0, 'credit': 30.0}, + # Delivery com2 to subcontractor + {'account_id': stock_valu_acc_id, 'product_id': self.comp2.id, 'debit': 0.0, 'credit': 20.0}, + {'account_id': stock_cop_acc_id, 'product_id': self.comp2.id, 'debit': 20.0, 'credit': 0.0}, + # Delivery com2 to subcontractor + {'account_id': stock_valu_acc_id, 'product_id': self.comp1.id, 'debit': 0.0, 'credit': 10.0}, + {'account_id': stock_cop_acc_id, 'product_id': self.comp1.id, 'debit': 10.0, 'credit': 0.0}, + ]) + class TestBomPriceSubcontracting(TestBomPriceCommon):