Files
enterprise-addons/mrp_workorder/models/mrp_production.py
T

299 lines
12 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import base64
from ast import literal_eval
from datetime import datetime
from dateutil.relativedelta import relativedelta
from odoo import fields, models, _, api
from odoo.exceptions import UserError
from odoo.tools import file_open
class MrpProduction(models.Model):
_inherit = 'mrp.production'
_start_name = "date_start"
_stop_name = "date_finished"
check_ids = fields.One2many('quality.check', 'production_id', string="Checks")
employee_ids = fields.Many2many('hr.employee', string="working employees", compute='_compute_employee_ids', compute_sudo=True)
log_note = fields.Text(string="Log note")
picking_type_auto_close = fields.Boolean(related='picking_type_id.auto_close_production')
state_color = fields.Integer("State Color", compute='_compute_state_color')
@api.depends('state')
def _compute_state_color(self):
colors = {'draft': 0, 'confirmed': 4, 'progress': 3, 'to_close': 5, 'done': 10, 'cancel': 1}
for production in self:
production.state_color = colors[production.state]
def write(self, vals):
res = super().write(vals)
if 'lot_producing_ids' in vals and self._has_workorders():
self.workorder_ids.check_ids.filtered(lambda c: c.test_type_id.technical_name == 'register_production').write({'lot_ids': self.lot_producing_ids.ids})
return res
def action_add_byproduct(self):
self.ensure_one()
action = self.env['stock.move'].with_context(order_id=self.id).action_add_from_catalog_byproduct()
action['target'] = 'new'
action['context']['dialog_size'] = 'extra-large'
return action
def action_add_component(self):
self.ensure_one()
action = self.env['stock.move'].with_context(order_id=self.id).action_add_from_catalog_raw()
action['target'] = 'new'
action['context']['dialog_size'] = 'extra-large'
return action
def action_add_workorder(self):
default_blocking_wo_id = self.workorder_ids[-1].id if self.workorder_ids else False
return {
'type': 'ir.actions.act_window',
'res_model': 'mrp_production.additional.workorder',
'views': [[self.env.ref('mrp_workorder.view_mrp_production_additional_workorder_wizard').id, 'form']],
'name': _('Add Work Order'),
'target': 'new',
'context': {
'default_production_id': self.id,
'default_blocked_by_workorder_id': default_blocking_wo_id,
}
}
def action_log_note(self):
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'res_id': self.id,
'res_model': 'mrp.production',
'views': [[self.env.ref('mrp_workorder.mrp_production_view_form_log_note').id, 'form']],
'name': _('Add log note'),
'target': 'new',
'context': {
'default_production_id': self.id,
}
}
def action_open_shop_floor(self):
""" Opens shop floor on Overview workcenter with a filter for current MO """
self.ensure_one()
action = self.env['ir.actions.actions']._for_xml_id('mrp_workorder.action_mrp_display')
action['context'] = literal_eval(action['context']) | {
'search_default_name': self.name,
'workcenter_id': 0, # Sets active WC to Overview
'search_default_blocked': True,
'shouldHideNewWorkcenterButton': True,
'shouldKeepMoFilter': True,
}
del action['context']['search_default_filter_ready']
return action
@api.depends('workorder_ids', 'workorder_ids.employee_ids')
def _compute_employee_ids(self):
for record in self:
record.employee_ids = record.workorder_ids.employee_ids
def pre_button_mark_done(self):
res = super().pre_button_mark_done()
if res is True:
self.workorder_ids.verify_quality_checks()
return res
def _update_catalog_line_quantity(self, line, quantity, **kwargs):
super()._update_catalog_line_quantity(line, quantity)
if kwargs.get('from_shop_floor'):
line.quantity = quantity
line.manual_consumption = True
def _get_new_catalog_line_values(self, product_id, quantity, **kwargs):
values = super()._get_new_catalog_line_values(product_id, quantity)
if kwargs.get('from_shop_floor'):
values.update({
'additional': True,
'manual_consumption': True,
})
if workorder_id := kwargs.get('workorder_id'):
workorder = self.env['mrp.workorder'].browse(workorder_id)
values['workorder_id'] = workorder_id
values['operation_id'] = workorder.operation_id.id
return values
def can_load_samples(self):
return self.sudo().env['mrp.production'].search_count([]) == 0
def action_load_samples(self):
if not self.can_load_samples():
raise UserError(_('Unable to load samples when you already have existing manufacturing orders'))
warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)], limit=1)
def read_file_datas(path):
with file_open(path, "rb") as f:
return base64.b64encode(f.read())
products = [{'xml_id': xmlid, 'noupdate': True, 'values': {
'name': name,
'is_storable': True,
'uom_id': self.env.ref('uom.product_uom_unit').id,
'description': desc,
'default_code': code,
'image_1920': read_file_datas(img),
}} for (xmlid, name, desc, code, img) in (
(
'mrp.product_product_computer_desk',
'Table',
'Solid wood table',
'SAMPLE_TABLE',
'mrp/static/img/table.png',
),
(
'mrp.product_product_computer_desk_head',
'Table Top',
'Solid wood is a durable natural material.',
'SAMPLE_TABLE_TOP',
'mrp/static/img/table_top.png'
),
(
'mrp.product_product_computer_desk_leg',
'Table Leg',
'18″ x 2½″ Square Leg',
'SAMPLE_TABLE_LEG',
'mrp/static/img/table_leg.png'
),
)]
table, tabletop, tableleg = self.env['product.product']._load_records(products, True)
quants = [{'xml_id': xmlid, 'noupdate': True, 'values': {
'product_id': prod,
'inventory_quantity': qty,
'location_id': warehouse.lot_stock_id.id,
}} for (xmlid, prod, qty) in (
('mrp.mrp_inventory_1', tabletop.id, 1),
('mrp.mrp_inventory_2', tableleg.id, 4),
)]
self.env['stock.quant']._load_records(quants, True)._apply_inventory()
bom = self.env['mrp.bom']._load_records([{'xml_id': 'mrp.mrp_bom_desk', 'noupdate': True, 'values': {
'product_tmpl_id': table.product_tmpl_id.id,
'product_uom_id': self.env.ref('uom.product_uom_unit').id,
'sequence': 3,
'consumption': 'flexible',
'days_to_prepare_mo': 3,
}}], True)
bom_lines = [{'xml_id': xmlid, 'noupdate': True, 'values': {
'product_id': prod,
'product_qty': qty,
'product_uom_id': self.env.ref('uom.product_uom_unit').id,
'sequence': seq,
'bom_id': bom.id,
}} for (xmlid, prod, qty, seq) in (
('mrp.mrp_bom_desk_line_1', tabletop.id, 1, 1),
('mrp.mrp_bom_desk_line_2', tableleg.id, 4, 2),
)]
bom_lines = self.env['mrp.bom.line']._load_records(bom_lines, True)
MO = self.env['mrp.production']._load_records([{'xml_id': 'mrp.mrp_production_3', 'noupdate': True, 'values': {
'product_id': table.id,
'product_uom_id': self.env.ref('uom.product_uom_unit').id,
'product_qty': 1,
'date_start': datetime.today() + relativedelta(days=1),
'bom_id': bom.id,
}}], True)
self.env['stock.rule'].run_scheduler()
MO.action_confirm()
if self.env.user.has_group('mrp.group_mrp_routings'):
WC = self.env['mrp.workcenter']._load_records([{'xml_id': 'mrp.mrp_workcenter_3', 'noupdate': True, 'values': {
'name': 'Assembly line 1',
'resource_calendar_id': self.env.ref('resource.resource_calendar_std').id,
}}], True)
routing = self.env['mrp.routing.workcenter']._load_records([{
'xml_id': 'mrp.mrp_routing_workcenter_5', 'noupdate': True, 'values': {
'bom_id': bom.id,
'workcenter_id': WC.id,
'time_cycle': 120,
'sequence': 10,
'name': 'Assembly',
}
}], True)
bom_lines.operation_id = routing
quality_points = [{'xml_id': xmlid, 'noupdate': True, 'values': {
'product_ids': [table.id],
'picking_type_ids': [warehouse.manu_type_id.id],
'operation_id': routing.id,
'test_type_id': self.env.ref(testtype).id,
'note': note,
'title': title,
'sequence': seq,
'component_id': comp,
'worksheet_document': worksheet_doc and read_file_datas(worksheet_doc),
}} for (xmlid, testtype, note, title, seq, comp, worksheet_doc) in (
(
'mrp_workorder.quality_point_register_serial_production',
'mrp_workorder.test_type_register_production',
'Register the produced quantity.',
'Register production',
5,
None,
None,
),
(
'mrp_workorder.quality_point_component_registration',
'mrp_workorder.test_type_register_consumed_materials',
'Please register consumption of the table top.',
'Component Registration: Table Head',
20,
tabletop.id,
'mrp/static/img/cutting-worksheet-1.pdf',
),
(
'mrp_workorder.quality_point_instructions',
'quality.test_type_instructions',
'Please ensure you are using the new SRX679 screwdriver.',
'Choice of screwdriver',
30,
None,
'mrp/static/img/cutting-worksheet-1.pdf',
),
(
'mrp_workorder.quality_point_component_registration_2',
'mrp_workorder.test_type_register_consumed_materials',
'Please register consumption of the table legs.',
'Component Registration: Table Legs',
70,
tableleg.id,
'mrp/static/img/cutting-worksheet-4.pdf',
),
(
'mrp_workorder.quality_point_register_production',
'quality.test_type_instructions',
'Please attach the legs to the table as shown below.',
'Table Legs',
60,
None,
'mrp/static/img/cutting-worksheet-4.pdf',
),
(
'mrp_workorder.quality_point_print_labels',
'mrp_workorder.test_type_print_label',
None,
'Print Labels',
90,
None,
None,
),
)]
self.env['quality.point']._load_records(quality_points, True)
MO.action_update_bom()