Merge branch 'develop' into feature/流程用扫码完成

This commit is contained in:
胡尧
2024-09-13 08:53:16 +08:00
25 changed files with 1602 additions and 589 deletions

View File

@@ -79,6 +79,7 @@
<field name="name" string="日常机床保养"/> <field name="name" string="日常机床保养"/>
<field name="created_user_id" string="创建人"/> <field name="created_user_id" string="创建人"/>
<field name="maintenance_equipment_category_id" string="设备类别"/> <field name="maintenance_equipment_category_id" string="设备类别"/>
<filter name="filter_active" string="已归档" domain="[('active','=',False)]"/>
</search> </search>
</field> </field>
</record> </record>

View File

@@ -4,6 +4,7 @@ from collections import defaultdict
from odoo import fields, models, api from odoo import fields, models, api
from odoo.addons.resource.models.resource import Intervals from odoo.addons.resource.models.resource import Intervals
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
import math
class ResWorkcenter(models.Model): class ResWorkcenter(models.Model):
@@ -195,7 +196,9 @@ class ResWorkcenter(models.Model):
def get_integer_and_decimal_parts(self, value): def get_integer_and_decimal_parts(self, value):
integer_part = int(value) integer_part = int(value)
decimal_part = value - integer_part decimal_part = value - integer_part
return int(integer_part), int(decimal_part) if decimal_part > 0:
decimal_part = round(decimal_part, 2) * 60
return int(integer_part), math.ceil(decimal_part)
# 处理排程是否超过日产能 # 处理排程是否超过日产能
def deal_available_default_capacity(self, date_planned): def deal_available_default_capacity(self, date_planned):
@@ -204,7 +207,8 @@ class ResWorkcenter(models.Model):
date_planned_end = date_planned_end.strftime('%Y-%m-%d') date_planned_end = date_planned_end.strftime('%Y-%m-%d')
plan_ids = self.env['sf.production.plan'].sudo().search([('date_planned_start', '>=', date_planned_start), plan_ids = self.env['sf.production.plan'].sudo().search([('date_planned_start', '>=', date_planned_start),
('date_planned_start', '<', ('date_planned_start', '<',
date_planned_end), ('state', '!=', 'draft')]) date_planned_end),
('state', 'not in', ['draft', 'cancel'])])
if plan_ids: if plan_ids:
sum_qty = sum([p.product_qty for p in plan_ids]) sum_qty = sum([p.product_qty for p in plan_ids])
if sum_qty >= self.default_capacity: if sum_qty >= self.default_capacity:
@@ -219,7 +223,8 @@ class ResWorkcenter(models.Model):
date_planned_end = date_planned_end.strftime('%Y-%m-%d %H:00:00') date_planned_end = date_planned_end.strftime('%Y-%m-%d %H:00:00')
plan_ids = self.env['sf.production.plan'].sudo().search([('date_planned_start', '>=', date_planned_start), plan_ids = self.env['sf.production.plan'].sudo().search([('date_planned_start', '>=', date_planned_start),
('date_planned_start', '<', ('date_planned_start', '<',
date_planned_end), ('state', '!=', 'draft')]) date_planned_end),
('state', 'not in', ['draft', 'cancel'])])
if plan_ids: if plan_ids:
sum_qty = sum([p.product_qty for p in plan_ids]) sum_qty = sum([p.product_qty for p in plan_ids])

1
sf_message/__init__.py Normal file
View File

@@ -0,0 +1 @@
from . import models

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': '机企猫智能工厂 消息提醒',
'version': '1.0',
'summary': '智能工厂消息提醒模块',
'sequence': 1,
'description': """
""",
'category': 'sf',
'website': 'https://www.sf.jikimo.com',
'depends': ['base', 'sf_base'],
'data': [
'security/ir.model.access.csv',
'views/sf_message_template_view.xml',
],
'test': [
],
'license': 'LGPL-3',
'installable': True,
'auto_install': False,
'application': False,
}

View File

@@ -0,0 +1 @@
from . import sf_message_template

View File

@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api
class SfMessageTemplate(models.Model):
_name = "sf.message.template"
_description = u'消息模板'
name = fields.Char(string=u"名称", required=True)
type = fields.Selection([
('待接单', '待接单'),
('待排程', '待排程'),
('坯料采购', '坯料采购'),
('坯料发料', '坯料发料'),
('待编程', '待编程'),
('调拨入库', '调拨入库'),
('功能刀具组装', '功能刀具组装'),
('功能刀具寿命到期', '功能刀具寿命到期'),
('程序用刀计划异常', '程序用刀计划异常'),
('工单无CNC程序', '工单无CNC程序'),
('生产线无功能刀具', '生产线无功能刀具'),
('工单无定位数据', '工单无定位数据'),
('工单FTP无文件', '工单FTP无文件'),
('工单加工失败', '工单加工失败'),
('设备故障及异常', '设备故障及异常'),
('工单逾期预警', '工单逾期预警'),
('工单已逾期', '工单已逾期'),
('销售订单逾期', '销售订单逾期'),
('销售订单已逾期', '销售订单已逾期'),
('待质量判定', '待质量判定'),
('生产完工待入库', '生产完工待入库'),
('订单发货', '订单发货')
], string='类型', required=True)
description = fields.Char(string=u"描述")
content = fields.Html(string=u"内容", render_engine='qweb', translate=True, prefetch=True, sanitize=False)
msgtype = fields.Selection(
[('text', u'文字'), ('markdown', u'Markdown')], u'消息类型',
required=True, default='markdown')
notification_department_id = fields.Many2one('hr.department', u'通知部门', required=True)
notification_employee_ids = fields.Many2many('hr.employee', string=u'员工',
domain="[('department_id', '=',notification_department_id)]",
required=True)
active = fields.Boolean(string=u"是否有效", default=True)
@api.onchange('notification_department_id')
def _clear_employee_ids(self):
if self.notification_department_id:
self.notification_employee_ids = False

View File

@@ -0,0 +1,5 @@
<odoo>
<data>
</data>
</odoo>

View File

@@ -0,0 +1,15 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sf_message_template_group_sale_salemanager,sf_message_template,model_sf_message_template,sf_base.group_sale_salemanager,1,1,1,0
access_sf_message_template_group_purchase,sf_message_template,model_sf_message_template,sf_base.group_purchase,1,1,1,0
access_sf_message_template_group_sf_stock_user,sf_message_template,model_sf_message_template,sf_base.group_sf_stock_user,1,1,1,0
access_sf_message_template_group_sf_order_user,sf_message_template,model_sf_message_template,sf_base.group_sf_order_user,1,1,1,0
access_sf_message_template_group_sf_tool_user,sf_message_template,model_sf_message_template,sf_base.group_sf_tool_user,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sf_message_template_group_sale_salemanager sf_message_template model_sf_message_template sf_base.group_sale_salemanager 1 1 1 0
3 access_sf_message_template_group_purchase sf_message_template model_sf_message_template sf_base.group_purchase 1 1 1 0
4 access_sf_message_template_group_sf_stock_user sf_message_template model_sf_message_template sf_base.group_sf_stock_user 1 1 1 0
5 access_sf_message_template_group_sf_order_user sf_message_template model_sf_message_template sf_base.group_sf_order_user 1 1 1 0
6 access_sf_message_template_group_sf_tool_user sf_message_template model_sf_message_template sf_base.group_sf_tool_user 1 1 1 0

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- © <2016> <top hy>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<odoo>
<data>
<record id="sf_message_template_view_form" model="ir.ui.view">
<field name="name">sf.message.template.view.form</field>
<field name="model">sf.message.template</field>
<field name="arch" type="xml">
<form string="消息模板">
<sheet>
<div class="oe_title">
<label for="name"/>
<h1>
<field name="name" class="w-100" required="1"/>
</h1>
</div>
<group>
<field name="type"/>
<field name="content" widget="html" class="oe-bordered-editor"
options="{'style-inline': true, 'codeview': true, 'dynamic_placeholder': true}"/>
<field name="description"/>
<field name="msgtype"/>
<field name="type"/>
<field name="notification_department_id"/>
<field name="notification_employee_ids" widget="many2many_tags"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="sf_message_template_view_tree" model="ir.ui.view">
<field name="name">sf.message.template.view.tree</field>
<field name="model">sf.message.template</field>
<field name="arch" type="xml">
<tree string="消息模板">
<field name="name"/>
<field name="type"/>
<field name="content"/>
<field name="msgtype"/>
<field name="type"/>
<field name="notification_department_id"/>
<field name="notification_employee_ids" widget="many2many_tags"/>
<field name="description"/>
</tree>
</field>
</record>
<record id="sf_message_template_search_view" model="ir.ui.view">
<field name="name">sf.message.template.search.view</field>
<field name="model">sf.message.template</field>
<field name="arch" type="xml">
<search>
<field name="name" string="模糊搜索"
filter_domain="['|','|',('name','like',self),('type','like',self),('description','like',self)]"/>
<field name="name"/>
<filter name="filter_active" string="已归档" domain="[('active','=',False)]"/>
</search>
</field>
</record>
<!--定义单证类型视图动作-->
<record id="sf_message_template_action" model="ir.actions.act_window">
<field name="name">消息模板</field>
<field name="res_model">sf.message.template</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="sf_message_template_view_tree"/>
</record>
<menuitem id="msg_set_menu" name="消息设置" parent="base.menu_administration" sequence="1"/>
<menuitem id="sf_message_template_send_menu" name="消息模板" parent="msg_set_menu"
action="sf_message_template_action" sequence="1"/>
</data>
</odoo>

View File

@@ -56,6 +56,18 @@ class QuickEasyOrder(models.Model):
processing_time = fields.Integer('加工时长(min)') processing_time = fields.Integer('加工时长(min)')
sale_order_id = fields.Many2one('sale.order', '销售订单号') sale_order_id = fields.Many2one('sale.order', '销售订单号')
part_drawing_number = fields.Char('零件图号')
machining_drawings = fields.Binary('2D加工图纸')
@api.onchange('parameter_ids')
def _compute_parameter_ids(self):
my_parameter_ids = {}
for item in self:
for item1 in item.parameter_ids:
my_parameter_ids[item1.process_id.id] = item1.ids[0]
my_parameter_ids = list(my_parameter_ids.values())
item.write({'parameter_ids': [(6, 0, my_parameter_ids)]})
@api.depends('unit_price', 'quantity') @api.depends('unit_price', 'quantity')
def _compute_total_amount(self): def _compute_total_amount(self):
for item in self: for item in self:

View File

@@ -73,12 +73,14 @@
<field name="material_model_id" options="{'no_create': True}" required="1"/> <field name="material_model_id" options="{'no_create': True}" required="1"/>
<!-- <field name="process_id"/>--> <!-- <field name="process_id"/>-->
<field name="parameter_ids" widget="many2many_tags" string="表面工艺参数" <field name="parameter_ids" widget="many2many_tags" string="表面工艺参数"
options="{'no_create': True}" required="1"/> options="{'no_create': True}"/>
<field name="machining_precision" required="1"/> <field name="machining_precision" required="1"/>
<field name="processing_time"/> <field name="processing_time"/>
<field name="quantity" options="{'format': false}"/> <field name="quantity" options="{'format': false}"/>
<field name="unit_price"/> <field name="unit_price"/>
<field name="price" options="{'format': false}"/> <field name="price" options="{'format': false}"/>
<field name="part_drawing_number"/>
<field name="machining_drawings" widget="pdf_viewer"/>
<field name="sale_order_id" <field name="sale_order_id"
attrs='{"invisible": [("sale_order_id","=",False)],"readonly": [("sale_order_id","!=",False)]}'/> attrs='{"invisible": [("sale_order_id","=",False)],"readonly": [("sale_order_id","!=",False)]}'/>
</group> </group>

View File

@@ -100,8 +100,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="property_supplier_payment_term_id" position="before"> <field name="property_supplier_payment_term_id" position="before">
<field name="purchase_user_id" context="{'supplier_rank': supplier_rank }" <field name="purchase_user_id" context="{'supplier_rank': supplier_rank }"
widget="many2one_avatar_user" widget="many2one_avatar_user"/>
attrs="{'required' : [('supplier_rank','>', 0)]}"/>
</field> </field>
<xpath expr="//field[@name='property_account_position_id']" position="attributes"> <xpath expr="//field[@name='property_account_position_id']" position="attributes">
<attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute> <attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute>

View File

@@ -122,7 +122,8 @@ class Manufacturing_Connect(http.Controller):
tool_assembly.write({ tool_assembly.write({
'after_assembly_tool_loading_length': float(data_list[1] or "0"), # 高度(总长度) 'after_assembly_tool_loading_length': float(data_list[1] or "0"), # 高度(总长度)
'after_assembly_functional_tool_diameter': float(data_list[2] or "0") * 2, # 直径 'after_assembly_functional_tool_diameter': float(data_list[2] or "0") * 2, # 直径
'after_assembly_knife_tip_r_angle': float(data_list[3] or "0") # R角 'after_assembly_knife_tip_r_angle': float(data_list[3] or "0"), # R角
'bool_preset_parameter': True
}) })
except Exception as e: except Exception as e:
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}

View File

@@ -10,4 +10,5 @@ from . import temporary_data_processing_methods
from . import stock from . import stock
from . import jikimo_bom from . import jikimo_bom
from . import tool_inventory from . import tool_inventory
from . import functional_cutting_tool_model from . import functional_cutting_tool_model
# from . import product_product

View File

