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/wizard | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/mrp/wizard')
| -rw-r--r-- | addons/mrp/wizard/__init__.py | 8 | ||||
| -rw-r--r-- | addons/mrp/wizard/change_production_qty.py | 103 | ||||
| -rw-r--r-- | addons/mrp/wizard/change_production_qty_views.xml | 33 | ||||
| -rw-r--r-- | addons/mrp/wizard/mrp_consumption_warning.py | 60 | ||||
| -rw-r--r-- | addons/mrp/wizard/mrp_consumption_warning_views.xml | 57 | ||||
| -rw-r--r-- | addons/mrp/wizard/mrp_immediate_production.py | 82 | ||||
| -rw-r--r-- | addons/mrp/wizard/mrp_immediate_production_views.xml | 27 | ||||
| -rw-r--r-- | addons/mrp/wizard/mrp_production_backorder.py | 38 | ||||
| -rw-r--r-- | addons/mrp/wizard/mrp_production_backorder.xml | 44 | ||||
| -rw-r--r-- | addons/mrp/wizard/mrp_workcenter_block_view.xml | 41 | ||||
| -rw-r--r-- | addons/mrp/wizard/stock_warn_insufficient_qty.py | 19 | ||||
| -rw-r--r-- | addons/mrp/wizard/stock_warn_insufficient_qty_views.xml | 13 |
12 files changed, 525 insertions, 0 deletions
diff --git a/addons/mrp/wizard/__init__.py b/addons/mrp/wizard/__init__.py new file mode 100644 index 00000000..d90ee8f5 --- /dev/null +++ b/addons/mrp/wizard/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import change_production_qty +from . import stock_warn_insufficient_qty +from . import mrp_production_backorder +from . import mrp_consumption_warning +from . import mrp_immediate_production diff --git a/addons/mrp/wizard/change_production_qty.py b/addons/mrp/wizard/change_production_qty.py new file mode 100644 index 00000000..4a58bc7b --- /dev/null +++ b/addons/mrp/wizard/change_production_qty.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, _ +from odoo.exceptions import UserError +from odoo.tools import float_is_zero, float_round + + +class ChangeProductionQty(models.TransientModel): + _name = 'change.production.qty' + _description = 'Change Production Qty' + + mo_id = fields.Many2one('mrp.production', 'Manufacturing Order', + required=True, ondelete='cascade') + product_qty = fields.Float( + 'Quantity To Produce', + digits='Product Unit of Measure', required=True) + + @api.model + def default_get(self, fields): + res = super(ChangeProductionQty, self).default_get(fields) + if 'mo_id' in fields and not res.get('mo_id') and self._context.get('active_model') == 'mrp.production' and self._context.get('active_id'): + res['mo_id'] = self._context['active_id'] + if 'product_qty' in fields and not res.get('product_qty') and res.get('mo_id'): + res['product_qty'] = self.env['mrp.production'].browse(res['mo_id']).product_qty + return res + + @api.model + def _update_finished_moves(self, production, new_qty, old_qty): + """ Update finished product and its byproducts. This method only update + the finished moves not done or cancel and just increase or decrease + their quantity according the unit_ratio. It does not use the BoM, BoM + modification during production would not be taken into consideration. + """ + modification = {} + for move in production.move_finished_ids: + if move.state in ('done', 'cancel'): + continue + qty = (new_qty - old_qty) * move.unit_factor + modification[move] = (move.product_uom_qty + qty, move.product_uom_qty) + move.write({'product_uom_qty': move.product_uom_qty + qty}) + return modification + + def change_prod_qty(self): + precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') + for wizard in self: + production = wizard.mo_id + produced = sum(production.move_finished_ids.filtered(lambda m: m.product_id == production.product_id).mapped('quantity_done')) + if wizard.product_qty < produced: + format_qty = '%.{precision}f'.format(precision=precision) + raise UserError(_( + "You have already processed %(quantity)s. Please input a quantity higher than %(minimum)s ", + quantity=format_qty % produced, + minimum=format_qty % produced + )) + old_production_qty = production.product_qty + new_production_qty = wizard.product_qty + done_moves = production.move_finished_ids.filtered(lambda x: x.state == 'done' and x.product_id == production.product_id) + qty_produced = production.product_id.uom_id._compute_quantity(sum(done_moves.mapped('product_qty')), production.product_uom_id) + + factor = (new_production_qty - qty_produced) / (old_production_qty - qty_produced) + update_info = production._update_raw_moves(factor) + documents = {} + for move, old_qty, new_qty in update_info: + iterate_key = production._get_document_iterate_key(move) + if iterate_key: + document = self.env['stock.picking']._log_activity_get_documents({move: (new_qty, old_qty)}, iterate_key, 'UP') + for key, value in document.items(): + if documents.get(key): + documents[key] += [value] + else: + documents[key] = [value] + production._log_manufacture_exception(documents) + finished_moves_modification = self._update_finished_moves(production, new_production_qty - qty_produced, old_production_qty - qty_produced) + if finished_moves_modification: + production._log_downside_manufactured_quantity(finished_moves_modification) + production.write({'product_qty': new_production_qty}) + + for wo in production.workorder_ids: + operation = wo.operation_id + wo.duration_expected = wo._get_duration_expected(ratio=new_production_qty / old_production_qty) + quantity = wo.qty_production - wo.qty_produced + if production.product_id.tracking == 'serial': + quantity = 1.0 if not float_is_zero(quantity, precision_digits=precision) else 0.0 + else: + quantity = quantity if (quantity > 0 and not float_is_zero(quantity, precision_digits=precision)) else 0 + wo._update_qty_producing(quantity) + if wo.qty_produced < wo.qty_production and wo.state == 'done': + wo.state = 'progress' + if wo.qty_produced == wo.qty_production and wo.state == 'progress': + wo.state = 'done' + if wo.next_work_order_id.state == 'pending': + wo.next_work_order_id.state = 'ready' + # assign moves; last operation receive all unassigned moves + # TODO: following could be put in a function as it is similar as code in _workorders_create + # TODO: only needed when creating new moves + moves_raw = production.move_raw_ids.filtered(lambda move: move.operation_id == operation and move.state not in ('done', 'cancel')) + if wo == production.workorder_ids[-1]: + moves_raw |= production.move_raw_ids.filtered(lambda move: not move.operation_id) + moves_finished = production.move_finished_ids.filtered(lambda move: move.operation_id == operation) #TODO: code does nothing, unless maybe by_products? + moves_raw.mapped('move_line_ids').write({'workorder_id': wo.id}) + (moves_finished + moves_raw).write({'workorder_id': wo.id}) + return {} diff --git a/addons/mrp/wizard/change_production_qty_views.xml b/addons/mrp/wizard/change_production_qty_views.xml new file mode 100644 index 00000000..8d5004d7 --- /dev/null +++ b/addons/mrp/wizard/change_production_qty_views.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <data> + + <!-- Change Product Quantity --> + <record id="view_change_production_qty_wizard" model="ir.ui.view"> + <field name="name">Change Quantity To Produce</field> + <field name="model">change.production.qty</field> + <field name="arch" type="xml"> + <form string="Change Product Qty"> + <group> + <field name="product_qty"/> + <field name="mo_id" invisible="1"/> + </group> + <footer> + <button name="change_prod_qty" string="Approve" + colspan="1" type="object" class="btn-primary"/> + <button string="Cancel" class="btn-secondary" special="cancel" /> + </footer> + </form> + </field> + </record> + + <record id="action_change_production_qty" model="ir.actions.act_window"> + <field name="name">Change Quantity To Produce</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">change.production.qty</field> + <field name="view_mode">form</field> + <field name="target">new</field> + </record> + + </data> +</odoo> diff --git a/addons/mrp/wizard/mrp_consumption_warning.py b/addons/mrp/wizard/mrp_consumption_warning.py new file mode 100644 index 00000000..bae87759 --- /dev/null +++ b/addons/mrp/wizard/mrp_consumption_warning.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models, api + + +class MrpConsumptionWarning(models.TransientModel): + _name = 'mrp.consumption.warning' + _description = "Wizard in case of consumption in warning/strict and more component has been used for a MO (related to the bom)" + + mrp_production_ids = fields.Many2many('mrp.production') + mrp_production_count = fields.Integer(compute="_compute_mrp_production_count") + + consumption = fields.Selection([ + ('flexible', 'Allowed'), + ('warning', 'Allowed with warning'), + ('strict', 'Blocked')], compute="_compute_consumption") + mrp_consumption_warning_line_ids = fields.One2many('mrp.consumption.warning.line', 'mrp_consumption_warning_id') + + @api.depends("mrp_production_ids") + def _compute_mrp_production_count(self): + for wizard in self: + wizard.mrp_production_count = len(wizard.mrp_production_ids) + + @api.depends("mrp_consumption_warning_line_ids.consumption") + def _compute_consumption(self): + for wizard in self: + consumption_map = set(wizard.mrp_consumption_warning_line_ids.mapped("consumption")) + wizard.consumption = "strict" in consumption_map and "strict" or "warning" in consumption_map and "warning" or "flexible" + + def action_confirm(self): + action_from_do_finish = False + if self.env.context.get('from_workorder'): + if self.env.context.get('active_model') == 'mrp.workorder': + action_from_do_finish = self.env['mrp.workorder'].browse(self.env.context.get('active_id')).do_finish() + action_from_mark_done = self.mrp_production_ids.with_context(skip_consumption=True).button_mark_done() + return action_from_do_finish or action_from_mark_done + + def action_cancel(self): + if self.env.context.get('from_workorder') and len(self.mrp_production_ids) == 1: + return { + 'type': 'ir.actions.act_window', + 'res_model': 'mrp.production', + 'views': [[self.env.ref('mrp.mrp_production_form_view').id, 'form']], + 'res_id': self.mrp_production_ids.id, + 'target': 'main', + } + +class MrpConsumptionWarningLine(models.TransientModel): + _name = 'mrp.consumption.warning.line' + _description = "Line of issue consumption" + + mrp_consumption_warning_id = fields.Many2one('mrp.consumption.warning', "Parent Wizard", readonly=True, required=True, ondelete="cascade") + mrp_production_id = fields.Many2one('mrp.production', "Manufacturing Order", readonly=True, required=True, ondelete="cascade") + consumption = fields.Selection(related="mrp_production_id.consumption") + + product_id = fields.Many2one('product.product', "Product", readonly=True, required=True) + product_uom_id = fields.Many2one('uom.uom', "Unit of Measure", related="product_id.uom_id", readonly=True) + product_consumed_qty_uom = fields.Float("Consumed", readonly=True) + product_expected_qty_uom = fields.Float("To Consume", readonly=True) diff --git a/addons/mrp/wizard/mrp_consumption_warning_views.xml b/addons/mrp/wizard/mrp_consumption_warning_views.xml new file mode 100644 index 00000000..a09d66db --- /dev/null +++ b/addons/mrp/wizard/mrp_consumption_warning_views.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <data> + + <!-- MO Consumption Warning --> + <record id="view_mrp_consumption_warning_form" model="ir.ui.view"> + <field name="name">Consumption Warning</field> + <field name="model">mrp.consumption.warning</field> + <field name="arch" type="xml"> + <form string="Consumption Warning"> + <field name="mrp_production_ids" invisible="1"/> + <field name="consumption" invisible="1"/> + <field name="mrp_production_count" invisible="1"/> + <div class="m-2"> + You consumed a different quantity than expected for the following products. + <b attrs="{'invisible': [('consumption', '=', 'strict')]}"> + Please confirm it has been done on purpose. + </b> + <b attrs="{'invisible': [('consumption', '!=', 'strict')]}"> + Please review your component consumption or ask a manager to validate + <span attrs="{'invisible':[('mrp_production_count', '!=', 1)]}">this manufacturing order</span> + <span attrs="{'invisible':[('mrp_production_count', '=', 1)]}">these manufacturing orders</span>. + </b> + </div> + <field name="mrp_consumption_warning_line_ids" nolabel="1"> + <tree create="0" delete="0" editable="top"> + <field name="mrp_production_id" attrs="{'column_invisible':[('parent.mrp_production_count', '=', 1)]}" force_save="1"/> + <field name="consumption" invisible="1" force_save="1"/> + <field name="product_id" force_save="1"/> + <field name="product_uom_id" groups="uom.group_uom" force_save="1"/> + <field name="product_expected_qty_uom" force_save="1"/> + <field name="product_consumed_qty_uom" force_save="1"/> + </tree> + </field> + <footer> + <button name="action_confirm" string="Force" + groups="mrp.group_mrp_manager" attrs="{'invisible': [('consumption', '!=', 'strict')]}" + colspan="1" type="object" class="btn-primary"/> + <button name="action_confirm" string="Confirm" attrs="{'invisible': [('consumption', '=', 'strict')]}" + colspan="1" type="object" class="btn-primary"/> + <button name="action_cancel" string="Review Consumption" + colspan="1" type="object" class="btn-primary"/> + </footer> + </form> + </field> + </record> + + <record id="action_mrp_consumption_warning" model="ir.actions.act_window"> + <field name="name">Consumption Warning</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">mrp.consumption.warning</field> + <field name="view_mode">form</field> + <field name="target">new</field> + </record> + + </data> +</odoo> diff --git a/addons/mrp/wizard/mrp_immediate_production.py b/addons/mrp/wizard/mrp_immediate_production.py new file mode 100644 index 00000000..d1e1b27d --- /dev/null +++ b/addons/mrp/wizard/mrp_immediate_production.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import _, api, fields, models +from odoo.exceptions import UserError +from odoo.tools import float_compare + + +class MrpImmediateProductionLine(models.TransientModel): + _name = 'mrp.immediate.production.line' + _description = 'Immediate Production Line' + + immediate_production_id = fields.Many2one('mrp.immediate.production', 'Immediate Production', required=True) + production_id = fields.Many2one('mrp.production', 'Production', required=True) + to_immediate = fields.Boolean('To Process') + + +class MrpImmediateProduction(models.TransientModel): + _name = 'mrp.immediate.production' + _description = 'Immediate Production' + + @api.model + def default_get(self, fields): + res = super().default_get(fields) + if 'immediate_production_line_ids' in fields: + if self.env.context.get('default_mo_ids'): + res['mo_ids'] = self.env.context['default_mo_ids'] + res['immediate_production_line_ids'] = [(0, 0, {'to_immediate': True, 'production_id': mo_id[1]}) for mo_id in res['mo_ids']] + return res + + mo_ids = fields.Many2many('mrp.production', 'mrp_production_production_rel') + show_productions = fields.Boolean(compute='_compute_show_production') + immediate_production_line_ids = fields.One2many( + 'mrp.immediate.production.line', + 'immediate_production_id', + string="Immediate Production Lines") + + @api.depends('immediate_production_line_ids') + def _compute_show_production(self): + for wizard in self: + wizard.show_productions = len(wizard.immediate_production_line_ids.production_id) > 1 + + def process(self): + productions_to_do = self.env['mrp.production'] + productions_not_to_do = self.env['mrp.production'] + for line in self.immediate_production_line_ids: + if line.to_immediate is True: + productions_to_do |= line.production_id + else: + productions_not_to_do |= line.production_id + + for production in productions_to_do: + error_msg = "" + if production.product_tracking in ('lot', 'serial') and not production.lot_producing_id: + production.action_generate_serial() + if production.product_tracking == 'serial' and float_compare(production.qty_producing, 1, precision_rounding=production.product_uom_id.rounding) == 1: + production.qty_producing = 1 + else: + production.qty_producing = production.product_qty - production.qty_produced + production._set_qty_producing() + for move in production.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.product_uom_qty: + move_line.qty_done = min(move_line.product_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'): + error_msg += "\n - %s" % move.product_id.display_name + + if error_msg: + error_msg = _('You need to supply Lot/Serial Number for products:') + error_msg + raise UserError(error_msg) + + productions_to_validate = self.env.context.get('button_mark_done_production_ids') + if productions_to_validate: + productions_to_validate = self.env['mrp.production'].browse(productions_to_validate) + productions_to_validate = productions_to_validate - productions_not_to_do + return productions_to_validate.with_context(skip_immediate=True).button_mark_done() + return True + diff --git a/addons/mrp/wizard/mrp_immediate_production_views.xml b/addons/mrp/wizard/mrp_immediate_production_views.xml new file mode 100644 index 00000000..9c98f67c --- /dev/null +++ b/addons/mrp/wizard/mrp_immediate_production_views.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<odoo> + <record id="view_immediate_production" model="ir.ui.view"> + <field name="name">mrp.immediate.production.view.form</field> + <field name="model">mrp.immediate.production</field> + <field name="arch" type="xml"> + <form string="Immediate production?"> + <group> + <p>You have not recorded <i>produced</i> quantities yet, by clicking on <i>apply</i> Odoo will produce all the finished products and consume all components.</p> + </group> + + <field name="show_productions" invisible="1"/> + <field name="immediate_production_line_ids" nolabel="1" attrs="{'invisible': [('show_productions', '=', False)]}">> + <tree create="0" delete="0" editable="top"> + <field name="production_id"/> + <field name="to_immediate" widget="boolean_toggle"/> + </tree> + </field> + + <footer> + <button name="process" string="Apply" type="object" class="btn-primary"/> + <button string="Cancel" class="btn-secondary" special="cancel" /> + </footer> + </form> + </field> + </record> +</odoo> diff --git a/addons/mrp/wizard/mrp_production_backorder.py b/addons/mrp/wizard/mrp_production_backorder.py new file mode 100644 index 00000000..681b3fff --- /dev/null +++ b/addons/mrp/wizard/mrp_production_backorder.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + + +class MrpProductionBackorderLine(models.TransientModel): + _name = 'mrp.production.backorder.line' + _description = "Backorder Confirmation Line" + + mrp_production_backorder_id = fields.Many2one('mrp.production.backorder', 'MO Backorder', required=True, ondelete="cascade") + mrp_production_id = fields.Many2one('mrp.production', 'Manufacturing Order', required=True, ondelete="cascade", readonly=True) + to_backorder = fields.Boolean('To Backorder') + + +class MrpProductionBackorder(models.TransientModel): + _name = 'mrp.production.backorder' + _description = "Wizard to mark as done or create back order" + + mrp_production_ids = fields.Many2many('mrp.production') + + mrp_production_backorder_line_ids = fields.One2many( + 'mrp.production.backorder.line', + 'mrp_production_backorder_id', + string="Backorder Confirmation Lines") + show_backorder_lines = fields.Boolean("Show backorder lines", compute="_compute_show_backorder_lines") + + @api.depends('mrp_production_backorder_line_ids') + def _compute_show_backorder_lines(self): + for wizard in self: + wizard.show_backorder_lines = len(wizard.mrp_production_backorder_line_ids) > 1 + + def action_close_mo(self): + return self.mrp_production_ids.with_context(skip_backorder=True).button_mark_done() + + def action_backorder(self): + mo_ids_to_backorder = self.mrp_production_backorder_line_ids.filtered(lambda l: l.to_backorder).mrp_production_id.ids + return self.mrp_production_ids.with_context(skip_backorder=True, mo_ids_to_backorder=mo_ids_to_backorder).button_mark_done() diff --git a/addons/mrp/wizard/mrp_production_backorder.xml b/addons/mrp/wizard/mrp_production_backorder.xml new file mode 100644 index 00000000..7b116eb3 --- /dev/null +++ b/addons/mrp/wizard/mrp_production_backorder.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <data> + + <!-- MO Backorder --> + <record id="view_mrp_production_backorder_form" model="ir.ui.view"> + <field name="name">Create Backorder</field> + <field name="model">mrp.production.backorder</field> + <field name="arch" type="xml"> + <form string="Create a Backorder"> + <group> + <p> + Create a backorder if you expect to process the remaining products later. Do not create a backorder if you will not process the remaining products. + </p> + </group> + <field name="show_backorder_lines" invisible="1"/> + <field name="mrp_production_backorder_line_ids" nolabel="1" attrs="{'invisible': [('show_backorder_lines', '=', False)]}"> + <tree create="0" delete="0" editable="top"> + <field name="mrp_production_id" force_save="1"/> + <field name="to_backorder" widget="boolean_toggle"/> + </tree> + </field> + <footer> + <button name="action_backorder" string="Create backorder" + colspan="1" type="object" class="btn-primary" attrs="{'invisible': [('show_backorder_lines', '!=', False)]}"/> + <button name="action_backorder" string="Validate" + colspan="1" type="object" class="btn-primary" attrs="{'invisible': [('show_backorder_lines', '=', False)]}"/> + <button name="action_close_mo" type="object" string="No Backorder" attrs="{'invisible': [('show_backorder_lines', '!=', False)]}"/> + <button string="Discard" class="btn-secondary" special="cancel" /> + </footer> + </form> + </field> + </record> + + <record id="action_mrp_production_backorder" model="ir.actions.act_window"> + <field name="name">You produced less than initial demand</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">mrp.production.backorder</field> + <field name="view_mode">form</field> + <field name="target">new</field> + </record> + + </data> +</odoo> diff --git a/addons/mrp/wizard/mrp_workcenter_block_view.xml b/addons/mrp/wizard/mrp_workcenter_block_view.xml new file mode 100644 index 00000000..8104b8ea --- /dev/null +++ b/addons/mrp/wizard/mrp_workcenter_block_view.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <!-- Workcenter Block Dialog --> + <record id="mrp_workcenter_block_wizard_form" model="ir.ui.view"> + <field name="name">mrp.workcenter.productivity.form</field> + <field name="model">mrp.workcenter.productivity</field> + <field name="arch" type="xml"> + <form string="Block Workcenter"> + <group> + <field name="loss_id" class="oe_inline" domain="[('manual','=',True)]"/> + <field name="description" placeholder="Add a description..."/> + <field name="workcenter_id" invisible="1"/> + <field name="company_id" invisible="1"/> + </group> + <footer> + <button name="button_block" string="Block" type="object" class="btn-danger text-uppercase"/> + <button string="Cancel" class="btn-secondary" special="cancel" /> + </footer> + </form> + </field> + </record> + + <record id="act_mrp_block_workcenter" model="ir.actions.act_window"> + <field name="name">Block Workcenter</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">mrp.workcenter.productivity</field> + <field name="view_mode">form</field> + <field name="context">{'default_workcenter_id': active_id}</field> + <field name="view_id" eval="mrp_workcenter_block_wizard_form"/> + <field name="target">new</field> + </record> + + <record id="act_mrp_block_workcenter_wo" model="ir.actions.act_window"> + <field name="name">Block Workcenter</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">mrp.workcenter.productivity</field> + <field name="view_mode">form</field> + <field name="view_id" eval="mrp_workcenter_block_wizard_form"/> + <field name="target">new</field> + </record> +</odoo> diff --git a/addons/mrp/wizard/stock_warn_insufficient_qty.py b/addons/mrp/wizard/stock_warn_insufficient_qty.py new file mode 100644 index 00000000..335c5424 --- /dev/null +++ b/addons/mrp/wizard/stock_warn_insufficient_qty.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + + +class StockWarnInsufficientQtyUnbuild(models.TransientModel): + _name = 'stock.warn.insufficient.qty.unbuild' + _inherit = 'stock.warn.insufficient.qty' + _description = 'Warn Insufficient Unbuild Quantity' + + unbuild_id = fields.Many2one('mrp.unbuild', 'Unbuild') + + def _get_reference_document_company_id(self): + return self.unbuild_id.company_id + + def action_done(self): + self.ensure_one() + return self.unbuild_id.action_unbuild() diff --git a/addons/mrp/wizard/stock_warn_insufficient_qty_views.xml b/addons/mrp/wizard/stock_warn_insufficient_qty_views.xml new file mode 100644 index 00000000..63df4691 --- /dev/null +++ b/addons/mrp/wizard/stock_warn_insufficient_qty_views.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <record id="stock_warn_insufficient_qty_unbuild_form_view" model="ir.ui.view"> + <field name="name">stock.warn.insufficient.qty.unbuild</field> + <field name="model">stock.warn.insufficient.qty.unbuild</field> + <field name="inherit_id" ref="stock.stock_warn_insufficient_qty_form_view"/> + <field name="arch" type="xml"> + <xpath expr="//div[@name='description']" position="inside"> + Do you confirm you want to unbuild <strong><field name="quantity" readonly="True"/></strong><field name="product_uom_name" readonly="True" class="mx-1"/>from location <strong><field name="location_id" readonly="True"/></strong>? This may lead to inconsistencies in your inventory. + </xpath> + </field> + </record> +</odoo> |
