[IMP] mrp,mrp_*,repair: MRP back to basics 6

mrp
===
- no time has been recorded on operations then give warning with apply button

- do not allow to mass edit UOM in any manufacturing state

- set value of lot/serial from MO and set read only on unbuild from MO

- remove "archive operation" icon

repair
======
Currently it is not possible to select a return on a repair order unless save it first. so after this commit user can able to select it without save it.
only show picking related to selected product

closes odoo/odoo#106571

Task: 2845380
X-original-commit: dd60647ce41547ecd00bbde45ddf564a7ada91c7
Related: odoo/enterprise#34403
Signed-off-by: William Henrotin (whe) <whe@odoo.com>
This commit is contained in:
Jigar Vaghela
2022-11-25 18:55:35 +01:00
committed by William Henrotin
parent 34fabe5469
commit 82c1443254
9 changed files with 23 additions and 38 deletions
+10 -3
View File
@@ -1791,8 +1791,11 @@ class MrpProduction(models.Model):
'state': 'done',
'product_uom_qty': 0.0,
})
diff_per_production = {}
for production in self:
diff_per_production[production] = 1
if production.qty_produced != production.product_qty:
diff_per_production[production] = production.qty_produced/production.product_qty
production.write({
'date_finished': fields.Datetime.now(),
'product_qty': production.qty_produced,
@@ -1801,8 +1804,11 @@ class MrpProduction(models.Model):
'state': 'done',
})
for workorder in self.workorder_ids.filtered(lambda w: w.state not in ('done', 'cancel')):
workorder.duration_expected = workorder._get_duration_expected()
for workorder in self.workorder_ids:
if workorder.state not in ('done', 'cancel'):
workorder.duration_expected = workorder._get_duration_expected()
if workorder.duration == 0.0:
workorder.duration = workorder.duration_expected * diff_per_production[workorder.production_id]
if not backorders:
if self.env.context.get('from_workorder'):
@@ -1968,6 +1974,7 @@ class MrpProduction(models.Model):
'view_id': self.env.ref('mrp.mrp_unbuild_form_view_simplified').id,
'type': 'ir.actions.act_window',
'context': {'default_product_id': self.product_id.id,
'default_lot_id': self.lot_producing_id.id,
'default_mo_id': self.id,
'default_company_id': self.company_id.id,
'default_location_id': self.location_dest_id.id,
+2 -14
View File
@@ -53,8 +53,7 @@ class MrpUnbuild(models.Model):
mo_bom_id = fields.Many2one('mrp.bom', 'Bill of Material used on the Production Order', related='mo_id.bom_id')
lot_id = fields.Many2one(
'stock.lot', 'Lot/Serial Number',
domain="[('product_id', '=', product_id), ('company_id', '=', company_id)]", check_company=True,
states={'done': [('readonly', True)]})
domain="[('product_id', '=', product_id), ('company_id', '=', company_id)]", check_company=True)
has_tracking=fields.Selection(related='product_id.tracking', readonly=True)
location_id = fields.Many2one(
'stock.location', 'Source Location',
@@ -102,23 +101,12 @@ class MrpUnbuild(models.Model):
self.product_id = self.mo_id.product_id.id
self.bom_id = self.mo_id.bom_id
self.product_uom_id = self.mo_id.product_uom_id
self.lot_id = self.mo_id.lot_producing_id
if self.has_tracking == 'serial':
self.product_qty = 1
else:
self.product_qty = self.mo_id.product_qty
if self.lot_id and self.lot_id not in self.mo_id.move_finished_ids.move_line_ids.lot_id:
return {'warning': {
'title': _("Warning"),
'message': _("The selected serial number does not correspond to the one used in the manufacturing order, please select another one.")
}}
@api.onchange('lot_id')
def _onchange_lot_id(self):
if self.mo_id and self.lot_id and self.lot_id not in self.mo_id.move_finished_ids.move_line_ids.lot_id:
return {'warning': {
'title': _("Warning"),
'message': _("The selected serial number does not correspond to the one used in the manufacturing order, please select another one.")
}}
@api.onchange('product_id')
def _onchange_product_id(self):
-1
View File
@@ -349,7 +349,6 @@ class TestTraceability(TestMrpCommon):
unbuild_form = Form(self.env['mrp.unbuild'])
unbuild_form.mo_id = mo
unbuild_form.lot_id = lot
unbuild_form.save().action_unbuild()
mo_form = Form(self.env['mrp.production'])
-11
View File
@@ -305,13 +305,6 @@ class TestUnbuild(TestMrpCommon):
self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location, lot_id=lot_final), 5, 'You should have consumed 3 final product in stock')
with self.assertRaises(AssertionError):
x.product_id = p_final
x.bom_id = bom
x.mo_id = mo
x.product_qty = 3
x.save()
self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location, lot_id=lot_final), 5, 'You should have consumed 3 final product in stock')
x = Form(self.env['mrp.unbuild'])
@@ -319,7 +312,6 @@ class TestUnbuild(TestMrpCommon):
x.bom_id = bom
x.mo_id = mo
x.product_qty = 3
x.lot_id = lot_final
x.save().action_unbuild()
self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location, lot_id=lot_final), 2, 'You should have consumed 3 final product in stock')
@@ -331,7 +323,6 @@ class TestUnbuild(TestMrpCommon):
x.bom_id = bom
x.mo_id = mo
x.product_qty = 2
x.lot_id = lot_final
x.save().action_unbuild()
self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location, lot_id=lot_final), 0, 'You should have 0 finalproduct in stock')
@@ -343,7 +334,6 @@ class TestUnbuild(TestMrpCommon):
x.bom_id = bom
x.mo_id = mo
x.product_qty = 5
x.lot_id = lot_final
x.save().action_unbuild()
self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location, lot_id=lot_final, allow_negative=True), -5, 'You should have negative quantity for final product in stock')
@@ -814,7 +804,6 @@ class TestUnbuild(TestMrpCommon):
#unbuild order
unbuild_form = Form(self.env['mrp.unbuild'])
unbuild_form.mo_id = mo
unbuild_form.lot_id = product_1_sn
unbuild_form.save().action_unbuild()
#mo2
+4 -4
View File
@@ -17,7 +17,7 @@
<field name="priority" optional="show" widget="priority" nolabel="1"/>
<field name="message_needaction" invisible="1"/>
<field name="name" decoration-bf="1"/>
<field name="date_planned_start" readonly="1" optional="show" widget="remaining_days"/>
<field name="date_planned_start" optional="show" widget="remaining_days"/>
<field name="date_deadline" widget="remaining_days" attrs="{'invisible': [('state', 'in', ['done', 'cancel'])]}" optional="hide"/>
<field name="product_id" readonly="1" optional="show"/>
<field name="lot_producing_id" optional="hide"/>
@@ -34,7 +34,7 @@
decoration-danger="reservation_state != 'assigned' and components_availability_state == 'late'"/>
<field name="reservation_state" optional="hide" decoration-danger="reservation_state == 'confirmed'" decoration-success="reservation_state == 'assigned'"/>
<field name="product_qty" sum="Total Qty" string="Quantity" readonly="1" optional="show"/>
<field name="product_uom_id" string="UoM" options="{'no_open':True,'no_create':True}" groups="uom.group_uom" optional="show"/>
<field name="product_uom_id" string="UoM" readonly="1" options="{'no_open':True,'no_create':True}" groups="uom.group_uom" optional="show"/>
<field name="production_duration_expected" attrs="{'invisible': [('production_duration_expected', '=', 0)]}" groups="mrp.group_mrp_routings" widget="float_time" sum="Total expected duration" optional="show"/>
<field name="production_real_duration" attrs="{'invisible': [('production_real_duration', '=', 0)]}" groups="mrp.group_mrp_routings" widget="float_time" sum="Total real duration" optional="show"/>
<field name="company_id" readonly="1" groups="base.group_multi_company" optional="show"/>
@@ -348,11 +348,11 @@
<field name="manual_consumption" invisible="1" force_save="1"/>
<field name="show_details_visible" invisible="1"/>
<field name="lot_ids" widget="many2many_tags"
optional="hide"
optional="hide"
readonly="1"
string="Lot/Serial Numbers"
help="Displays the consumed Lot/Serial Numbers."
groups="stock.group_production_lot"
groups="stock.group_production_lot"
attrs="{'invisible': ['|', ('show_details_visible', '=', False), ('parent.state', '=', 'draft')],
'column_invisible': [('parent.show_lot_ids', '=', False)]}"
options="{'create': [('parent.use_create_components_lots', '!=', False)]}"
+1 -1
View File
@@ -49,7 +49,7 @@
<attribute name="attrs">{'column_invisible': [('parent.product_id', '!=', False)]}</attribute>
</xpath>
<xpath expr="//field[@name='bom_product_template_attribute_value_ids']" position="after">
<button name="action_archive" class="btn-link" type="object" string="Archive Operation" icon="fa-times"/>
<button name="action_archive" class="oe_right" type="object" string="Archive Operation"/>
</xpath>
<xpath expr="//field[@name='blocked_by_operation_ids']" position="replace">
</xpath>
+2 -2
View File
@@ -117,7 +117,7 @@
<field name="location_id" options="{'no_create': True}" groups="stock.group_stock_multi_locations"/>
<field name="location_dest_id" options="{'no_create': True}" groups="stock.group_stock_multi_locations"/>
<field name="has_tracking" invisible="1"/>
<field name="lot_id" attrs="{'invisible': [('has_tracking', '=', 'none')], 'required': [('has_tracking', '!=', 'none')]}" groups="stock.group_production_lot"/>
<field name="lot_id" attrs="{'invisible': [('has_tracking', '=', 'none')], 'required': [('has_tracking', '!=', 'none')], 'readonly':['|', ('mo_id','!=',False), ('state', '=', 'done')]}" groups="stock.group_production_lot" force_save="1"/>
<field name="company_id" groups="base.group_multi_company"/>
</group>
</group>
@@ -156,7 +156,7 @@
<field name="location_id" options="{'no_create': True}" groups="stock.group_stock_multi_locations"/>
<field name="location_dest_id" options="{'no_create': True}" groups="stock.group_stock_multi_locations"/>
<field name="has_tracking" invisible="1"/>
<field name="lot_id" attrs="{'invisible': [('has_tracking', '=', 'none')], 'required': [('has_tracking', '!=', 'none')]}" groups="stock.group_production_lot"/>
<field name="lot_id" readonly="1" attrs="{'invisible': [('has_tracking', '=', 'none')], 'required': [('has_tracking', '!=', 'none')]}" groups="stock.group_production_lot"/>
<field name="company_id" groups="base.group_multi_company" readonly="1"/>
</group>
</group>
+3 -1
View File
@@ -131,13 +131,15 @@ class Repair(models.Model):
invoice_state = fields.Selection(string='Invoice State', related='invoice_id.state')
priority = fields.Selection([('0', 'Normal'), ('1', 'Urgent')], default='0', string="Priority")
@api.depends('product_id')
def _compute_allowed_picking_type_ids(self):
'''
computes the ids of return picking types
'''
out_picking_types = self.env['stock.picking.type'].search_read(domain=[('code', '=', 'outgoing')],
fields=['return_picking_type_id'], load='')
self.allowed_picking_type_ids = [pick_type['return_picking_type_id'] for pick_type in out_picking_types]
self.allowed_picking_type_ids = [
pt['return_picking_type_id'] for pt in out_picking_types if pt['return_picking_type_id']]
@api.depends('partner_id')
def _compute_default_address_id(self):
+1 -1
View File
@@ -89,7 +89,7 @@
<field name="address_id" groups="account.group_delivery_invoice_address"/>
<field name="sale_order_id"/>
<field name="allowed_picking_type_ids" invisible="1"/>
<field name="picking_id" domain="[('picking_type_id','in', allowed_picking_type_ids)]" options="{'no_create': True}"/>
<field name="picking_id" domain="[('picking_type_id','in', allowed_picking_type_ids), ('product_id','=',product_id)]" options="{'no_create': True}"/>
</group>
<group>
<field name="schedule_date"/>