Merge branch refs/heads/develop into refs/heads/release/release_2.1

This commit is contained in:
禹翔辉
2024-07-25 15:25:07 +08:00
199 changed files with 16677 additions and 1231 deletions

View File

@@ -313,42 +313,27 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
'applicant': None,
'sf_functional_tool_assembly_id': None})
def create_cam_work_plan(self, cnc_processing_ids):
def create_cam_work_plan(self, cnc_processing):
"""
根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划
"""
for cnc_processing in cnc_processing_ids:
status = False
if cnc_processing.cutting_tool_name:
functional_tools = self.env['sf.real.time.distribution.of.functional.tools'].sudo().search(
[('name', '=', cnc_processing.cutting_tool_name)])
if functional_tools:
for functional_tool in functional_tools:
if functional_tool.on_tool_stock_num == 0:
if functional_tool.tool_stock_num == 0 and functional_tool.side_shelf_num == 0:
status = True
else:
status = True
if status:
knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
'name': cnc_processing.workorder_id.production_id.name,
'cam_procedure_code': cnc_processing.program_name,
'filename': cnc_processing.cnc_id.name,
'functional_tool_name': cnc_processing.cutting_tool_name,
'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
'process_type': cnc_processing.processing_type,
'margin_x_y': float(cnc_processing.margin_x_y),
'margin_z': float(cnc_processing.margin_z),
'finish_depth': float(cnc_processing.depth_of_processing_z),
'extension_length': float(cnc_processing.cutting_tool_extension_length),
'shank_model': cnc_processing.cutting_tool_handle_type,
'estimated_processing_time': cnc_processing.estimated_processing_time,
})
logging.info('CAM工单程序用刀计划创建成功')
# 创建装刀请求
knife_plan.apply_for_tooling()
else:
logging.info('功能刀具【%s】满足CNC用刀需求' % cnc_processing.cutting_tool_name)
knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
'name': cnc_processing.workorder_id.production_id.name,
'cam_procedure_code': cnc_processing.program_name,
'filename': cnc_processing.cnc_id.name,
'functional_tool_name': cnc_processing.cutting_tool_name,
'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
'process_type': cnc_processing.processing_type,
'margin_x_y': float(cnc_processing.margin_x_y),
'margin_z': float(cnc_processing.margin_z),
'finish_depth': float(cnc_processing.depth_of_processing_z),
'extension_length': float(cnc_processing.cutting_tool_extension_length),
'shank_model': cnc_processing.cutting_tool_handle_type,
'estimated_processing_time': cnc_processing.estimated_processing_time,
})
logging.info('CAM工单程序用刀计划创建成功')
# 创建装刀请求
knife_plan.apply_for_tooling()
def unlink_cam_plan(self, production):
for item in production:
@@ -669,6 +654,20 @@ class FunctionalToolAssembly(models.Model):
:return:
"""
picking_num = fields.Integer('调拨单数量', compute='compute_picking_num', store=True)
@api.depends('assemble_status')
def compute_picking_num(self):
for item in self:
picking_ids = self.env['stock.picking'].sudo().search([('origin', '=', item.assembly_order_code)])
item.picking_num = len(picking_ids)
def open_tool_stock_picking(self):
action = self.env.ref('stock.action_picking_tree_all')
result = action.read()[0]
result['domain'] = [('origin', '=', self.assembly_order_code)]
return result
@api.model_create_multi
def create(self, vals):
obj = super(FunctionalToolAssembly, self).create(vals)
@@ -758,7 +757,7 @@ class FunctionalToolDismantle(models.Model):
num = "%03d" % m
return 'GNDJ-CJD-%s-%s' % (datetime, num)
functional_tool_id = fields.Many2one('sf.functional.cutting.tool.entity', '功能刀具', required=True,
functional_tool_id = fields.Many2one('sf.functional.cutting.tool.entity', '功能刀具', required=True, tracking=True,
domain=[('functional_tool_status', '!=', '已拆除'),
('current_location', '=', '刀具房')])
tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True,
@@ -776,8 +775,18 @@ class FunctionalToolDismantle(models.Model):
dismantle_person = fields.Char('拆解人', readonly=True)
image = fields.Binary('图片', readonly=True)
scrap_id = fields.Char('报废单号', readonly=True)
scrap_ids = fields.One2many('stock.scrap', 'functional_tool_dismantle_id', string='报废单号', readonly=True)
grinding_id = fields.Char('磨削单号', readonly=True)
picking_id = fields.Many2one('stock.picking', string='刀具物料调拨单')
picking_num = fields.Integer('调拨单数量', default=0, compute='compute_picking_num', store=True)
@api.depends('picking_id')
def compute_picking_num(self):
for item in self:
if item.picking_id:
item.picking_num = 1
else:
item.picking_num = 0
state = fields.Selection([('待拆解', '待拆解'), ('已拆解', '已拆解')], default='待拆解', tracking=True)
active = fields.Boolean('有效', default=True)
@@ -791,7 +800,14 @@ class FunctionalToolDismantle(models.Model):
handle_rfid = fields.Char(string='刀柄Rfid', compute='_compute_functional_tool_num', store=True)
handle_lot_id = fields.Many2one('stock.lot', string='刀柄序列号', compute='_compute_functional_tool_num',
store=True)
scrap_boolean = fields.Boolean(string='刀柄是否报废', default=False, tracking=True)
scrap_boolean = fields.Boolean(string='刀柄是否报废', default=False, tracking=True, compute='compute_scrap_boolean',
store=True)
@api.depends('dismantle_cause')
def compute_scrap_boolean(self):
for item in self:
if item.dismantle_cause not in ['寿命到期报废', '崩刀报废']:
item.scrap_boolean = False
# 整体式
integral_product_id = fields.Many2one('product.product', string='整体式刀具',
@@ -933,75 +949,50 @@ class FunctionalToolDismantle(models.Model):
self.rfid, self.functional_tool_id.current_location))
# 目标重复校验
self.location_duplicate_check()
location = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
location_dest = self.env['stock.location'].search([('name', '=', '刀具房')])
datas = {'scrap': [], 'picking': []}
# =================刀柄是否[报废]拆解=======
location_dest_scrap_ids = self.env['stock.location'].search([('name', 'in', ('Scrap', '报废'))])
if self.handle_rfid:
lot = self.env['stock.lot'].sudo().search([('rfid', '=', self.handle_rfid)])
if not lot:
raise ValidationError('Rfid为【%s】的功能刀具序列号不存在!' % self.handle_rfid)
functional_tool_assembly = self.functional_tool_id.functional_tool_name_id
raise ValidationError('Rfid为【%s】的刀柄序列号不存在!' % self.handle_rfid)
if self.scrap_boolean:
# 刀柄报废 入库到Scrap
lot.create_stock_quant(location, location_dest_scrap_ids[-1], False, code, False, False)
datas['scrap'].append({'lot_id': lot})
lot.tool_material_status = '报废'
else:
# 刀柄不报废 入库到刀具房
lot.create_stock_quant(location, location_dest, False, code, False, False)
datas['picking'].append({'lot_id': lot, 'destination': self.env['sf.shelf.location']})
lot.tool_material_status = '可用'
# ==============功能刀具[报废]拆解================
if self.dismantle_cause in ['寿命到期报废', '崩刀报废']:
# 除刀柄外物料报废 入库到Scrap
if self.integral_product_id:
self.integral_product_id.dismantle_stock_moves(False, self.integral_lot_id, location,
location_dest_scrap_ids[-1], code)
datas['scrap'].append({'lot_id': self.integral_lot_id})
elif self.blade_product_id:
self.blade_product_id.dismantle_stock_moves(False, self.blade_lot_id, location,
location_dest_scrap_ids[-1], code)
datas['scrap'].append({'lot_id': self.blade_lot_id})
if self.bar_product_id:
self.bar_product_id.dismantle_stock_moves(False, self.bar_lot_id, location,
location_dest_scrap_ids[-1], code)
datas['scrap'].append({'lot_id': self.bar_lot_id})
elif self.pad_product_id:
self.pad_product_id.dismantle_stock_moves(False, self.pad_lot_id, location,
location_dest_scrap_ids[-1], code)
datas['scrap'].append({'lot_id': self.pad_lot_id})
if self.chuck_product_id:
self.chuck_product_id.dismantle_stock_moves(False, self.chuck_lot_id, location,
location_dest_scrap_ids[-1], code)
# ===========功能刀具[磨削]拆解==============
# elif self.dismantle_cause in ['刀具需磨削']:
# location_dest = self.env['stock.location'].search([('name', '=', '磨削房')])
# # 除刀柄外物料拆解 入库到具体库位
# if self.integral_product_id:
# self.integral_product_id.dismantle_stock_moves(False, location, location_dest)
# elif self.blade_product_id:
# self.blade_product_id.dismantle_stock_moves(False, location, location_dest)
# if self.bar_product_id:
# self.bar_product_id.dismantle_stock_moves(False, location, location_dest)
# elif self.pad_product_id:
# self.pad_product_id.dismantle_stock_moves(False, location, location_dest)
# if self.chuck_product_id:
# self.chuck_product_id.dismantle_stock_moves(False, location, location_dest)
datas['scrap'].append({'lot_id': self.chuck_lot_id})
# ==============功能刀具[更换,磨削]拆解==============
elif self.dismantle_cause in ['更换为其他刀具', '刀具需磨削']:
# 除刀柄外物料拆解 入库到具体货位
if self.integral_freight_id:
self.integral_product_id.dismantle_stock_moves(self.integral_freight_id, self.integral_lot_id, location,
location_dest, code)
datas['picking'].append({'lot_id': self.integral_lot_id, 'destination': self.integral_freight_id})
elif self.blade_freight_id:
self.blade_product_id.dismantle_stock_moves(self.blade_freight_id, self.blade_lot_id, location,
location_dest, code)
datas['picking'].append({'lot_id': self.blade_lot_id, 'destination': self.blade_freight_id})
if self.bar_freight_id:
self.bar_product_id.dismantle_stock_moves(self.bar_freight_id, self.bar_lot_id, location,
location_dest, code)
datas['picking'].append({'lot_id': self.bar_lot_id, 'destination': self.bar_freight_id})
elif self.pad_freight_id:
self.pad_product_id.dismantle_stock_moves(self.pad_freight_id, self.pad_lot_id, location,
location_dest, code)
datas['picking'].append({'lot_id': self.pad_lot_id, 'destination': self.pad_freight_id})
if self.chuck_freight_id:
self.chuck_product_id.dismantle_stock_moves(self.chuck_freight_id, self.chuck_lot_id, location,
location_dest, code)
# ===============删除功能刀具的Rfid字段的值 赋值给Rfid(已拆解)字段=====
datas['picking'].append({'lot_id': self.chuck_lot_id, 'destination': self.chuck_freight_id})
self.create_tool_picking_scrap(datas)
# ===============创建功能刀具拆解移动记录=====
self.env['stock.move'].create_functional_tool_stock_move(self)
# 修改功能刀具数据
self.functional_tool_id.write({
'rfid_dismantle': self.functional_tool_id.rfid,
'rfid': '',
@@ -1009,37 +1000,173 @@ class FunctionalToolDismantle(models.Model):
})
# 修改拆解单的值
self.write({
'rfid_dismantle': self.rfid,
'dismantle_data': fields.Datetime.now(),
'dismantle_person': self.env.user.name,
'rfid': '',
'rfid': '%s(已拆解)' % self.rfid,
'state': '已拆解'
})
logging.info('%s】刀具拆解成功!' % self.name)
def create_tool_picking_scrap(self, datas):
scrap_data = datas['scrap']
picking_data = datas['picking']
if scrap_data:
for data in scrap_data:
if data:
self.env['stock.scrap'].create_tool_dismantle_stock_scrap(data['lot_id'], self)
if picking_data:
picking_id = self.env['stock.picking'].create_tool_dismantle_picking(self)
self.picking_id = picking_id.id
self.env['stock.move'].create_tool_stock_move({'data': picking_data, 'picking_id': picking_id})
# 将刀具物料出库库单的状态更改为就绪
picking_id.action_confirm()
# 修改刀具物料出库移动历史记录
self.env['stock.move'].write_tool_stock_move_line({'data': picking_data, 'picking_id': picking_id})
# 设置数量,并验证完成
picking_id.action_set_quantities_to_reservation()
picking_id.button_validate()
class ProductProduct(models.Model):
_inherit = 'product.product'
def action_open_reference1(self):
self.ensure_one()
return {
'res_model': self._name,
'type': 'ir.actions.act_window',
'views': [[False, "form"]],
'res_id': self.id,
}
def dismantle_stock_moves(self, shelf_location_id, lot_id, location_id, location_dest_id, code):
# 创建功能刀具拆解单产品库存移动记录
stock_move_id = self.env['stock.move'].sudo().create({
'name': code,
'product_id': self.id,
def open_function_tool_stock_move_line(self):
action = self.env.ref('sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_act')
result = action.read()[0]
result['domain'] = [('functional_tool_dismantle_id', '=', self.id), ('qty_done', '>', 0)]
return result
def open_tool_stock_picking(self):
action = self.env.ref('stock.action_picking_tree_all')
result = action.read()[0]
result['domain'] = [('origin', '=', self.code)]
return result
class StockPicking(models.Model):
_inherit = 'stock.picking'
def create_tool_dismantle_picking(self, obj):
"""
创建刀具物料入库单
"""
# 获取名称为内部调拨的作业类型
picking_type_id = self.env['stock.picking.type'].sudo().search([('name', '=', '内部调拨')])
location_id = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
location_dest_id = self.env['stock.location'].search([('name', '=', '刀具房')])
if not location_id:
raise ValidationError('缺少名称为【刀具组装位置】的仓库管理地点')
if not location_dest_id:
raise ValidationError('缺少名称为【刀具房】的仓库管理地点')
# 创建刀具物料出库单
picking_id = self.env['stock.picking'].create({
'name': self._get_name_stock1(picking_type_id),
'picking_type_id': picking_type_id.id,
'location_id': location_id.id,
'location_dest_id': location_dest_id.id,
'origin': obj.code
})
return picking_id
class StockMove(models.Model):
_inherit = 'stock.move'
def create_tool_stock_move(self, datas):
picking_id = datas['picking_id']
data = datas['data']
stock_move_ids = []
for res in data:
if res:
# 创建库存移动记录
stock_move_id = self.env['stock.move'].sudo().create({
'name': picking_id.name,
'picking_id': picking_id.id,
'product_id': res['lot_id'].product_id.id,
'location_id': picking_id.location_id.id,
'location_dest_id': picking_id.location_dest_id.id,
'product_uom_qty': 1.00,
'reserved_availability': 1.00
})
stock_move_ids.append(stock_move_id)
return stock_move_ids
def write_tool_stock_move_line(self, datas):
picking_id = datas['picking_id']
data = datas['data']
move_line_ids = picking_id.move_line_ids
for move_line_id in move_line_ids:
for res in data:
if move_line_id.lot_id.product_id == res['lot_id'].product_id:
move_line_id.write({
'destination_location_id': res.get('destination').id,
'lot_id': res.get('lot_id').id
})
return True
def create_functional_tool_stock_move(self, dismantle_id):
"""
对功能刀具拆解过程的功能刀具进行库存移动,以及创建移动历史
"""
location_dismantle_id = self.env['stock.location'].search([('name', '=', '拆解')])
if not location_dismantle_id:
raise ValidationError('缺少名称为【拆解】的仓库管理地点')
tool_id = dismantle_id.functional_tool_id
# 创建库存移动记录
stock_move_id = self.env['stock.move'].sudo().create({
'name': dismantle_id.code,
'product_id': tool_id.barcode_id.product_id.id,
'location_id': tool_id.current_location_id.id,
'location_dest_id': location_dismantle_id.id,
'product_uom_qty': 1.00,
'state': 'done'
})
# 创建移动历史记录
stock_move_line_id = self.env['stock.move.line'].sudo().create({
'product_id': self.id,
'lot_id': lot_id.id,
'product_id': tool_id.barcode_id.product_id.id,
'functional_tool_dismantle_id': dismantle_id.id,
'lot_id': tool_id.barcode_id.id,
'move_id': stock_move_id.id,
'destination_location_id': shelf_location_id.id if shelf_location_id else False,
'install_tool_time': fields.Datetime.now(),
'qty_done': 1.0,
'state': 'done',
'functional_tool_type_id': tool_id.sf_cutting_tool_type_id.id,
'diameter': tool_id.functional_tool_diameter,
'knife_tip_r_angle': tool_id.knife_tip_r_angle,
'code': tool_id.code,
'rfid': tool_id.rfid,
'functional_tool_name': tool_id.name,
'tool_groups_id': tool_id.tool_groups_id.id
})
return stock_move_id, stock_move_line_id
class CustomStockScrap(models.Model):
_inherit = 'stock.scrap'
functional_tool_dismantle_id = fields.Many2one('sf.functional.tool.dismantle', string="功能刀具拆解单")
def create_tool_dismantle_stock_scrap(self, lot, dismantle_id):
location_id = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
scrap_location_id = self.env['stock.location'].search([('name', 'in', ('Scrap', '报废'))])
if not location_id:
raise ValidationError('缺少名称为【刀具组装位置】的仓库管理地点')
if not scrap_location_id:
raise ValidationError('缺少名称为【Scrap】或【Scrap】的仓库管理地点')
stock_scrap_id = self.create({
'product_id': lot.product_id.id,
'lot_id': lot.id,
'location_id': location_id.id,
'scrap_location_id': scrap_location_id.id,
'functional_tool_dismantle_id': dismantle_id.id,
'origin': dismantle_id.code
})
# 完成报废单
stock_scrap_id.action_validate()
return stock_scrap_id

View File

@@ -252,11 +252,19 @@ class FunctionalCuttingToolEntity(models.Model):
def open_safety_stock(self):
action = self.env.ref('sf_tool_management.sf_real_time_distribution_of_functional_tools_view_act')
result = action.read()[0]
result['domain'] = [('name', '=', self.name), ('diameter', '=', self.functional_tool_diameter),
('knife_tip_r_angle', '=', self.knife_tip_r_angle),
('coarse_middle_thin', '=', self.coarse_middle_thin)]
result['domain'] = [('id', '=', self.safe_inventory_id.id)]
return result
def cnc_function_tool_use_verify(self):
"""
cnc程序用刀可用校验校验是否是制造订单所缺刀
"""
if self.tool_name_id.name:
cnc_processing_ids = self.env['sf.cnc.processing'].search(
[('tool_state', '=', '1'), ('cutting_tool_name', '=', self.tool_name_id.name)])
if cnc_processing_ids:
cnc_processing_ids.sudo().write({'tool_state': '0'})
def tool_inventory_displacement_out(self):
"""
机床当前刀库实时信息接口,功能刀具出库
@@ -267,6 +275,7 @@ class FunctionalCuttingToolEntity(models.Model):
self.create_stock_move(stock_location_id, False)
self.current_location_id = stock_location_id.id
self.current_shelf_location_id = False
# self.barcode_id.create_stock_quant(location_inventory_id, stock_location_id,
# self.functional_tool_name_id.id, '机床装刀', self.functional_tool_name_id,
# self.functional_tool_name_id.tool_groups_id)
@@ -372,6 +381,7 @@ class StockMoveLine(models.Model):
_order = 'date desc'
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具组装单')
functional_tool_dismantle_id = fields.Many2one('sf.functional.tool.dismantle', string='功能刀具拆解单')
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True,
group_expand='_read_group_functional_tool_type_id')
functional_tool_name = fields.Char('刀具名称')
@@ -392,6 +402,9 @@ class StockMoveLine(models.Model):
if self.functional_tool_name_id:
action = self.functional_tool_name_id.action_open_reference1()
return action
if self.functional_tool_dismantle_id:
action = self.functional_tool_dismantle_id.action_open_reference1()
return action
elif self.move_id:
action = self.move_id.action_open_reference()
if action['res_model'] != 'stock.move':
@@ -409,13 +422,14 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
_inherit = ['mail.thread']
_description = '功能刀具安全库存'
name = fields.Char('名称', readonly=True, compute='_compute_name', store=True)
name = fields.Char('名称', compute='_compute_num', store=True)
functional_name_id = fields.Many2one('sf.tool.inventory', string='功能刀具名称', required=True)
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=False, required=True)
sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=False,
group_expand='_read_mrs_cutting_tool_type_ids', store=True)
diameter = fields.Float(string='刀具直径(mm)', readonly=False)
knife_tip_r_angle = fields.Float(string='尖R角(mm)', readonly=False)
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', compute='_compute_num', store=True)
sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型',
compute='_compute_num', store=True,
group_expand='_read_mrs_cutting_tool_type_ids')
diameter = fields.Float(string='具直径(mm)', compute='_compute_num', store=True)
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', compute='_compute_num', store=True)
tool_stock_num = fields.Integer(string='刀具房数量', compute='_compute_stock_num', store=True)
side_shelf_num = fields.Integer(string='线边刀库数量', compute='_compute_stock_num', store=True)
on_tool_stock_num = fields.Integer(string='机内刀库数量', compute='_compute_stock_num', store=True)
@@ -460,22 +474,18 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
active = fields.Boolean(string='已归档', default=True)
@api.onchange('functional_name_id')
def _onchange_num(self):
@api.depends('functional_name_id', 'functional_name_id.diameter', 'functional_name_id.angle',
'functional_name_id.functional_cutting_tool_model_id')
def _compute_num(self):
for item in self:
if item.functional_name_id:
item.tool_groups_id = item.functional_name_id.tool_groups_id.id
item.sf_cutting_tool_type_id = item.functional_name_id.functional_cutting_tool_model_id.id
item.diameter = item.functional_name_id.diameter
item.knife_tip_r_angle = item.functional_name_id.angle
@api.depends('functional_name_id')
def _compute_name(self):
for obj in self:
if obj.tool_groups_id:
obj.name = obj.functional_name_id.name
item.name = item.functional_name_id.name
else:
obj.sudo().name = ''
item.sudo().name = ''
@api.constrains('min_stock_num', 'max_stock_num')
def _check_stock_num(self):
@@ -583,4 +593,10 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
for vals in vals_list:
vals['status_create'] = False
records = super(RealTimeDistributionOfFunctionalTools, self).create(vals_list)
for item in records:
if item:
record = self.search([('functional_name_id', '=', item.functional_name_id.id)])
if len(record) > 1:
raise ValidationError(
'功能刀具名称为【%s】的安全库存已经存在,请勿重复创建!!!' % item.functional_name_id.name)
return records

