From f7a681abff61289d70d65c7ab09b554279cf217f Mon Sep 17 00:00:00 2001 From: yhu-odoo Date: Fri, 3 Mar 2023 11:53:29 +0000 Subject: [PATCH] [IMP] mrp_subcontracting{, _dropshipping}: split subcontracting account move Considering a subcontracting use case where: component cost = 50 service cost = 100 we post: |account, |debit, |credit ----------------------------------------------- Receipt Component from vendor |Stock Valuation |50 | |Stock Input | |50 ----------------------------------------------- Invoice Component from vendor |Stock Input |50 | |Payable | |50 ----------------------------------------------- Resupply Component to subcontractor |Stock Valuation | |50 |Stock Output |50 | ---------------------------------------------- Receive Final from subcontractor |Stock Valuation |150 | |Stock Input | |150 ---------------------------------------------- Invoice Final from subcontractor |Stock Input |100 | |Payable | |100 ----------------------------------------------- Deliver Final to client |Stock Valuation | |150 |Stock Output |150 | ----------------------------------------------- Invoice Client |Stock Output | |150 |Receivable |150 | Stock Input/Output account are not balanced. In this commit, we split the credit value when received final from subcontractor to make them balanced. |account, |debit, |credit ----------------------------------------------- Receipt Component from vendor |Stock Valuation |50 | |Stock Input | |50 ----------------------------------------------- Invoice Component from vendor |Stock Input |50 | |Payable | |50 ----------------------------------------------- Resupply Component to subcontractor |Stock Valuation | |50 |Stock Output |50 | ---------------------------------------------- Receive Final from subcontractor |Stock Valuation |150 | |Stock Input | |100 |Stock Output | |50 ---------------------------------------------- Invoice Final from subcontractor |Stock Input |100 | |Payable | |100 ----------------------------------------------- Deliver Final to client |Stock Valuation | |150 |Stock Output |150 | ----------------------------------------------- Invoice Client |Stock Output | |150 |Receivable |150 | --- closes odoo/odoo#113853 Signed-off-by: Arnold Moyaux (arm) --- .../models/stock_move.py | 35 +++++++++++++++++ .../tests/test_subcontracting_account.py | 39 ++++++++++++++++++- .../tests/test_anglo_saxon_valuation.py | 3 +- 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/addons/mrp_subcontracting_account/models/stock_move.py b/addons/mrp_subcontracting_account/models/stock_move.py index d57c2c94df8..4469e7459bf 100644 --- a/addons/mrp_subcontracting_account/models/stock_move.py +++ b/addons/mrp_subcontracting_account/models/stock_move.py @@ -10,3 +10,38 @@ class StockMove(models.Model): def _should_force_price_unit(self): self.ensure_one() return self.is_subcontract or super()._should_force_price_unit() + + def _generate_valuation_lines_data(self, partner_id, qty, debit_value, credit_value, debit_account_id, credit_account_id, svl_id, description): + rslt = super()._generate_valuation_lines_data(partner_id, qty, debit_value, credit_value, debit_account_id, credit_account_id, svl_id, description) + + subcontract_production = self.production_id.filtered(lambda p: p.subcontractor_id) + if not subcontract_production: + 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 not currency.is_zero(subcontract_service_cost): + del rslt['credit_line_vals'] + component_cost = -credit_value + subcontract_service_cost + component_cost_account = self.product_id.product_tmpl_id.get_product_accounts()['stock_output'] + rslt['subcontract_credit_line_vals'] = { + 'name': description, + 'product_id': self.product_id.id, + 'quantity': qty, + 'product_uom_id': self.product_id.uom_id.id, + 'ref': description, + 'partner_id': partner_id, + 'balance': -subcontract_service_cost, + 'account_id': credit_account_id, + } + rslt['component_credit_line_vals'] = { + 'name': description, + 'product_id': self.product_id.id, + 'quantity': qty, + 'product_uom_id': self.product_id.uom_id.id, + 'ref': description, + 'partner_id': partner_id, + 'balance': component_cost, + 'account_id': component_cost_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 7e62091595e..dc42e38bb18 100644 --- a/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py +++ b/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py @@ -8,13 +8,20 @@ from odoo.tools.float_utils import float_round, float_compare from odoo.addons.mrp_subcontracting.tests.common import TestMrpSubcontractingCommon from odoo.addons.mrp_account.tests.test_bom_price import TestBomPriceCommon + class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon): def test_subcontracting_account_flow_1(self): + # 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') - self.env.ref('product.product_category_all').property_cost_method = 'fifo' + product_category_all = self.env.ref('product.product_category_all') + product_category_all.property_cost_method = 'fifo' + product_category_all.property_valuation = 'real_time' + stock_in_acc_id = product_category_all.property_stock_account_input_categ_id.id + stock_out_acc_id = product_category_all.property_stock_account_output_categ_id.id + stock_valu_acc_id = product_category_all.property_stock_valuation_account_id.id # IN 10@10 comp1 10@20 comp2 move1 = self.env['stock.move'].create({ @@ -44,6 +51,8 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon): move2.move_line_ids.qty_done = 10.0 move2._action_done() + 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 @@ -70,6 +79,21 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon): self.assertEqual(picking_receipt.move_ids.stock_valuation_layer_ids.value, 0) self.assertEqual(picking_receipt.move_ids.product_id.value_svl, 60) + amls = self.env['account.move.line'].search([('id', 'not in', all_amls_ids)]) + all_amls_ids += amls.ids + self.assertRecordValues(amls, [ + # Receipt from subcontractor + {'account_id': stock_valu_acc_id, 'product_id': self.finished.id, 'debit': 60.0, 'credit': 0.0}, + {'account_id': stock_in_acc_id, 'product_id': self.finished.id, 'debit': 0.0, 'credit': 30.0}, + {'account_id': stock_out_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_out_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_out_acc_id, 'product_id': self.comp1.id, 'debit': 10.0, 'credit': 0.0}, + ]) + # Do the same without any additionnal cost picking_form = Form(self.env['stock.picking']) picking_form.picking_type_id = self.env.ref('stock.picking_type_in') @@ -90,6 +114,19 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon): self.assertEqual(mo.move_finished_ids.stock_valuation_layer_ids.value, 30) self.assertEqual(picking_receipt.move_ids.product_id.value_svl, 90) + amls = self.env['account.move.line'].search([('id', 'not in', all_amls_ids)]) + self.assertRecordValues(amls, [ + # Receipt from subcontractor + {'account_id': stock_in_acc_id, 'product_id': self.finished.id, 'debit': 0.0, 'credit': 30.0}, + {'account_id': stock_valu_acc_id, 'product_id': self.finished.id, 'debit': 30.0, 'credit': 0.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_out_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_out_acc_id, 'product_id': self.comp1.id, 'debit': 10.0, 'credit': 0.0}, + ]) + 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 diff --git a/addons/mrp_subcontracting_dropshipping/tests/test_anglo_saxon_valuation.py b/addons/mrp_subcontracting_dropshipping/tests/test_anglo_saxon_valuation.py index 0623d848f6a..6c7f1bae8ae 100644 --- a/addons/mrp_subcontracting_dropshipping/tests/test_anglo_saxon_valuation.py +++ b/addons/mrp_subcontracting_dropshipping/tests/test_anglo_saxon_valuation.py @@ -83,8 +83,9 @@ class TestSubcontractingDropshippingValuation(ValuationReconciliationTestCommon) {'account_id': stock_valu_acc_id, 'product_id': self.product_a.id, 'debit': 0.0, 'credit': 20.0}, {'account_id': stock_out_acc_id, 'product_id': self.product_a.id, 'debit': 20.0, 'credit': 0.0}, # Receipt from subcontractor - {'account_id': stock_in_acc_id, 'product_id': self.product_a.id, 'debit': 0.0, 'credit': 220.0}, {'account_id': stock_valu_acc_id, 'product_id': self.product_a.id, 'debit': 220.0, 'credit': 0.0}, + {'account_id': stock_in_acc_id, 'product_id': self.product_a.id, 'debit': 0.0, 'credit': 200.0}, + {'account_id': stock_out_acc_id, 'product_id': self.product_a.id, 'debit': 0.0, 'credit': 20.0}, # Delivery to subcontractor {'account_id': stock_valu_acc_id, 'product_id': self.product_b.id, 'debit': 0.0, 'credit': 20.0}, {'account_id': stock_out_acc_id, 'product_id': self.product_b.id, 'debit': 20.0, 'credit': 0.0},