@@ -349,25 +349,100 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
class FunctionalToolAssembly(models.Model): class FunctionalToolAssembly(models.Model):
_name = 'sf.functional.tool.assembly' _name = 'sf.functional.tool.assembly'
_inherit = ['mail.thread'] _inherit = ['mail.thread', 'barcodes.barcode_events_mixin']
_description = '功能刀具组装' _description = '功能刀具组装'
_order = 'assemble_status, use_tool_time asc' _order = 'tool_loading_time desc, use_tool_time asc'
def on_barcode_scanned(self, barcode):
"""
智能工厂组装单处扫码校验刀具物料
"""
for record in self:
tool_assembly_id = self.env['sf.functional.tool.assembly'].browse(self.ids)
lot_ids = self.env['stock.lot'].sudo().search([('rfid', '=', barcode)])
if lot_ids:
for lot_id in lot_ids:
if lot_id.tool_material_status != '可用':
raise ValidationError(f'Rfid为【{barcode}】的刀柄已被占用,请重新扫描!!')
if lot_id.product_id == record.handle_product_id:
record.handle_code_id = lot_id.id
tool_assembly_id.handle_code_id = lot_id.id
else:
raise ValidationError('刀柄选择错误,请重新确认!!!')
else:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', barcode)])
if location:
if location == record.integral_freight_barcode_id:
tool_assembly_id.integral_verify = True
record.integral_verify = True
elif location == record.blade_freight_barcode_id:
tool_assembly_id.blade_verify = True
record.blade_verify = True
elif location == record.bar_freight_barcode_id:
tool_assembly_id.bar_verify = True
record.bar_verify = True
elif location == record.pad_freight_barcode_id:
tool_assembly_id.pad_verify = True
record.pad_verify = True
elif location == record.chuck_freight_barcode_id:
tool_assembly_id.chuck_verify = True
record.chuck_verify = True
else:
raise ValidationError('刀具选择错误,请重新确认!')
else:
raise ValidationError(f'扫描为【{barcode}】的货位不存在,请重新扫描!')
@api.depends('functional_tool_name') @api.depends('functional_tool_name')
def _compute_name(self): def _compute_name(self):
for obj in self: for obj in self:
obj.name = obj.assembly_order_code obj.name = obj.assembly_order_code
code = fields.Char('功能刀具编码', readonly=True)
rfid = fields.Char('Rfid', readonly=True) rfid = fields.Char('Rfid', readonly=True)
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=True) tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', store=True, compute='_compute_inventory_num')
name = fields.Char(string='名称', readonly=True, compute='_compute_name') name = fields.Char(string='名称', readonly=True, compute='_compute_name')
assembly_order_code = fields.Char(string='组装单编码', readonly=True) assembly_order_code = fields.Char(string='组装单编码', readonly=True)
functional_tool_name_id = fields.Many2one('product.product', string='功能刀具', readonly=True) functional_tool_name_id = fields.Many2one('product.product', string='功能刀具', readonly=True)
functional_tool_name = fields.Char(string='功能刀具名称', readonly=True) functional_tool_name = fields.Char(string='功能刀具名称', readonly=True, required=True)
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=True, tool_inventory_id = fields.Many2one('sf.tool.inventory', string='功能刀具清单', store=True,
group_expand='_read_group_functional_tool_type_ids') compute='_compute_functional_tool_name')
@api.depends('functional_tool_name')
def _compute_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.tool_inventory_id = inventory.id
item.after_assembly_functional_tool_name = item.functional_tool_name # 组装后名称
item.functional_tool_type_id = item.tool_inventory_id.functional_cutting_tool_model_id.id
item.tool_groups_id = item.tool_inventory_id.tool_groups_id.id # 刀具组
item.after_assembly_functional_tool_type_id = item.tool_inventory_id.functional_cutting_tool_model_id.id
item.after_assembly_functional_tool_diameter = item.tool_inventory_id.diameter # 直径
item.after_assembly_knife_tip_r_angle = item.tool_inventory_id.angle # R角
item.after_assembly_tool_loading_length = item.tool_inventory_id.tool_length # 总长度
item.after_assembly_functional_tool_length = item.tool_inventory_id.extension # 伸出长度
item.after_assembly_max_lifetime_value = item.tool_inventory_id.life_span # 最大寿命
@api.depends('tool_inventory_id', 'tool_inventory_id.functional_cutting_tool_model_id', 'tool_inventory_id.angle',
'tool_inventory_id.tool_groups_id', 'tool_inventory_id.diameter', 'tool_inventory_id.tool_length',
'tool_inventory_id.extension', 'tool_inventory_id.life_span')
def _compute_inventory_num(self):
for item in self:
if item.assemble_status != '01':
return True
if item.tool_inventory_id:
item.functional_tool_type_id = item.tool_inventory_id.functional_cutting_tool_model_id.id
item.tool_groups_id = item.tool_inventory_id.tool_groups_id.id # 刀具组
item.after_assembly_functional_tool_type_id = item.tool_inventory_id.functional_cutting_tool_model_id.id
item.after_assembly_functional_tool_diameter = item.tool_inventory_id.diameter # 直径
item.after_assembly_knife_tip_r_angle = item.tool_inventory_id.angle # R角
item.after_assembly_tool_loading_length = item.tool_inventory_id.tool_length # 总长度
item.after_assembly_max_lifetime_value = item.tool_inventory_id.life_span # 最大寿命
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型',
group_expand='_read_group_functional_tool_type_ids', store=True,
compute='_compute_inventory_num')
functional_tool_diameter = fields.Float(string='功能刀具直径(mm)', readonly=True) functional_tool_diameter = fields.Float(string='功能刀具直径(mm)', readonly=True)
knife_tip_r_angle = fields.Float(string='刀尖R角(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) coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')], string='粗/中/精', readonly=True)
@@ -375,16 +450,17 @@ class FunctionalToolAssembly(models.Model):
tool_loading_length = fields.Float(string='总长度(mm)', readonly=True) tool_loading_length = fields.Float(string='总长度(mm)', readonly=True)
functional_tool_length = fields.Float(string='伸出长(mm)', readonly=True) functional_tool_length = fields.Float(string='伸出长(mm)', readonly=True)
effective_length = fields.Float(string='有效长(mm)', readonly=True) effective_length = fields.Float(string='有效长(mm)', readonly=True)
loading_task_source = fields.Selection([('0', 'CAM装刀'), ('1', '机台换刀'), ('2', '按库存组装')], loading_task_source = fields.Selection(
string='装刀任务来源', readonly=True) [('0', 'CAM装刀'), ('1', '机台换刀'), ('2', '按库存组装'), ('3', '寿命到期组装')],
string='装刀任务来源', readonly=True)
use_tool_time = fields.Datetime(string='用刀时间', readonly=True) use_tool_time = fields.Datetime(string='用刀时间', readonly=True)
production_line_name_id = fields.Many2one('sf.production.line', 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_name_id = fields.Many2one('maintenance.equipment', string='申请机台', readonly=True)
machine_tool_code = fields.Char(string='机台号', readonly=True) machine_tool_code = fields.Char(string='机台号', readonly=True)
applicant = fields.Char(string='申请人', readonly=True) applicant = fields.Char(string='申请人', readonly=True)
apply_time = fields.Datetime(string='申请时间', default=fields.Datetime.now(), readonly=True) apply_time = fields.Datetime(string='申请时间', default=fields.Datetime.now(), readonly=True)
assemble_status = fields.Selection([('0', '待组装'), ('1', '组装')], string='组装状态', default='0', assemble_status = fields.Selection([('0', '待组装'), ('01', '组装'), ('1', '组装'), ('3', '已取消')],
tracking=True, readonly=True) string='组装状态', default='0', tracking=True, readonly=True)
cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号', readonly=True) cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号', readonly=True)
whether_standard_knife = fields.Boolean(string='是否标准刀', default=True, readonly=True) whether_standard_knife = fields.Boolean(string='是否标准刀', default=True, readonly=True)
reason_for_applying = fields.Char(string='申请原因', readonly=True) reason_for_applying = fields.Char(string='申请原因', readonly=True)
@@ -392,7 +468,7 @@ class FunctionalToolAssembly(models.Model):
alarm_value = fields.Integer(string='报警值(min)', readonly=True) alarm_value = fields.Integer(string='报警值(min)', readonly=True)
used_value = fields.Integer(string='已使用值(min)', readonly=True) used_value = fields.Integer(string='已使用值(min)', readonly=True)
image = fields.Binary('图片', readonly=True) image = fields.Binary('图片', readonly=False)
@api.model @api.model
def _read_group_functional_tool_type_ids(self, categories, domain, order): def _read_group_functional_tool_type_ids(self, categories, domain, order):
@@ -402,8 +478,9 @@ class FunctionalToolAssembly(models.Model):
# 刀具物料信息 # 刀具物料信息
# ==============整体式刀具型号============= # ==============整体式刀具型号=============
integral_freight_barcode_id = fields.Many2one('sf.shelf.location', string='整体式刀具货位') integral_freight_barcode_id = fields.Many2one('sf.shelf.location', string='整体式刀具货位', readonly=True,
integral_lot_id = fields.Many2one('stock.lot', string='整体式刀具批次') domain="[('product_id.cutting_tool_material_id.name', '=', '整体式刀具'),('product_num', '>', 0)]")
integral_lot_id = fields.Many2one('stock.lot', string='整体式刀具批次', readonly=True)
integral_product_id = fields.Many2one('product.product', string='整体式刀具名称', integral_product_id = fields.Many2one('product.product', string='整体式刀具名称',
compute='_compute_integral_product_id', store=True) compute='_compute_integral_product_id', store=True)
cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号', cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号',
@@ -412,16 +489,20 @@ class FunctionalToolAssembly(models.Model):
related='integral_product_id.specification_id') related='integral_product_id.specification_id')
sf_tool_brand_id_1 = fields.Many2one('sf.machine.brand', string='整体式刀具品牌', sf_tool_brand_id_1 = fields.Many2one('sf.machine.brand', string='整体式刀具品牌',
related='integral_product_id.brand_id') related='integral_product_id.brand_id')
integral_verify = fields.Boolean('整体刀校验', default=False)
@api.depends('integral_lot_id') @api.depends('integral_lot_id')
def _compute_integral_product_id(self): def _compute_integral_product_id(self):
for item in self: for item in self:
if item.integral_lot_id: if item.integral_lot_id:
item.integral_product_id = item.integral_lot_id.product_id.id item.integral_product_id = item.integral_lot_id.product_id.id
else:
item.integral_product_id = False
# =================刀片型号============= # =================刀片型号=============
blade_freight_barcode_id = fields.Many2one('sf.shelf.location', string='刀片货位') blade_freight_barcode_id = fields.Many2one('sf.shelf.location', string='刀片货位', readonly=True,
blade_lot_id = fields.Many2one('stock.lot', string='刀片批次') domain="[('product_id.cutting_tool_material_id.name', '=', '刀片'),('product_num', '>', 0)]")
blade_lot_id = fields.Many2one('stock.lot', string='刀片批次', readonly=True)
blade_product_id = fields.Many2one('product.product', string='刀片名称', compute='_compute_blade_product_id', blade_product_id = fields.Many2one('product.product', string='刀片名称', compute='_compute_blade_product_id',
store=True) store=True)
cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号', cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号',
@@ -429,16 +510,20 @@ class FunctionalToolAssembly(models.Model):
blade_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀片规格', blade_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀片规格',
related='blade_product_id.specification_id') related='blade_product_id.specification_id')
sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_product_id.brand_id') sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_product_id.brand_id')
blade_verify = fields.Boolean('刀片校验', default=False)
@api.depends('blade_lot_id') @api.depends('blade_lot_id')
def _compute_blade_product_id(self): def _compute_blade_product_id(self):
for item in self: for item in self:
if item.blade_lot_id: if item.blade_lot_id:
item.blade_product_id = item.blade_lot_id.product_id.id item.blade_product_id = item.blade_lot_id.product_id.id
else:
item.blade_product_id = False
# ==============刀杆型号================ # ==============刀杆型号================
bar_freight_barcode_id = fields.Many2one('sf.shelf.location', string='刀杆货位') bar_freight_barcode_id = fields.Many2one('sf.shelf.location', string='刀杆货位', readonly=True,
bar_lot_id = fields.Many2one('stock.lot', string='刀杆批次') domain="[('product_id.cutting_tool_material_id.name', '=', '刀杆'),('product_num', '>', 0)]")
bar_lot_id = fields.Many2one('stock.lot', string='刀杆批次', readonly=True)
bar_product_id = fields.Many2one('product.product', string='刀杆名称', compute='_compute_bar_product_id', bar_product_id = fields.Many2one('product.product', string='刀杆名称', compute='_compute_bar_product_id',
store=True) store=True)
cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号', cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号',
@@ -446,16 +531,20 @@ class FunctionalToolAssembly(models.Model):
bar_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀杆规格', bar_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀杆规格',
related='bar_product_id.specification_id') related='bar_product_id.specification_id')
sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_product_id.brand_id') sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_product_id.brand_id')
bar_verify = fields.Boolean('刀杆校验', default=False)
@api.depends('bar_lot_id') @api.depends('bar_lot_id')
def _compute_bar_product_id(self): def _compute_bar_product_id(self):
for item in self: for item in self:
if item.bar_lot_id: if item.bar_lot_id:
item.bar_product_id = item.bar_lot_id.product_id.id item.bar_product_id = item.bar_lot_id.product_id.id
else:
item.bar_product_id = False
# =============刀盘型号================ # =============刀盘型号================
pad_freight_barcode_id = fields.Many2one('sf.shelf.location', string='刀盘货位') pad_freight_barcode_id = fields.Many2one('sf.shelf.location', string='刀盘货位', readonly=True,
pad_lot_id = fields.Many2one('stock.lot', string='刀盘批次') domain="[('product_id.cutting_tool_material_id.name', '=', '刀盘'),('product_num', '>', 0)]")
pad_lot_id = fields.Many2one('stock.lot', string='刀盘批次', readonly=True)
pad_product_id = fields.Many2one('product.product', string='刀盘名称', compute='_compute_pad_product_id', pad_product_id = fields.Many2one('product.product', string='刀盘名称', compute='_compute_pad_product_id',
store=True) store=True)
cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号', cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号',
@@ -463,37 +552,42 @@ class FunctionalToolAssembly(models.Model):
pad_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀盘规格', pad_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀盘规格',
related='pad_product_id.specification_id') related='pad_product_id.specification_id')
sf_tool_brand_id_4 = fields.Many2one('sf.machine.brand', '刀盘品牌', related='pad_product_id.brand_id') sf_tool_brand_id_4 = fields.Many2one('sf.machine.brand', '刀盘品牌', related='pad_product_id.brand_id')
pad_verify = fields.Boolean('刀盘校验', default=False)
@api.depends('pad_lot_id') @api.depends('pad_lot_id')
def _compute_pad_product_id(self): def _compute_pad_product_id(self):
for item in self: for item in self:
if item.pad_lot_id: if item.pad_lot_id:
item.pad_product_id = item.pad_lot_id.product_id.id item.pad_product_id = item.pad_lot_id.product_id.id
else:
item.pad_product_id = False
# ==============刀柄型号============== # ==============刀柄型号==============
handle_freight_rfid = fields.Char('刀柄Rfid', compute='_compute_handle_product_id', store=True) handle_code_id = fields.Many2one('stock.lot', '刀柄序列号', readonly=True,
handle_code_id = fields.Many2one('stock.lot', '刀柄序列号') domain="[('product_id', '=', handle_product_id)]")
handle_product_id = fields.Many2one('product.product', string='刀柄名称', compute='_compute_handle_product_id', handle_freight_rfid = fields.Char('刀柄Rfid', compute='_compute_handle_rfid', store=True)
store=True) handle_product_id = fields.Many2one('product.product', string='刀柄名称', readonly=True)
cutting_tool_cutterhandle_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀柄型号', cutting_tool_cutterhandle_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀柄型号',
related='handle_product_id.cutting_tool_model_id') related='handle_product_id.cutting_tool_model_id')
handle_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀柄规格', handle_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀柄规格',
related='handle_product_id.specification_id') related='handle_product_id.specification_id')
sf_tool_brand_id_5 = fields.Many2one('sf.machine.brand', '刀柄品牌', related='handle_product_id.brand_id') sf_tool_brand_id_5 = fields.Many2one('sf.machine.brand', '刀柄品牌', related='handle_product_id.brand_id')
handle_verify = fields.Boolean('刀柄校验', default=False)
@api.depends('handle_code_id') @api.depends('handle_code_id')
def _compute_handle_product_id(self): def _compute_handle_rfid(self):
for item in self: for item in self:
if item.handle_code_id: if item.handle_code_id:
item.handle_product_id = item.handle_code_id.product_id.id
item.handle_freight_rfid = item.handle_code_id.rfid item.handle_freight_rfid = item.handle_code_id.rfid
item.rfid = item.handle_freight_rfid
else: else:
item.handle_product_id = False
item.handle_freight_rfid = False item.handle_freight_rfid = False
item.rfid = False
# ==============夹头型号============== # ==============夹头型号==============
chuck_freight_barcode_id = fields.Many2one('sf.shelf.location', string='夹头货位') chuck_freight_barcode_id = fields.Many2one('sf.shelf.location', string='夹头货位', readonly=True,
chuck_lot_id = fields.Many2one('stock.lot', string='夹头批次') domain="[('product_id.cutting_tool_material_id.name', '=', '夹头'),('product_num', '>', 0)]")
chuck_lot_id = fields.Many2one('stock.lot', string='夹头批次', readonly=True)
chuck_product_id = fields.Many2one('product.product', string='夹头名称', compute='_compute_chuck_product_id', chuck_product_id = fields.Many2one('product.product', string='夹头名称', compute='_compute_chuck_product_id',
store=True) store=True)
cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号', cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号',
@@ -501,12 +595,15 @@ class FunctionalToolAssembly(models.Model):
chuck_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='夹头规格', chuck_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='夹头规格',
related='chuck_product_id.specification_id') related='chuck_product_id.specification_id')
sf_tool_brand_id_6 = fields.Many2one('sf.machine.brand', '夹头品牌', related='chuck_product_id.brand_id') sf_tool_brand_id_6 = fields.Many2one('sf.machine.brand', '夹头品牌', related='chuck_product_id.brand_id')
chuck_verify = fields.Boolean('夹头校验', default=False)
@api.depends('chuck_lot_id') @api.depends('chuck_lot_id')
def _compute_chuck_product_id(self): def _compute_chuck_product_id(self):
for item in self: for item in self:
if item.chuck_lot_id: if item.chuck_lot_id:
item.chuck_product_id = item.chuck_lot_id.product_id.id item.chuck_product_id = item.chuck_lot_id.product_id.id
else:
item.chuck_product_id = False
# ==================待删除字段================== # ==================待删除字段==================
integral_freight_barcode = fields.Char('整体式刀具货位') integral_freight_barcode = fields.Char('整体式刀具货位')
@@ -525,30 +622,39 @@ class FunctionalToolAssembly(models.Model):
handle_name = fields.Char('') handle_name = fields.Char('')
chuck_code_id = fields.Many2one('stock.lot', '夹头序列号') chuck_code_id = fields.Many2one('stock.lot', '夹头序列号')
chuck_name = fields.Char('') chuck_name = fields.Char('')
# ====================暂时无用字段=========================
after_assembly_used_value = fields.Integer(string='组装后已使用值(min)', readonly=True)
# ============================================== # ==============================================
# 组装功能刀具参数信息 # 组装功能刀具参数信息
start_preset_bool = fields.Boolean('开始预调', default=False) start_preset_bool = fields.Boolean('开始预调', default=False)
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', readonly=True) barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', readonly=True)
after_assembly_functional_tool_name = fields.Char(string='组装后功能刀具名称', readonly=True) after_assembly_functional_tool_name = fields.Char(string='组装后功能刀具名称', store=True,
after_assembly_functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', compute='_compute_functional_tool_name')
string='组装后功能刀具类型', readonly=True) after_assembly_functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', store=True,
after_assembly_functional_tool_diameter = fields.Float(string='组装后功能刀具直径(mm)', readonly=True, string='组装后功能刀具类型',
digits=(10, 3)) compute='_compute_inventory_num')
after_assembly_knife_tip_r_angle = fields.Float(string='组装后刀尖R角(mm)', readonly=True, digits=(10, 3)) after_assembly_functional_tool_diameter = fields.Float(string='组装后功能刀具直径(mm)', digits=(10, 3), store=True,
after_assembly_new_former = fields.Selection([('0', ''), ('1', '')], string='组装后新/旧', readonly=True) compute='_compute_inventory_num')
after_assembly_knife_tip_r_angle = fields.Float(string='组装后刀尖R角(mm)', digits=(10, 3), store=True,
compute='_compute_inventory_num')
after_assembly_new_former = fields.Selection([('0', ''), ('1', '')], string='组装后新/旧', default='0',
store=True, compute='_compute_rota_tive')
cut_time = fields.Integer(string='已切削时间(min)', readonly=True) cut_time = fields.Integer(string='已切削时间(min)', readonly=True)
cut_length = fields.Float(string='已切削长度(mm)', readonly=True) cut_length = fields.Float(string='已切削长度(mm)', readonly=True)
cut_number = fields.Integer(string='已切削次数', readonly=True) cut_number = fields.Integer(string='已切削次数', readonly=True)
after_assembly_whether_standard_knife = fields.Boolean(string='组装后是否标准刀', default=True, readonly=True) after_assembly_whether_standard_knife = fields.Boolean(string='组装后是否标准刀', default=True, readonly=True)
after_assembly_coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')], after_assembly_coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')], store=True,
string='组装后粗/中/精', readonly=True) string='组装后粗/中/精', default='3',
after_assembly_max_lifetime_value = fields.Integer(string='组装后最大寿命值(min)', readonly=True) compute='_compute_rota_tive')
after_assembly_alarm_value = fields.Integer(string='组装后报警值(min)', readonly=True) after_assembly_max_lifetime_value = fields.Integer(string='组装后最大寿命值(min)', store=True,
after_assembly_used_value = fields.Integer(string='组装后已使用值(min)', readonly=True) compute='_compute_inventory_num')
after_assembly_tool_loading_length = fields.Float(string='组装后总长度(mm)', readonly=True, digits=(10, 3)) after_assembly_alarm_value = fields.Integer(string='组装后报警值(min)')
after_assembly_handle_length = fields.Float(string='组装后刀柄长度(mm)', readonly=True, digits=(10, 3)) after_assembly_tool_loading_length = fields.Float(string='组装后长度(mm)', digits=(10, 3), store=True,
after_assembly_functional_tool_length = fields.Float(string='组装后伸出长(mm)', readonly=True, digits=(10, 3)) compute='_compute_inventory_num')
after_assembly_handle_length = fields.Float(string='组装后刀柄长度(mm)', digits=(10, 3))
after_assembly_functional_tool_length = fields.Float(string='组装后伸出长(mm)', digits=(10, 3), store=True,
compute='_compute_length')
after_assembly_effective_length = fields.Float(string='组装后有效长(mm)', readonly=True) after_assembly_effective_length = fields.Float(string='组装后有效长(mm)', readonly=True)
L_D_number = fields.Float(string='L/D值(mm)', readonly=True) L_D_number = fields.Float(string='L/D值(mm)', readonly=True)
hiding_length = fields.Float(string='避空长(mm)', readonly=True) hiding_length = fields.Float(string='避空长(mm)', readonly=True)
@@ -562,10 +668,74 @@ class FunctionalToolAssembly(models.Model):
sf_machine_table_tool_changing_apply_id = fields.Many2one('sf.machine.table.tool.changing.apply', '机床换刀申请', sf_machine_table_tool_changing_apply_id = fields.Many2one('sf.machine.table.tool.changing.apply', '机床换刀申请',
readonly=True) readonly=True)
sf_cam_work_order_program_knife_plan_id = fields.Many2one('sf.cam.work.order.program.knife.plan', sf_cam_work_order_program_knife_plan_id = fields.Many2one('sf.cam.work.order.program.knife.plan',
'CAM工单程序用刀计划', readonly=True, ) 'CAM工单程序用刀计划', readonly=True)
active = fields.Boolean(string='已归档', default=True) active = fields.Boolean(string='已归档', default=True)
code = fields.Char('功能刀具编码', compute='_compute_code')
@api.depends('after_assembly_tool_loading_length', 'after_assembly_handle_length')
def _compute_length(self):
for item in self:
if item.after_assembly_tool_loading_length > item.after_assembly_handle_length:
item.after_assembly_functional_tool_length = (
item.after_assembly_tool_loading_length - item.after_assembly_handle_length)
@api.depends('integral_freight_barcode_id', 'blade_freight_barcode_id')
def _compute_rota_tive(self):
for item in self:
rota_tive_boolean = False
if item.integral_freight_barcode_id:
# 整体刀
if item.integral_freight_barcode_id.rotative_Boolean:
rota_tive_boolean = True
elif item.blade_freight_barcode_id:
# 刀片
if item.blade_freight_barcode_id.rotative_Boolean:
rota_tive_boolean = True
if rota_tive_boolean:
item.after_assembly_coarse_middle_thin = '1'
item.after_assembly_new_former = '1'
else:
item.after_assembly_coarse_middle_thin = '3'
item.after_assembly_new_former = '0'
@api.onchange('handle_product_id')
def _onchange_after_assembly_handle_length(self):
for item in self:
if item:
if item.handle_product_id:
item.after_assembly_handle_length = item.handle_product_id.cutting_tool_shank_length
@api.depends('after_assembly_functional_tool_type_id', 'cutting_tool_cutterhandle_model_id',
'after_assembly_functional_tool_diameter', 'after_assembly_tool_loading_length',
'after_assembly_knife_tip_r_angle', 'after_assembly_functional_tool_length',
'after_assembly_handle_length')
def _compute_code(self):
for obj in self:
if obj.cutting_tool_cutterhandle_model_id:
code = obj.cutting_tool_cutterhandle_model_id.code.split('-', 1)[0]
str_1 = '%s-GNDJ-%s-D%sL%sR%sB%sH%s' % (
code, obj.after_assembly_functional_tool_type_id.code, obj.after_assembly_functional_tool_diameter,
obj.after_assembly_tool_loading_length, obj.after_assembly_knife_tip_r_angle,
round(obj.after_assembly_functional_tool_length, 3), obj.after_assembly_handle_length)
obj.code = '%s-%s' % (str_1, self._get_code_1(str_1))
else:
obj.code = ''
def _get_code_1(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
def action_open_reference1(self): def action_open_reference1(self):
self.ensure_one() self.ensure_one()
return { return {
@@ -575,41 +745,326 @@ class FunctionalToolAssembly(models.Model):
'res_id': self.id, 'res_id': self.id,
} }
def put_start_preset(self): def start_preset(self):
self.search([('start_preset_bool', '=', True)]).write({'start_preset_bool': False}) """
开始组装
"""
# 设置初始值
self.start_preset_bool = True
self.assemble_status = '01'
self.after_assembly_coarse_middle_thin = '3'
self.after_assembly_new_former = '0'
# 调用功能刀具名称对应的清单的BOM获取对应刀具物料信息
bom = self._get_inventory_bom(self.tool_inventory_id)
# 根据BOM自动配置物料的值
self._set_tool_material(bom)
logging.info('功能刀具开始组装初始化值成功!')
def _set_tool_material(self, bom):
"""根据BOM对刀具物料进行初始配置"""
options = bom.get('options')
# 配置刀柄信息
for handle_id in bom.get('handle_ids'):
if handle_id:
if not self.handle_product_id:
self.handle_product_id = handle_id.id
break
# 刀柄之外的物料配置
if options == '刀柄+整体式刀具':
# 配置整体式刀具
integra_lot_id = self._get_old_tool_material_lot(bom.get('integral_ids'))
integra_location_lot_id = self._get_shelf_location_lot(integra_lot_id)
self.integral_freight_barcode_id = integra_location_lot_id.shelf_location_id.id
self.integral_lot_id = integra_location_lot_id.lot_id.id
else:
# 配置刀片
blade_lot_id = self._get_old_tool_material_lot(bom.get('blade_ids'))
blade_location_lot_id = self._get_shelf_location_lot(blade_lot_id)
self.blade_freight_barcode_id = blade_location_lot_id.shelf_location_id.id
self.blade_lot_id = blade_location_lot_id.lot_id.id
if options == '刀柄+刀杆+刀片':
# 配置刀杆
bar_lot_id = self._get_old_tool_material_lot(bom.get('bar_ids'))
bar_location_lot_id = self._get_shelf_location_lot(bar_lot_id)
self.bar_freight_barcode_id = bar_location_lot_id.shelf_location_id.id
self.bar_lot_id = bar_location_lot_id.lot_id.id
elif options == '刀柄+刀盘+刀片':
# 配置刀盘
pad_lot_id = self._get_old_tool_material_lot(bom.get('pad_ids'))
pad_location_lot_id = self._get_shelf_location_lot(pad_lot_id)
self.pad_freight_barcode_id = pad_location_lot_id.shelf_location_id.id
self.pad_lot_id = pad_location_lot_id.lot_id.id
def _get_old_tool_material_lot(self, material_ids):
""" 根据先进先出原则选择物料批次 """
location_id = self.env['stock.location'].search([('name', '=', '刀具房')])
stock_quant = self.env['stock.quant'].sudo().search(
[('location_id', '=', location_id.id), ('product_id', 'in', material_ids.ids), ('quantity', '>', '0')],
order='lot_id', limit=1)
if stock_quant:
return stock_quant.lot_id
else:
raise ValidationError(f'{material_ids[0].cutting_tool_material_id.name}】物料库存不足,请先进行盘点或采购')
def _get_shelf_location_lot(self, lot_id):
"""根据所给的刀具物料批次号,返回一个刀具物料货位、批次信息"""
location_lots = self.env['sf.shelf.location.lot'].sudo().search([('lot_id', '=', lot_id.id)])
if not location_lots:
raise ValidationError(f'没有查询到批次为【{lot_id.name}】物料的货位信息!')
else:
return location_lots[0]
def _get_inventory_bom(self, inventory_id):
"""获取BOM的刀具物料产品信息"""
product_ids = inventory_id.jikimo_bom_ids.product_ids # BOM配置的物料产品
options = inventory_id.jikimo_bom_ids.options # BOM产品组装类型
if not product_ids or not options:
raise ValidationError('功能刀具清单的BOM未进行配置请先配置BOM信息')
handle_ids = product_ids.filtered(lambda a: a.cutting_tool_material_id.name == '刀柄')
integral_ids = product_ids.filtered(lambda a: a.cutting_tool_material_id.name == '整体式刀具')
blade_ids = product_ids.filtered(lambda a: a.cutting_tool_material_id.name == '刀片')
bar_ids = product_ids.filtered(lambda a: a.cutting_tool_material_id.name == '刀杆')
pad_ids = product_ids.filtered(lambda a: a.cutting_tool_material_id.name == '刀盘')
if not handle_ids:
raise ValidationError('功能刀具清单的BOM未配置[刀柄]信息请先配置BOM再开始组装')
if options == '刀柄+整体式刀具':
if not integral_ids:
raise ValidationError('功能刀具清单的BOM未配置[刀柄]信息请先配置BOM再开始组装')
return {'options': options, 'handle_ids': handle_ids, 'integral_ids': integral_ids}
elif options == '刀柄+刀杆+刀片':
if not blade_ids:
raise ValidationError('功能刀具清单的BOM未配置[刀片]信息请先配置BOM再开始组装')
if not bar_ids:
raise ValidationError('功能刀具清单的BOM未配置[刀杆]信息请先配置BOM再开始组装')
return {'options': options, 'handle_ids': handle_ids, 'blade_ids': blade_ids, 'bar_ids': bar_ids}
elif options == '刀柄+刀盘+刀片':
if not blade_ids:
raise ValidationError('功能刀具清单的BOM未配置[刀片]信息请先配置BOM再开始组装')
if not pad_ids:
raise ValidationError('功能刀具清单的BOM未配置[刀盘]信息请先配置BOM再开始组装')
return {'options': options, 'handle_ids': handle_ids, 'blade_ids': blade_ids, 'pad_ids': pad_ids}
else:
raise ValidationError(f'功能刀具清单BOM的组装方式错误{options}')
def set_tool_lot(self):
# 获取BOM的刀具物料产品信息
tool_data = self._get_inventory_bom(self.tool_inventory_id)
# 获取刀具类型
tool_type = self.env.context.get('tool_type')
if tool_type == '刀柄':
tool_material_ids = tool_data.get('handle_ids')
tool_material_tree_id = self.env.ref('sf_tool_management.view_tool_product_tree')
elif tool_type == '整体式刀具':
tool_material_ids = self._get_all_material_location_lot(tool_data.get('integral_ids'))
tool_material_tree_id = self.env.ref('sf_tool_management.view_shelf_location_lot_tree_1')
elif tool_type == '刀片':
tool_material_ids = self._get_all_material_location_lot(tool_data.get('blade_ids'))
tool_material_tree_id = self.env.ref('sf_tool_management.view_shelf_location_lot_tree_2')
elif tool_type == '刀杆':
tool_material_ids = self._get_all_material_location_lot(tool_data.get('bar_ids'))
tool_material_tree_id = self.env.ref('sf_tool_management.view_shelf_location_lot_tree_3')
else:
tool_material_ids = self._get_all_material_location_lot(tool_data.get('pad_ids'))
tool_material_tree_id = self.env.ref('sf_tool_management.view_shelf_location_lot_tree_4')
if tool_type == '刀柄':
return {
"type": "ir.actions.act_window",
"res_model": "product.product",
"views": [[tool_material_tree_id.id, "tree"],
[self.env.ref('sf_tool_management.view_tool_product_search').id, "search"]],
"target": "new",
"domain": [('id', 'in', tool_material_ids.ids)],
"context": {'tool_id': self.id}
}
elif tool_type in ['整体式刀具', '刀片', '刀杆', '刀盘']:
return {
"type": "ir.actions.act_window",
"res_model": "sf.shelf.location.lot",
"views": [[tool_material_tree_id.id, "tree"]],
"target": "new",
"domain": [('id', 'in', tool_material_ids.ids)],
"context": {'tool_id': self.id}
}
def _get_all_material_location_lot(self, material_ids):
""" 获取所有满足条件 """
location_id = self.env['stock.location'].search([('name', '=', '刀具房')])
stock_quant_ids = self.env['stock.quant'].sudo().search(
[('location_id', '=', location_id.id), ('product_id', 'in', material_ids.ids if material_ids else []),
('quantity', '>', '0')])
lot_ids = []
for stock_quant_id in stock_quant_ids:
lot_ids.append(stock_quant_id.lot_id.id)
location_lots = self.env['sf.shelf.location.lot'].sudo().search([('lot_id', 'in', lot_ids)])
return location_lots
def functional_tool_assembly(self):
"""
功能刀具确认组装
:return:
"""
logging.info('功能刀具开始组装!')
# 对物料做必填判断
self.materials_must_be_judged()
product_id = self.env['product.product']
# 创建组装入库单
# 创建功能刀具批次/序列号记录
stock_lot = product_id.create_assemble_warehouse_receipt(self)
# 封装功能刀具数据,用于创建功能刀具记录
desc_2 = self.get_desc(stock_lot, self)
# 创建功能刀具组装入库单
self.env['stock.picking'].create_tool_stocking_picking(stock_lot, self)
# 创建刀具物料出库单
self.env['stock.picking'].create_tool_stocking_picking1(self)
# ============================创建功能刀具列表、安全库存记录===============================
# 创建功能刀具列表记录
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.tool_inventory_id.id
}, record_1)
# =====================修改功能刀具组装单、机床换刀申请、CAM工单程序用刀计划的状态==============
if self.sf_machine_table_tool_changing_apply_id:
# 修改机床换刀申请的状态
self.env['sf.machine.table.tool.changing.apply'].sudo().search([
('id', '=', self.sf_machine_table_tool_changing_apply_id.id)
]).write({'status': '3'})
elif self.sf_cam_work_order_program_knife_plan_id:
# 修改CAM工单程序用刀计划状态
cam_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().search([
('id', '=', self.sf_cam_work_order_program_knife_plan_id.id)
])
cam_plan.write({'plan_execute_status': '2'})
# ============修改组装单状态为已组装=================================
self.write({ self.write({
'after_assembly_tool_loading_length': 0, 'assemble_status': '1',
'after_assembly_functional_tool_diameter': 0, 'start_preset_bool': False,
'after_assembly_knife_tip_r_angle': 0, 'tool_loading_person': self.env.user.name,
'start_preset_bool': True 'tool_loading_time': fields.Datetime.now()
}) })
logging.info('功能刀具组装完成!')
def materials_must_be_judged(self):
"""
功能刀具组装必填判断
"""
# 物料准确性校验
# 物料必填校验
if not self.handle_code_id:
raise ValidationError('缺少【刀柄】物料信息!')
if self.integral_lot_id:
if not self.integral_verify:
raise ValidationError('【整体式刀具】未进行验证!')
elif self.blade_lot_id:
if not self.blade_verify:
raise ValidationError('【刀片】未进行验证!')
if self.bar_lot_id:
if not self.bar_verify:
raise ValidationError('【刀杆】未进行验证!')
elif self.pad_lot_id:
if not self.pad_verify:
raise ValidationError('【刀盘】未进行验证!')
# 组装参数必填校验
if self.after_assembly_max_lifetime_value == 0:
raise ValidationError('组装参数信息【最大寿命值】不能为0')
if self.after_assembly_functional_tool_diameter <= 0:
raise ValidationError('组装参数信息【刀具直径】不能小于等于0')
if self.after_assembly_tool_loading_length == 0:
raise ValidationError('组装参数信息【总长度】不能为0')
if self.after_assembly_handle_length == 0:
raise ValidationError('组装参数信息【刀柄长度】不能为0')
if self.after_assembly_tool_loading_length < self.after_assembly_handle_length:
raise ValidationError('组装参数信息【刀柄长度】不能大于【总长度】!')
def get_desc(self, stock_lot, functional_tool_assembly_id):
return { return {
'type': 'ir.actions.act_window', 'barcode_id': stock_lot.id,
'res_model': 'sf.functional.tool.assembly.order', 'code': self.code,
'name': '功能刀具组装单', 'name': self.tool_inventory_id.name,
'view_mode': 'form', 'tool_name_id': self.tool_inventory_id.id,
'target': 'new', 'rfid': self.rfid,
'context': {'default_name': self.name, 'tool_groups_id': self.tool_groups_id.id,
'default_assembly_order_code': self.assembly_order_code, 'functional_tool_name_id': functional_tool_assembly_id.id,
'default_production_line_name_id': self.production_line_name_id.id, 'sf_cutting_tool_type_id': self.after_assembly_functional_tool_type_id.id,
'default_machine_tool_name_id': self.machine_tool_name_id.id, 'cutting_tool_integral_model_id': self.integral_product_id.id,
'default_cutter_spacing_code_id': self.cutter_spacing_code_id.id, 'cutting_tool_blade_model_id': self.blade_product_id.id,
'default_functional_tool_name': self.functional_tool_name, 'cutting_tool_cutterbar_model_id': self.bar_product_id.id,
'default_functional_tool_type_id': self.functional_tool_type_id.id, 'cutting_tool_cutterpad_model_id': self.pad_product_id.id,
'default_tool_groups_id': self.tool_groups_id.id, 'cutting_tool_cutterhandle_model_id': self.handle_product_id.id,
'default_functional_tool_diameter': self.functional_tool_diameter, 'cutting_tool_cutterhead_model_id': self.chuck_product_id.id,
'default_knife_tip_r_angle': self.knife_tip_r_angle,
'default_tool_loading_length': self.tool_loading_length, 'functional_tool_diameter': self.after_assembly_functional_tool_diameter,
'default_functional_tool_length': self.functional_tool_length, 'knife_tip_r_angle': self.after_assembly_knife_tip_r_angle,
'default_effective_length': self.effective_length, 'coarse_middle_thin': self.after_assembly_coarse_middle_thin,
'default_whether_standard_knife': self.whether_standard_knife, 'new_former': self.after_assembly_new_former,
'default_coarse_middle_thin': self.coarse_middle_thin, 'tool_loading_length': self.after_assembly_tool_loading_length,
'default_new_former': self.new_former, 'handle_length': self.after_assembly_handle_length,
'default_use_tool_time': self.use_tool_time, 'functional_tool_length': self.after_assembly_functional_tool_length,
'default_reason_for_applying': self.reason_for_applying '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,
} }
# def put_start_preset(self):
# # 打开组装弹窗开始组装
# self.search([('start_preset_bool', '=', True)]).write({'start_preset_bool': False})
# self.write({
# 'after_assembly_tool_loading_length': 0,
# 'after_assembly_functional_tool_diameter': 0,
# 'after_assembly_knife_tip_r_angle': 0,
# 'start_preset_bool': True
# })
# return {
# 'type': 'ir.actions.act_window',
# 'res_model': 'sf.functional.tool.assembly.order',
# 'name': '功能刀具组装单',
# 'view_mode': 'form',
# 'target': 'new',
# 'context': {'default_name': self.name,
# 'default_assembly_order_code': self.assembly_order_code,
# 'default_production_line_name_id': self.production_line_name_id.id,
# 'default_machine_tool_name_id': self.machine_tool_name_id.id,
# 'default_cutter_spacing_code_id': self.cutter_spacing_code_id.id,
# 'default_functional_tool_name': self.functional_tool_name,
# 'default_functional_tool_type_id': self.functional_tool_type_id.id,
# 'default_tool_groups_id': self.tool_groups_id.id,
# 'default_functional_tool_diameter': self.functional_tool_diameter,
# 'default_knife_tip_r_angle': self.knife_tip_r_angle,
# 'default_tool_loading_length': self.tool_loading_length,
# 'default_functional_tool_length': self.functional_tool_length,
# 'default_effective_length': self.effective_length,
# 'default_whether_standard_knife': self.whether_standard_knife,
# 'default_coarse_middle_thin': self.coarse_middle_thin,
# 'default_new_former': self.new_former,
# 'default_use_tool_time': self.use_tool_time,
# 'default_reason_for_applying': self.reason_for_applying
# }
# }
def _get_code(self, loading_task_source): def _get_code(self, loading_task_source):
""" """
自动生成组装单编码 自动生成组装单编码
@@ -622,6 +1077,8 @@ class FunctionalToolAssembly(models.Model):
code = 'J' + datetime code = 'J' + datetime
elif loading_task_source == '2': elif loading_task_source == '2':
code = 'K' + datetime code = 'K' + datetime
elif loading_task_source == '3':
code = 'S' + datetime
else: else:
code = False code = False
functional_tool_assembly = self.env['sf.functional.tool.assembly'].sudo().search( functional_tool_assembly = self.env['sf.functional.tool.assembly'].sudo().search(
@@ -648,6 +1105,13 @@ class FunctionalToolAssembly(models.Model):
return functional_tool return functional_tool
return False return False
bool_preset_parameter = fields.Boolean('', default=False)
def get_tool_preset_parameter(self):
if not self.bool_preset_parameter:
raise ValidationError('没有获取到测量数据, 请确认刀具预调仪操作是否正确!')
return True
def assemble_single_print(self): def assemble_single_print(self):
""" """
todo 组装单打印 todo 组装单打印
@@ -1032,6 +1496,50 @@ class FunctionalToolDismantle(models.Model):
}) })
logging.info('%s】刀具拆解成功!' % self.name) logging.info('%s】刀具拆解成功!' % self.name)
# ==================根据条件创建功能刀具组装单=======================
# 如果报废原因为【寿命到期报废】并且刀柄不报废时, 创建功能刀具组装单
if self.dismantle_cause in ['寿命到期报废'] and not self.scrap_boolean:
# 创建组装单
assembly_id = self.env['sf.functional.tool.assembly'].sudo().create({
'functional_tool_name': self.functional_tool_id.name,
'handle_code_id': self.handle_lot_id.id,
'handle_product_id': self.handle_product_id.id,
'loading_task_source': '3',
'reason_for_applying': '刀具寿命到期'
})
action = self.env.ref('sf_tool_management.sf_functional_tool_assembly_form')
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'title': '组装单创建完成',
'message': '请组装同名称的功能刀具',
'type': 'info',
'links': [{
'label': '组装单',
'url': f'#action={action.id}&id={assembly_id.id}&model=sf.functional.tool.assembly',
}],
},
}
# {
# 'type': 'ir.actions.act_window',
# 'res_model': 'sf.functional.tool.assembly',
# 'view_type': 'form',
# 'view_mode': 'form',
# 'res_id': assembly_id.id,
# }
# 'params': {
# 'title': _('The following replenishment order has been generated'),
# 'message': '%s',
# 'links': [{
# 'label': order.display_name,
# 'url': f'#action={action.id}&id={order.id}&model=purchase.order',
# }],
# 'sticky': False,
# }
def create_tool_picking_scrap(self, datas): def create_tool_picking_scrap(self, datas):
scrap_data = datas['scrap'] scrap_data = datas['scrap']
picking_data = datas['picking'] picking_data = datas['picking']