View File

@@ -37,14 +37,10 @@ class ToolDatasync(models.Model):
def _cron_tool_datasync_all(self):
try:
self.env['stock.lot'].sudo().sync_enroll_tool_material_stock_all()
self.env['stock.lot'].sudo().sync_enroll_fixture_material_stock_all()
self.env['sf.tool.material.search'].sudo().sync_enroll_tool_material_all()
self.env['stock.lot'].sudo().sync_enroll_tool_material_stock_all()
self.env['sf.fixture.material.search'].sudo().sync_enroll_fixture_material_all()
self.env['stock.lot'].sudo().sync_enroll_fixture_material_stock_all()
self.env['sf.functional.cutting.tool.entity'].sudo().esync_enroll_functional_tool_entity_all()
logging.info("已全部同步完成!!!")
# self.env['sf.functional.tool.warning'].sudo().sync_enroll_functional_tool_warning_all()
@@ -106,7 +102,7 @@ class StockLot(models.Model):
logging.info("没有刀具物料序列号信息")
except Exception as e:
logging.info("刀具物料序列号同步失败:%s" % e)
class ToolMaterial(models.Model):
_inherit = 'sf.tool.material.search'
@@ -198,7 +194,7 @@ class FunctionalCuttingToolEntity(models.Model):
for item in objs_all:
val = {
'id': item.id,
'code': item.code,
'code': False if not item.code else item.code.split('-', 1)[1],
'name': item.name,
'rfid': item.rfid,
'tool_groups_name': item.tool_groups_id.name,

View File

@@ -29,13 +29,102 @@ class CNCprocessing(models.Model):
# else:
# raise ValidationError("MES装刀指令发送失败")
def cnc_tool_checkout(self, cnc_processing_ids):
"""
根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划
"""
logging.info('开始进行工单cnc程序用刀校验')
logging.info(f'cnc_processing_ids:{cnc_processing_ids}')
if not cnc_processing_ids:
return False
cam_id = self.env['sf.cam.work.order.program.knife.plan']
production_ids = [] # 制造订单集
datas = {'缺刀': {}, '无效刀': {}} # 缺刀/无效刀集
for cnc_processing in cnc_processing_ids:
# ======创建字典: {'缺刀': {'制造订单1': {'加工面1': [], ...}, ...}, '无效刀': {'制造订单1': {'加工面1': [], ...}, ...}}======
production_name = cnc_processing.workorder_id.production_id.name # 制造订单
processing_panel = cnc_processing.workorder_id.processing_panel # 加工面
if production_name not in list(datas['缺刀'].keys()):
datas['缺刀'].update({production_name: {processing_panel: []}})
datas['无效刀'].update({production_name: {processing_panel: []}})
production_ids.append(cnc_processing.workorder_id.production_id)
else:
if processing_panel not in list(datas['缺刀'].get(production_name).keys()):
datas['缺刀'].get(production_name).update({processing_panel: []})
datas['无效刀'].get(production_name).update({processing_panel: []})
# ======================================
if cnc_processing.cutting_tool_name:
tool_name = cnc_processing.cutting_tool_name
# 检验CNC用刀是否是功能刀具清单中的刀具
tool_inventory_id = self.env['sf.tool.inventory'].sudo().search([('name', '=', tool_name)])
if not tool_inventory_id:
if cnc_processing.cutting_tool_name not in datas['无效刀'][production_name][processing_panel]:
datas['无效刀'][production_name][processing_panel].append(cnc_processing.cutting_tool_name)
cnc_processing.tool_state = '2'
logging.info(f'"无效刀"[{production_name}{processing_panel}{cnc_processing.cutting_tool_name}]')
# 跳过本次循环
continue
# 校验CNC用刀在系统是否存在
functional_tools = self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('tool_name_id', '=', tool_inventory_id.id), ('functional_tool_status', '=', '正常')])
# 判断线边、机内是否有满足条件的刀
if not functional_tools.filtered(lambda p: p.current_location in ('线边刀库', '机内刀库')):
if cnc_processing.cutting_tool_name not in datas['缺刀'][production_name][processing_panel]:
datas['缺刀'][production_name][processing_panel].append(cnc_processing.cutting_tool_name)
cnc_processing.tool_state = '1'
logging.info(f'"缺刀"[{production_name}{processing_panel}{cnc_processing.cutting_tool_name}]')
# 判断是否有满足条件的刀
if not functional_tools:
# 创建CAM申请装刀记录
cam_id.create_cam_work_plan(cnc_processing)
logging.info('成功调用CAM工单程序用刀计划创建方法')
logging.info(f'datas:{datas}')
for production_id in production_ids:
logging.info(f'production_id: {production_id}')
if production_id:
data1 = datas['无效刀'].get(production_id.name) # data1: {'加工面1': [], ...}
data2 = datas['缺刀'].get(production_id.name) # data2: {'加工面1': [], ...}
# tool_state_remark1 = ''
tool_state_remark2 = ''
# 对无效刀信息进行处理
for key in data1:
if data1.get(key):
# if tool_state_remark1 != '':
# tool_state_remark1 = f'{tool_state_remark1}\n{key}无效刀:{data1.get(key)}'
# else:
# tool_state_remark1 = f'{key}无效刀:{data1.get(key)}'
# 无效刀处理逻辑
# 1、创建制造订单无效刀检测结果记录
logging.info('创建制造订单无效刀检测结果记录!')
production_id.detection_result_ids.create({
'production_id': production_id.id,
'processing_panel': key,
'routing_type': 'CNC加工',
'rework_reason': 'programming', # 原因:编程(programming)
'detailed_reason': '无效功能刀具',
'test_results': '返工',
'handle_result': '待处理'
})
# 对缺刀信息进行处理
for key in data2:
if data2.get(key):
if tool_state_remark2 != '':
tool_state_remark2 = f'{tool_state_remark2}\n{key}缺刀:{data2.get(key)}'
else:
tool_state_remark2 = f'{key}缺刀:{data2.get(key)}'
# 将备注信息存入制造订单功能刀具状态的备注字段
logging.info('修改制造订单功能刀具状态的备注字段')
production_id.write({
'tool_state_remark': tool_state_remark2,
# 'tool_state_remark2': tool_state_remark1
})
logging.info('工单cnc程序用刀校验已完成')
@api.model_create_multi
def create(self, vals):
obj = super(CNCprocessing, self).create(vals)
for item in obj:
# 调用CAM工单程序用刀计划创建方法
self.env['sf.cam.work.order.program.knife.plan'].create_cam_work_plan(item)
logging.info('成功调用CAM工单程序用刀计划创建方法')
# 调用CAM工单程序用刀计划创建方法
self.cnc_tool_checkout(obj)
return obj

