diff --git a/addons/mrp/__manifest__.py b/addons/mrp/__manifest__.py index 398395012d2..d68e7873145 100644 --- a/addons/mrp/__manifest__.py +++ b/addons/mrp/__manifest__.py @@ -21,7 +21,6 @@ 'wizard/stock_warn_insufficient_qty_views.xml', 'wizard/mrp_production_backorder.xml', 'wizard/mrp_consumption_warning_views.xml', - 'wizard/mrp_immediate_production_views.xml', 'wizard/stock_assign_serial_numbers.xml', 'wizard/mrp_production_split.xml', 'views/mrp_views_menus.xml', diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index 76efb19ad25..cc885a22c1c 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -243,6 +243,8 @@ class MrpProduction(models.Model): compute='_compute_show_allocation', help='Technical Field used to decide whether the button "Allocation" should be displayed.') allow_workorder_dependencies = fields.Boolean('Allow Work Order Dependencies') + show_produce = fields.Boolean(compute='_compute_show_produce', help='Technical field to check if produce button can be shown') + show_produce_all = fields.Boolean(compute='_compute_show_produce', help='Technical field to check if produce all button can be shown') _sql_constraints = [ ('name_uniq', 'unique(name, company_id)', 'Reference must be unique per Company!'), @@ -734,6 +736,14 @@ class MrpProduction(models.Model): Command.delete(move.id) for move in production.move_finished_ids if move.bom_line_id ] + @api.depends('state', 'product_qty', 'qty_producing') + def _compute_show_produce(self): + for production in self: + state_ok = production.state in ('confirmed', 'progress', 'to_close') + qty_none_or_all = production.qty_producing in (0, production.product_qty) + production.show_produce_all = state_ok and qty_none_or_all + production.show_produce = state_ok and not qty_none_or_all + @api.onchange('qty_producing', 'lot_producing_id') def _onchange_producing(self): self._set_qty_producing() @@ -1217,19 +1227,6 @@ class MrpProduction(models.Model): if self.product_id.tracking == 'serial': self._set_qty_producing() - def _action_generate_immediate_wizard(self): - view = self.env.ref('mrp.view_immediate_production') - return { - 'name': _('Immediate Production?'), - 'type': 'ir.actions.act_window', - 'view_mode': 'form', - 'res_model': 'mrp.immediate.production', - 'views': [(view.id, 'form')], - 'view_id': view.id, - 'target': 'new', - 'context': dict(self.env.context, default_mo_ids=[(4, mo.id) for mo in self]), - } - def action_confirm(self): self._check_company() for production in self: @@ -1349,7 +1346,7 @@ class MrpProduction(models.Model): :rtype: list """ issues = [] - if self.env.context.get('skip_consumption', False) or self.env.context.get('skip_immediate', False): + if self.env.context.get('skip_consumption', False): return issues for order in self: if order.consumption == 'flexible' or not order.bom_id or not order.bom_id.bom_line_ids: @@ -1755,8 +1752,6 @@ class MrpProduction(models.Model): def button_mark_done(self): self._button_mark_done_sanity_checks() - if not self.env.context.get('button_mark_done_production_ids'): - self = self.with_context(button_mark_done_production_ids=self.ids) res = self._pre_button_mark_done() if res is not True: return res @@ -1830,7 +1825,7 @@ class MrpProduction(models.Model): action = { 'res_model': 'mrp.production', 'type': 'ir.actions.act_window', - 'context': dict(context, mo_ids_to_backorder=None, button_mark_done_production_ids=None) + 'context': dict(context, mo_ids_to_backorder=None) } if len(backorders) == 1: action.update({ @@ -1846,19 +1841,24 @@ class MrpProduction(models.Model): return action def _pre_button_mark_done(self): - productions_to_immediate = self._check_immediate() - if productions_to_immediate: - return productions_to_immediate._action_generate_immediate_wizard() - + immediate_productions = self.browse() for production in self: + if not float_is_zero(production.qty_producing, precision_rounding=production.product_uom_id.rounding) or any( + not float_is_zero(ml.qty_done, precision_digits=ml.product_uom_id.rounding) for + ml in production.move_raw_ids.move_line_ids.filtered(lambda m: m.state not in ('done', 'cancel'))): + immediate_productions |= production + continue + production._set_quantities() + + for production in immediate_productions: if float_is_zero(production.qty_producing, precision_rounding=production.product_uom_id.rounding): raise UserError(_('The quantity to produce must be positive!')) if production.move_raw_ids and not any(production.move_raw_ids.mapped('quantity_done')): raise UserError(_("You must indicate a non-zero amount consumed for at least one of your components")) - consumption_issues = self._get_consumption_issues() + consumption_issues = immediate_productions._get_consumption_issues() if consumption_issues: - return self._action_generate_consumption_wizard(consumption_issues) + return immediate_productions._action_generate_consumption_wizard(consumption_issues) quantity_issues = self._get_quantity_produced_issues() if quantity_issues: @@ -2178,18 +2178,6 @@ class MrpProduction(models.Model): duplicates = co_prod_move_lines.filtered(lambda ml: ml.qty_done and ml.lot_id == lot) return bool(duplicates) - def _check_immediate(self): - immediate_productions = self.browse() - if self.env.context.get('skip_immediate'): - return immediate_productions - pd = self.env['decimal.precision'].precision_get('Product Unit of Measure') - for production in self: - if all(float_is_zero(ml.qty_done, precision_digits=pd) for - ml in production.move_raw_ids.move_line_ids.filtered(lambda m: m.state not in ('done', 'cancel')) - ) and float_is_zero(production.qty_producing, precision_digits=pd): - immediate_productions |= production - return immediate_productions - def _pre_action_split_merge_hook(self, merge=False, split=False): if not merge and not split: return True @@ -2228,3 +2216,27 @@ class MrpProduction(models.Model): continue vals['move_orig_ids'] = [Command.set(vals['move_orig_ids'])] return origs + + def _set_quantities(self): + self.ensure_one() + missing_lot_id_products = "" + if self.product_tracking in ('lot', 'serial') and not self.lot_producing_id: + self.action_generate_serial() + if self.product_tracking == 'serial' and float_compare(self.qty_producing, 1, precision_rounding=self.product_uom_id.rounding) == 1: + self.qty_producing = 1 + else: + self.qty_producing = self.product_qty - self.qty_produced + self._set_qty_producing() + for move in self.move_raw_ids.filtered(lambda m: m.state not in ['done', 'cancel']): + rounding = move.product_uom.rounding + for move_line in move.move_line_ids: + if move_line.reserved_uom_qty: + move_line.qty_done = min(move_line.reserved_uom_qty, move_line.move_id.should_consume_qty) + if float_compare(move.quantity_done, move.should_consume_qty, precision_rounding=rounding) >= 0: + break + if float_compare(move.product_uom_qty, move.quantity_done, precision_rounding=move.product_uom.rounding) == 1: + if move.has_tracking in ('serial', 'lot'): + missing_lot_id_products += "\n - %s" % move.product_id.display_name + if missing_lot_id_products: + error_msg = _('You need to supply Lot/Serial Number for products:') + missing_lot_id_products + raise UserError(error_msg) diff --git a/addons/mrp/security/ir.model.access.csv b/addons/mrp/security/ir.model.access.csv index 505dfd86d86..b57c31b160e 100644 --- a/addons/mrp/security/ir.model.access.csv +++ b/addons/mrp/security/ir.model.access.csv @@ -54,8 +54,6 @@ access_mrp_production_backorder,access.mrp.production.backorder,model_mrp_produc access_mrp_production_backorder_line,access.mrp.production.backorder.line,model_mrp_production_backorder_line,mrp.group_mrp_user,1,1,1,0 access_mrp_consumption_warning,access.mrp.consumption.warning,model_mrp_consumption_warning,mrp.group_mrp_user,1,1,1,0 access_mrp_consumption_warning_line,access.mrp.consumption.warning.line,model_mrp_consumption_warning_line,mrp.group_mrp_user,1,1,1,0 -access_mrp_immediate_production,access.mrp.immediate.production,model_mrp_immediate_production,mrp.group_mrp_user,1,1,1,0 -access_mrp_immediate_production_line,access.mrp.immediate.production.line,model_mrp_immediate_production_line,mrp.group_mrp_user,1,1,1,0 access_mrp_workcenter_tag_group_user,access.mrp.workcenter.tag,model_mrp_workcenter_tag,mrp.group_mrp_user,1,0,0,0 access_mrp_workcenter_tag_manager,access.mrp.workcenter.tag,model_mrp_workcenter_tag,mrp.group_mrp_manager,1,1,1,1 access_mrp_production_split_multi,access.mrp.production.split.multi,model_mrp_production_split_multi,mrp.group_mrp_user,1,1,1,0 diff --git a/addons/mrp/tests/common_consume_tracked_component.py b/addons/mrp/tests/common_consume_tracked_component.py index 82f78152a5d..1e5f37a70d6 100644 --- a/addons/mrp/tests/common_consume_tracked_component.py +++ b/addons/mrp/tests/common_consume_tracked_component.py @@ -220,14 +220,4 @@ class TestConsumeTrackedComponentCommon(common.TransactionCase): i += 1 if isAvailable: - mark_done_action = mrp_productions[i].button_mark_done() - immediate_production_wizard = Form( - self.env['mrp.immediate.production'] - .with_context(**mark_done_action['context']) - ).save() - error = False - try: - immediate_production_wizard.process() - except UserError: - error = True - self.assertFalse(error, "Immediate Production Wizard shall not raise an error.") + mrp_productions[i].button_mark_done() diff --git a/addons/mrp/tests/test_backorder.py b/addons/mrp/tests/test_backorder.py index 543aafdc67e..6c9bc302c89 100644 --- a/addons/mrp/tests/test_backorder.py +++ b/addons/mrp/tests/test_backorder.py @@ -291,9 +291,6 @@ class TestMrpProductionBackorder(TestMrpCommon): self.env['stock.quant']._update_available_quantity(p2, self.stock_location_components, 2.0) mo.action_assign() res_dict = mo.button_mark_done() - self.assertEqual(res_dict.get('res_model'), 'mrp.immediate.production') - immediate_wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save() - res_dict = immediate_wizard.process() self.assertEqual(res_dict.get('res_model'), 'mrp.production.backorder') backorder_wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])) @@ -302,10 +299,7 @@ class TestMrpProductionBackorder(TestMrpCommon): self.assertEqual(action.get('res_model'), 'mrp.production') backorder_mo_form = Form(self.env[action['res_model']].with_context(action['context']).browse(action['res_id'])) backorder_mo = backorder_mo_form.save() - res_dict = backorder_mo.button_mark_done() - self.assertEqual(res_dict.get('res_model'), 'mrp.immediate.production') - immediate_wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save() - immediate_wizard.process() + backorder_mo.button_mark_done() self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location), 2, "Incorrect number of final product produced.") self.assertEqual(len(self.env['stock.lot'].search([('product_id', '=', p_final.id)])), 2, "Serial Numbers were not correctly produced.") diff --git a/addons/mrp/tests/test_order.py b/addons/mrp/tests/test_order.py index a0e6c6ed150..f6f85f38524 100644 --- a/addons/mrp/tests/test_order.py +++ b/addons/mrp/tests/test_order.py @@ -1598,9 +1598,6 @@ class TestMrpOrder(TestMrpCommon): self.env['stock.quant']._update_available_quantity(p2, self.stock_location_components, 5.0) mo.action_assign() res_dict = mo.button_mark_done() - self.assertEqual(res_dict.get('res_model'), 'mrp.immediate.production') - wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save() - wizard.process() self.assertEqual(mo.move_raw_ids.mapped('state'), ['done', 'done']) self.assertEqual(mo.move_raw_ids.mapped('quantity_done'), [1, 1]) self.assertEqual(mo.move_finished_ids.state, 'done') @@ -1628,9 +1625,6 @@ class TestMrpOrder(TestMrpCommon): self.env['stock.quant']._update_available_quantity(p2, self.stock_location_components, 5.0) mo.action_assign() action = mo.button_mark_done() - self.assertEqual(action.get('res_model'), 'mrp.immediate.production') - wizard = Form(self.env[action['res_model']].with_context(action['context'])).save() - action = wizard.process() self.assertEqual(action.get('res_model'), 'mrp.production.backorder') wizard = Form(self.env[action['res_model']].with_context(action['context'])).save() action = wizard.action_backorder() @@ -1648,9 +1642,6 @@ class TestMrpOrder(TestMrpCommon): self.env['stock.quant']._update_available_quantity(p1, self.stock_location_components, 5.0) self.env['stock.quant']._update_available_quantity(p2, self.stock_location_components, 5.0) action = mo.button_mark_done() - self.assertEqual(action.get('res_model'), 'mrp.immediate.production') - wizard = Form(self.env[action['res_model']].with_context(action['context'])).save() - action = wizard.process() self.assertEqual(action.get('res_model'), 'mrp.production.backorder') wizard = Form(self.env[action['res_model']].with_context(action['context'])).save() action = wizard.action_backorder() @@ -1682,10 +1673,7 @@ class TestMrpOrder(TestMrpCommon): mo3.action_confirm() mo3.action_assign() mos = mo1 | mo2 | mo3 - res_dict = mos.button_mark_done() - self.assertEqual(res_dict.get('res_model'), 'mrp.immediate.production') - wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save() - wizard.process() + mos.button_mark_done() self.assertEqual(mos.move_raw_ids.mapped('state'), ['done'] * 6) self.assertEqual(mos.move_raw_ids.mapped('quantity_done'), [1] * 6) self.assertEqual(mos.move_finished_ids.mapped('state'), ['done'] * 3) @@ -1749,10 +1737,7 @@ class TestMrpOrder(TestMrpCommon): self.env['stock.quant']._update_available_quantity(p1, self.stock_location_components, 5.0) self.env['stock.quant']._update_available_quantity(p2, self.stock_location_components, 5.0) mo.action_assign() - res_dict = mo.button_mark_done() - self.assertEqual(res_dict.get('res_model'), 'mrp.immediate.production') - wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save() - wizard.process() + mo.button_mark_done() self.assertEqual(mo.move_raw_ids.mapped('state'), ['done'] * 2) self.assertEqual(mo.move_raw_ids.mapped('quantity_done'), [1] * 2) self.assertEqual(mo.move_finished_ids.state, 'done') @@ -1787,10 +1772,7 @@ class TestMrpOrder(TestMrpCommon): mo = mo_form.save() mo.action_confirm() mo.action_assign() - res_dict = mo.button_mark_done() - self.assertEqual(res_dict.get('res_model'), 'mrp.immediate.production') - wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save() - wizard.process() + mo.button_mark_done() self.assertEqual(mo.move_raw_ids.state, 'done') self.assertEqual(mo.move_raw_ids.quantity_done, 12) self.assertEqual(mo.move_finished_ids.state, 'done') @@ -1848,10 +1830,7 @@ class TestMrpOrder(TestMrpCommon): mo_form.bom_id = bom mo = mo_form.save() mo.action_confirm() - action = mo.button_mark_done() - self.assertEqual(action.get('res_model'), 'mrp.immediate.production') - wizard = Form(self.env[action['res_model']].with_context(action['context'])).save() - action = wizard.process() + mo.button_mark_done() self.assertEqual(mo.move_raw_ids.product_uom_qty, 0.2) self.assertEqual(mo.move_raw_ids.quantity_done, 0.2) @@ -1968,10 +1947,7 @@ class TestMrpOrder(TestMrpCommon): self.assertEqual(mo_product_final_form.reservation_state, 'assigned') # produce - res_dict = mo_product_final_form.button_mark_done() - self.assertEqual(res_dict.get('res_model'), 'mrp.immediate.production') - wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save() - wizard.process() + mo_product_final_form.button_mark_done() # check that in _generate_consumed_move_line, # we do not create an extra move line because @@ -2056,10 +2032,7 @@ class TestMrpOrder(TestMrpCommon): self.assertEqual(mo_2.workorder_ids[0].state, 'waiting') # produce - res_dict = (mo_1 | mo_2).button_mark_done() - self.assertEqual(res_dict.get('res_model'), 'mrp.immediate.production') - wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save() - wizard.process() + (mo_1 | mo_2).button_mark_done() self.assertEqual(mo_1.state, 'done') self.assertEqual(mo_2.state, 'done') @@ -2224,10 +2197,7 @@ class TestMrpOrder(TestMrpCommon): mo.action_assign() self.assertEqual(list(mo.workorder_ids.mapped("state")), ["ready"]) - res_dict = mo.button_mark_done() - self.assertEqual(res_dict.get('res_model'), 'mrp.immediate.production') - wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save() - wizard.process() + mo.button_mark_done() self.assertEqual(list(mo.workorder_ids.mapped("state")), ["done"]) def test_products_with_variants(self): diff --git a/addons/mrp/tests/test_traceability.py b/addons/mrp/tests/test_traceability.py index 14eb9d00043..80403f9a98a 100644 --- a/addons/mrp/tests/test_traceability.py +++ b/addons/mrp/tests/test_traceability.py @@ -413,9 +413,7 @@ class TestTraceability(TestMrpCommon): mo_form.product_qty = 15 mo = mo_form.save() mo.action_confirm() - action = mo.button_mark_done() - wizard = Form(self.env[action['res_model']].with_context(action['context'])).save() - wizard.process() + mo.button_mark_done() # Produce 15 x productB mo_form = Form(self.env['mrp.production']) diff --git a/addons/mrp/views/mrp_production_views.xml b/addons/mrp/views/mrp_production_views.xml index 174ac12346f..1687c86e7df 100644 --- a/addons/mrp/views/mrp_production_views.xml +++ b/addons/mrp/views/mrp_production_views.xml @@ -92,25 +92,25 @@
-