View File

@@ -3,4 +3,4 @@ from odoo import models, fields
class SyncFunctionalCuttingToolModel(models.Model): class SyncFunctionalCuttingToolModel(models.Model):
_inherit = 'sf.functional.cutting.tool.model' _inherit = 'sf.functional.cutting.tool.model'
cutting_tool_type_ids = fields.Many2many('sf.cutting.tool.type', string='刀具物料类型') cutting_tool_type_ids = fields.Many2many('sf.cutting.tool.type', string='适用刀具物料类型', required=True)

View File

@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from collections import Counter
from xml import etree from xml import etree
from odoo import models, fields, api, Command from odoo import models, fields, api, Command
from odoo.exceptions import UserError from odoo.exceptions import UserError, AccessError
from odoo.http import request from odoo.http import request
@@ -28,6 +29,26 @@ class jikimo_bom(models.Model):
result.append((bom.id, '功能刀具物料清单')) result.append((bom.id, '功能刀具物料清单'))
return result return result
def check_types_in_list(self):
# 统计每个元素的类型
type_counts = Counter(item.cutting_tool_material_id.name for item in self.product_ids)
return all(count > 0 for count in type_counts.values()) and len(type_counts) == self.options.split('+')
def write(self, vals):
# 在更新模型时记录旧的 Many2many ID 列表
if 'product_ids' in vals:
old_product_counter = Counter(self.product_ids.ids)
super(jikimo_bom, self).write(vals)
new_product_counter = Counter(self.product_ids.ids)
delete_product_counter = old_product_counter - new_product_counter
if delete_product_counter:
# 删除操作
if self.check_types_in_list():
return True
else:
raise UserError('每种物料最少要有一个')
return super(jikimo_bom, self).write(vals)
def bom_product_domains(self, assembly_options): def bom_product_domains(self, assembly_options):
self.options = assembly_options self.options = assembly_options
cutting_tool_materials = self.env['sf.cutting.tool.material'].search( cutting_tool_materials = self.env['sf.cutting.tool.material'].search(
@@ -65,6 +86,7 @@ class jikimo_bom(models.Model):
# product = self.env['product.product'].search(domain) # product = self.env['product.product'].search(domain)
# if product: # if product:
# products = products + product # products = products + product
domains = domains + [('stock_move_count', '>', 0)]
return domains return domains
def generate_bill_materials(self, assembly_options): def generate_bill_materials(self, assembly_options):
@@ -88,6 +110,16 @@ class jikimo_bom_line(models.Model):
class ProductProduct(models.Model): class ProductProduct(models.Model):
_inherit = 'product.product' _inherit = 'product.product'
_order = 'cutting_tool_material_id, cutting_tool_type_id'
stock_move_count = fields.Integer(string='stock_move count', compute='_compute_stock_move_count', store=True)
@api.depends('stock_move_ids')
def _compute_stock_move_count(self):
for record in self:
if record.stock_move_ids:
record.stock_move_count = len(record.stock_move_ids)
else:
record.stock_move_count = 0
def search(self, args, offset=0, limit=None, order=None, count=False): def search(self, args, offset=0, limit=None, order=None, count=False):
# 你可以在这里修改 `args` 以调整搜索条件 # 你可以在这里修改 `args` 以调整搜索条件

View File

@@ -1,4 +1,9 @@
import logging
from datetime import timedelta, datetime, date
from odoo import api, fields, models, _ from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
class ShelfLocation(models.Model): class ShelfLocation(models.Model):
@@ -58,3 +63,289 @@ class StockPicking(models.Model):
if move_lines: if move_lines:
self.env['stock.move.line'].sudo().button_function_tool_use_verify(move_lines) self.env['stock.move.line'].sudo().button_function_tool_use_verify(move_lines)
return res return res
def create_tool_stocking_picking(self, stock_lot, 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,
'origin': obj.assembly_order_code
})
# 创建作业详情对象记录,并绑定到刀具组装入库单
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,
'install_tool_time': fields.Datetime.now(),
'qty_done': 1,
'functional_tool_name_id': obj.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.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)
def tool_location_num(self, freight_barcode_id, lot_id):
location_lot = self.env['sf.shelf.location.lot'].sudo().search([('lot_id', '=', lot_id.id), (
'shelf_location_id', '=', freight_barcode_id.id)])
if not location_lot:
raise ValidationError(
f'[{freight_barcode_id.barcode}]货位的[{lot_id.name}]批次物料已用完,请重新选择!')
def create_tool_stocking_picking1(self, obj):
"""
创建刀具物料出库单
"""
# 获取名称为内部调拨的作业类型
picking_type_id = self.env['stock.picking.type'].sudo().search([('name', '=', '内部调拨')])
# 创建刀具物料出库单
picking_id = self.env['stock.picking'].create({
'name': self._get_name_stock1(picking_type_id),
'picking_type_id': picking_type_id.id,
'location_id': self.env['stock.location'].search([('name', '=', '刀具房')]).id,
'location_dest_id': self.env['stock.location'].search([('name', '=', '刀具组装位置')]).id,
'origin': obj.assembly_order_code
})
# =============刀具物料出库===================
stock_move_id = self.env['stock.move']
datas = {'data': [], 'picking_id': picking_id}
if obj.handle_code_id:
if obj.handle_code_id.tool_material_status == '在用':
raise ValidationError(f'Rfid为{obj.handle_code_id.rfid}的刀柄已被使用,请重新选择!')
# 修改刀柄序列号状态为【在用】
obj.handle_code_id.sudo().write({'tool_material_status': '在用'})
datas['data'].append(
{'current_location_id': self.env['sf.shelf.location'], 'lot_id': obj.handle_code_id})
if obj.integral_product_id:
self.tool_location_num(obj.integral_freight_barcode_id, obj.integral_lot_id)
datas['data'].append(
{'current_location_id': obj.integral_freight_barcode_id, 'lot_id': obj.integral_lot_id})
if obj.blade_product_id:
self.tool_location_num(obj.blade_freight_barcode_id, obj.blade_lot_id)
datas['data'].append(
{'current_location_id': obj.blade_freight_barcode_id, 'lot_id': obj.blade_lot_id})
if obj.bar_product_id:
self.tool_location_num(obj.bar_freight_barcode_id, obj.bar_lot_id)
datas['data'].append(
{'current_location_id': obj.bar_freight_barcode_id, 'lot_id': obj.bar_lot_id})
if obj.pad_product_id:
self.tool_location_num(obj.pad_freight_barcode_id, obj.pad_lot_id)
datas['data'].append(
{'current_location_id': obj.pad_freight_barcode_id, 'lot_id': obj.pad_lot_id})
if obj.chuck_product_id:
self.tool_location_num(obj.chuck_freight_barcode_id, obj.chuck_lot_id)
datas['data'].append(
{'current_location_id': obj.chuck_freight_barcode_id, 'lot_id': obj.chuck_lot_id})
# 创建刀具物料出库库存移动记录
stock_move_id.create_tool_material_stock_moves(datas)
# 将刀具物料出库库单的状态更改为就绪
picking_id.action_confirm()
# 修改刀具物料出库移动历史记录
stock_move_id.write_tool_material_stock_move_lines(datas)
# 设置数量,并验证完成
picking_id.action_set_quantities_to_reservation()
picking_id.button_validate()
logging.info(f'刀具物料调拨单状态:{picking_id.state}')
def _get_name_stock1(self, picking_type_id):
name = f'{picking_type_id.sequence_id.prefix}DJ/{date.today().strftime("%y")}'
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 = "%05d" % 1
else:
m = int(stock_id.name[-5:]) + 1
num = "%05d" % m
return name + str(num)
class StockMove(models.Model):
_inherit = 'stock.move'
def create_tool_material_stock_moves(self, datas):
picking_id = datas['picking_id']
data = datas['data']
stock_move_ids = []
for res in data:
if res:
if res['lot_id'].product_qty <= 0:
raise ValidationError(
f'[{res["lot_id"].product_id.name}产品的{res["lot_id"].name}]批次/序列号库存不足!')
# 创建库存移动记录
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_material_stock_move_lines(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({
'current_location_id': res.get('current_location_id').id,
'lot_id': res.get('lot_id').id
})
return True
class ProductProduct(models.Model):
_inherit = 'product.product'
def create_assemble_warehouse_receipt(self, obj):
"""
创建功能刀具批次/序列号记录
"""
product_id = self.env['product.product'].search([('categ_type', '=', '功能刀具'), ('tracking', '=', 'serial')])
if not product_id:
logging.info('没有搜索到功能刀具产品:%s' % product_id)
raise ValidationError('没有找到按唯一序列号追溯的功能刀具产品信息!')
stock_lot = self.env['stock.lot'].create({
'name': self.get_stock_lot_name(obj),
'product_id': product_id[0].id,
'company_id': self.env.company.id
})
return stock_lot
def get_stock_lot_name(self, obj):
"""
生成功能刀具序列号
"""
company = obj.cutting_tool_cutterhandle_model_id.code.split('-', 1)[0]
new_time = datetime.strptime(str(fields.Date.today()), "%Y-%m-%d").strftime("%Y%m%d")
code = '%s-GNDJ-%s-%s' % (company, obj.after_assembly_functional_tool_type_id.code, new_time)
stock_lot_id = self.env['stock.lot'].sudo().search(
[('name', 'like', code)], 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 '%s-%s' % (code, num)
def set_tool_material(self):
tool_id = self.env.context.get('tool_id')
tool_assembly_id = self.env['sf.functional.tool.assembly'].sudo().search([('id', '=', tool_id)])
if len(self) > 1:
raise ValidationError('请不要多选')
else:
tool_assembly_id.handle_product_id = self.id
tool_assembly_id.handle_code_id = False
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'message': '刀柄信息更改成功',
'type': 'success',
'next': {'type': 'ir.actions.act_window_close'}
}
}
class SfShelfLocationLot(models.Model):
_inherit = 'sf.shelf.location.lot'
product_id = fields.Many2one('product.product', '产品', compute='_compute_product_id', store=True)
cutting_tool_type = fields.Char(string="刀具物料类型", compute='_compute_product_id', store=True)
cutting_tool_type_id = fields.Many2one('sf.cutting.tool.type', string='类型',
related='product_id.cutting_tool_type_id')
cutting_tool_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='型号名称',
related='product_id.cutting_tool_model_id')
specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='物料号',
related='product_id.specification_id')
brand_id = fields.Many2one('sf.machine.brand', '品牌', related='product_id.brand_id')
cutting_tool_blade_diameter = fields.Float('刃部直径(mm)', related='product_id.cutting_tool_blade_diameter')
cutting_tool_blade_tip_working_size = fields.Char('刀尖R角(mm)',
related='product_id.cutting_tool_blade_tip_working_size')
cutting_tool_blade_radius = fields.Char('刀尖圆弧半径(mm)',
related='product_id.cutting_tool_blade_tip_circular_arc_radius')
cutting_tool_cutter_arbor_diameter = fields.Float('刀杆直径(mm)',
related='product_id.cutting_tool_cutter_arbor_diameter')
cutting_tool_cutter_head_diameter = fields.Float('刀盘直径(mm)',
related='product_id.cutting_tool_cutter_head_diameter')
fit_blade_shape_id = fields.Many2one('maintenance.equipment.image', '适配刀片形状',
related='product_id.fit_blade_shape_id')
@api.depends('lot_id')
def _compute_product_id(self):
for item in self:
if item.lot_id:
item.product_id = item.lot_id.product_id.id
item.cutting_tool_type = item.lot_id.product_id.cutting_tool_type
def set_tool_material(self):
tool_type = self.env.context.get('tool_type')
tool_id = self.env.context.get('tool_id')
tool_assembly_id = self.env['sf.functional.tool.assembly'].sudo().search([('id', '=', tool_id)])
if len(self) > 1:
raise ValidationError('请不要多选')
if tool_type == '整体式刀具':
tool_assembly_id.integral_freight_barcode_id = self.shelf_location_id.id
tool_assembly_id.integral_lot_id = self.lot_id.id
tool_assembly_id.integral_verify = False
elif tool_type == '刀片':
tool_assembly_id.blade_freight_barcode_id = self.shelf_location_id.id
tool_assembly_id.blade_lot_id = self.lot_id.id
tool_assembly_id.blade_verify = False
elif tool_type == '刀杆':
tool_assembly_id.bar_freight_barcode_id = self.shelf_location_id.id
tool_assembly_id.bar_lot_id = self.lot_id.id
tool_assembly_id.bar_verify = False
elif tool_type == '刀盘':
tool_assembly_id.pad_freight_barcode_id = self.shelf_location_id.id
tool_assembly_id.pad_lot_id = self.lot_id.id
tool_assembly_id.pad_verify = False
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'message': f'[{tool_type}]物料信息更改成功',
'type': 'success',
'next': {'type': 'ir.actions.act_window_close'}
}
}

