summaryrefslogtreecommitdiff
path: root/addons/mrp_subcontracting_account
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/mrp_subcontracting_account
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/mrp_subcontracting_account')
-rw-r--r--addons/mrp_subcontracting_account/__init__.py4
-rw-r--r--addons/mrp_subcontracting_account/__manifest__.py15
-rw-r--r--addons/mrp_subcontracting_account/models/__init__.py4
-rw-r--r--addons/mrp_subcontracting_account/models/stock_picking.py25
-rw-r--r--addons/mrp_subcontracting_account/tests/__init__.py4
-rw-r--r--addons/mrp_subcontracting_account/tests/test_subcontracting_account.py138
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)