Files
test/sf_tool_management/wizard/wizard.py

937 lines
53 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import logging
from datetime import timedelta, datetime
from odoo import fields, models, api
from odoo.exceptions import ValidationError
class ToolChangeRequirementInformation(models.TransientModel):
_name = 'sf.tool.change.requirement.information'
_description = '换刀需求信息'
code = fields.Char('编码', readonly=True)
rfid = fields.Char('Rfid', readonly=True)
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=True)
name = fields.Char('名称', related='maintenance_equipment_id.name', store=True, readonly=True)
maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='CNC机床', readonly=True)
production_line_id = fields.Many2one('sf.production.line', string='生产线', readonly=True)
machine_table_type_id = fields.Many2one('maintenance.equipment.category', string='机床类型', readonly=True)
machine_tool_code = fields.Char(string='机台号', store=True, invisible=True, readonly=True)
cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号', readonly=True)
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', readonly=True)
functional_tool_name = fields.Char(string='功能刀具名称', readonly=True)
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=True)
tool_position_interface_type = fields.Selection(
[('BT刀柄式', 'BT刀柄式'), ('SK刀柄式', 'SK刀柄式'), ('HSK刀柄式', 'HSK刀柄式'),
('CAT刀柄式', 'CAT刀柄式'), ('ISO刀盘式', 'ISO刀盘式'), ('DIN刀盘式', 'DIN刀盘式'),
('直装固定式', '直装固定式')], string='刀位接口型号', readonly=True)
diameter = fields.Float(string='刀具直径(mm)', readonly=True)
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', readonly=True)
max_lifetime_value = fields.Integer(string='最大寿命值(min)', readonly=True)
alarm_value = fields.Integer(string='报警值(min)', readonly=True)
used_value = fields.Integer(string='已使用值(min)', readonly=True)
whether_standard_knife = fields.Boolean(string='是否标准刀', default=True, readonly=True)
extension_length = fields.Float(string='伸出长(mm)', readonly=True)
effective_length = fields.Float(string='有效长(mm)', readonly=True)
# 待换功能刀具信息
replacement_tool_name = fields.Char(string='待换功能刀具名称', compute='_compute_name')
replacement_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='待换功能刀具类型')
replacement_diameter = fields.Float(string='待换刀具直径(mm)')
replacement_knife_tip_r_angle = fields.Float(string='待换刀具刀尖R角(mm)', required=True)
replacement_tool_setting_length = fields.Float(string='待换刀具总长度(mm)', required=True)
replacement_extension_length = fields.Float(string='待换刀具伸出长(mm)')
replacement_effective_length = fields.Float(string='待换刀具有效长(mm)')
replacement_tool_coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')], required=True,
string='待换刀具粗/中/精', default='3')
replacement_max_lifetime_value = fields.Integer(string='待换刀具最大寿命值(min)')
replacement_alarm_value = fields.Integer(string='待换刀具报警值(min)')
replacement_used_value = fields.Integer(string='待换刀具已使用值(min)')
new_former = fields.Selection([('0', ''), ('1', '')], string='新/旧', default='0', required=True)
replacement_whether_standard_knife = fields.Boolean(string='待换刀具是否标准刀', default=True)
used_tool_time = fields.Datetime(string='用刀时间',
default=lambda self: fields.Datetime.now() + timedelta(hours=4))
applicant = fields.Char(string='申请人', default=lambda self: self.env.user.name, readonly=True)
reason_for_applying = fields.Char(string='申请原因')
@api.depends('replacement_diameter', 'replacement_knife_tip_r_angle', 'tool_groups_id')
def _compute_name(self):
for obj in self:
if obj.tool_groups_id:
obj.replacement_tool_name = '%s-D%sR%s' % (
obj.tool_groups_id.name, obj.replacement_diameter,
obj.replacement_knife_tip_r_angle)
else:
obj.replacement_tool_name = None
@api.constrains('replacement_knife_tip_r_angle', 'replacement_diameter', 'replacement_tool_coarse_middle_thin',
'new_former')
def _check_length_or_diamenter(self):
for obj in self:
if obj.replacement_diameter == 0 and obj.replacement_knife_tip_r_angle == 0:
raise ValidationError('待换功能刀具信息【刀具直径】和【刀尖R角】不能同时为0')
if not obj.new_former:
raise ValidationError('待换功能刀具信息【新/旧】不能位空!!!')
if not obj.replacement_tool_coarse_middle_thin:
raise ValidationError('待换功能刀具信息【粗/中/精】不能位空!!!')
def tool_changing_apply(self):
"""
确认换刀申请(按键)
:return:
"""
record = self.env['sf.machine.table.tool.changing.apply'].search(
[('maintenance_equipment_id', '=', self.maintenance_equipment_id.id),
('cutter_spacing_code_id', '=', self.cutter_spacing_code_id.id)
])
# 搜索满足需求的功能刀具
functional_tool = self.env['sf.functional.tool.assembly'].get_functional_tool({
'after_assembly_functional_tool_name': self.replacement_tool_name,
'after_assembly_functional_tool_diameter': self.replacement_diameter,
'after_assembly_knife_tip_r_angle': self.replacement_knife_tip_r_angle,
'after_assembly_coarse_middle_thin': self.replacement_tool_coarse_middle_thin
})
# 如果有满足需求的刀具,就返回刀具信息
if functional_tool:
record.write({'status': '3'})
# todo 将功能刀具信息传递到机床
return functional_tool
# 如果没有满足需求的刀具,就创建功能刀具组装单
else:
# 功能刀具组装创建新任务(new_assembly_task)
sf_functional_tool_assembly = self.env['sf.functional.tool.assembly'].sudo().create({
'functional_tool_name': self.replacement_tool_name,
'tool_groups_id': self.tool_groups_id.id,
'functional_tool_type_id': self.replacement_tool_type_id.id,
'functional_tool_diameter': self.replacement_diameter,
'knife_tip_r_angle': self.replacement_knife_tip_r_angle,
'coarse_middle_thin': self.replacement_tool_coarse_middle_thin,
'new_former': self.new_former,
'tool_loading_length': self.replacement_tool_setting_length,
'functional_tool_length': self.replacement_extension_length,
'effective_length': self.replacement_effective_length,
'loading_task_source': '1',
'use_tool_time': self.used_tool_time,
'production_line_name_id': self.production_line_id.id,
'machine_tool_name_id': self.maintenance_equipment_id.id,
'applicant': self.applicant,
'apply_time': fields.Datetime.now(),
'cutter_spacing_code_id': self.cutter_spacing_code_id.id,
'whether_standard_knife': self.whether_standard_knife,
'reason_for_applying': self.reason_for_applying,
'sf_machine_table_tool_changing_apply_id': record.id
})
# 修改机床换刀申请状态
record.write({
'status': '1',
'sf_functional_tool_assembly_id': sf_functional_tool_assembly.id
})
# 关闭弹出窗口
return {'type': 'ir.actions.act_window_close'}
class ToolTransferRequestInformation(models.TransientModel):
_name = 'sf.tool.transfer.request.information'
_description = '刀具转移申请信息'
name = fields.Char('名称', related='maintenance_equipment_id.name', store=True, readonly=True)
maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='CNC机床', readonly=True)
production_line_id = fields.Many2one('sf.production.line', string='生产线', readonly=True)
machine_table_type_id = fields.Many2one('maintenance.equipment.category', string='机床类型', readonly=True)
machine_tool_code = fields.Char(string='机台号', store=True, invisible=True, readonly=True)
cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号', readonly=True)
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', readonly=True)
functional_tool_name = fields.Char(string='功能刀具名称', readonly=True)
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=True)
tool_position_interface_type = fields.Selection(
[('BT刀柄式', 'BT刀柄式'), ('SK刀柄式', 'SK刀柄式'), ('HSK刀柄式', 'HSK刀柄式'),
('CAT刀柄式', 'CAT刀柄式'), ('ISO刀盘式', 'ISO刀盘式'), ('DIN刀盘式', 'DIN刀盘式'),
('直装固定式', '直装固定式')], string='刀位接口型号', readonly=True)
diameter = fields.Float(string='刀具直径(mm)', readonly=True)
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', readonly=True)
max_lifetime_value = fields.Integer(string='最大寿命值(min)', readonly=True)
alarm_value = fields.Integer(string='报警值(min)', readonly=True)
used_value = fields.Integer(string='已使用值(min)', readonly=True)
whether_standard_knife = fields.Boolean(string='是否标准刀', default=True, readonly=True)
extension_length = fields.Float(string='伸出长(mm)', readonly=True)
effective_length = fields.Float(string='有效长(mm)', readonly=True)
# 转移刀具信息
transfer_target = fields.Selection([('机台', '机台'),
('线边刀库', '线边刀库'),
('刀具房', '刀具房')], string='转移到:', default='线边刀库')
new_cnc_machine_table_id = fields.Many2one('sf.machine_tool', string='机床名称')
new_production_line_id = fields.Many2one('sf.production.line', string='目标生产线')
new_machine_tool_code = fields.Char(string='机床号')
new_cutter_spacing_code = fields.Char(string='目标刀位号')
magazine_tool_warehouse_district = fields.Char(string='线边刀库库区')
magazine_tool_warehouse_position = fields.Char(string='线边刀库库位')
tool_room_warehouse_district = fields.Char(string='刀具房库区')
tool_room_warehouse_position = fields.Char(string='刀具房库位')
def tool_transfer_apply(self):
"""
todo 刀具转移申请信息确定按钮
:return:
"""
self.env['sf.machine.table.tool.changing.apply'].search(
[('name', '=', self.CNC_machine_table_id.id)]).write({'status': '2'})
class FunctionalToolAssemblyOrder(models.TransientModel):
_name = 'sf.functional.tool.assembly.order'
_inherit = ["barcodes.barcode_events_mixin"]
_description = '功能刀具组装单'
assembly_order_code = fields.Char(string='组装单编码', readonly=True)
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=True)
functional_tool_name_id = fields.Many2one('product.product', string='功能刀具', readonly=True)
functional_tool_name = fields.Char(string='功能刀具名称', readonly=True)
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=True,
group_expand='_read_group_functional_tool_type_ids')
functional_tool_diameter = fields.Float(string='功能刀具直径(mm)', readonly=True)
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', readonly=True)
coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')], string='粗/中/精', readonly=True)
new_former = fields.Selection([('0', ''), ('1', '')], string='新/旧', readonly=True)
tool_loading_length = fields.Float(string='总长度(mm)', readonly=True)
functional_tool_length = fields.Float(string='伸出长(mm)', readonly=True)
effective_length = fields.Float(string='有效长(mm)', readonly=True)
loading_task_source = fields.Selection([('0', 'CAM装刀'), ('1', '机台换刀'), ('2', '按库存组装')],
string='装刀任务来源', readonly=True)
use_tool_time = fields.Datetime(string='用刀时间', readonly=True)
production_line_name_id = fields.Many2one('sf.production.line', string='申请产线', readonly=True)
machine_tool_name_id = fields.Many2one('maintenance.equipment', string='申请机台', readonly=True)
machine_tool_code = fields.Char(string='机台号', readonly=True)
applicant = fields.Char(string='申请人', readonly=True)
apply_time = fields.Datetime(string='申请时间', default=fields.Datetime.now(), readonly=True)
assemble_status = fields.Selection([('0', '待组装'), ('1', '已组装')], string='组装状态', default='0',
readonly=True)
cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号', readonly=True)
whether_standard_knife = fields.Boolean(string='是否标准刀', default=True, readonly=True)
reason_for_applying = fields.Char(string='申请原因', readonly=True)
max_lifetime_value = fields.Integer(string='最大寿命值(min)', readonly=True)
alarm_value = fields.Integer(string='报警值(min)', readonly=True)
used_value = fields.Integer(string='已使用值(min)', readonly=True)
image = fields.Binary('图片')
@api.onchange('functional_tool_name')
def _onchange_functional_tool_name(self):
for item in self:
if item.functional_tool_name:
inventory = self.env['sf.tool.inventory'].sudo().search([('name', '=', item.functional_tool_name)])
if inventory:
item.after_name_id = inventory.id
# 功能刀具组装信息
# ===============整体式刀具型号=================
integral_freight_barcode = fields.Char('整体式刀具货位')
integral_product_id = fields.Many2one('product.product', string='整体式刀具名称',
compute='_compute_integral_product_id', store=True)
cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号',
related='integral_product_id.cutting_tool_model_id')
integral_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='整体式刀具规格',
related='integral_product_id.specification_id')
sf_tool_brand_id_1 = fields.Many2one('sf.machine.brand', string='整体式刀具品牌',
related='integral_product_id.brand_id')
@api.depends('integral_freight_barcode')
def _compute_integral_product_id(self):
if self.integral_freight_barcode:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.integral_freight_barcode)])
if location:
if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else:
material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '整体式刀具':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.integral_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是整体式刀具,请重新选择!' % (
location.barcode, location.product_id.name))
else:
raise ValidationError('编码为【%s】的货位不存在!' % self.integral_freight_barcode)
# ===============刀片型号====================
blade_freight_barcode = fields.Char('刀片货位')
blade_product_id = fields.Many2one('product.product', string='刀片名称', compute='_compute_blade_product_id',
store=True)
cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号',
related='blade_product_id.cutting_tool_model_id')
blade_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀片规格',
related='blade_product_id.specification_id')
sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_product_id.brand_id')
@api.depends('blade_freight_barcode')
def _compute_blade_product_id(self):
if self.blade_freight_barcode:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.blade_freight_barcode)])
if location:
if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else:
material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '刀片':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.blade_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是刀片,请重新选择!' % (
location.barcode, location.product_id.name))
else:
raise ValidationError('编码为【%s】的货位不存在!' % self.blade_freight_barcode)
# ====================刀杆型号==================
bar_freight_barcode = fields.Char('刀杆货位')
bar_product_id = fields.Many2one('product.product', string='刀杆名称', compute='_compute_bar_product_id',
store=True)
cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号',
related='bar_product_id.cutting_tool_model_id')
bar_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀杆规格',
related='bar_product_id.specification_id')
sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_product_id.brand_id')
@api.depends('bar_freight_barcode')
def _compute_bar_product_id(self):
if self.bar_freight_barcode:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.bar_freight_barcode)])
if location:
if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else:
material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '刀杆':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.bar_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是刀杆,请重新选择!' % (
location.barcode, location.product_id.name))
else:
raise ValidationError('编码为【%s】的货位不存在!' % self.bar_freight_barcode)
# ===============刀盘型号===================
pad_freight_barcode = fields.Char('刀盘货位')
pad_product_id = fields.Many2one('product.product', string='刀盘名称', compute='_compute_pad_product_id',
store=True)
cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号',
related='pad_product_id.cutting_tool_model_id')
pad_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀盘规格',
related='pad_product_id.specification_id')
sf_tool_brand_id_4 = fields.Many2one('sf.machine.brand', '刀盘品牌', related='pad_product_id.brand_id')
@api.depends('pad_freight_barcode')
def _compute_pad_product_id(self):
if self.pad_freight_barcode:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.pad_freight_barcode)])
if location:
if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else:
material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '刀盘':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.pad_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是刀盘,请重新选择!' % (
location.barcode, location.product_id.name))
else:
raise ValidationError('编码为【%s】的货位不存在!' % self.pad_freight_barcode)
# ================刀柄型号===============
handle_freight_rfid = fields.Char('刀柄Rfid', compute='_compute_rfid')
handle_code_id = fields.Many2one('stock.lot', '刀柄序列号', required=True,
domain=[('product_id.cutting_tool_material_id.name', '=', '刀柄'),
('tool_material_status', '=', '可用')])
handle_product_id = fields.Many2one('product.product', string='刀柄名称', compute='_compute_handle_product_id',
store=True)
cutting_tool_cutterhandle_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀柄型号',
related='handle_code_id.product_id.cutting_tool_model_id')
handle_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀柄规格',
related='handle_code_id.product_id.specification_id')
sf_tool_brand_id_5 = fields.Many2one('sf.machine.brand', '刀柄品牌', related='handle_code_id.product_id.brand_id')
@api.depends('handle_code_id')
def _compute_handle_product_id(self):
if self.handle_code_id:
self.handle_product_id = self.handle_code_id.product_id.id
else:
self.pad_product_id = False
# =================夹头型号==============
chuck_freight_barcode = fields.Char('夹头货位')
chuck_product_id = fields.Many2one('product.product', string='夹头名称', compute='_compute_chuck_product_id',
store=True)
cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号',
related='chuck_product_id.cutting_tool_model_id')
chuck_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='夹头规格',
related='chuck_product_id.specification_id')
sf_tool_brand_id_6 = fields.Many2one('sf.machine.brand', '夹头品牌', related='chuck_product_id.brand_id')
@api.depends('chuck_freight_barcode')
def _compute_chuck_product_id(self):
if self.chuck_freight_barcode:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.chuck_freight_barcode)])
if location:
if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else:
material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '夹头':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.chuck_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是夹头,请重新选择!' % (
location.barcode, location.product_id.name))
else:
raise ValidationError('编码为【%s】的货位不存在!' % self.chuck_freight_barcode)
# ========================================
def on_barcode_scanned(self, barcode):
"""
智能工厂组装单处扫码绑定刀具物料
"""
for record in self:
lot_ids = self.env['stock.lot'].sudo().search([('rfid', '=', barcode)])
if lot_ids:
for lot_id in lot_ids:
if lot_id.quant_ids[-1].location_id.name in '刀具房':
record.handle_code_id = lot_id.id
elif lot_id.quant_ids[-1].location_id.name == '刀具组装位置':
raise ValidationError('该刀柄已使用,请重新扫描!!!')
else:
raise ValidationError('该刀柄未入库,请重新扫描!!!')
else:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', barcode)])
if location:
material_name = location.product_id.cutting_tool_material_id.name
if material_name == '夹头':
record.chuck_freight_barcode = barcode
elif material_name == '整体式刀具':
record.integral_freight_barcode = barcode
record.blade_freight_barcode = ''
record.bar_freight_barcode = ''
record.pad_freight_barcode = ''
elif material_name == '刀片':
record.blade_freight_barcode = barcode
record.integral_freight_barcode = ''
elif material_name == '刀杆':
record.bar_freight_barcode = barcode
record.integral_freight_barcode = ''
record.pad_freight_barcode = ''
elif material_name == '刀盘':
record.pad_freight_barcode = barcode
record.integral_freight_barcode = ''
record.bar_freight_barcode = ''
else:
raise ValidationError('扫描的刀具物料不存在,请重新扫描!')
else:
raise ValidationError('扫描的刀具物料不存在,请重新扫描!')
@api.depends('handle_code_id')
def _compute_rfid(self):
for item in self:
if item:
item.rfid = item.handle_code_id.rfid
item.handle_freight_rfid = item.handle_code_id.rfid
else:
item.rfid = None
item.handle_freight_rfid = None
# 组装功能刀具参数信息
after_name_id = fields.Many2one('sf.tool.inventory', string='功能刀具名称', required=True)
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号')
rfid = fields.Char('Rfid', compute='_compute_rfid')
code = fields.Char(string='功能刀具编码', compute='_compute_code')
after_assembly_functional_tool_name = fields.Char(string='组装后功能刀具名称', compute='_compute_name', store=True)
after_assembly_functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model',
string='组装后功能刀具类型')
after_assembly_functional_tool_diameter = fields.Float(string='组装后功能刀具直径(mm)')
after_assembly_knife_tip_r_angle = fields.Float(string='组装后刀尖R角(mm)')
after_assembly_new_former = fields.Selection([('0', ''), ('1', '')], string='组装后新/旧', default='0')
cut_time = fields.Integer(string='已切削时间(min)')
cut_length = fields.Float(string='已切削长度(mm)')
cut_number = fields.Integer(string='已切削次数')
after_assembly_whether_standard_knife = fields.Boolean(string='组装后是否标准刀', default=True)
after_assembly_coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')],
string='组装后粗/中/精', default='3')
after_assembly_max_lifetime_value = fields.Integer(string='组装后最大寿命值(min)')
after_assembly_alarm_value = fields.Integer(string='组装后报警值(min)')
after_assembly_used_value = fields.Integer(string='组装后已使用值(min)')
after_assembly_tool_loading_length = fields.Float(string='组装后总长度(mm)')
after_assembly_functional_tool_length = fields.Float(string='组装后伸出长(mm)', required=True)
after_assembly_effective_length = fields.Float(string='组装后有效长(mm)')
L_D_number = fields.Float(string='L/D值(mm)', compute='_compute_l_d_number')
hiding_length = fields.Float(string='避空长(mm)')
after_tool_groups_id = fields.Many2one('sf.tool.groups', string='组装后刀具组')
@api.onchange('after_name_id')
def _onchange_number(self):
for item in self:
if item.after_name_id:
item.after_assembly_functional_tool_diameter = item.after_name_id.diameter
item.after_assembly_knife_tip_r_angle = item.after_name_id.angle
item.after_assembly_max_lifetime_value = item.after_name_id.life_span
item.after_assembly_tool_loading_length = item.after_name_id.tool_length
item.after_assembly_functional_tool_length = item.after_name_id.extension
item.hiding_length = item.after_name_id.blade_length
item.after_assembly_functional_tool_type_id = item.after_name_id.functional_cutting_tool_model_id.id
item.after_tool_groups_id = item.after_name_id.tool_groups_id.id
else:
item.after_assembly_functional_tool_type_id = item.functional_tool_type_id
item.after_tool_groups_id = item.tool_groups_id.id
# functional_tool_cutting_type = fields.Char(string='功能刀具切削类型', readonly=False)
# res_partner_id = fields.Many2one('res.partner', '智能工厂', domain="[('is_factory', '=', True)]")
@api.depends('after_assembly_functional_tool_type_id', 'integral_specification_id', 'bar_specification_id',
'pad_specification_id', 'handle_specification_id', 'after_assembly_tool_loading_length')
def _compute_code(self):
for obj in self:
str_1 = 'GNDJ-%s' % obj.after_assembly_functional_tool_type_id.code
str_2 = ''
if obj.handle_specification_id:
if obj.integral_specification_id:
str_2 = '%s-D%sL%sB%sH%s-' % (
str_1, obj.integral_specification_id.blade_diameter, obj.after_assembly_tool_loading_length,
obj.integral_specification_id.blade_length, obj.handle_specification_id.total_length)
elif obj.bar_specification_id:
str_2 = '%s-D%sL%sB%sH%s-' % (
str_1, obj.bar_specification_id.cutter_arbor_diameter, obj.after_assembly_tool_loading_length,
obj.bar_specification_id.blade_length, obj.handle_specification_id.total_length)
elif obj.pad_specification_id:
str_2 = '%s-D%sL%sB%sH%s-' % (
str_1, obj.pad_specification_id.cutter_head_diameter, obj.after_assembly_tool_loading_length,
obj.pad_specification_id.cut_depth_max, obj.handle_specification_id.total_length,
)
else:
obj.code = str_2
return True
obj.code = str_2 + str(self._get_code(str_2))
else:
obj.code = str_2
def _get_code(self, str_2):
functional_tool_assembly = self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('code', 'like', str_2)],
limit=1,
order="id desc"
)
if not functional_tool_assembly:
num = "%03d" % 1
else:
m = int(functional_tool_assembly.code[-3:]) + 1
num = "%03d" % m
return num
@api.depends('after_name_id')
def _compute_name(self):
for obj in self:
if obj.after_name_id:
obj.after_assembly_functional_tool_name = obj.after_name_id.name
else:
obj.after_assembly_functional_tool_name = ''
@api.onchange('integral_freight_barcode')
def _onchange_after_assembly_functional_tool_diameter(self):
for obj in self:
if obj.integral_product_id:
obj.after_assembly_functional_tool_diameter = obj.integral_product_id.cutting_tool_blade_diameter
else:
obj.after_assembly_functional_tool_diameter = 0
@api.onchange('blade_freight_barcode')
def _onchange_after_assembly_knife_tip_r_angle(self):
for obj in self:
if obj.blade_product_id:
obj.after_assembly_knife_tip_r_angle = obj.blade_product_id.cutting_tool_blade_tip_circular_arc_radius
else:
obj.after_assembly_knife_tip_r_angle = 0
@api.depends('hiding_length', 'after_assembly_functional_tool_diameter')
def _compute_l_d_number(self):
for record in self:
if record.hiding_length != 0 and record.after_assembly_functional_tool_diameter != 0:
record.L_D_number = record.hiding_length / record.after_assembly_functional_tool_diameter
else:
record.L_D_number = 0
@api.constrains('after_assembly_tool_loading_length', 'after_assembly_functional_tool_length',
'after_assembly_max_lifetime_value', 'after_assembly_alarm_value',
'after_assembly_effective_length', 'hiding_length')
def _check_length_control(self):
for obj in self:
if obj.after_assembly_tool_loading_length == 0:
raise ValidationError('组装参数信息【总长度】不能为0')
if obj.after_assembly_functional_tool_length == 0:
raise ValidationError('组装参数信息【伸出长】不能为0')
if obj.after_assembly_max_lifetime_value == 0:
raise ValidationError('组装参数信息【最大寿命值】不能为0')
if obj.after_assembly_alarm_value == 0:
raise ValidationError('组装参数信息【报警值】不能为0')
if obj.after_assembly_effective_length == 0:
raise ValidationError('组装参数信息【有效长】不能为0')
if obj.hiding_length == 0:
raise ValidationError('组装参数信息【避空长】不能为0')
def functional_tool_assembly(self):
"""
功能刀具组装
:return:
"""
# 获取组装单对象
functional_tool_assembly = self.env['sf.functional.tool.assembly'].search([
('assembly_order_code', '=', self.assembly_order_code),
('machine_tool_name_id', '=', self.machine_tool_name_id.id),
('cutter_spacing_code_id', '=', self.cutter_spacing_code_id.id),
('assemble_status', '=', '0'),
])
# 对物料做必填判断
self.materials_must_be_judged()
product_id = self.env['product.product'].search([('name', '=', '功能刀具')])
# 创建组装入库单
# 创建功能刀具批次/序列号记录
stock_lot = product_id.create_assemble_warehouse_receipt(self.id, functional_tool_assembly, self)
# 创建刀具组装入库单
self.env['stock.picking'].create_stocking_picking(stock_lot, functional_tool_assembly, self)
# 刀具物料出库
if self.handle_code_id:
product_id.tool_material_stock_moves(self.handle_code_id, self.assembly_order_code)
if self.integral_product_id:
self.integral_product_id.material_stock_moves(self.integral_freight_barcode,self.assembly_order_code)
if self.blade_product_id:
self.blade_product_id.material_stock_moves(self.blade_freight_barcode,self.assembly_order_code)
if self.bar_product_id:
self.bar_product_id.material_stock_moves(self.bar_freight_barcode,self.assembly_order_code)
if self.pad_product_id:
self.pad_product_id.material_stock_moves(self.pad_freight_barcode,self.assembly_order_code)
if self.chuck_product_id:
self.chuck_product_id.material_stock_moves(self.chuck_freight_barcode,self.assembly_order_code)
# ============================创建功能刀具列表、安全库存记录===============================
# 封装功能刀具数据
desc_2 = self.get_desc_2(stock_lot, functional_tool_assembly)
# 创建功能刀具列表记录
record_1 = self.env['sf.functional.cutting.tool.entity'].create(desc_2)
# 创建安全库存信息
self.env['sf.real.time.distribution.of.functional.tools'].create_or_edit_safety_stock({
'functional_name_id': self.after_name_id.id,
'sf_cutting_tool_type_id': self.after_assembly_functional_tool_type_id.id,
'tool_groups_id': self.after_tool_groups_id.id,
'diameter': self.after_assembly_functional_tool_diameter,
'knife_tip_r_angle': self.after_assembly_knife_tip_r_angle,
'coarse_middle_thin': self.after_assembly_coarse_middle_thin,
}, record_1)
# =====================修改功能刀具组装单、机床换刀申请、CAM工单程序用刀计划的状态==============
# 封装功能刀具数据
desc_1 = self.get_desc_1(stock_lot)
# 修改功能刀具组装单信息
functional_tool_assembly.write(desc_1)
if functional_tool_assembly.sf_machine_table_tool_changing_apply_id:
# 修改机床换刀申请的状态
self.env['sf.machine.table.tool.changing.apply'].sudo().search([
('id', '=', functional_tool_assembly.sf_machine_table_tool_changing_apply_id.id)
]).write({'status': '3'})
elif functional_tool_assembly.sf_cam_work_order_program_knife_plan_id:
# 修改CAM工单程序用刀计划状态
cam_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().search([
('id', '=', functional_tool_assembly.sf_cam_work_order_program_knife_plan_id.id)
])
cam_plan.write({'plan_execute_status': '2'})
# 关闭弹出窗口
return {'type': 'ir.actions.act_window_close'}
def materials_must_be_judged(self):
"""
功能刀具组装物料必填判断
"""
if not self.integral_product_id and not self.blade_product_id:
raise ValidationError('【整体式刀具】和【刀片】必须填写一个!')
if self.blade_product_id:
if not self.bar_product_id and not self.pad_product_id:
raise ValidationError('【刀盘】和【刀杆】必须填写一个!')
def get_desc_1(self, stock_lot):
return {
'barcode_id': stock_lot.id,
'code': self.code,
'rfid': self.rfid,
'tool_groups_id': self.after_tool_groups_id.id,
'integral_freight_barcode': self.integral_freight_barcode,
'blade_freight_barcode': self.blade_freight_barcode,
'bar_freight_barcode': self.bar_freight_barcode,
'pad_freight_barcode': self.pad_freight_barcode,
'handle_code_id': self.handle_code_id.id,
'chuck_freight_barcode': self.chuck_freight_barcode,
'after_assembly_functional_tool_name': self.after_assembly_functional_tool_name,
'after_assembly_functional_tool_type_id': self.after_assembly_functional_tool_type_id.id,
'after_assembly_functional_tool_diameter': self.after_assembly_functional_tool_diameter,
'after_assembly_knife_tip_r_angle': self.after_assembly_knife_tip_r_angle,
'after_assembly_new_former': self.after_assembly_new_former,
'cut_time': self.cut_time,
'cut_length': self.cut_length,
'cut_number': self.cut_number,
'after_assembly_whether_standard_knife': self.after_assembly_whether_standard_knife,
'after_assembly_coarse_middle_thin': self.after_assembly_coarse_middle_thin,
'after_assembly_max_lifetime_value': self.after_assembly_max_lifetime_value,
'after_assembly_alarm_value': self.after_assembly_alarm_value,
'after_assembly_used_value': self.after_assembly_used_value,
'after_assembly_tool_loading_length': self.after_assembly_tool_loading_length,
'after_assembly_functional_tool_length': self.after_assembly_functional_tool_length,
'after_assembly_effective_length': self.after_assembly_effective_length,
'L_D_number': self.L_D_number,
'hiding_length': self.hiding_length,
'assemble_status': '1',
'tool_loading_person': self.env.user.name,
'image': self.image,
'tool_loading_time': fields.Datetime.now()
}
def get_desc_2(self, stock_lot, functional_tool_assembly_id):
return {
'barcode_id': stock_lot.id,
'code': self.code,
'name': self.after_name_id.name,
'tool_name_id': self.after_name_id.id,
'rfid': self.rfid,
'tool_groups_id': self.after_tool_groups_id.id,
'functional_tool_name_id': functional_tool_assembly_id.id,
'sf_cutting_tool_type_id': self.after_assembly_functional_tool_type_id.id,
'cutting_tool_integral_model_id': self.integral_product_id.id,
'cutting_tool_blade_model_id': self.blade_product_id.id,
'cutting_tool_cutterbar_model_id': self.bar_product_id.id,
'cutting_tool_cutterpad_model_id': self.pad_product_id.id,
'cutting_tool_cutterhandle_model_id': self.handle_product_id.id,
'cutting_tool_cutterhead_model_id': self.chuck_product_id.id,
'functional_tool_diameter': self.after_assembly_functional_tool_diameter,
'knife_tip_r_angle': self.after_assembly_knife_tip_r_angle,
'coarse_middle_thin': self.after_assembly_coarse_middle_thin,
'new_former': self.after_assembly_new_former,
'tool_loading_length': self.after_assembly_tool_loading_length,
'functional_tool_length': self.after_assembly_functional_tool_length,
'effective_length': self.after_assembly_effective_length,
'max_lifetime_value': self.after_assembly_max_lifetime_value,
'alarm_value': self.after_assembly_alarm_value,
'used_value': self.after_assembly_used_value,
'whether_standard_knife': self.after_assembly_whether_standard_knife,
'L_D_number': self.L_D_number,
'hiding_length': self.hiding_length,
'cut_time': self.cut_time,
'cut_length': self.cut_length,
'cut_number': self.cut_number,
'image': self.image,
}
class StockPicking(models.Model):
_inherit = 'stock.picking'
def create_stocking_picking(self, stock_lot, functional_tool_assembly, obj):
"""
创建刀具组装入库单
"""
# 获取名称为刀具组装入库的作业类型
picking_type_id = self.env['stock.picking.type'].sudo().search([('name', '=', '刀具组装入库')])
# 创建刀具组装入库单
picking_id = self.env['stock.picking'].create({
'name': self._get_name_stock(picking_type_id),
'picking_type_id': picking_type_id.id,
'location_id': picking_type_id.default_location_src_id.id,
'location_dest_id': picking_type_id.default_location_dest_id.id,
})
# 创建作业详情对象记录,并绑定到刀具组装入库单
self.env['stock.move.line'].create({
'picking_id': picking_id.id,
'product_id': stock_lot.product_id.id,
'location_id': picking_id.location_id.id,
'location_dest_id': picking_id.location_dest_id.id,
'lot_id': stock_lot.id,
'qty_done': 1,
'functional_tool_name_id': functional_tool_assembly.id,
'functional_tool_type_id': obj.functional_tool_type_id.id,
'diameter': obj.after_assembly_functional_tool_diameter,
'knife_tip_r_angle': obj.after_assembly_knife_tip_r_angle,
'code': obj.code,
'rfid': obj.rfid,
'functional_tool_name': obj.after_assembly_functional_tool_name,
'tool_groups_id': obj.after_tool_groups_id.id
})
# 将刀具组装入库单的状态更改为就绪
picking_id.action_confirm()
picking_id.button_validate()
def _get_name_stock(self, picking_type_id):
name = picking_type_id.sequence_id.prefix + str(
datetime.strptime(str(fields.Date.today()), "%Y-%m-%d").strftime("%Y%m%d"))
stock_id = self.env['stock.picking'].sudo().search(
[('name', 'like', name), ('picking_type_id', '=', picking_type_id.id)],
limit=1,
order="id desc"
)
if not stock_id:
num = "%03d" % 1
else:
m = int(stock_id.name[-3:]) + 1
num = "%03d" % m
return name + str(num)
class ProductProduct(models.Model):
_inherit = 'product.product'
def create_assemble_warehouse_receipt(self, tool_assembly_order_id, functional_tool_assembly, obj):
"""
创建功能刀具批次/序列号记录
"""
product_id = self.env['product.product'].search([('name', '=', '功能刀具')])
logging.info("product_id: %s" % product_id)
stock_lot = self.env['stock.lot'].create({
'name': self.get_stock_lot_name(tool_assembly_order_id),
'product_id': product_id.id,
'company_id': self.env.company.id
})
# 获取位置对象
location_inventory_id = self.env['stock.location'].search([('name', '=', 'Production')])
stock_location_id = self.env['stock.location'].search([('name', '=', '组装后')])
# 创建功能刀具该批次/序列号 库存移动和移动历史
stock_lot.create_stock_quant(location_inventory_id, stock_location_id, functional_tool_assembly.id,
self.assembly_order_code, obj, obj.after_tool_groups_id)
return stock_lot
def get_stock_lot_name(self, tool_assembly_order_id):
"""
生成功能刀具序列号
"""
tool_assembly_order = self.env['sf.functional.tool.assembly.order'].search(
[('id', '=', tool_assembly_order_id)])
code = 'JKM-T-' + str(tool_assembly_order.after_assembly_functional_tool_type_id.code) + '-' + str(
tool_assembly_order.after_assembly_functional_tool_diameter) + '-'
new_time = datetime.strptime(str(fields.Date.today()), "%Y-%m-%d").strftime("%Y%m%d")
code += str(new_time) + '-'
stock_lot_id = self.env['stock.lot'].sudo().search(
[('name', 'like', new_time), ('product_id.name', '=', '功能刀具')],
limit=1,
order="id desc"
)
if not stock_lot_id:
num = "%03d" % 1
else:
m = int(stock_lot_id.name[-3:]) + 1
num = "%03d" % m
return code + str(num)
def tool_material_stock_moves(self, tool_material, assembly_order_code):
"""
对刀具物料进行库存移动到 刀具组装位置
"""
# 获取位置对象
location_inventory_id = tool_material.quant_ids.location_id[-1]
stock_location_id = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
# 创建功能刀具该批次/序列号 库存移动和移动历史
tool_material.create_stock_quant(location_inventory_id, stock_location_id, None, assembly_order_code, False, False)
def material_stock_moves(self, shelf_location_barcode, assembly_order_code):
# 创建库存移动记录
stock_move_id = self.env['stock.move'].sudo().create({
'name': assembly_order_code,
'product_id': self.id,
'location_id': self.env['stock.location'].search([('name', '=', '刀具房')]).id,
'location_dest_id': self.env['stock.location'].search([('name', '=', '刀具组装位置')]).id,
'product_uom_qty': 1.00,
'state': 'done'
})
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', shelf_location_barcode)])
# 创建移动历史记录
stock_move_line_id = self.env['stock.move.line'].sudo().create({
'product_id': self.id,
'move_id': stock_move_id.id,
'current_location_id': location.id,
'install_tool_time': fields.Datetime.now(),
'qty_done': 1.0,
'state': 'done',
})
if location.product_num > 0:
location.product_num = location.product_num - 1
else:
raise ValidationError(
'%s】货位的【%s】产品库存数量为零,请采购入库后再重新组装!' % (location.barcode, location.product_id.name))
return stock_move_id, stock_move_line_id
class StockLot(models.Model):
_inherit = 'stock.lot'
def create_stock_quant(self, location_inventory_id, stock_location_id, functional_tool_assembly_id, name, obj,
tool_groups_id):
"""
对功能刀具组装过程的功能刀具和刀具物料进行库存移动,以及创建移动历史
"""
# 创建库存移动记录
stock_move_id = self.env['stock.move'].sudo().create({
'name': name,
'product_id': self.product_id.id,
'location_id': location_inventory_id.id,
'location_dest_id': stock_location_id.id,
'product_uom_qty': 1.00,
'state': 'done'
})
# 创建移动历史记录
stock_move_line_id = self.env['stock.move.line'].sudo().create({
'product_id': self.product_id.id,
'functional_tool_name_id': functional_tool_assembly_id,
'lot_id': self.id,
'move_id': stock_move_id.id,
'install_tool_time': fields.Datetime.now(),
'qty_done': 1.0,
'state': 'done',
'functional_tool_type_id': False if not obj else obj.functional_tool_type_id.id,
'diameter': None if not obj else obj.after_assembly_functional_tool_diameter,
'knife_tip_r_angle': None if not obj else obj.after_assembly_knife_tip_r_angle,
'code': '' if not obj else obj.code,
'rfid': '' if not obj else obj.rfid,
'functional_tool_name': '' if not obj else obj.after_assembly_functional_tool_name,
'tool_groups_id': False if not tool_groups_id else tool_groups_id.id
})
return stock_move_id, stock_move_line_id
class StockQuant(models.Model):
_inherit = 'stock.quant'
@api.model_create_multi
def create(self, vals_list):
records = super(StockQuant, self).create(vals_list)
for record in records:
if record.lot_id.product_id.categ_id.name == '刀具':
record.lot_id.enroll_tool_material_stock()
return records