View File

@@ -5,10 +5,10 @@ from odoo.http import request
class ToolInventory(models.Model): class ToolInventory(models.Model):
_inherit = 'sf.tool.inventory' _inherit = 'sf.tool.inventory'
_description = '功能刀具清单' _description = '功能刀具清单'
knife_handle_model = fields.Selection([('BT30', 'BT30'), ('BT40', 'BT40'), ('BT50', 'BT50'), ('GSK30', 'GSK30'), ('GSK40', 'GSK40'), ('GSK50', 'GSK50')], string='使用刀柄型号') knife_handle_model = fields.Selection([('BT30', 'BT30'), ('BT40', 'BT40'), ('BT50', 'BT50'), ('GSK30', 'GSK30'), ('GSK40', 'GSK40'), ('GSK50', 'GSK50')], string='使用刀柄型号', required=True)
jikimo_bom_ids = fields.One2many('jikimo.bom','tool_inventory_id', 'bom单') jikimo_bom_ids = fields.One2many('jikimo.bom','tool_inventory_id', 'bom单')
blade_length = fields.Float('刃长(mm)')
def bom_mainfest(self): def bom_mainfest(self):
jikimo_bom_ids = self.mapped('jikimo_bom_ids') jikimo_bom_ids = self.mapped('jikimo_bom_ids')
if not jikimo_bom_ids: if not jikimo_bom_ids:
self._bom_mainfest() self._bom_mainfest()

