[IMP] mrp: Remove mrp.immediate.production model
closes odoo/odoo#108446 Task: 3094741 Related: odoo/upgrade#4163 Signed-off-by: William Henrotin (whe) <whe@odoo.com>
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
@@ -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()
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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'])
|
||||
|
||||
@@ -92,25 +92,25 @@
|
||||
<header>
|
||||
<field name="confirm_cancel" invisible="1"/>
|
||||
<field name="show_lock" invisible="1"/>
|
||||
<button name="button_mark_done" attrs="{'invisible': ['|', '|', ('state', 'in', ('draft', 'cancel', 'done', 'to_close')), ('qty_producing', '=', 0), ('move_raw_ids', '!=', [])]}" string="Validate" type="object" class="oe_highlight"
|
||||
confirm="There are no components to consume. Are you still sure you want to continue?" data-hotkey="g"/>
|
||||
<button name="button_mark_done" attrs="{'invisible': ['|', '|', ('state', 'in', ('draft', 'cancel', 'done', 'to_close')), ('qty_producing', '=', 0), ('move_raw_ids', '=', [])]}" string="Validate" type="object" class="oe_highlight" data-hotkey="g"/>
|
||||
<field name="show_produce" invisible="1"/>
|
||||
<field name="show_produce_all" invisible="1"/>
|
||||
<button name="button_mark_done" attrs="{'invisible': [
|
||||
'|',
|
||||
('move_raw_ids', '=', []),
|
||||
'&',
|
||||
('show_produce', '=', False)]}" string="Produce" type="object" class="oe_highlight" data-hotkey="g"/>
|
||||
<button name="button_mark_done" attrs="{'invisible': [
|
||||
'|',
|
||||
('state', 'not in', ('confirmed', 'progress')),
|
||||
('qty_producing', '!=', 0),
|
||||
('state', '!=', 'to_close')]}" string="Mark as Done" type="object" class="oe_highlight" data-hotkey="g"/>
|
||||
('move_raw_ids', '=', []),
|
||||
('show_produce_all', '=', False)]}" string="Produce All" type="object" class="oe_highlight" data-hotkey="g"/>
|
||||
<button name="button_mark_done" attrs="{'invisible': [
|
||||
'|',
|
||||
('move_raw_ids', '!=', []),
|
||||
'&',
|
||||
('show_produce', '=', False)]}" string="Produce" type="object" class="oe_highlight" data-hotkey="g"
|
||||
confirm="There are no components to consume. Are you still sure you want to continue?"/>
|
||||
<button name="button_mark_done" attrs="{'invisible': [
|
||||
'|',
|
||||
('state', 'not in', ('confirmed', 'progress')),
|
||||
('qty_producing', '!=', 0),
|
||||
('state', '!=', 'to_close')]}" string="Mark as Done" type="object" class="oe_highlight" data-hotkey="g"
|
||||
('move_raw_ids', '!=', []),
|
||||
('show_produce_all', '=', False)]}" string="Produce All" type="object" class="oe_highlight" data-hotkey="g"
|
||||
confirm="There are no components to consume. Are you still sure you want to continue?"/>
|
||||
<button name="action_confirm" attrs="{'invisible': [('state', '!=', 'draft')]}" string="Confirm" type="object" class="oe_highlight" data-hotkey="v"/>
|
||||
<button name="button_plan" attrs="{'invisible': ['|', '|', ('state', 'not in', ('confirmed', 'progress', 'to_close')), ('workorder_ids', '=', []), ('is_planned', '=', True)]}" type="object" string="Plan" class="oe_highlight" data-hotkey="x"/>
|
||||
@@ -330,7 +330,8 @@
|
||||
<field name="location_dest_id" domain="[('id', 'child_of', parent.location_dest_id)]" invisible="1"/>
|
||||
<field name="state" invisible="1" force_save="1"/>
|
||||
<field name="should_consume_qty" invisible="1"/>
|
||||
<field name="product_uom_qty" widget="mrp_should_consume" force_save="1" string="To Consume" attrs="{'readonly': ['&', ('parent.state', '!=', 'draft'), '|', '&', ('parent.state', 'not in', ('confirmed', 'progress', 'to_close')), ('parent.is_planned', '!=', True), ('parent.is_locked', '=', True)]}"/>
|
||||
<field name="product_uom_qty" force_save="1" string="To Consume" attrs="{'readonly': ['&', ('parent.state', '!=', 'draft'), '|', '&', ('parent.state', 'not in', ('confirmed', 'progress', 'to_close')), ('parent.is_planned', '!=', True), ('parent.is_locked', '=', True)], 'column_invisible': [('parent.show_produce_all', '=', False)]}"/>
|
||||
<field name="product_uom_qty" widget="mrp_should_consume" force_save="1" string="To Consume" attrs="{'readonly': ['&', ('parent.state', '!=', 'draft'), '|', '&', ('parent.state', 'not in', ('confirmed', 'progress', 'to_close')), ('parent.is_planned', '!=', True), ('parent.is_locked', '=', True)], 'column_invisible': [('parent.show_produce_all', '=', True)]}"/>
|
||||
<field name="product_uom" attrs="{'readonly': [('state', '!=', 'draft'), ('id', '!=', False)]}" options="{'no_open': True, 'no_create': True}" groups="uom.group_uom"/>
|
||||
<field name="product_type" invisible="1"/>
|
||||
<field name="product_qty" invisible="1" readonly="1"/>
|
||||
|
||||
@@ -5,6 +5,5 @@ 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
|
||||
from . import stock_assign_serial_numbers
|
||||
from . import mrp_production_split
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
# -*- 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.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'):
|
||||
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
|
||||
@@ -1,27 +0,0 @@
|
||||
<?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 colspan="2">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" data-hotkey="q"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel" data-hotkey="z" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -219,8 +219,7 @@ class TestAnalyticAccount(TestMrpAnalyticAccount):
|
||||
self.assertEqual(len(mo.move_raw_ids.analytic_account_line_id), 0)
|
||||
|
||||
# Mark as done
|
||||
wizard_dict = mo.button_mark_done()
|
||||
Form(self.env[(wizard_dict.get('res_model'))].with_context(wizard_dict['context'])).save().process()
|
||||
mo.button_mark_done()
|
||||
self.assertEqual(mo.state, 'done')
|
||||
self.assertEqual(len(mo.move_raw_ids.analytic_account_line_id), 1)
|
||||
|
||||
|
||||
@@ -90,9 +90,7 @@ class TestRepairTraceability(TestMrpCommon):
|
||||
mo = mo_form.save()
|
||||
mo.action_confirm()
|
||||
mo.action_assign()
|
||||
action = mo.button_mark_done()
|
||||
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
|
||||
wizard.process()
|
||||
mo.button_mark_done()
|
||||
return mo
|
||||
|
||||
stock_location = self.env.ref('stock.stock_location_stock')
|
||||
|
||||
@@ -765,7 +765,7 @@ tour.stepUtils.openBuggerMenu("li.breadcrumb-item.active:contains('Manufacturing
|
||||
run: "text 1",
|
||||
},
|
||||
|
||||
...tour.stepUtils.statusbarButtonsSteps('Mark as Done', _t("Mark as Done"), ".o_statusbar_status .btn.dropdown-toggle:contains('To Close')"),
|
||||
...tour.stepUtils.statusbarButtonsSteps('Produce All', _t("Produce All"), ".o_statusbar_status .btn.dropdown-toggle:contains('To Close')"),
|
||||
{
|
||||
edition: "enterprise",
|
||||
trigger: '.o_menu_toggle',
|
||||
|
||||
Reference in New Issue
Block a user