制造订单 工单回退
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import random
|
||||||
import re
|
import re
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
@@ -69,6 +70,50 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
|
|
||||||
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效',
|
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效',
|
||||||
tracking=True)
|
tracking=True)
|
||||||
|
back_button_display = fields.Boolean(default=False, compute='_compute_back_button_display', store=True)
|
||||||
|
|
||||||
|
@api.depends('state')
|
||||||
|
def _compute_back_button_display(self):
|
||||||
|
for record in self:
|
||||||
|
sorted_workorders = record.production_id.workorder_ids.filtered(lambda w: w.state != 'cancel').sorted(
|
||||||
|
key=lambda w: w.sequence)
|
||||||
|
if not sorted_workorders:
|
||||||
|
continue
|
||||||
|
position = next((idx for idx, workorder in enumerate(sorted_workorders) if workorder.id == record.id), -1)
|
||||||
|
cur_workorder = sorted_workorders[position]
|
||||||
|
if position == len(sorted_workorders) - 1:
|
||||||
|
picking_ids = cur_workorder.production_id.sale_order_id.picking_ids
|
||||||
|
finished_product_area = picking_ids.filtered(
|
||||||
|
lambda picking: picking.location_dest_id.name == '成品存货区' and picking.state == 'done'
|
||||||
|
)
|
||||||
|
if finished_product_area:
|
||||||
|
moves = self.env['stock.move'].search([
|
||||||
|
('name', '=', cur_workorder.production_id.name),
|
||||||
|
('state', '!=', 'cancel')
|
||||||
|
])
|
||||||
|
finish_move = next((move for move in moves if move.location_dest_id.name == '制造后'), None)
|
||||||
|
if not finish_move and not cur_workorder.is_subcontract:
|
||||||
|
record.back_button_display = True
|
||||||
|
else:
|
||||||
|
record.back_button_display = any(
|
||||||
|
finish_move.move_dest_ids.ids not in move.ids and record.state == 'done'
|
||||||
|
for picking in finished_product_area
|
||||||
|
for move in picking.move_ids
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
if record.state == 'done':
|
||||||
|
record.back_button_display = True
|
||||||
|
else:
|
||||||
|
record.back_button_display = False
|
||||||
|
else:
|
||||||
|
next_workorder = sorted_workorders[position + 1]
|
||||||
|
next_state = next_workorder.state
|
||||||
|
if ((next_state == 'ready' and not next_workorder.is_subcontract) or (next_workorder.state == 'pending' and next_workorder.is_subcontract)) and cur_workorder.state == 'done':
|
||||||
|
record.back_button_display = True
|
||||||
|
else:
|
||||||
|
record.back_button_display = False
|
||||||
|
if cur_workorder.is_subcontract:
|
||||||
|
record.back_button_display = False
|
||||||
|
|
||||||
@api.depends('processing_panel')
|
@api.depends('processing_panel')
|
||||||
def _compute_processing_panel_selection(self):
|
def _compute_processing_panel_selection(self):
|
||||||
@@ -85,6 +130,78 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
|
|
||||||
manual_quotation = fields.Boolean('人工编程', default=False, compute=_compute_manual_quotation, store=True)
|
manual_quotation = fields.Boolean('人工编程', default=False, compute=_compute_manual_quotation, store=True)
|
||||||
|
|
||||||
|
def button_back(self):
|
||||||
|
if self.production_id.state == 'rework':
|
||||||
|
raise UserError('制造订单为返工时不能进行工单回退')
|
||||||
|
sorted_workorders = self.production_id.workorder_ids.filtered(lambda w: w.state != 'cancel').sorted(
|
||||||
|
key=lambda w: w.sequence)
|
||||||
|
position = next((idx for idx, workorder in enumerate(sorted_workorders) if workorder.id == self.id), -1)
|
||||||
|
cur_workorder = sorted_workorders[position]
|
||||||
|
if position == len(sorted_workorders) - 1:
|
||||||
|
# 末工序
|
||||||
|
picking_ids = cur_workorder.production_id.sale_order_id.picking_ids
|
||||||
|
finished_product_area = picking_ids.filtered(
|
||||||
|
lambda picking: picking.location_dest_id.name == '成品存货区' and picking.state == 'done'
|
||||||
|
)
|
||||||
|
moves = self.env['stock.move'].search([
|
||||||
|
('name', '=', cur_workorder.production_id.name),
|
||||||
|
('state', '!=', 'cancel')
|
||||||
|
])
|
||||||
|
finish_move = next((move for move in moves if move.location_dest_id.name == '制造后'), None) or []
|
||||||
|
if any(
|
||||||
|
finish_move.move_dest_ids.ids in move.ids
|
||||||
|
for picking in finished_product_area
|
||||||
|
for move in picking.move_ids
|
||||||
|
):
|
||||||
|
raise UserError('已入库,无法回退')
|
||||||
|
else:
|
||||||
|
move_finished = cur_workorder.production_id.move_finished_ids
|
||||||
|
random_element = random.choice(move_finished)
|
||||||
|
moves = self.env['stock.move'].search([
|
||||||
|
('name', '=', random_element.name),
|
||||||
|
('state', '!=', 'cancel')
|
||||||
|
])
|
||||||
|
move_lines = self.env['stock.move.line'].search([
|
||||||
|
('reference', '=', random_element.name),
|
||||||
|
('state', '!=', 'cancel')
|
||||||
|
])
|
||||||
|
moves.state = 'assigned'
|
||||||
|
move_lines.state = 'assigned'
|
||||||
|
self.time_ids.date_end = None
|
||||||
|
cur_workorder.state = 'progress'
|
||||||
|
cur_workorder.production_id.state = 'progress'
|
||||||
|
quality_check = self.env['quality.check'].search(
|
||||||
|
[('workorder_id', '=', self.id)])
|
||||||
|
for check_order in quality_check:
|
||||||
|
if check_order.point_id.is_inspect:
|
||||||
|
check_order.state = 'waiting'
|
||||||
|
else:
|
||||||
|
check_order.state = 'none'
|
||||||
|
# move_dest_ids
|
||||||
|
finished_quants = moves.mapped('move_line_ids.lot_id.quant_ids')
|
||||||
|
finished_quants.quantity = 0
|
||||||
|
finish_move = next((move for move in moves if move.location_dest_id.name == '制造后'), None)
|
||||||
|
finish_move.move_dest_ids.reserved_availability = 0
|
||||||
|
# finish_move.move_dest_ids.move_line_ids.reserved_uom_qty = 0
|
||||||
|
else:
|
||||||
|
next_workorder = sorted_workorders[position + 1]
|
||||||
|
next_state = next_workorder.state
|
||||||
|
if next_state not in ['pending', 'waiting', 'ready']:
|
||||||
|
raise UserError('下工序已经开始,无法回退')
|
||||||
|
if next_workorder.is_subcontract:
|
||||||
|
next_workorder.picking_ids.write({'state': 'waiting'})
|
||||||
|
next_workorder.state = 'pending'
|
||||||
|
self.time_ids.date_end = None
|
||||||
|
cur_workorder.state = 'progress'
|
||||||
|
cur_workorder.production_id.state = 'progress'
|
||||||
|
quality_check = self.env['quality.check'].search(
|
||||||
|
[('workorder_id', '=', self.id)])
|
||||||
|
for check_order in quality_check:
|
||||||
|
if check_order.point_id.is_inspect:
|
||||||
|
check_order.state = 'waiting'
|
||||||
|
else:
|
||||||
|
check_order.state = 'none'
|
||||||
|
|
||||||
def _compute_working_users(self):
|
def _compute_working_users(self):
|
||||||
super()._compute_working_users()
|
super()._compute_working_users()
|
||||||
for item in self:
|
for item in self:
|
||||||
@@ -1117,6 +1234,7 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
mo.get_move_line(workorder.production_id, workorder))
|
mo.get_move_line(workorder.production_id, workorder))
|
||||||
else:
|
else:
|
||||||
workorder.state = 'waiting'
|
workorder.state = 'waiting'
|
||||||
|
|
||||||
# 重写工单开始按钮方法
|
# 重写工单开始按钮方法
|
||||||
def button_start(self):
|
def button_start(self):
|
||||||
# 判断工单状态是否为等待组件
|
# 判断工单状态是否为等待组件
|
||||||
@@ -1283,7 +1401,8 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
'detailed_reason': record.detailed_reason,
|
'detailed_reason': record.detailed_reason,
|
||||||
'processing_panel': record.processing_panel,
|
'processing_panel': record.processing_panel,
|
||||||
'routing_type': record.routing_type,
|
'routing_type': record.routing_type,
|
||||||
'handle_result': '待处理' if record.test_results in ['返工', '报废'] or record.is_rework is True else '',
|
'handle_result': '待处理' if record.test_results in ['返工',
|
||||||
|
'报废'] or record.is_rework is True else '',
|
||||||
'test_results': record.test_results,
|
'test_results': record.test_results,
|
||||||
'test_report': record.detection_report})],
|
'test_report': record.detection_report})],
|
||||||
'is_scrap': True if record.test_results == '报废' else False
|
'is_scrap': True if record.test_results == '报废' else False
|
||||||
@@ -1300,7 +1419,8 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
raise UserError('请先完成该工单的工艺外协再进行操作')
|
raise UserError('请先完成该工单的工艺外协再进行操作')
|
||||||
# 表面工艺外协,最后一张工单
|
# 表面工艺外协,最后一张工单
|
||||||
workorders = self.production_id.workorder_ids
|
workorders = self.production_id.workorder_ids
|
||||||
subcontract_workorders = workorders.filtered(lambda wo: wo.is_subcontract == True and wo.state != 'cancel').sorted('sequence')
|
subcontract_workorders = workorders.filtered(
|
||||||
|
lambda wo: wo.is_subcontract == True and wo.state != 'cancel').sorted('sequence')
|
||||||
if self == subcontract_workorders[-1]:
|
if self == subcontract_workorders[-1]:
|
||||||
# 给下一个库存移动就绪
|
# 给下一个库存移动就绪
|
||||||
self.move_subcontract_workorder_ids[0].move_dest_ids._action_done()
|
self.move_subcontract_workorder_ids[0].move_dest_ids._action_done()
|
||||||
@@ -1523,6 +1643,7 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
# 根据工单对应的【作业_个性化记录】配置页签
|
# 根据工单对应的【作业_个性化记录】配置页签
|
||||||
if any(item.code == 'PTD' for item in mw.routing_workcenter_id.individuation_page_ids):
|
if any(item.code == 'PTD' for item in mw.routing_workcenter_id.individuation_page_ids):
|
||||||
mw.individuation_page_PTD = True
|
mw.individuation_page_PTD = True
|
||||||
|
|
||||||
# =============================================================================================
|
# =============================================================================================
|
||||||
|
|
||||||
is_inspect = fields.Boolean('需送检', compute='_compute_is_inspect', store=True, default=False)
|
is_inspect = fields.Boolean('需送检', compute='_compute_is_inspect', store=True, default=False)
|
||||||
@@ -1659,8 +1780,8 @@ class CNCprocessing(models.Model):
|
|||||||
|
|
||||||
# 将FTP的多面的程序单文件下载到临时目录
|
# 将FTP的多面的程序单文件下载到临时目录
|
||||||
def download_file_tmp(self, production_no, processing_panel):
|
def download_file_tmp(self, production_no, processing_panel):
|
||||||
remotepath = os.path.join('/home/ftp/ftp_root/NC', production_no, 'return', processing_panel)
|
remotepath = os.path.join('/home/ftp/ftp_root/NC', 'production_no', 'return', processing_panel)
|
||||||
serverdir = os.path.join('/tmp', production_no, 'return', processing_panel)
|
serverdir = os.path.join('/tmp', 'production_no', 'return', processing_panel)
|
||||||
ftp_resconfig = self.env['res.config.settings'].get_values()
|
ftp_resconfig = self.env['res.config.settings'].get_values()
|
||||||
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), ftp_resconfig['ftp_user'],
|
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), ftp_resconfig['ftp_user'],
|
||||||
ftp_resconfig['ftp_password'])
|
ftp_resconfig['ftp_password'])
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='date_planned_finished']" position="replace">
|
<xpath expr="//field[@name='date_planned_finished']" position="replace">
|
||||||
<field name="date_planned_finished" string="计划结束日期" optional="hide"/>
|
<field name="date_planned_finished" string="计划结束日期" optional="hide"/>
|
||||||
|
<field name="back_button_display" invisible="1"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//button[@name='button_start']" position="attributes">
|
<xpath expr="//button[@name='button_start']" position="attributes">
|
||||||
<!-- <attribute name="attrs">{'invisible': ['|', '|', '|','|','|', ('production_state','in', ('draft',-->
|
<!-- <attribute name="attrs">{'invisible': ['|', '|', '|','|','|', ('production_state','in', ('draft',-->
|
||||||
@@ -58,6 +59,10 @@
|
|||||||
<attribute name="attrs">{'invisible': [('state', '!=', 'ready')]}
|
<attribute name="attrs">{'invisible': [('state', '!=', 'ready')]}
|
||||||
</attribute>
|
</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
|
<xpath expr="//button[@name='button_start']" position="after">
|
||||||
|
<button name="button_back" string="回退" type="object" class="btn-primary" attrs="{'invisible': [('back_button_display', '=', False)]}" confirm="是否确认回退"/>
|
||||||
|
</xpath>
|
||||||
<xpath expr="//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="attributes">
|
<xpath expr="//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="attributes">
|
||||||
<attribute name="attrs">{'invisible':
|
<attribute name="attrs">{'invisible':
|
||||||
['|',("user_permissions","=",False),("name","=","获取CNC加工程序")]}
|
['|',("user_permissions","=",False),("name","=","获取CNC加工程序")]}
|
||||||
|
|||||||
Reference in New Issue
Block a user