View File

@@ -35,11 +35,12 @@
<field name="name"/> <field name="name"/>
<!-- <field name="categ_id"/>--> <!-- <field name="categ_id"/>-->
<field name="cutting_tool_material_id"/> <field name="cutting_tool_material_id"/>
<field name="cutting_tool_type_id"/>
<field name="cutting_tool_model_id"/> <field name="cutting_tool_model_id"/>
<field name="specification_id"/> <field name="specification_id"/>
<field name="brand_id"/> <field name="brand_id"/>
<field name="qty_available"/> <field name="qty_available"/>
</tree> </tree>
</field> </field>
</page> </page>

View File

@@ -11,4 +11,131 @@
</xpath> </xpath>
</field> </field>
</record> </record>
<record id="view_tool_product_tree" model="ir.ui.view">
<field name="name">刀柄</field>
<field name="model">product.product</field>
<field name="arch" type="xml">
<tree create="0" export_xlsx="0" delete="0">
<header>
<button string="确认" name="set_tool_material" type="object"
class="treeHeaderBtn"/>
</header>
<field name="name"/>
<field name="cutting_tool_type_id"/>
<field name="cutting_tool_model_id"/>
<field name="specification_id"/>
<field name="cutting_tool_shank_length"/>
<field name="cutting_tool_taper_shank_model"/>
<field name="brand_id"/>
<field name="qty_available" string="数量"/>
</tree>
</field>
</record>
<record id="view_tool_product_search" model="ir.ui.view">
<field name="model">product.product</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
</search>
</field>
</record>
<record id="view_shelf_location_lot_tree_1" model="ir.ui.view">
<field name="name">sf.shelf.location.lot.tree</field>
<field name="model">sf.shelf.location.lot</field>
<field name="arch" type="xml">
<tree create="0" export_xlsx="0" delete="0">
<header>
<button string="确认" name="set_tool_material" type="object"
class="treeHeaderBtn"/>
</header>
<field name="product_id"/>
<field name="cutting_tool_type_id"/>
<field name="cutting_tool_model_id"/>
<field name="specification_id"/>
<field name="cutting_tool_blade_diameter"/>
<field name="cutting_tool_blade_tip_working_size"/>
<field name="brand_id"/>
<field name="shelf_location_id"/>
<field name="lot_id"/>
</tree>
</field>
</record>
<record id="view_shelf_location_lot_tree_2" model="ir.ui.view">
<field name="name">sf.shelf.location.lot.tree</field>
<field name="model">sf.shelf.location.lot</field>
<field name="arch" type="xml">
<tree create="0" export_xlsx="0" delete="0">
<header>
<button string="确认" name="set_tool_material" type="object"
class="treeHeaderBtn"/>
</header>
<field name="product_id"/>
<field name="cutting_tool_type_id"/>
<field name="cutting_tool_model_id"/>
<field name="specification_id"/>
<field name="fit_blade_shape_id"/>
<field name="cutting_tool_blade_radius"/>
<field name="brand_id"/>
<field name="shelf_location_id"/>
<field name="lot_id"/>
</tree>
</field>
</record>
<record id="view_shelf_location_lot_tree_3" model="ir.ui.view">
<field name="name">sf.shelf.location.lot.tree</field>
<field name="model">sf.shelf.location.lot</field>
<field name="arch" type="xml">
<tree create="0" export_xlsx="0" delete="0">
<header>
<button string="确认" name="set_tool_material" type="object"
class="treeHeaderBtn"/>
</header>
<field name="product_id"/>
<field name="cutting_tool_type_id"/>
<field name="cutting_tool_model_id"/>
<field name="specification_id"/>
<field name="cutting_tool_cutter_arbor_diameter"/>
<field name="fit_blade_shape_id"/>
<field name="brand_id"/>
<field name="shelf_location_id"/>
<field name="lot_id"/>
</tree>
</field>
</record>
<record id="view_shelf_location_lot_tree_4" model="ir.ui.view">
<field name="name">sf.shelf.location.lot.tree</field>
<field name="model">sf.shelf.location.lot</field>
<field name="arch" type="xml">
<tree create="0" export_xlsx="0" delete="0">
<header>
<button string="确认" name="set_tool_material" type="object"
class="treeHeaderBtn"/>
</header>
<field name="product_id"/>
<field name="cutting_tool_type_id"/>
<field name="cutting_tool_model_id"/>
<field name="specification_id"/>
<field name="cutting_tool_cutter_head_diameter"/>
<field name="fit_blade_shape_id"/>
<field name="brand_id"/>
<field name="shelf_location_id"/>
<field name="lot_id"/>
</tree>
</field>
</record>
</odoo> </odoo>

