diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/mrp_subcontracting_account | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/mrp_subcontracting_account')
6 files changed, 190 insertions, 0 deletions
diff --git a/addons/mrp_subcontracting_account/__init__.py b/addons/mrp_subcontracting_account/__init__.py new file mode 100644 index 00000000..dc5e6b69 --- /dev/null +++ b/addons/mrp_subcontracting_account/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import models diff --git a/addons/mrp_subcontracting_account/__manifest__.py b/addons/mrp_subcontracting_account/__manifest__.py new file mode 100644 index 00000000..c43bb0c1 --- /dev/null +++ b/addons/mrp_subcontracting_account/__manifest__.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +{ + 'name': 'Subcontracting Management with Stock Valuation', + 'version': '0.1', + 'category': 'Hidden', + 'description': """ + This bridge module allows to manage subcontracting with valuation. + """, + 'depends': ['mrp_subcontracting', 'mrp_account'], + 'installable': True, + 'auto_install': True, + 'license': 'LGPL-3', +} diff --git a/addons/mrp_subcontracting_account/models/__init__.py b/addons/mrp_subcontracting_account/models/__init__.py new file mode 100644 index 00000000..ac951744 --- /dev/null +++ b/addons/mrp_subcontracting_account/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import stock_picking diff --git a/addons/mrp_subcontracting_account/models/stock_picking.py b/addons/mrp_subcontracting_account/models/stock_picking.py new file mode 100644 index 00000000..087c60c0 --- /dev/null +++ b/addons/mrp_subcontracting_account/models/stock_picking.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models +from odoo.osv.expression import OR + + +class StockPicking(models.Model): + _inherit = 'stock.picking' + + def action_view_stock_valuation_layers(self): + action = super(StockPicking, self).action_view_stock_valuation_layers() + subcontracted_productions = self._get_subcontracted_productions() + if not subcontracted_productions: + return action + domain = action['domain'] + 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 diff --git a/addons/mrp_subcontracting_account/tests/__init__.py b/addons/mrp_subcontracting_account/tests/__init__.py new file mode 100644 index 00000000..99d0c6d6 --- /dev/null +++ b/addons/mrp_subcontracting_account/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import test_subcontracting_account diff --git a/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py b/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py new file mode 100644 index 00000000..d857828f --- /dev/null +++ b/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.mrp_subcontracting.tests.common import TestMrpSubcontractingCommon +from odoo.tests.common import Form + +class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon): + def test_subcontracting_account_flow_1(self): + 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' + + # IN 10@10 comp1 10@20 comp2 + move1 = self.env['stock.move'].create({ + 'name': 'IN 10 units @ 10.00 per unit', + 'location_id': self.supplier_location.id, + 'location_dest_id': self.env.company.subcontracting_location_id.id, + 'product_id': self.comp1.id, + 'product_uom': self.uom_unit.id, + 'product_uom_qty': 10.0, + 'price_unit': 10.0, + }) + move1._action_confirm() + move1._action_assign() + move1.move_line_ids.qty_done = 10.0 + move1._action_done() + move2 = self.env['stock.move'].create({ + 'name': 'IN 10 units @ 20.00 per unit', + 'location_id': self.supplier_location.id, + 'location_dest_id': self.env.company.subcontracting_location_id.id, + 'product_id': self.comp2.id, + 'product_uom': self.uom_unit.id, + 'product_uom_qty': 10.0, + 'price_unit': 20.0, + }) + move2._action_confirm() + move2._action_assign() + move2.move_line_ids.qty_done = 10.0 + move2._action_done() + + 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() + picking_receipt.move_lines.price_unit = 30.0 + + picking_receipt.action_confirm() + picking_receipt.move_lines.quantity_done = 1.0 + picking_receipt._action_done() + + mo = picking_receipt._get_subcontracted_productions() + # Finished is made of 1 comp1 and 1 comp2. + # Cost of comp1 = 10 + # Cost of comp2 = 20 + # --> Cost of finished = 10 + 20 = 30 + # Additionnal cost = 30 (from the purchase order line or directly set on the stock move here) + # Total cost of subcontracting 1 unit of finished = 30 + 30 = 60 + 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) + + # Check the created manufacturing order + mo = self.env['mrp.production'].search([('bom_id', '=', self.bom.id)]) + wh = picking_receipt.picking_type_id.warehouse_id + + 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) |