View File

@@ -21,3 +21,40 @@ class ShelfLocation(models.Model):
continue
item.tool_rfid = ''
item.tool_name_id = False
class StockMoveLine(models.Model):
_inherit = 'stock.move.line'
@api.model_create_multi
def create(self, vals_list):
records = super(StockMoveLine, self).create(vals_list)
move_lines = records.filtered(lambda a: a.product_id.categ_id.name == '功能刀具' and a.state == 'done')
if move_lines: # 校验是否为功能刀具移动历史
self.button_function_tool_use_verify(move_lines)
return records
def button_function_tool_use_verify(self, move_lines):
"""
对所有从【刀具房】到【制造前】的功能刀具进行校验(校验是否为制造订单所缺的刀)
"""
location_id = self.env['stock.location'].search([('name', '=', '刀具房')])
location_dest_id = self.env['stock.location'].search([('name', '=', '制造前')])
line_ids = move_lines.filtered(
lambda a: a.location_id == location_id and a.location_dest_id == location_dest_id)
for line_id in line_ids:
if line_id.lot_id:
self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('barcode_id', '=', line_id.lot_id.id),
('functional_tool_status', '=', '正常')]).cnc_function_tool_use_verify()
class StockPicking(models.Model):
_inherit = 'stock.picking'
def button_validate(self):
res = super().button_validate()
move_lines = self.move_line_ids.filtered(lambda a: a.product_id.categ_id.name == '功能刀具')
if move_lines:
self.env['stock.move.line'].sudo().button_function_tool_use_verify(move_lines)
return res