View File

@@ -446,19 +446,23 @@
<field name="use_tool_time"/> <field name="use_tool_time"/>
<field name="production_line_name_id" optional="hide"/> <field name="production_line_name_id" optional="hide"/>
<field name="machine_tool_name_id" optional="hide"/> <field name="machine_tool_name_id" optional="hide"/>
<field name="applicant"/> <field name="applicant" optional="hide"/>
<field name="apply_time"/> <field name="apply_time"/>
<field name="assemble_status" optional="hide"/> <field name="assemble_status" widget='badge'
decoration-info="assemble_status == '0'"
decoration-warning="assemble_status == '01'"
decoration-success="assemble_status == '1'"
/>
<field name="name" invisible="True"/> <!-- <field name="name" invisible="True"/>-->
<field name="machine_tool_code" invisible="True"/> <!-- <field name="machine_tool_code" invisible="True"/>-->
<field name="cutter_spacing_code_id" invisible="True"/> <!-- <field name="cutter_spacing_code_id" invisible="True"/>-->
<field name="whether_standard_knife" invisible="True"/> <!-- <field name="whether_standard_knife" invisible="True"/>-->
<field name="reason_for_applying" invisible="True"/> <!-- <field name="reason_for_applying" invisible="True"/>-->
<field name="functional_tool_type_id" invisible="True"/> <!-- <field name="functional_tool_type_id" invisible="True"/>-->
<button string="组装" name="put_start_preset" type="object" <!-- <button string="组装" name="put_start_preset" type="object"-->
attrs="{'invisible': [('assemble_status', '!=', '0')]}" <!-- attrs="{'invisible': [('assemble_status', '!=', '0')]}"-->
class="btn-primary"/> <!-- class="btn-primary"/>-->
</tree> </tree>
</field> </field>
</record> </record>
@@ -467,19 +471,23 @@
<field name="name">功能刀具组装</field> <field name="name">功能刀具组装</field>
<field name="model">sf.functional.tool.assembly</field> <field name="model">sf.functional.tool.assembly</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form create="0" delete="0" edit="0"> <form create="0" delete="0" edit="1">
<header> <header>
<!-- <button string="修改编码" name="put_assembly_order_code" type="object"--> <button string="开始组装" name="start_preset" type="object"
<!-- class="btn-primary" confirm="是否确认修改编码"/>--> attrs="{'invisible': [('assemble_status', 'not in', ['0'])]}"
<button string="组装" name="put_start_preset" type="object"
attrs="{'invisible': [('assemble_status', '!=', '0')]}"
class="btn-primary"/> class="btn-primary"/>
<field name="assemble_status" widget="statusbar" statusbar_visible="0,1"/> <button string="确认组装" name="functional_tool_assembly" type="object"
attrs="{'invisible': [('assemble_status', 'not in', ['01'])]}"
class="btn-primary"/>
<button name="get_tool_preset_parameter" string="获取测量值"
type="object" class="btn-primary"
attrs="{'invisible': [('assemble_status', 'in', ['0','1','2'])]}"
/>
<field name="assemble_status" widget="statusbar" statusbar_visible="0,01,1"/>
</header> </header>
<sheet> <sheet>
<div class="oe_button_box" name="button_box"> <div class="oe_button_box" name="button_box">
<button class="oe_stat_button" name="open_tool_stock_picking" icon="fa-truck" type="object" <button class="oe_stat_button" name="open_tool_stock_picking" icon="fa-truck" type="object">
attrs="{'invisible': [('assemble_status', '!=', '1')]}">
<div name="delivery_count" class="o_field_widget o_readonly_modifier o_field_statinfo"> <div name="delivery_count" class="o_field_widget o_readonly_modifier o_field_statinfo">
<span class="o_stat_info o_stat_value"> <span class="o_stat_info o_stat_value">
<field name="picking_num"/> <field name="picking_num"/>
@@ -488,6 +496,10 @@
</div> </div>
</button> </button>
</div> </div>
<div class="o_employee_avatar">
<field name="image" widget="image" class="oe_avatar m-0"
attrs="{'readonly': [('assemble_status', '!=', '01')]}"/>
</div>
<div class="oe_title"> <div class="oe_title">
<h1> <h1>
<field name="assembly_order_code"/> <field name="assembly_order_code"/>
@@ -496,116 +508,77 @@
<field name="name" invisible="1"/> <field name="name" invisible="1"/>
<group> <group>
<group> <group>
<field name="production_line_name_id"/> <field name="functional_tool_name"/>
<field name="machine_tool_name_id"/> <field name="functional_tool_type_id"/>
<field name="cutter_spacing_code_id"/> <field name="tool_groups_id"/>
<field name="sf_machine_table_tool_changing_apply_id"
attrs="{'invisible': [('sf_machine_table_tool_changing_apply_id','=',False)]}"/>
<field name="sf_cam_work_order_program_knife_plan_id"
attrs="{'invisible': [('sf_cam_work_order_program_knife_plan_id','=',False)]}"/>
</group> </group>
<group> <group>
<field name="image" nolabel="1" widget="image"/> <field name="functional_tool_diameter" string="刀具直径(mm)"/>
<field name="knife_tip_r_angle"/>
<field name="tool_loading_length" string="总长度(mm)"/>
<field name="functional_tool_length"/>
</group> </group>
</group> </group>
<notebook> <notebook>
<page string="组装信息" attrs="{'invisible': [('assemble_status', '=', '0')]}"> <page string="组装信息">
<group col="1"> <field name="_barcode_scanned" widget="barcode_handler"/>
<group attrs="{'invisible': [('assemble_status', '=', '0')]}">
<group col="1"> <group col="1">
<group> <group col="1">
<div>
<separator string="刀柄:" style="font-size: 13px;"/>
</div>
<group> <group>
<field name="barcode_id" invisible="True"/> <field name="handle_code_id" string="序列号" placeholder="请选择"
<field name="rfid" string="功能刀具rfid"/> options="{'no_create': True, 'no_quick_create': True}"/>
<field name="code"/> <field name="handle_freight_rfid" string="Rfid"/>
<field name="after_assembly_functional_tool_name" <field name="handle_product_id" string="名称"/>
string="功能刀具名称"/> <field name="cutting_tool_cutterhandle_model_id" string="型号"/>
<field name="after_assembly_functional_tool_type_id" <field name="handle_specification_id" string="规格"/>
string="功能刀具类型"/> <field name="sf_tool_brand_id_5" string="品牌"/>
<field name="tool_groups_id"/>
<field name="after_assembly_whether_standard_knife"
string="是否标准刀"/>
<field name="after_assembly_coarse_middle_thin" string="粗/中/精"/>
<field name="after_assembly_new_former" string="新/旧"/>
<field name="cut_time"
attrs="{'invisible': [('after_assembly_new_former', '=', '0')]}"/>
<field name="cut_length"
attrs="{'invisible': [('after_assembly_new_former', '=', '0')]}"/>
<field name="cut_number"
attrs="{'invisible': [('after_assembly_new_former', '=', '0')]}"/>
</group>
<group>
<field name="after_assembly_functional_tool_diameter"
string="刀具直径(mm)"/>
<field name="after_assembly_knife_tip_r_angle" string="刀尖R角(mm)"/>
<field name="after_assembly_tool_loading_length" string="总长度(mm)"/>
<field name="after_assembly_handle_length" string="刀柄长度(mm)"/>
<field name="after_assembly_functional_tool_length"
string="伸出长(mm)"/>
<field name="after_assembly_max_lifetime_value"
string="最大寿命值(min)"/>
<field name="after_assembly_alarm_value" string="报警值(min)"/>
<field name="after_assembly_used_value" string="已使用值(min)"
invisible="1"/>
<field name="after_assembly_effective_length" string="有效长(mm)"
invisible="1"/>
<field name="L_D_number" invisible="1"/>
<field name="hiding_length" invisible="1"/>
</group> </group>
<div>
<button string="更多" name="set_tool_lot" type="object"
class="btn-primary" context="{'tool_type': '刀柄'}"
attrs="{'invisible': [('assemble_status', 'not in', ['0','01'])]}"/>
</div>
</group> </group>
</group> </group>
</group>
<group>
<group col="1" attrs="{'invisible': [('handle_code_id', '=', False)]}">
<div>
<separator string="刀柄:" style="font-size: 13px;"/>
</div>
<group>
<field name="handle_code_id" string="序列号" placeholder="请选择"
options="{'no_create': True, 'no_quick_create': True}"/>
<field name="handle_freight_rfid" string="Rfid"/>
<field name="handle_product_id" string="名称"/>
<field name="cutting_tool_cutterhandle_model_id" string="型号"/>
<field name="handle_specification_id" string="规格"/>
<field name="sf_tool_brand_id_5" string="品牌"/>
</group>
</group>
<group col="1" attrs="{'invisible': [('chuck_freight_barcode_id', '=', False)]}">
<div>
<separator string="夹头:" style="font-size: 13px;"/>
</div>
<group>
<group>
<field name="chuck_freight_barcode_id" string="货位"/>
<field name="chuck_lot_id" string="批次"/>
<field name="chuck_product_id" string="名称"/>
<field name="cutting_tool_cutterhead_model_id" string="型号"/>
<field name="chuck_specification_id" string="规格"/>
<field name="sf_tool_brand_id_6" string="品牌"/>
</group>
</group>
</group>
</group>
<group>
<group col="1"> <group col="1">
<group col="1" <group col="1"
attrs="{'invisible': [('integral_freight_barcode_id', '=', False)]}"> attrs="{'invisible': [('integral_lot_id', '=', False),'|','|','|', ('blade_lot_id', '!=', False),('bar_lot_id', '!=', False),('pad_lot_id', '!=', False),('assemble_status', 'not in', ['0','01'])]}">
<div> <div>
<separator string="整体式刀具:" style="font-size: 13px;"/> <separator string="整体式刀具:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<field name="integral_freight_barcode_id" string="货位"/> <group>
<field name="integral_lot_id" string="批次"/> <field name="integral_freight_barcode_id" string="货位"/>
<field name="integral_product_id" string="名称"/> <field name="integral_lot_id" string="批次"/>
<field name="cutting_tool_integral_model_id" string="型号"/> <field name="integral_product_id" string="名称"/>
<field name="integral_specification_id" string="规格"/> <field name="cutting_tool_integral_model_id" string="型号"/>
<field name="sf_tool_brand_id_1" string="品牌"/> <field name="integral_specification_id" string="规格"/>
<field name="sf_tool_brand_id_1" string="品牌"/>
</group>
<group>
<field name="integral_verify" string="" readonly="1"/>
</group>
</group> </group>
</group>
<group col="1"
attrs="{'invisible': [('blade_freight_barcode_id', '=', False)]}">
<div> <div>
<separator string="刀片:" style="font-size: 13px;"/> <button string="更多" name="set_tool_lot" type="object"
class="btn-primary" context="{'tool_type': '整体式刀具'}"
attrs="{'invisible': [('assemble_status', 'not in', ['0','01'])]}"/>
</div> </div>
</group>
</group>
</group>
<group attrs="{'invisible': [('assemble_status', '=', '0')]}">
<group col="1"
attrs="{'invisible': [('blade_lot_id', '=', False),'|', ('integral_lot_id', '!=', False),('assemble_status', 'not in', ['0','01'])]}">
<div>
<separator string="刀片:" style="font-size: 13px;"/>
</div>
<group>
<group> <group>
<field name="blade_freight_barcode_id" string="货位"/> <field name="blade_freight_barcode_id" string="货位"/>
<field name="blade_lot_id" string="批次"/> <field name="blade_lot_id" string="批次"/>
@@ -614,10 +587,19 @@
<field name="blade_specification_id" string="规格"/> <field name="blade_specification_id" string="规格"/>
<field name="sf_tool_brand_id_2" string="品牌"/> <field name="sf_tool_brand_id_2" string="品牌"/>
</group> </group>
<group>
<field name="blade_verify" string="" readonly="1"/>
</group>
</group> </group>
<div>
<button string="更多" name="set_tool_lot" type="object"
class="btn-primary" context="{'tool_type': '刀片'}"
attrs="{'invisible': [('assemble_status', 'not in', ['0','01'])]}"/>
</div>
</group> </group>
<group col="1"> <group col="1">
<group col="1" attrs="{'invisible': [('bar_freight_barcode_id', '=', False)]}"> <group col="1"
attrs="{'invisible': [('bar_lot_id', '=', False),'|','|',('integral_lot_id', '!=', False),('pad_lot_id', '!=', False),('assemble_status', 'not in', ['0','01'])]}">
<div> <div>
<separator string="刀杆:" style="font-size: 13px;"/> <separator string="刀杆:" style="font-size: 13px;"/>
</div> </div>
@@ -630,9 +612,18 @@
<field name="bar_specification_id" string="规格"/> <field name="bar_specification_id" string="规格"/>
<field name="sf_tool_brand_id_3" string="品牌"/> <field name="sf_tool_brand_id_3" string="品牌"/>
</group> </group>
<group>
<field name="bar_verify" string="" readonly="1"/>
</group>
</group> </group>
<div>
<button string="更多" name="set_tool_lot" type="object"
class="btn-primary" context="{'tool_type': '刀杆'}"
attrs="{'invisible': [('assemble_status', 'not in', ['0','01'])]}"/>
</div>
</group> </group>
<group col="1" attrs="{'invisible': [('pad_freight_barcode_id', '=', False)]}"> <group col="1"
attrs="{'invisible': [('pad_lot_id', '=', False),'|','|',('integral_lot_id', '!=', False),('bar_lot_id', '!=', False),('assemble_status', 'not in', ['0','01'])]}">
<div> <div>
<separator string="刀盘:" style="font-size: 13px;"/> <separator string="刀盘:" style="font-size: 13px;"/>
</div> </div>
@@ -645,30 +636,69 @@
<field name="pad_specification_id" string="规格"/> <field name="pad_specification_id" string="规格"/>
<field name="sf_tool_brand_id_4" string="品牌"/> <field name="sf_tool_brand_id_4" string="品牌"/>
</group> </group>
<group>
<field name="pad_verify" string="" readonly="1"/>
</group>
</group> </group>
<div>
<button string="更多" name="set_tool_lot" type="object"
class="btn-primary" context="{'tool_type': '刀盘'}"
attrs="{'invisible': [('assemble_status', 'not in', ['0','01'])]}"/>
</div>
</group> </group>
</group> </group>
</group> </group>
</page> <group col="1" attrs="{'invisible': [('assemble_status', '=', '0')]}">
<page string="申请信息"> <group col="1">
<group> <group string="组装参数信息">
<group> <group>
<field name="functional_tool_name"/> <field name="barcode_id" invisible="True"/>
<field name="functional_tool_type_id"/> <field name="rfid" string="功能刀具rfid"/>
<field name="tool_groups_id"/> <field name="code"/>
<field name="functional_tool_diameter" string="刀具直径(mm)"/> <field name="after_assembly_functional_tool_name"
<field name="knife_tip_r_angle"/> string="功能刀具名称"/>
<field name="tool_loading_length" string="总长度(mm)"/> <field name="after_assembly_functional_tool_type_id"
<field name="functional_tool_length"/> string="功能刀具类型"/>
<field name="effective_length"/> <field name="tool_groups_id"/>
</group> <field name="after_assembly_whether_standard_knife"
<group> string="是否标准刀" invisible="1"/>
<field name="whether_standard_knife"/> <field name="after_assembly_coarse_middle_thin" string="粗/中/精"
<field name="coarse_middle_thin"/> attrs="{'readonly': [('assemble_status', 'in', ['1','2'])]}"/>
<field name="new_former"/> <field name="after_assembly_new_former" string="新/旧"
<field name="use_tool_time"/> attrs="{'readonly': [('assemble_status', 'in', ['1','2'])]}"/>
<field name="reason_for_applying"/> <field name="cut_time"
<!-- <field name="functional_tool_cutting_type"/>--> attrs="{'invisible': [('after_assembly_new_former', '=', '0')]}"/>
<field name="cut_length"
attrs="{'invisible': [('after_assembly_new_former', '=', '0')]}"/>
<field name="cut_number"
attrs="{'invisible': [('after_assembly_new_former', '=', '0')]}"/>
</group>
<group>
<field name="after_assembly_functional_tool_diameter" readonly="0"
string="刀具直径(mm)"
attrs="{'readonly': [('assemble_status', 'in', ['1','2'])]}"/>
<field name="after_assembly_knife_tip_r_angle" readonly="0"
string="刀尖R角(mm)"
attrs="{'readonly': [('assemble_status', 'in', ['1','2'])]}"/>
<field name="after_assembly_tool_loading_length" readonly="0"
string="总长度(mm)"
attrs="{'readonly': [('assemble_status', 'in', ['1','2'])]}"/>
<field name="after_assembly_handle_length" string="刀柄长度(mm)"
attrs="{'readonly': [('assemble_status', 'in', ['1','2'])]}"/>
<field name="after_assembly_functional_tool_length"
string="伸出长(mm)"/>
<field name="after_assembly_max_lifetime_value"
string="最大寿命值(min)"/>
<field name="after_assembly_alarm_value" string="报警值(min)"
invisible="1"/>
<field name="after_assembly_used_value" string="已使用值(min)"
invisible="1"/>
<field name="after_assembly_effective_length" string="有效长(mm)"
invisible="1"/>
<field name="L_D_number" invisible="1"/>
<field name="hiding_length" invisible="1"/>
</group>
</group>
</group> </group>
</group> </group>
</page> </page>
@@ -685,9 +715,27 @@
<page string="其他"> <page string="其他">
<group> <group>
<group> <group>
<field name="production_line_name_id"
attrs="{'invisible': [('production_line_name_id','=',False)]}"/>
<field name="machine_tool_name_id"
attrs="{'invisible': [('machine_tool_name_id','=',False)]}"/>
<field name="cutter_spacing_code_id"
attrs="{'invisible': [('cutter_spacing_code_id','=',False)]}"/>
<field name="use_tool_time"/>
<field name="reason_for_applying"/>
<field name="sf_machine_table_tool_changing_apply_id"
attrs="{'invisible': [('sf_machine_table_tool_changing_apply_id','=',False)]}"/>
<field name="sf_cam_work_order_program_knife_plan_id"
attrs="{'invisible': [('sf_cam_work_order_program_knife_plan_id','=',False)]}"/>
<field name="check_box_1" invisible="True"/> <field name="check_box_1" invisible="True"/>
<field name="remark"/> <field name="remark"/>
</group> </group>
<group>
<field name="effective_length"/>
<field name="whether_standard_knife"/>
<field name="coarse_middle_thin" invisible="1"/>
<field name="new_former" invisible="1"/>
</group>
</group> </group>
</page> </page>
</notebook> </notebook>
@@ -705,20 +753,19 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<search> <search>
<field name="functional_tool_name"/> <field name="functional_tool_name"/>
<field name="tool_groups_id"/>
<field name="functional_tool_diameter"/>
<field name="knife_tip_r_angle"/>
<field name="assembly_order_code"/> <field name="assembly_order_code"/>
<field name="code" string="功能刀具编码"/> <field name="code" string="功能刀具编码"/>
<field name="barcode_id"/> <field name="barcode_id"/>
<field name="functional_tool_type_id"/>
<field name="tool_groups_id"/> <filter name="no_assemble_status" string="未组装" domain="[('assemble_status', 'in', ['0','01'])]"/>
<field name="loading_task_source" string="任务来源"/>
<field name="production_line_name_id"/>
<field name="machine_tool_name_id"/>
<field name="applicant"/>
<filter name="no_assemble_status" string="未组装" domain="[('assemble_status', '=', '0')]"/>
<filter name="yes_assemble_status" string="已组装" domain="[('assemble_status', '=', '1')]"/> <filter name="yes_assemble_status" string="已组装" domain="[('assemble_status', '=', '1')]"/>
<separator/> <separator/>
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/> <filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
<searchpanel> <searchpanel>
<field name="assemble_status" enable_counters="1" icon="fa-filter"/>
<field name="functional_tool_type_id" enable_counters="1" icon="fa-filter"/> <field name="functional_tool_type_id" enable_counters="1" icon="fa-filter"/>
</searchpanel> </searchpanel>
@@ -743,7 +790,7 @@
<field name="view_mode">tree,form,search</field> <field name="view_mode">tree,form,search</field>
<!-- <field name="view_id" ref="sf_functional_tool_assembly_tree"/>--> <!-- <field name="view_id" ref="sf_functional_tool_assembly_tree"/>-->
<field name="search_view_id" ref="sf_functional_tool_assembly_search"/> <field name="search_view_id" ref="sf_functional_tool_assembly_search"/>
<field name="context">{'search_default_no_assemble_status':1}</field> <field name="context">{'search_default_no_assemble_status':[1,01]}</field>
</record> </record>

