Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化制造功能

This commit is contained in:
mgw
2024-07-26 17:22:59 +08:00
11 changed files with 137 additions and 65 deletions

View File

@@ -532,9 +532,3 @@ div:has(.o_required_modifier) > label::before {
position: unset;
}
// 修改表格下拉框会被表格下面数据框覆盖的bug
.tab-pane .o_field_widget {
position: relative;
z-index: 1;
}

View File

@@ -486,7 +486,9 @@ class Manufacturing_Connect(http.Controller):
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
[
('rfid_code', '=', rfid_code), ('type', '=', '上产线'),
('production_id', '=', order.production_id.id)])
('production_id', '=', order.production_id.id),
('workorder_id', '=', order.id),
('workorder_state', '=', 'done')])
if workpiece_delivery.status == '待下发':
workpiece_delivery.write({'is_manual_work': True})
else:
@@ -548,8 +550,11 @@ class Manufacturing_Connect(http.Controller):
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
[
('rfid_code', '=', rfid_code), ('type', '=', '下产线'),
('production_id', '=', order.production_id.id)])
delivery_Arr.append(workpiece_delivery.id)
('production_id', '=', order.production_id.id),
('workorder_id', '=', order.id),
('workorder_state', '=', 'done')])
if workpiece_delivery:
delivery_Arr.append(workpiece_delivery.id)
else:
res = {'Succeed': False, 'ErrorCode': 204,
'Error': 'DeviceId为%s没有对应的已配送工件数据' % ret['DeviceId']}

View File

