307 lines
22 KiB
Python
307 lines
22 KiB
Python
# -*- coding: utf-8 -*-
|
||
# Part of YiZuo. See LICENSE file for full copyright and licensing details.
|
||
import logging
|
||
from odoo.exceptions import UserError, ValidationError
|
||
from datetime import datetime
|
||
from odoo import models, api, fields, _
|
||
from odoo.tools import groupby
|
||
|
||
|
||
class ReworkWizard(models.TransientModel):
|
||
_name = 'sf.rework.wizard'
|
||
_description = '返工向导'
|
||
|
||
workorder_id = fields.Many2one('mrp.workorder', string='工单')
|
||
product_id = fields.Many2one('product.product')
|
||
production_id = fields.Many2one('mrp.production', string='制造订单号')
|
||
workorder_ids = fields.Many2many('mrp.workorder', 'rework_wizard_to_work_order', string='所有工单',
|
||
domain="[('production_id', '=', production_id),('state','=','done')]")
|
||
hidden_workorder_ids = fields.Char('')
|
||
rework_reason = fields.Selection(
|
||
[("programming", "编程"), ("cutter", "刀具"), ("clamping", "装夹"),
|
||
("operate computer", "操机"),
|
||
("technology", "工艺"), ("customer redrawing", "客户改图")], string="原因")
|
||
detailed_reason = fields.Text('详细原因')
|
||
routing_type = fields.Selection([
|
||
('装夹预调', '装夹预调'),
|
||
('CNC加工', 'CNC加工')], string="工序类型")
|
||
# 根据工单的加工面来显示
|
||
processing_panel_id = fields.Many2many('sf.processing.panel', string="加工面")
|
||
is_reprogramming = fields.Boolean(string='申请重新编程', default=False)
|
||
is_reprogramming_readonly = fields.Boolean(string='申请重新编程(只读)', default=False)
|
||
is_clamp_measure = fields.Boolean(string='保留装夹测量数据', default=True)
|
||
reprogramming_num = fields.Integer('重新编程次数', default=0)
|
||
programming_state = fields.Selection(
|
||
[('待编程', '待编程'), ('编程中', '编程中'), ('已编程', '已编程'), ('已编程未下发', '已编程未下发'),
|
||
('已下发', '已下发')],
|
||
string='编程状态')
|
||
|
||
tool_state = fields.Selection(string='功能刀具状态', related='production_id.tool_state')
|
||
|
||
@api.onchange('hidden_workorder_ids')
|
||
def _onchange_hidden_workorder_ids(self):
|
||
for item in self:
|
||
if item.hidden_workorder_ids not in ['', None, False]:
|
||
hidden_workorder_list = item.hidden_workorder_ids.split(',')
|
||
# 获取加工面对应需要返工的工单
|
||
rw_ids = item.workorder_ids.filtered(
|
||
lambda w: str(w.ids[0]) in hidden_workorder_list and w.processing_panel not in ['', None, False])
|
||
grouped_rw_ids = {key: list(group) for key, group in groupby(rw_ids, key=lambda w: w.processing_panel)}
|
||
for panel, panel_rw_ids in grouped_rw_ids.items():
|
||
work_ids = item.workorder_ids.filtered(lambda w: w.state == 'done' and w.processing_panel == panel)
|
||
if len(work_ids) == 3 and len(panel_rw_ids) != 3:
|
||
for work_id in work_ids:
|
||
if work_id not in panel_rw_ids:
|
||
hidden_workorder_list.append(str(work_id.ids[0]))
|
||
elif len(work_ids) == 2 and len(panel_rw_ids) < 2 and panel_rw_ids[0].name == 'CNC加工':
|
||
if rw_ids.filtered(lambda w: (w.sequence < panel_rw_ids[0].sequence
|
||
and w.processing_panel != panel_rw_ids[0].processing_panel)):
|
||
hidden_workorder_list.append(str(work_ids.filtered(
|
||
lambda w: (w.processing_panel == panel_rw_ids[0].processing_panel
|
||
and w.name == '装夹预调')).ids[0]))
|
||
hidden_workorder_list.sort()
|
||
item.hidden_workorder_ids = ','.join(hidden_workorder_list)
|
||
|
||
def efficacy_rework_wo(self, wk_ids):
|
||
"""限制判断 """
|
||
# 判断检测结果待处理所对应的工单是否勾选
|
||
result_ids = self.production_id.detection_result_ids.filtered(lambda dr: dr.handle_result == '待处理')
|
||
work_id_list = []
|
||
if result_ids:
|
||
work_id_list = [self.workorder_ids.filtered(
|
||
lambda wk: (wk.name == result_id.routing_type and wk.processing_panel == result_id.processing_panel
|
||
and wk.state == 'done')).id
|
||
for result_id in result_ids]
|
||
if len(wk_ids.filtered(lambda wk: wk.id in work_id_list)) != len(work_id_list):
|
||
raise ValidationError('存在【检测结果】为【待处理】所对应的工单未进行勾选!!!')
|
||
# 获取已完成的标准工单
|
||
grouped_rw_ids = {key: list(group) for key, group in groupby(wk_ids, key=lambda w: w.processing_panel)}
|
||
for panel, panel_rw_ids in grouped_rw_ids.items():
|
||
# 1、当制造订单内ZM面的工单都已完成时,返工勾选工序时只能勾选上ZM面的所有工序进行返工
|
||
work_ids = self.workorder_ids.filtered(lambda w: w.state == 'done' and w.processing_panel == panel)
|
||
if len(work_ids) == 3 and len(panel_rw_ids) != 3:
|
||
raise ValidationError(
|
||
'因为[%s]面的工单已全部完成,如果要对[%s]面的工单进行返工,请勾选这个面的所有工单。' % (panel, panel))
|
||
# 2、当FM工单在CNC工单进行选择返工,并将已全部完成的ZM面工序全部勾选上时,FM工单上所有的已完成的工单(装夹预调工单)也必须进行勾选
|
||
if not wk_ids.filtered(lambda wk: wk.name == '装夹预调' and wk.processing_panel == panel):
|
||
if wk_ids.filtered(lambda wk: wk.name == 'CNC加工' and wk.processing_panel == panel):
|
||
sequence_max = wk_ids.filtered(lambda wk: wk.name == 'CNC加工' and wk.processing_panel == panel).sequence
|
||
for wk_id in wk_ids.filtered(lambda wk: wk.sequence < sequence_max):
|
||
if len(wk_ids.filtered(lambda wk: wk.processing_panel == wk_id.processing_panel)) == 3:
|
||
raise ValidationError(
|
||
'由于在[%s]面之前存在整个面进行了勾选的情况,所以在勾选了[%s]面的【CNC加工】工单的时,请勾选[%s]面的装夹预调工单!' % (
|
||
panel, panel, panel))
|
||
|
||
def confirm(self):
|
||
if self.routing_type in ['装夹预调', 'CNC加工']:
|
||
self.is_clamp_measure = False
|
||
self.workorder_id.is_rework = True
|
||
self.production_id.write({'detection_result_ids': [(0, 0, {
|
||
'rework_reason': self.rework_reason,
|
||
'detailed_reason': self.detailed_reason,
|
||
'processing_panel': self.workorder_id.processing_panel,
|
||
'routing_type': self.workorder_id.routing_type,
|
||
'handle_result': '待处理' if self.workorder_id.test_results == '返工' or self.workorder_id.is_rework is True else '',
|
||
'test_results': '返工' if not self.routing_type == 'CNC加工' else self.workorder_id.test_results,
|
||
'test_report': self.workorder_id.detection_report})]})
|
||
self.workorder_id.button_finish()
|
||
else:
|
||
if self.hidden_workorder_ids:
|
||
hidden_workorder_list = self.hidden_workorder_ids.split(',')
|
||
rework_workorder_ids = self.workorder_ids.filtered(lambda w: str(w.id) in hidden_workorder_list)
|
||
# 调用效验方法
|
||
self.efficacy_rework_wo(rework_workorder_ids)
|
||
else:
|
||
raise ValidationError('请选择返工工单!!!')
|
||
if rework_workorder_ids:
|
||
clamp_workorder_ids = None
|
||
if rework_workorder_ids:
|
||
# 限制
|
||
# 1、单独返工CNC工单则不解绑托盘RFID,如单独返工装夹预调工单,则自动解绑托盘RFID;
|
||
# 2、返工CNC工单和装夹预调工单则自动解绑RFID
|
||
clamp_workorder_ids = rework_workorder_ids.filtered(lambda rp: rp.routing_type == '装夹预调')
|
||
if clamp_workorder_ids:
|
||
for clamp_workorder_id in clamp_workorder_ids:
|
||
self.production_id.workorder_ids.filtered(
|
||
lambda wk: wk.processing_panel == clamp_workorder_id.processing_panel).write(
|
||
{'rfid_code': None})
|
||
# 返工工单状态设置为【返工】
|
||
rework_workorder_ids.write({'state': 'rework'})
|
||
# 查询返工工单对应的工艺设计记录,并调用方法拼接数据,用于创建新的工单
|
||
workorders_values = []
|
||
for work in rework_workorder_ids:
|
||
route = self.production_id.technology_design_ids.filtered(
|
||
lambda item: (item.route_id.name in work.name and item.process_parameters_id
|
||
and item.process_parameters_id == work.surface_technics_parameters_id) or
|
||
(item.route_id.name == work.name and item.panel
|
||
and item.panel == work.processing_panel))
|
||
if route:
|
||
work_list = self.env['mrp.workorder'].json_workorder_str(self.production_id, route[0])
|
||
work_list[2].update({'tag_type': '重新加工', 'sequence': 0})
|
||
workorders_values.append(work_list)
|
||
# 创建新工单,并进行返工配置的相关操作
|
||
if workorders_values:
|
||
# 创建新工单、工序排序、完成检测结果单据
|
||
self.production_id.write({'workorder_ids': workorders_values, 'is_rework': True})
|
||
new_work_ids = self.production_id.workorder_ids.filtered(lambda kw: kw.sequence == 0)
|
||
new_pre_workorder_ids = self.production_id.workorder_ids.filtered(
|
||
lambda kw: kw.routing_type == '装夹预调' and kw.sequence == 0)
|
||
self.production_id._reset_work_order_sequence()
|
||
self.production_id.detection_result_ids.filtered(
|
||
lambda ap1: ap1.handle_result == '待处理').write({'handle_result': '已处理'})
|
||
panels = [] # 返工的加工面
|
||
# ===================保留装夹测量数据=====================
|
||
if self.is_clamp_measure and clamp_workorder_ids and new_pre_workorder_ids:
|
||
for new_pre_workorder in new_pre_workorder_ids:
|
||
if new_pre_workorder.processing_panel and new_pre_workorder.processing_panel not in panels:
|
||
panels.append(new_pre_workorder.processing_panel)
|
||
for rework_clamp_workorder in clamp_workorder_ids:
|
||
if new_pre_workorder.sequence == rework_clamp_workorder.sequence + 1:
|
||
new_pre_workorder.write(
|
||
{'X1_axis': rework_clamp_workorder.X1_axis,
|
||
'Y1_axis': rework_clamp_workorder.Y1_axis
|
||
, 'Z1_axis': rework_clamp_workorder.Z1_axis,
|
||
'X2_axis': rework_clamp_workorder.X2_axis
|
||
, 'Y2_axis': rework_clamp_workorder.Y2_axis,
|
||
'Z2_axis': rework_clamp_workorder.Z2_axis
|
||
, 'X3_axis': rework_clamp_workorder.X3_axis,
|
||
'Y3_axis': rework_clamp_workorder.Y3_axis
|
||
, 'Z3_axis': rework_clamp_workorder.Z3_axis,
|
||
'X4_axis': rework_clamp_workorder.X4_axis
|
||
, 'Y4_axis': rework_clamp_workorder.Y4_axis,
|
||
'Z4_axis': rework_clamp_workorder.Z4_axis
|
||
, 'X5_axis': rework_clamp_workorder.X5_axis,
|
||
'Y5_axis': rework_clamp_workorder.Y5_axis
|
||
, 'Z5_axis': rework_clamp_workorder.Z5_axis,
|
||
'X6_axis': rework_clamp_workorder.X6_axis
|
||
, 'Y6_axis': rework_clamp_workorder.Y6_axis,
|
||
'Z6_axis': rework_clamp_workorder.Z6_axis
|
||
, 'X7_axis': rework_clamp_workorder.X7_axis,
|
||
'Y7_axis': rework_clamp_workorder.Y7_axis
|
||
, 'Z7_axis': rework_clamp_workorder.Z7_axis,
|
||
'X8_axis': rework_clamp_workorder.X8_axis
|
||
, 'Y8_axis': rework_clamp_workorder.Y8_axis,
|
||
'Z8_axis': rework_clamp_workorder.Z8_axis
|
||
, 'X9_axis': rework_clamp_workorder.X9_axis,
|
||
'Y9_axis': rework_clamp_workorder.Y9_axis
|
||
, 'Z9_axis': rework_clamp_workorder.Z9_axis,
|
||
'X10_axis': rework_clamp_workorder.X10_axis
|
||
, 'Y10_axis': rework_clamp_workorder.Y10_axis,
|
||
'Z10_axis': rework_clamp_workorder.Z10_axis
|
||
, 'X_deviation_angle': rework_clamp_workorder.X_deviation_angle,
|
||
'material_center_point': rework_clamp_workorder.material_center_point
|
||
})
|
||
break
|
||
# =====================不申请重新编程====================
|
||
if self.is_reprogramming is False:
|
||
if self.programming_state in ['已编程', '已下发']:
|
||
if self.reprogramming_num >= 1 and self.programming_state == '已编程':
|
||
for panel_name in panels:
|
||
self.production_id.get_new_program(panel_name)
|
||
if self.reprogramming_num >= 0 and self.programming_state == '已下发':
|
||
# ============= 处理CNC加工加工工单的 CNC程序和cmm程序 信息=============
|
||
for cnc_work in new_work_ids.filtered(lambda wk: wk.name == 'CNC加工'):
|
||
ret = {'programming_list': []}
|
||
old_cnc_rework = max(self.production_id.workorder_ids.filtered(
|
||
lambda crw: crw.processing_panel == cnc_work.processing_panel
|
||
and crw.state == 'rework' and crw.routing_type == 'CNC加工'),
|
||
key=lambda w: w.create_date
|
||
)
|
||
# 获取当前工单的CNC程序和cmm程序
|
||
if old_cnc_rework.cnc_ids:
|
||
for item_line in old_cnc_rework.cnc_ids:
|
||
vals = {
|
||
'sequence_number': item_line.sequence_number,
|
||
'program_name': item_line.program_name,
|
||
'cutting_tool_name': item_line.cutting_tool_name,
|
||
'cutting_tool_no': item_line.cutting_tool_no,
|
||
'processing_type': item_line.processing_type,
|
||
'margin_x_y': item_line.margin_x_y,
|
||
'margin_z': item_line.margin_z,
|
||
'depth_of_processing_z': item_line.depth_of_processing_z,
|
||
'cutting_tool_extension_length': item_line.cutting_tool_extension_length,
|
||
'estimated_processing_time': item_line.estimated_processing_time,
|
||
'cutting_tool_handle_type': item_line.cutting_tool_handle_type,
|
||
'program_path': item_line.program_path,
|
||
'ftp_path': item_line.program_path,
|
||
'processing_panel': cnc_work.processing_panel,
|
||
'program_create_date': datetime.strftime(item_line.program_create_date,
|
||
'%Y-%m-%d %H:%M:%S'),
|
||
'remark': item_line.remark
|
||
}
|
||
ret['programming_list'].append(vals)
|
||
for cmm_line in old_cnc_rework.cmm_ids:
|
||
vals = {
|
||
'sequence_number': cmm_line.sequence_number,
|
||
'program_name': cmm_line.program_name,
|
||
'program_path': cmm_line.program_path,
|
||
'ftp_path': cmm_line.program_path,
|
||
'processing_panel': cnc_work.processing_panel,
|
||
'program_create_date': datetime.strftime(
|
||
cmm_line.program_create_date,
|
||
'%Y-%m-%d %H:%M:%S')
|
||
}
|
||
ret['programming_list'].append(vals)
|
||
# 获取新的
|
||
new_cnc_workorder = self.production_id.workorder_ids.filtered(
|
||
lambda ap1: ap1.processing_panel == cnc_work.processing_panel
|
||
and ap1.state not in (
|
||
'rework', 'done') and ap1.routing_type == 'CNC加工'
|
||
)
|
||
if not new_cnc_workorder.cnc_ids:
|
||
new_cnc_workorder.write({
|
||
'cnc_ids': new_cnc_workorder.cnc_ids.sudo()._json_cnc_processing(
|
||
cnc_work.processing_panel, ret),
|
||
'cmm_ids': new_cnc_workorder.cmm_ids.sudo()._json_cmm_program(
|
||
cnc_work.processing_panel, ret),
|
||
'cnc_worksheet': old_cnc_rework.cnc_worksheet})
|
||
# ========== 处理装夹预调 【装夹图纸】 数据 ================
|
||
for new_pre_work in new_pre_workorder_ids:
|
||
pre_rework = max(self.production_id.workorder_ids.filtered(
|
||
lambda pr: (pr.processing_panel == new_pre_work.processing_panel
|
||
and pr.state in ['rework'] and pr.routing_type == '装夹预调')),
|
||
key=lambda w1: w1.create_date)
|
||
new_pre_work.write(
|
||
{'processing_drawing': pre_rework.processing_drawing})
|
||
self.production_id.write({'state': 'progress', 'is_rework': False})
|
||
elif self.programming_state in ['待编程', '编程中']:
|
||
self.production_id.write(
|
||
{'programming_state': '编程中', 'work_state': '编程中', 'is_rework': True})
|
||
# =================================================
|
||
if self.production_id.state == 'progress':
|
||
self.production_id.write({'programming_state': '已编程', 'work_state': '已编程'})
|
||
if self.reprogramming_num >= 1 and self.programming_state == '已编程':
|
||
productions_not_delivered = self.env['mrp.production'].search(
|
||
[('programming_no', '=', self.production_id.programming_no),
|
||
('programming_state', '=', '已编程未下发')])
|
||
if productions_not_delivered:
|
||
productions_not_delivered.write(
|
||
{'state': 'progress', 'programming_state': '已编程', 'work_state': '已编程',
|
||
'is_rework': False})
|
||
# ==================申请重新编程=======================
|
||
if self.is_reprogramming is True:
|
||
self.production_id.update_programming_state()
|
||
self.production_id.write(
|
||
{'programming_state': '编程中', 'work_state': '编程中', 'state': 'progress'})
|
||
|
||
@api.onchange('production_id')
|
||
def onchange_processing_panel_id(self):
|
||
for item in self:
|
||
domain = [('id', '=', False)]
|
||
production_id = item.production_id
|
||
if production_id:
|
||
if self.env.user.has_group('sf_base.group_sf_order_user'):
|
||
panel_ids = []
|
||
panel_arr = production_id.product_id.model_processing_panel
|
||
for p in production_id.detection_result_ids.filtered(
|
||
lambda ap1: ap1.handle_result == '待处理'):
|
||
if p.processing_panel not in panel_arr:
|
||
panel_arr += ','.join(p.processing_panel)
|
||
for item in panel_arr.split(','):
|
||
panel = self.env['sf.processing.panel'].search(
|
||
[('name', 'ilike', item)])
|
||
if panel:
|
||
panel_ids.append(panel.id)
|
||
domain = {'processing_panel_id': [('id', 'in', panel_ids)]}
|
||
return {'domain': domain}
|