View File

@@ -5,7 +5,7 @@
<field name="model">sf.tool.inventory</field> <field name="model">sf.tool.inventory</field>
<field name="inherit_id" ref="sf_base.view_tool_inventory_tree"/> <field name="inherit_id" ref="sf_base.view_tool_inventory_tree"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='type']" position="before"> <xpath expr="//field[@name='extension']" position="before">
<field name="knife_handle_model" /> <field name="knife_handle_model" />
<button name="bom_mainfest" string="bom清单" type="object" class="btn-link" <button name="bom_mainfest" string="bom清单" type="object" class="btn-link"
icon="fa-refresh" /> icon="fa-refresh" />

View File

@@ -598,361 +598,175 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
else: else:
record.L_D_number = 0 record.L_D_number = 0
def functional_tool_assembly(self): # def functional_tool_assembly(self):
""" # """
功能刀具组装 # 功能刀具组装
:return: # :return:
""" # """
logging.info('功能刀具开始组装!') # logging.info('功能刀具开始组装!')
# 获取组装单对象 # # 获取组装单对象
functional_tool_assembly = self.env['sf.functional.tool.assembly'].search([ # functional_tool_assembly = self.env['sf.functional.tool.assembly'].search([
('assembly_order_code', '=', self.assembly_order_code), # ('assembly_order_code', '=', self.assembly_order_code),
('machine_tool_name_id', '=', self.machine_tool_name_id.id), # ('machine_tool_name_id', '=', self.machine_tool_name_id.id),
('cutter_spacing_code_id', '=', self.cutter_spacing_code_id.id), # ('cutter_spacing_code_id', '=', self.cutter_spacing_code_id.id),
('assemble_status', '=', '0'), # ('assemble_status', '=', '0'),
]) # ])
# 对物料做必填判断 # # 对物料做必填判断
self.materials_must_be_judged() # self.materials_must_be_judged()
#
product_id = self.env['product.product'] # product_id = self.env['product.product']
# 创建组装入库单 # # 创建组装入库单
# 创建功能刀具批次/序列号记录 # # 创建功能刀具批次/序列号记录
stock_lot = product_id.create_assemble_warehouse_receipt(self.id, functional_tool_assembly, self) # stock_lot = product_id.create_assemble_warehouse_receipt(self.id, functional_tool_assembly, self)
# 封装功能刀具数据,用于更新组装单信息 # # 封装功能刀具数据,用于更新组装单信息
desc_1 = self.get_desc_1(stock_lot) # desc_1 = self.get_desc_1(stock_lot)
# 封装功能刀具数据,用于创建功能刀具记录 # # 封装功能刀具数据,用于创建功能刀具记录
desc_2 = self.get_desc_2(stock_lot, functional_tool_assembly) # desc_2 = self.get_desc_2(stock_lot, functional_tool_assembly)
# 创建功能刀具组装入库单 # # 创建功能刀具组装入库单
self.env['stock.picking'].create_tool_stocking_picking(stock_lot, functional_tool_assembly, self) # self.env['stock.picking'].create_tool_stocking_picking(stock_lot, functional_tool_assembly, self)
# 创建刀具物料出库单 # # 创建刀具物料出库单
self.env['stock.picking'].create_tool_stocking_picking1(self) # self.env['stock.picking'].create_tool_stocking_picking1(self)
#
# ============================创建功能刀具列表、安全库存记录=============================== # # ============================创建功能刀具列表、安全库存记录===============================
# 创建功能刀具列表记录 # # 创建功能刀具列表记录
record_1 = self.env['sf.functional.cutting.tool.entity'].create(desc_2) # 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({ # self.env['sf.real.time.distribution.of.functional.tools'].create_or_edit_safety_stock({
'functional_name_id': self.after_name_id.id # 'functional_name_id': self.after_name_id.id
}, record_1) # }, record_1)
#
# =====================修改功能刀具组装单、机床换刀申请、CAM工单程序用刀计划的状态============== # # =====================修改功能刀具组装单、机床换刀申请、CAM工单程序用刀计划的状态==============
# 修改功能刀具组装单信息 # # 修改功能刀具组装单信息
functional_tool_assembly.write(desc_1) # functional_tool_assembly.write(desc_1)
if functional_tool_assembly.sf_machine_table_tool_changing_apply_id: # if functional_tool_assembly.sf_machine_table_tool_changing_apply_id:
# 修改机床换刀申请的状态 # # 修改机床换刀申请的状态
self.env['sf.machine.table.tool.changing.apply'].sudo().search([ # self.env['sf.machine.table.tool.changing.apply'].sudo().search([
('id', '=', functional_tool_assembly.sf_machine_table_tool_changing_apply_id.id) # ('id', '=', functional_tool_assembly.sf_machine_table_tool_changing_apply_id.id)
]).write({'status': '3'}) # ]).write({'status': '3'})
elif functional_tool_assembly.sf_cam_work_order_program_knife_plan_id: # elif functional_tool_assembly.sf_cam_work_order_program_knife_plan_id:
# 修改CAM工单程序用刀计划状态 # # 修改CAM工单程序用刀计划状态
cam_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().search([ # 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) # ('id', '=', functional_tool_assembly.sf_cam_work_order_program_knife_plan_id.id)
]) # ])
cam_plan.write({'plan_execute_status': '2'}) # cam_plan.write({'plan_execute_status': '2'})
#
logging.info('功能刀具组装完成!') # logging.info('功能刀具组装完成!')
#
# 关闭弹出窗口 # # 关闭弹出窗口
return {'type': 'ir.actions.act_window_close'} # return {'type': 'ir.actions.act_window_close'}
#
def materials_must_be_judged(self): # def materials_must_be_judged(self):
""" # """
功能刀具组装必填判断 # 功能刀具组装必填判断
""" # """
# 物料必填校验 # # 物料必填校验
if not self.handle_code_id: # if not self.handle_code_id:
raise ValidationError('缺少【刀柄】物料信息!') # raise ValidationError('缺少【刀柄】物料信息!')
if not self.integral_product_id and not self.blade_product_id: # if not self.integral_product_id and not self.blade_product_id:
raise ValidationError('【整体式刀具】和【刀片】必须填写一个!') # raise ValidationError('【整体式刀具】和【刀片】必须填写一个!')
if self.blade_product_id: # if self.blade_product_id:
if not self.bar_product_id and not self.pad_product_id: # if not self.bar_product_id and not self.pad_product_id:
raise ValidationError('【刀盘】和【刀杆】必须填写一个!') # raise ValidationError('【刀盘】和【刀杆】必须填写一个!')
# 组装参数必填校验 # # 组装参数必填校验
if self.after_assembly_functional_tool_length == 0: # if self.after_assembly_functional_tool_length == 0:
raise ValidationError('组装参数信息【伸出长】不能为0') # raise ValidationError('组装参数信息【伸出长】不能为0')
if self.after_assembly_max_lifetime_value == 0: # if self.after_assembly_max_lifetime_value == 0:
raise ValidationError('组装参数信息【最大寿命值】不能为0') # raise ValidationError('组装参数信息【最大寿命值】不能为0')
if self.after_assembly_alarm_value == 0: # if self.after_assembly_alarm_value == 0:
raise ValidationError('组装参数信息【报警值】不能为0') # raise ValidationError('组装参数信息【报警值】不能为0')
# if self.after_assembly_effective_length == 0: # # if self.after_assembly_effective_length == 0:
# raise ValidationError('组装参数信息【有效长】不能为0') # # raise ValidationError('组装参数信息【有效长】不能为0')
# if self.hiding_length == 0: # # if self.hiding_length == 0:
# raise ValidationError('组装参数信息【避空长】不能为0') # # raise ValidationError('组装参数信息【避空长】不能为0')
if self.after_assembly_functional_tool_diameter == 0: # if self.after_assembly_functional_tool_diameter == 0:
raise ValidationError('组装参数信息【刀具直径】不能为0') # raise ValidationError('组装参数信息【刀具直径】不能为0')
if self.after_assembly_tool_loading_length == 0: # if self.after_assembly_tool_loading_length == 0:
raise ValidationError('组装参数信息【总长度】不能为0') # raise ValidationError('组装参数信息【总长度】不能为0')
if self.after_assembly_handle_length == 0: # if self.after_assembly_handle_length == 0:
raise ValidationError('组装参数信息【刀柄长度】不能为0') # raise ValidationError('组装参数信息【刀柄长度】不能为0')
if self.after_assembly_tool_loading_length < self.after_assembly_handle_length: # if self.after_assembly_tool_loading_length < self.after_assembly_handle_length:
raise ValidationError('组装参数信息【刀柄长度】不能大于【总长度】!') # raise ValidationError('组装参数信息【刀柄长度】不能大于【总长度】!')
#
def get_desc_1(self, stock_lot): # def get_desc_1(self, stock_lot):
return { # return {
'start_preset_bool': False, # 'start_preset_bool': False,
'barcode_id': stock_lot.id, # 'barcode_id': stock_lot.id,
'code': self.code, # 'code': self.code,
'rfid': self.rfid, # 'rfid': self.rfid,
'tool_groups_id': self.after_tool_groups_id.id, # 'tool_groups_id': self.after_tool_groups_id.id,
'handle_code_id': self.handle_code_id.id, # 'handle_code_id': self.handle_code_id.id,
'integral_freight_barcode_id': self.integral_freight_barcode_id.id, # 'integral_freight_barcode_id': self.integral_freight_barcode_id.id,
'integral_lot_id': self.integral_freight_lot_id.lot_id.id, # 'integral_lot_id': self.integral_freight_lot_id.lot_id.id,
'blade_freight_barcode_id': self.blade_freight_barcode_id.id, # 'blade_freight_barcode_id': self.blade_freight_barcode_id.id,
'blade_lot_id': self.blade_freight_lot_id.lot_id.id, # 'blade_lot_id': self.blade_freight_lot_id.lot_id.id,
'bar_freight_barcode_id': self.bar_freight_barcode_id.id, # 'bar_freight_barcode_id': self.bar_freight_barcode_id.id,
'bar_lot_id': self.bar_freight_lot_id.lot_id.id, # 'bar_lot_id': self.bar_freight_lot_id.lot_id.id,
'pad_freight_barcode_id': self.pad_freight_barcode_id.id, # 'pad_freight_barcode_id': self.pad_freight_barcode_id.id,
'pad_lot_id': self.pad_freight_lot_id.lot_id.id, # 'pad_lot_id': self.pad_freight_lot_id.lot_id.id,
'chuck_freight_barcode_id': self.chuck_freight_barcode_id.id, # 'chuck_freight_barcode_id': self.chuck_freight_barcode_id.id,
'chuck_lot_id': self.chuck_freight_lot_id.lot_id.id, # 'chuck_lot_id': self.chuck_freight_lot_id.lot_id.id,
#
'after_assembly_functional_tool_name': self.after_assembly_functional_tool_name, # '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_type_id': self.after_assembly_functional_tool_type_id.id,
'after_assembly_functional_tool_diameter': self.after_assembly_functional_tool_diameter, # '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_knife_tip_r_angle': self.after_assembly_knife_tip_r_angle,
'after_assembly_new_former': self.after_assembly_new_former, # 'after_assembly_new_former': self.after_assembly_new_former,
'cut_time': self.cut_time, # 'cut_time': self.cut_time,
'cut_length': self.cut_length, # 'cut_length': self.cut_length,
'cut_number': self.cut_number, # 'cut_number': self.cut_number,
'after_assembly_whether_standard_knife': self.after_assembly_whether_standard_knife, # 'after_assembly_whether_standard_knife': self.after_assembly_whether_standard_knife,
'after_assembly_coarse_middle_thin': self.after_assembly_coarse_middle_thin, # 'after_assembly_coarse_middle_thin': self.after_assembly_coarse_middle_thin,
'after_assembly_max_lifetime_value': self.after_assembly_max_lifetime_value, # 'after_assembly_max_lifetime_value': self.after_assembly_max_lifetime_value,
'after_assembly_alarm_value': self.after_assembly_alarm_value, # 'after_assembly_alarm_value': self.after_assembly_alarm_value,
'after_assembly_used_value': self.after_assembly_used_value, # 'after_assembly_used_value': self.after_assembly_used_value,
'after_assembly_tool_loading_length': self.after_assembly_tool_loading_length, # 'after_assembly_tool_loading_length': self.after_assembly_tool_loading_length,
'after_assembly_handle_length': self.after_assembly_handle_length, # 'after_assembly_handle_length': self.after_assembly_handle_length,
'after_assembly_functional_tool_length': self.after_assembly_functional_tool_length, # 'after_assembly_functional_tool_length': self.after_assembly_functional_tool_length,
'after_assembly_effective_length': self.after_assembly_effective_length, # 'after_assembly_effective_length': self.after_assembly_effective_length,
'L_D_number': self.L_D_number, # 'L_D_number': self.L_D_number,
'hiding_length': self.hiding_length, # 'hiding_length': self.hiding_length,
'assemble_status': '1', # 'assemble_status': '1',
'tool_loading_person': self.env.user.name, # 'tool_loading_person': self.env.user.name,
'image': self.image, # 'image': self.image,
'tool_loading_time': fields.Datetime.now() # 'tool_loading_time': fields.Datetime.now()
} # }
#
def get_desc_2(self, stock_lot, functional_tool_assembly_id): # def get_desc_2(self, stock_lot, functional_tool_assembly_id):
return { # return {
'barcode_id': stock_lot.id, # 'barcode_id': stock_lot.id,
'code': self.code, # 'code': self.code,
'name': self.after_name_id.name, # 'name': self.after_name_id.name,
'tool_name_id': self.after_name_id.id, # 'tool_name_id': self.after_name_id.id,
'rfid': self.rfid, # 'rfid': self.rfid,
'tool_groups_id': self.after_tool_groups_id.id, # 'tool_groups_id': self.after_tool_groups_id.id,
'functional_tool_name_id': functional_tool_assembly_id.id, # 'functional_tool_name_id': functional_tool_assembly_id.id,
'sf_cutting_tool_type_id': self.after_assembly_functional_tool_type_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_integral_model_id': self.integral_product_id.id,
'cutting_tool_blade_model_id': self.blade_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_cutterbar_model_id': self.bar_product_id.id,
'cutting_tool_cutterpad_model_id': self.pad_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_cutterhandle_model_id': self.handle_product_id.id,
'cutting_tool_cutterhead_model_id': self.chuck_product_id.id, # 'cutting_tool_cutterhead_model_id': self.chuck_product_id.id,
#
'functional_tool_diameter': self.after_assembly_functional_tool_diameter, # 'functional_tool_diameter': self.after_assembly_functional_tool_diameter,
'knife_tip_r_angle': self.after_assembly_knife_tip_r_angle, # 'knife_tip_r_angle': self.after_assembly_knife_tip_r_angle,
'coarse_middle_thin': self.after_assembly_coarse_middle_thin, # 'coarse_middle_thin': self.after_assembly_coarse_middle_thin,
'new_former': self.after_assembly_new_former, # 'new_former': self.after_assembly_new_former,
'tool_loading_length': self.after_assembly_tool_loading_length, # 'tool_loading_length': self.after_assembly_tool_loading_length,
'handle_length': self.after_assembly_handle_length, # 'handle_length': self.after_assembly_handle_length,
'functional_tool_length': self.after_assembly_functional_tool_length, # 'functional_tool_length': self.after_assembly_functional_tool_length,
'effective_length': self.after_assembly_effective_length, # 'effective_length': self.after_assembly_effective_length,
#
'max_lifetime_value': self.after_assembly_max_lifetime_value, # 'max_lifetime_value': self.after_assembly_max_lifetime_value,
'alarm_value': self.after_assembly_alarm_value, # 'alarm_value': self.after_assembly_alarm_value,
'used_value': self.after_assembly_used_value, # 'used_value': self.after_assembly_used_value,
'whether_standard_knife': self.after_assembly_whether_standard_knife, # 'whether_standard_knife': self.after_assembly_whether_standard_knife,
'L_D_number': self.L_D_number, # 'L_D_number': self.L_D_number,
'hiding_length': self.hiding_length, # 'hiding_length': self.hiding_length,
'cut_time': self.cut_time, # 'cut_time': self.cut_time,
'cut_length': self.cut_length, # 'cut_length': self.cut_length,
'cut_number': self.cut_number, # 'cut_number': self.cut_number,
'image': self.image, # 'image': self.image,
} # }
class StockPicking(models.Model):
_inherit = 'stock.picking'
def create_tool_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,
'origin': obj.assembly_order_code
})
# 创建作业详情对象记录,并绑定到刀具组装入库单
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,
'install_tool_time': fields.Datetime.now(),
'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)
def create_tool_stocking_picking1(self, obj):
"""
创建刀具物料出库单
"""
# 获取名称为内部调拨的作业类型
picking_type_id = self.env['stock.picking.type'].sudo().search([('name', '=', '内部调拨')])
# 创建刀具物料出库单
picking_id = self.env['stock.picking'].create({
'name': self._get_name_stock1(picking_type_id),
'picking_type_id': picking_type_id.id,
'location_id': self.env['stock.location'].search([('name', '=', '刀具房')]).id,
'location_dest_id': self.env['stock.location'].search([('name', '=', '刀具组装位置')]).id,
'origin': obj.assembly_order_code
})
# =============刀具物料出库===================
stock_move_id = self.env['stock.move']
datas = {'data': [], 'picking_id': picking_id}
if obj.handle_code_id:
# 修改刀柄序列号状态为【在用】
obj.handle_code_id.sudo().write({'tool_material_status': '在用'})
datas['data'].append(
{'current_location_id': self.env['sf.shelf.location'], 'lot_id': obj.handle_code_id})
if obj.integral_product_id:
datas['data'].append(
{'current_location_id': obj.integral_freight_barcode_id, 'lot_id': obj.integral_freight_lot_id.lot_id})
if obj.blade_product_id:
datas['data'].append(
{'current_location_id': obj.blade_freight_barcode_id, 'lot_id': obj.blade_freight_lot_id.lot_id})
if obj.bar_product_id:
datas['data'].append(
{'current_location_id': obj.bar_freight_barcode_id, 'lot_id': obj.bar_freight_lot_id.lot_id})
if obj.pad_product_id:
datas['data'].append(
{'current_location_id': obj.pad_freight_barcode_id, 'lot_id': obj.pad_freight_lot_id.lot_id})
if obj.chuck_product_id:
datas['data'].append(
{'current_location_id': obj.chuck_freight_barcode_id, 'lot_id': obj.chuck_freight_lot_id.lot_id})
# 创建刀具物料出库库存移动记录
stock_move_id.create_tool_material_stock_moves(datas)
# 将刀具物料出库库单的状态更改为就绪
picking_id.action_confirm()
# 修改刀具物料出库移动历史记录
stock_move_id.write_tool_material_stock_move_lines(datas)
# 设置数量,并验证完成
picking_id.action_set_quantities_to_reservation()
picking_id.button_validate()
logging.info(f'刀具物料调拨单状态:{picking_id.state}')
def _get_name_stock1(self, picking_type_id):
name = f'{picking_type_id.sequence_id.prefix}DJ/{date.today().strftime("%y")}'
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 = "%05d" % 1
else:
m = int(stock_id.name[-5:]) + 1
num = "%05d" % m
return name + str(num)
class StockMove(models.Model):
_inherit = 'stock.move'
def create_tool_material_stock_moves(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_material_stock_move_lines(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({
'current_location_id': res.get('current_location_id').id,
'lot_id': res.get('lot_id').id
})
return True
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([('categ_type', '=', '功能刀具'), ('tracking', '=', 'serial')])
if not product_id:
logging.info('没有搜索到功能刀具产品:%s' % product_id)
raise ValidationError('没有找到按唯一序列号追溯的功能刀具产品信息!')
stock_lot = self.env['stock.lot'].create({
'name': self.get_stock_lot_name(obj),
'product_id': product_id[0].id,
'company_id': self.env.company.id
})
return stock_lot
def get_stock_lot_name(self, obj):
"""
生成功能刀具序列号
"""
company = obj.cutting_tool_cutterhandle_model_id.code.split('-', 1)[0]
new_time = datetime.strptime(str(fields.Date.today()), "%Y-%m-%d").strftime("%Y%m%d")
code = '%s-GNDJ-%s-%s' % (company, obj.after_assembly_functional_tool_type_id.code, new_time)
stock_lot_id = self.env['stock.lot'].sudo().search(
[('name', 'like', code)], 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 '%s-%s' % (code, num)

View File

@@ -427,10 +427,10 @@
</group> </group>
</sheet> </sheet>
<footer> <footer>
<button string="确定" name="functional_tool_assembly" type="object" class="btn-primary" <!-- <button string="确定" name="functional_tool_assembly" type="object" class="btn-primary"-->
attrs="{'invisible': [('obtain_measurement_status', '=', False),('enable_tool_presetter', '=', True)]}" <!-- attrs="{'invisible': [('obtain_measurement_status', '=', False),('enable_tool_presetter', '=', True)]}"-->
confirm="是否确认申请组装"/> <!-- confirm="是否确认申请组装"/>-->
<button string="取消" class="btn-secondary" special="cancel"/> <!-- <button string="取消" class="btn-secondary" special="cancel"/>-->
</footer> </footer>
</form> </form>
</field> </field>