From 37200abfc5684935f932bf42923add145f5dfd1e Mon Sep 17 00:00:00 2001 From: Arnold Moyaux Date: Wed, 31 Jul 2019 12:32:38 +0000 Subject: [PATCH] [REF] mrp_subcontracting: lot produced/consumed management Currently, the subcontract picking present multiple difficulties: - The user has to introduce multiple time the lot produced. In register components button and then create a new move line with the show details operation button. - Same problem with the correction system. The user has to modify the lot in details operation and then go on the subcontract production and unlock and edit it. In order to facilitate those behavior. A move line will be automaticaly created during the register components process. Also the subcontract moves for components will be available in the detail operations tab. --- addons/mrp_subcontracting/__init__.py | 1 + addons/mrp_subcontracting/__manifest__.py | 1 + addons/mrp_subcontracting/models/__init__.py | 1 + .../mrp_subcontracting/models/stock_move.py | 30 ++++++++++- .../models/stock_move_line.py | 21 ++++++++ .../models/stock_picking.py | 50 ++++--------------- .../tests/test_subcontracting.py | 15 ------ .../views/stock_move_views.xml | 26 ++++++++++ .../views/stock_picking_views.xml | 8 --- addons/mrp_subcontracting/wizard/__init__.py | 4 ++ .../wizard/mrp_product_produce.py | 40 +++++++++++++++ 11 files changed, 131 insertions(+), 66 deletions(-) create mode 100644 addons/mrp_subcontracting/models/stock_move_line.py create mode 100644 addons/mrp_subcontracting/views/stock_move_views.xml create mode 100644 addons/mrp_subcontracting/wizard/__init__.py create mode 100644 addons/mrp_subcontracting/wizard/mrp_product_produce.py diff --git a/addons/mrp_subcontracting/__init__.py b/addons/mrp_subcontracting/__init__.py index cde864bae21..35e7c9600c5 100644 --- a/addons/mrp_subcontracting/__init__.py +++ b/addons/mrp_subcontracting/__init__.py @@ -1,3 +1,4 @@ # -*- coding: utf-8 -*- from . import models +from . import wizard diff --git a/addons/mrp_subcontracting/__manifest__.py b/addons/mrp_subcontracting/__manifest__.py index 6c34d2ba291..146a620edac 100644 --- a/addons/mrp_subcontracting/__manifest__.py +++ b/addons/mrp_subcontracting/__manifest__.py @@ -12,6 +12,7 @@ 'data': [ 'data/mrp_subcontracting_data.xml', 'views/stock_warehouse_views.xml', + 'views/stock_move_views.xml', 'views/stock_picking_views.xml', 'views/mrp_bom_views.xml', 'views/res_partner_views.xml', diff --git a/addons/mrp_subcontracting/models/__init__.py b/addons/mrp_subcontracting/models/__init__.py index 98238bd9a1b..3e55733a730 100644 --- a/addons/mrp_subcontracting/models/__init__.py +++ b/addons/mrp_subcontracting/models/__init__.py @@ -4,6 +4,7 @@ from . import mrp_bom from . import res_company from . import res_partner from . import stock_move +from . import stock_move_line from . import stock_picking from . import stock_warehouse diff --git a/addons/mrp_subcontracting/models/stock_move.py b/addons/mrp_subcontracting/models/stock_move.py index 8e149dd2cbe..eba26222c8b 100644 --- a/addons/mrp_subcontracting/models/stock_move.py +++ b/addons/mrp_subcontracting/models/stock_move.py @@ -3,13 +3,36 @@ from collections import defaultdict -from odoo import models, _ -from odoo.exceptions import UserError +from odoo import fields, models class StockMove(models.Model): _inherit = 'stock.move' + is_subcontract = fields.Boolean(copy=False) + subcontract_components_ids = fields.One2many('stock.move.line', + compute='_compute_subcontract_move_line_ids', + inverse='_inverse_subcontract_move_line_ids', + string='Subcontracted Components', readonly=False) + + def action_show_details(self): + action = super(StockMove, self).action_show_details() + action['context'].update({ + 'show_lots_m2o': True, + 'show_lots_text': False, + }) + return action + + def _compute_subcontract_move_line_ids(self): + for move in self: + if move.is_subcontract: + move.subcontract_components_ids = move.move_orig_ids.production_id.move_raw_ids.move_line_ids + + def _inverse_subcontract_move_line_ids(self): + for move in self: + if move.is_subcontract: + (move.move_orig_ids.production_id.move_raw_ids.move_line_ids - move.subcontract_components_ids).unlink() + def _get_subcontract_bom(self): self.ensure_one() bom = self.env['mrp.bom']._bom_subcontract_find( @@ -35,6 +58,9 @@ class StockMove(models.Model): error_message += _('If there is well a BoM of type subcontracting defined, check if you have set the correct subcontractors on it.') raise UserError(error_message % (move.product_id.name, move.product_id.name)) subcontract_details_per_picking[move.picking_id].append((move, bom)) + move.write({ + 'is_subcontract': True, + }) for picking, subcontract_details in subcontract_details_per_picking.items(): picking._subcontracted_produce(subcontract_details) return super(StockMove, self)._action_confirm(merge=merge, merge_into=merge_into) diff --git a/addons/mrp_subcontracting/models/stock_move_line.py b/addons/mrp_subcontracting/models/stock_move_line.py new file mode 100644 index 00000000000..32ddade892e --- /dev/null +++ b/addons/mrp_subcontracting/models/stock_move_line.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models + + +class StockMoveLine(models.Model): + _inherit = 'stock.move.line' + + def write(self, values): + move_lines_subcontracted = self.filtered(lambda ml: ml.move_id.is_subcontract) + if not move_lines_subcontracted: + return super(StockMoveLine, self).write(values) + for ml in move_lines_subcontracted: + candidates = ml.move_id.move_orig_ids.move_line_ids + candidate = candidates.filtered(lambda c: + c.qty_done == ml.qty_done and ml.product_uom_qty == c.product_uom_qty and + ml.product_uom_id == c.product_uom_id and c.lot_id == ml.lot_id) + candidate = candidate and candidate[0] or self.env['stock.move.line'] + candidate.write(values) + return super(StockMoveLine, self).write(values) diff --git a/addons/mrp_subcontracting/models/stock_picking.py b/addons/mrp_subcontracting/models/stock_picking.py index b08eaf6d78a..4ab048ad799 100644 --- a/addons/mrp_subcontracting/models/stock_picking.py +++ b/addons/mrp_subcontracting/models/stock_picking.py @@ -8,7 +8,6 @@ class StockPicking(models.Model): _inherit = 'stock.picking' display_action_record_components = fields.Boolean(compute='_compute_display_action_record_components') - display_view_subcontracted_move_lines = fields.Boolean(compute='_compute_display_view_subcontracted_move_lines') @api.depends('state') def _compute_display_action_record_components(self): @@ -29,26 +28,6 @@ class StockPicking(models.Model): continue picking.display_action_record_components = True - @api.depends('state') - def _compute_display_view_subcontracted_move_lines(self): - for picking in self: - # Hide if not encoding state - if picking.state in ('draft', 'cancel'): - continue - if not picking._is_subcontract(): - continue - # Hide until state done if no move is tracked, if tracked until something was produced - subcontracted_productions = picking._get_subcontracted_productions() - subcontracted_moves = subcontracted_productions.mapped('move_raw_ids') - subcontracted_moves |= subcontracted_productions.mapped('move_finished_ids') - if all(subcontracted_move.has_tracking == 'none' for subcontracted_move in subcontracted_moves): - if picking.state != 'done': - continue - # Hide if nothing was produced - if all(subcontracted_move.quantity_done == 0 for subcontracted_move in subcontracted_moves): - continue - picking.display_view_subcontracted_move_lines = True - # ------------------------------------------------------------------------- # Action methods # ------------------------------------------------------------------------- @@ -60,29 +39,18 @@ class StockPicking(models.Model): subcontracted_production.button_mark_done() return res - def action_view_subcontracted_move_lines(self): - """ Returns a list view with the move lines of the subcontracted products. To find them, we - look on the origin moves of the move lines of the picking if there is a manufacturing order. - """ - self.ensure_one() - subcontracted_productions = self._get_subcontracted_productions() - subcontracted_move_lines = self.env['stock.move.line'] - for subcontracted_production in subcontracted_productions: - subcontracted_move_lines |= subcontracted_production.move_raw_ids.mapped('move_line_ids') - subcontracted_move_lines |= subcontracted_production.move_finished_ids.mapped('move_line_ids') - action = self.env.ref('stock.stock_move_line_action').read()[0] - action['context'] = {} - action['domain'] = [('id', 'in', subcontracted_move_lines.ids)] - return action - def action_record_components(self): self.ensure_one() - subcontracted_productions = self._get_subcontracted_productions() - to_register = subcontracted_productions.filtered(lambda mo: mo.state not in ('to_close', 'done')) - if to_register: - mo = to_register[0] + for move in self.move_lines: + production = move.move_orig_ids.production_id + if not production or production.state in ('done', 'to_close'): + continue action = self.env.ref('mrp.act_mrp_product_produce').read()[0] - action['context'] = dict(self.env.context, active_id=mo.id) + action['context'] = dict( + self.env.context, + active_id=production.id, + default_subcontract_move_id=move.id + ) return action # ------------------------------------------------------------------------- diff --git a/addons/mrp_subcontracting/tests/test_subcontracting.py b/addons/mrp_subcontracting/tests/test_subcontracting.py index f715f1466e6..58ad3928d44 100644 --- a/addons/mrp_subcontracting/tests/test_subcontracting.py +++ b/addons/mrp_subcontracting/tests/test_subcontracting.py @@ -188,7 +188,6 @@ class TestSubcontractingFlows(SavepointCase): # Nothing should be tracked self.assertFalse(picking_receipt.display_action_record_components) - self.assertFalse(picking_receipt.display_view_subcontracted_move_lines) # Check the created manufacturing order mo = self.env['mrp.production'].search([('bom_id', '=', self.bom.id)]) @@ -218,9 +217,6 @@ class TestSubcontractingFlows(SavepointCase): picking_receipt.button_validate() self.assertEquals(mo.state, 'done') - # Now that the picking is done, the details stat button should be visible - self.assertTrue(picking_receipt.display_view_subcontracted_move_lines) - # Available quantities should be negative at the subcontracting location for each components avail_qty_comp1 = self.env['stock.quant']._get_available_quantity(self.comp1, self.subcontractor_partner1.property_stock_supplier, allow_negative=True) avail_qty_comp2 = self.env['stock.quant']._get_available_quantity(self.comp2, self.subcontractor_partner1.property_stock_supplier, allow_negative=True) @@ -250,7 +246,6 @@ class TestSubcontractingFlows(SavepointCase): # Nothing should be tracked self.assertFalse(picking_receipt.display_action_record_components) - self.assertFalse(picking_receipt.display_view_subcontracted_move_lines) # Pickings should directly be created mo = self.env['mrp.production'].search([('bom_id', '=', self.bom.id)]) @@ -275,9 +270,6 @@ class TestSubcontractingFlows(SavepointCase): picking_receipt.button_validate() self.assertEquals(mo.state, 'done') - # Now that the picking is done, the details stat button should be visible - self.assertTrue(picking_receipt.display_view_subcontracted_move_lines) - # Available quantities should be negative at the subcontracting location for each components avail_qty_comp1 = self.env['stock.quant']._get_available_quantity(self.comp1, self.subcontractor_partner1.property_stock_supplier, allow_negative=True) avail_qty_comp2 = self.env['stock.quant']._get_available_quantity(self.comp2, self.subcontractor_partner1.property_stock_supplier, allow_negative=True) @@ -314,7 +306,6 @@ class TestSubcontractingFlows(SavepointCase): # Nothing should be tracked self.assertFalse(picking_receipt.display_action_record_components) - self.assertFalse(picking_receipt.display_view_subcontracted_move_lines) # Pickings should directly be created mo = self.env['mrp.production'].search([('bom_id', '=', self.bom.id)]) @@ -336,9 +327,6 @@ class TestSubcontractingFlows(SavepointCase): picking_receipt.button_validate() self.assertEquals(mo.state, 'done') - # Now that the picking is done, the details stat button should be visible - self.assertTrue(picking_receipt.display_view_subcontracted_move_lines) - # Available quantities should be negative at the subcontracting location for each components avail_qty_comp1 = self.env['stock.quant']._get_available_quantity(self.comp1, self.subcontractor_partner1.property_stock_supplier, allow_negative=True) avail_qty_comp2 = self.env['stock.quant']._get_available_quantity(self.comp2, self.subcontractor_partner1.property_stock_supplier, allow_negative=True) @@ -524,7 +512,6 @@ class TestSubcontractingTracking(TransactionCase): # We should be able to call the 'record_components' button self.assertTrue(picking_receipt.display_action_record_components) - self.assertFalse(picking_receipt.display_view_subcontracted_move_lines) # Check the created manufacturing order mo = self.env['mrp.production'].search([('bom_id', '=', self.bom_tracked.id)]) @@ -571,8 +558,6 @@ class TestSubcontractingTracking(TransactionCase): # We should not be able to call the 'record_components' button self.assertFalse(picking_receipt.display_action_record_components) - # We should see the move lines stat button - self.assertTrue(picking_receipt.display_view_subcontracted_move_lines) picking_receipt.move_lines.quantity_done = 1 picking_receipt.move_lines.move_line_ids.lot_name = 'lot00001test' diff --git a/addons/mrp_subcontracting/views/stock_move_views.xml b/addons/mrp_subcontracting/views/stock_move_views.xml new file mode 100644 index 00000000000..0f1f7a8801d --- /dev/null +++ b/addons/mrp_subcontracting/views/stock_move_views.xml @@ -0,0 +1,26 @@ + + + + stock.move.operations.form.inherit.mrp.subcontracting + stock.move + + + + +

Components

+ + + + + + + + + +
+ +

Subcontracted Product

+
+
+
+
\ No newline at end of file diff --git a/addons/mrp_subcontracting/views/stock_picking_views.xml b/addons/mrp_subcontracting/views/stock_picking_views.xml index 23145eeabbf..e5b87e618eb 100644 --- a/addons/mrp_subcontracting/views/stock_picking_views.xml +++ b/addons/mrp_subcontracting/views/stock_picking_views.xml @@ -5,14 +5,6 @@ stock.picking - - -