@@ -29,41 +29,39 @@ class MrpProduction(models.Model):
detection_result_ids = fields.One2many('sf.detection.result', 'production_id', '检测报告')
tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='功能刀具状态', default='0',
store=True, compute='_compute_tool_state')
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', readonly=True)
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True)
tool_state_remark2 = fields.Text(string='功能刀具状态备注(无效刀)', readonly=True)
@api.depends('workorder_ids.tool_state_remark')
def _compute_tool_state_remark(self):
for item in self:
if item.workorder_ids:
workorder_ids = item.workorder_ids.filtered(lambda a: a.state not in ('rework', '返工'))
if workorder_ids.filtered(lambda a: a.tool_state_remark):
work_ids = workorder_ids.filtered(lambda a: a.tool_state_remark)
tool_state_remark = ''
for work_id in work_ids:
tool_state_remark = f"{work_id.tool_state_remark}\n"
item.tool_state_remark = tool_state_remark
else:
item.tool_state_remark = False
@api.depends('workorder_ids.tool_state')
def _compute_tool_state(self):
# if self.workorder_ids:
for item in self:
if item.workorder_ids:
tool_state = item.tool_state
workorder_ids = item.workorder_ids.filtered(lambda a: a.state not in ('rework', '返工'))
if workorder_ids.filtered(lambda a: a.tool_state == '2'):
item.tool_state = '2'
elif workorder_ids.filtered(lambda a: a.tool_state == '1'):
tool_state_remark = ''
data = {}
# 获取所有缺刀工单加工面对应缺的刀
for work in workorder_ids.filtered(lambda a: a.tool_state == '1'):
if work.processing_panel not in list(data.keys()):
data.update({work.processing_panel: []})
for cnc in work.cnc_ids.filtered(lambda a: a.tool_state == '1'):
if cnc.cutting_tool_name not in data[work.processing_panel]:
data[work.processing_panel].append(cnc.cutting_tool_name)
# 按格式生成缺刀提示信息
for key in data:
if data.get(key) and not data.get(key):
if tool_state_remark != '':
tool_state_remark = f'{tool_state_remark}\n{key}缺刀:{data.get(key)}'
else:
tool_state_remark = f'{key}缺刀:{data.get(key)}'
item.tool_state = '1'
item.tool_state_remark = tool_state_remark
item.tool_state_remark2 = ''
else:
item.tool_state = '0'
item.tool_state_remark = ''
item.tool_state_remark2 = ''
if tool_state == '2' and item.tool_state != '2':
item.detection_result_ids.filtered(
lambda a: a.detailed_reason == '无效功能刀具' and a.handle_result == '待处理').write(
{'handle_result': '已处理'})
# state = fields.Selection(selection_add=[
# ('pending_scheduling', '待排程'),
@@ -734,7 +732,7 @@ class MrpProduction(models.Model):
for production in self:
logging.info('qty_produced:%s' % production.qty_produced)
if production.qty_produced == '0.0':
if production.qty_produced == 0.0:
production.qty_produced = 1.0
production.write({
'date_finished': fields.Datetime.now(),
@@ -897,12 +895,17 @@ class MrpProduction(models.Model):
result),
'cmm_ids': panel_workorder.cmm_ids.sudo()._json_cmm_program(processing_panel, result),
'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
logging.info('len(cnc_worksheet):%s' % len(panel_workorder.cnc_worksheet))
pre_workorder = production.workorder_ids.filtered(lambda
ap: ap.routing_type == '装夹预调' and ap.processing_panel == processing_panel and ap.state not in (
'rework', 'done'))
if pre_workorder:
pre_workorder.write(
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
# if production.state == 'rework' and production.programming_state == '已编程未下发':
# production.write(
# {'state': 'progress', 'programming_state': '已编程', 'is_rework': False})
# logging.info('返工含有已编程未下发的程序更新完成:%s' % production.name)
logging.info('更新程序完成:%s' % production.name)
else:

View File

@@ -180,11 +180,27 @@ class ResMrpWorkOrder(models.Model):
# 功能刀具状态
tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='功能刀具状态', default='0',
store=True, compute='_compute_tool_state')
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True)
@api.depends('cnc_ids.tool_state')
def _compute_tool_state_remark(self):
for item in self:
if item.cnc_ids:
if item.cnc_ids.filtered(lambda a: a.tool_state == '2'):
item.tool_state_remark = None
elif item.cnc_ids.filtered(lambda a: a.tool_state == '1'):
tool_state_remark = f'{item.processing_panel}缺刀:['
cnc_ids = item.cnc_ids.filtered(lambda a: a.tool_state == '1')
for cnc_id in cnc_ids:
tool_state_remark = f"{tool_state_remark}'{cnc_id.cutting_tool_name}'"
item.tool_state_remark = f"{tool_state_remark}]"
else:
item.tool_state_remark = None
@api.depends('cnc_ids.tool_state')
def _compute_tool_state(self):
for item in self:
if item:
if item.cnc_ids:
if item.cnc_ids.filtered(lambda a: a.tool_state == '2'):
item.tool_state = '2'
elif item.cnc_ids.filtered(lambda a: a.tool_state == '1'):
@@ -567,12 +583,16 @@ class ResMrpWorkOrder(models.Model):
up_route = self.env['sf.agv.task.route'].search([('route_type', '=', '上产线')], limit=1, order='id asc')
down_route = self.env['sf.agv.task.route'].search([('route_type', '=', '下产线')], limit=1, order='id asc')
return [
[0, '', {'production_id': production.id, 'type': '上产线', 'route_id': up_route.id,
'feeder_station_start_id': up_route.start_site_id.id,
'feeder_station_destination_id': up_route.end_site_id.id}],
[0, '', {'production_id': production.id, 'type': '下产线', 'route_id': down_route.id,
'feeder_station_start_id': down_route.start_site_id.id,
'feeder_station_destination_id': down_route.end_site_id.id}]]
[0, '',
{'production_id': production.id, 'production_line_id': production.production_line_id.id, 'type': '上产线',
'route_id': up_route.id,
'feeder_station_start_id': up_route.start_site_id.id,
'feeder_station_destination_id': up_route.end_site_id.id}],
[0, '',
{'production_id': production.id, 'production_line_id': production.production_line_id.id, 'type': '下产线',
'route_id': down_route.id,
'feeder_station_start_id': down_route.start_site_id.id,
'feeder_station_destination_id': down_route.end_site_id.id}]]
# 拼接工单对象属性值(表面工艺)
def _json_workorder_surface_process_str(self, production, route, process_parameter, supplier_id):
@@ -757,6 +777,10 @@ class ResMrpWorkOrder(models.Model):
[('production_id', '=', workorder.production_id.id),
('processing_panel', '=', workorder.processing_panel),
('routing_type', '=', 'CNC加工'), ('state', 'in', ['pending'])])
unclamp_workorder = self.env['mrp.workorder'].search(
[('production_id', '=', workorder.production_id.id),
('sequence', '=', workorder.sequence - 1),
('state', 'in', ['done'])])
if workorder.state not in ['cancel', 'progress', 'rework']:
if workorder.production_id.state == 'rework':
logging.info('len(re_work):%s' % len(re_work))
@@ -782,8 +806,6 @@ class ResMrpWorkOrder(models.Model):
if workorder.production_id.is_rework is True:
if re_work or cnc_workorder:
workorder.state = 'waiting'
if workorder.production_id.tool_state in ['1', '2'] and workorder.state != 'pending':
workorder.state = 'waiting'
elif workorder.routing_type == 'CNC加工' and workorder.state not in ['done', 'rework', 'cancel']:
pre_workorder = self.env['mrp.workorder'].search(
@@ -815,20 +837,33 @@ class ResMrpWorkOrder(models.Model):
workorder.is_rework is False and workorder.state not in [
'done', 'rework',
'cancel']:
if (re_work or cnc_workorder) and workorder.production_id.is_rework is False:
workorder.state = 'ready'
if workorder.production_id.is_rework is False:
if re_work or cnc_workorder or unclamp_workorder:
workorder.state = 'ready'
# if (re_work or cnc_workorder) and workorder.production_id.is_rework is False:
# workorder.state = 'ready'
if workorder.routing_type == '表面工艺' and workorder.state not in ['done', 'progress']:
unclamp_workorder = self.env['mrp.workorder'].search(
[('production_id', '=', workorder.production_id.id),
('sequence', '=', workorder.sequence - 1),
('state', 'in', ['done'])])
if unclamp_workorder:
workorder.state = 'ready'
# else:
# if workorder.state not in ['cancel', 'rework']:
# workorder.state = 'rework'
# 当工单对应制造订单的功能刀具状态为 【无效刀】时,先对的第一个装夹预调工单状态设置为 【等待组件】
if workorder.production_id.tool_state in ['1', '2']:
if workorder.routing_type == '装夹预调':
if workorder.state in ['ready']:
workorder.state = 'waiting'
continue
elif workorder.state == 'pending' and self.search(
[('production_id', '=', workorder.production_id.id),
('sequence', '=', workorder.sequence - 1),
('state', 'in', ['done', 'rework'])]):
workorder.state = 'waiting'
continue
logging.info('工序:%s' % workorder.sequence)
logging.info('工单最终状态:%s' % workorder.state)
# else:
# if workorder.state not in ['cancel', 'rework']:
# workorder.state = 'rework'
# elif workorder.routing_type == 'CNC加工' and workorder.state not in ['done', 'cancel', 'progress',
# 'rework']:
# per_work = self.env['mrp.workorder'].search(
@@ -879,8 +914,12 @@ class ResMrpWorkOrder(models.Model):
raise UserError(_('该制造订单还未下发CNC程序请稍后再试'))
else:
if self.production_id.tool_state in ['1', '2']:
if self.production_id.tool_state == '1':
state = '缺刀'
else:
state = '无效刀'
raise UserError(
f'制造订单【{self.production_id.name}】功能刀具状态为【{self.production_id.tool_state}】!')
f'制造订单【{self.production_id.name}】功能刀具状态为【{state}】!')
if self.routing_type == '解除装夹':
'''
记录开始时间
@@ -1404,7 +1443,8 @@ class WorkPieceDelivery(models.Model):
[('上产线', '上产线'), ('下产线', '下产线'), ('运送空料架', '运送空料架')], string='类型')
delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration')
status = fields.Selection(
[('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态', default='待下发',
[('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送'), ('已取消', '已取消')], string='状态',
default='待下发',
tracking=True)
is_cnc_program_down = fields.Boolean('程序是否下发', default=False, tracking=True)
is_manual_work = fields.Boolean('人工操作', default=False)

View File

@@ -475,7 +475,8 @@
<field name="status" readonly="1" widget="badge"
decoration-success="status == '已配送'"
decoration-warning="status == '待下发'"
decoration-danger="status == '待配送'"/>
decoration-danger="status == '待配送'"
decoration-info="status== '已取消'"/>
</tree>
</field>
</page>
@@ -635,7 +636,9 @@
<field name="status" widget="badge"
decoration-success="status == '已配送'"
decoration-warning="status == '待下发'"
decoration-danger="status == '待配送'"/>
decoration-danger="status == '待配送'"
decoration-info="status == '已取消'"
/>
<field name="name"/>
<field name="production_id"/>
<field name="type" readonly="1"/>
@@ -731,7 +734,7 @@
</field>
<field name="view_mode">tree,form</field>
<field name="domain">
[('type','in',['上产线','下产线']),('workorder_state','=','done'),('is_manual_work','=',false)]
[('type','in',['上产线','下产线']),('workorder_state','in',['done','rework']),('is_manual_work','=',false)]
</field>
</record>

View File

@@ -31,6 +31,8 @@ class ReworkWizard(models.TransientModel):
('已下发', '已下发')],
string='编程状态')
tool_state = fields.Selection(string='功能刀具状态', related='production_id.tool_state')
def confirm(self):
if self.routing_type in ['装夹预调', 'CNC加工']:
self.workorder_id.is_rework = True
@@ -69,6 +71,12 @@ class ReworkWizard(models.TransientModel):
lambda ap: ap.processing_panel == panel.name and ap.state != 'rework')
if panel_workorder:
panel_workorder.write({'state': 'rework'})
panel_workorder.filtered(
lambda wo: wo.routing_type == '装夹预调').workpiece_delivery_ids.filtered(
lambda wd: wd.status == '待下发').write({'status': '已取消'})
# workpiece = self.env['sf.workpiece.delivery'].search([('status', '=', '待下发'), (
# 'workorder_id', '=',
# panel_workorder.filtered(lambda wd: wd.routing_type == '装夹预调').id)])
product_routing_workcenter = self.env['sf.product.model.type.routing.sort'].search(
[('product_model_type_id', '=', self.production_id.product_id.product_model_type_id.id)],
order='sequence asc'
@@ -137,7 +145,7 @@ class ReworkWizard(models.TransientModel):
ret),
'cmm_ids': new_cnc_workorder.cmm_ids.sudo()._json_cmm_program(panel.name,
ret),
'cnc_worksheet': new_cnc_workorder.cnc_worksheet})
'cnc_worksheet': cnc_rework.cnc_worksheet})
new_pre_workorder = self.production_id.workorder_ids.filtered(lambda
p: p.routing_type == '装夹预调' and p.processing_panel == panel.name and p.state not in (
'rework', 'done'))
@@ -157,6 +165,13 @@ class ReworkWizard(models.TransientModel):
{'programming_state': '编程中', 'work_state': '编程中'})
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(
{'programming_state': '已编程', 'work_state': '已编程', 'is_rework': False})
@api.onchange('production_id')
def onchange_processing_panel_id(self):

View File

@@ -9,6 +9,7 @@
<field name="production_id" invisible="True"/>
<field name="workorder_id" invisible="True"/>
<field name="product_id" invisible="True"/>
<field name="tool_state" invisible="True"/>
<field name="routing_type" invisible="True"/>
<group>
<field name="processing_panel_id" options="{'no_create': True}"
@@ -25,15 +26,16 @@
decoration-warning="programming_state =='编程中'"
decoration-danger="programming_state =='已编程'" readonly="1"/>
</div>
<div attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","not in",["已下发"])]}'>
<div attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","not in",["已下发"])],"readonly": [("tool_state", "=", "2")]}'>
<span style='font-weight:bold;'>申请重新编程
<field name="is_reprogramming" force_save="1"/>
<field name="is_reprogramming" force_save="1"
attrs='{"readonly": [("tool_state", "=", "2")]}'/>
</span>
</div>
<div attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","in",["已下发"])],"readonly": [("is_reprogramming_readonly","=",False)]}'>
<div attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","in",["已下发"])],"readonly": ["|",("is_reprogramming_readonly","=",False),("tool_state", "=", "2")]}'>
<span style='font-weight:bold;'>申请重新编程
<field name="is_reprogramming_readonly"
attrs='{"readonly": [("is_reprogramming_readonly","=",False)]}'/>
attrs='{"readonly": ["|",("is_reprogramming_readonly","=",False),("tool_state", "=", "2")]}'/>
</span>
</div>
<group>

View File

@@ -819,7 +819,7 @@ class FunctionalToolDismantle(models.Model):
integral_lot_id = fields.Many2one('stock.lot', string='整体式刀具批次', compute='_compute_functional_tool_num',
store=True)
integral_freight_id = fields.Many2one('sf.shelf.location', '整体式刀具目标货位',
domain="[('product_id', 'in', (integral_product_id, False)),('location_id.name', '=', '刀具房')]")
domain="[('product_id', 'in', (integral_product_id, False)),('rotative_Boolean', '=', True)]")
# 刀片
blade_product_id = fields.Many2one('product.product', string='刀片', compute='_compute_functional_tool_num',
@@ -829,7 +829,7 @@ class FunctionalToolDismantle(models.Model):
blade_brand_id = fields.Many2one('sf.machine.brand', string='刀片品牌', related='blade_product_id.brand_id')
blade_lot_id = fields.Many2one('stock.lot', string='刀片批次', compute='_compute_functional_tool_num', store=True)
blade_freight_id = fields.Many2one('sf.shelf.location', '刀片目标货位',
domain="[('product_id', 'in', (blade_product_id, False)),('location_id.name', '=', '刀具房')]")
domain="[('product_id', 'in', (blade_product_id, False)),('rotative_Boolean', '=', True)]")
# 刀杆
bar_product_id = fields.Many2one('product.product', string='刀杆', compute='_compute_functional_tool_num',
@@ -839,7 +839,7 @@ class FunctionalToolDismantle(models.Model):
bar_brand_id = fields.Many2one('sf.machine.brand', string='刀杆品牌', related='bar_product_id.brand_id')
bar_lot_id = fields.Many2one('stock.lot', string='刀杆批次', compute='_compute_functional_tool_num', store=True)
bar_freight_id = fields.Many2one('sf.shelf.location', '刀杆目标货位',
domain="[('product_id', 'in', (bar_product_id, False)),('location_id.name', '=', '刀具房')]")
domain="[('product_id', 'in', (bar_product_id, False)),('rotative_Boolean', '=', True)]")
# 刀盘
pad_product_id = fields.Many2one('product.product', string='刀盘', compute='_compute_functional_tool_num',
@@ -849,7 +849,7 @@ class FunctionalToolDismantle(models.Model):
pad_brand_id = fields.Many2one('sf.machine.brand', string='刀盘品牌', related='pad_product_id.brand_id')
pad_lot_id = fields.Many2one('stock.lot', string='刀盘批次', compute='_compute_functional_tool_num', store=True)
pad_freight_id = fields.Many2one('sf.shelf.location', '刀盘目标货位',
domain="[('product_id', 'in', (pad_product_id, False)),('location_id.name', '=', '刀具房')]")
domain="[('product_id', 'in', (pad_product_id, False)),('rotative_Boolean', '=', True)]")
# 夹头
chuck_product_id = fields.Many2one('product.product', string='夹头', compute='_compute_functional_tool_num',
@@ -859,7 +859,7 @@ class FunctionalToolDismantle(models.Model):
chuck_brand_id = fields.Many2one('sf.machine.brand', string='夹头品牌', related='chuck_product_id.brand_id')
chuck_lot_id = fields.Many2one('stock.lot', string='夹头批次', compute='_compute_functional_tool_num', store=True)
chuck_freight_id = fields.Many2one('sf.shelf.location', '夹头目标货位',
domain="[('product_id', 'in', (chuck_product_id, False)),('location_id.name', '=', '刀具房')]")
domain="[('product_id', 'in', (chuck_product_id, False)),('rotative_Boolean', '=', True)]")
@api.onchange('functional_tool_id')
def _onchange_freight(self):

View File

@@ -105,6 +105,12 @@ class CNCprocessing(models.Model):
'test_results': '返工',
'handle_result': '待处理'
})
# if not production_id.is_rework:
# production_id.write({
# 'is_rework': True
# })
# production_id.workorder_ids.filtered(
# lambda a: a.processing_panel == key and not a.is_rework).write({'is_rework': True})
# 对缺刀信息进行处理
for key in data2:
if data2.get(key):

View File

@@ -254,6 +254,7 @@ class SfShelf(models.Model):
shelf_height = fields.Float(string='货架高度(m)')
shelf_layer = fields.Integer(string='货架层数')
layer_capacity = fields.Integer(string='层数容量')
shelf_rotative_Boolean = fields.Boolean('循环货架', default=False)
# 是否有货位
is_there_area = fields.Boolean(string='是否有货位', compute='_compute_is_there_area', default=False, store=True)
@@ -361,6 +362,7 @@ class ShelfLocation(models.Model):
name = fields.Char('货位名称', required=True, size=20)
barcode = fields.Char('货位编码', copy=False, size=50)
rotative_Boolean = fields.Boolean('循环货位', related='shelf_id.shelf_rotative_Boolean', store=True)
qr_code = fields.Binary(string='二维码', compute='_compute_location_qr_code', store=True)
# 货架

View File

@@ -23,6 +23,7 @@
<field name="shelf_height" string="货架高度(m)"/>
<field name="shelf_layer" string="货架层数"/>
<field name="layer_capacity" string="层数容量"/>
<field name="shelf_rotative_Boolean"/>
</group>
<notebook>
<page string="货位">
@@ -169,6 +170,7 @@
<group>
<field name="barcode" readonly="1"/>
<field name="name" readonly="1"/>
<field name="rotative_Boolean" invisible="1"/>
<field name="shelf_id" readonly="1"/>
<field name="location_id" readonly="1"/>
<field name="product_id"/>