1、优化扫码的托盘已绑定工单的提示信息;2、优化采购订单未审核时,金额数据不能改变的bug;3、功能刀具拆解单新增根据不同情况扫库位码录入五种物料的目的库位的信息;4、功能刀具拆解单新增拆解后的Rfid字段,新增拆解单状态字段,新增刀具物料库位信息搜索过滤;5、功能刀具拆解单新增确认拆解按钮,完成点击确认拆解后的刀具物料是否报废、磨削或者更换的不同条件进行拆解后物料的不同去向的功能及生成移动历史,解除功能刀具Rfid的绑定并更改状态等。6、优化功能刀具管理下的菜单目录布局;7、

This commit is contained in:
yuxianghui
2024-04-22 17:59:48 +08:00
parent 857d5d8916
commit 080a3d7175
7 changed files with 318 additions and 120 deletions

View File

@@ -988,7 +988,7 @@ class SfWorkOrderBarcodes(models.Model):
# [('routing_type', '=', '装夹预调'), ('production_id', '=', self.production_id.id)])
workorder_old = self.env['mrp.workorder'].search([('rfid_code', '=', barcode)])
if workorder_old:
raise UserError('该托盘已绑定工件,请先解除绑定!!!')
raise UserError('该托盘已绑定%s】制造订单,请先解除绑定!!!' % workorder_old.production_id.name)
if workorder:
if workorder.routing_type == '装夹预调':
if workorder.state in ['done']:

View File

@@ -94,7 +94,7 @@
</xpath>
<xpath expr="//field[@name='order_line']" position="attributes">
<attribute name="attrs">{'readonly': ['&amp;',('state', 'in', ['purchase']),('check_status','in',
['pending','approved'])]}
['approved'])]}
</attribute>
</xpath>
<field name="partner_ref" position="attributes">

View File

@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
import re
import logging
from datetime import timedelta
@@ -643,11 +645,35 @@ class FunctionalToolDismantle(models.Model):
"""
扫码
"""
tool_id = self.env['sf.functional.cutting.tool.entity'].sudo().search([('rfid', '=', barcode)])
if tool_id:
self.functional_tool_id = tool_id.id
# 对barcode进行校验是否为货位编码
if not re.match(r'^[A-Za-z0-9]+-[A-Za-z0-9]+-\d{3}-\d{3}$', barcode):
tool_id = self.env['sf.functional.cutting.tool.entity'].sudo().search([('rfid', '=', barcode)])
if tool_id:
self.functional_tool_id = tool_id.id
else:
raise ValidationError('Rfid为【%s】的功能刀具不存在,请重新扫描!' % barcode)
else:
pass
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', barcode)])
if not location:
raise ValidationError('%s】该货位不存在,请重新扫码!' % barcode)
else:
# 判断是否有夹头物料
if not self.chuck_product_id:
# 判断是否有整体式刀具物料
if self.integral_product_id:
# 判断货位是否为空货位 或者 是存有整体式刀具的货位
if location.product_id in [False, self.integral_product_id]:
self.integral_freight_id = location.id
else:
raise ValidationError('%s】该货位已存在【%s】产品,请重新扫码!' % location.barcode,
location.product_id.name)
# 判断是否有刀片物料
elif self.blade_product_id:
# 判断是否有刀杆物料
if self.bar_product_id:
pass
else:
pass
name = fields.Char('名称', related='functional_tool_id.name')
@@ -659,6 +685,7 @@ class FunctionalToolDismantle(models.Model):
diameter = fields.Integer(string='刀具直径(mm)', compute='_compute_functional_tool_num', store=True)
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', compute='_compute_functional_tool_num', store=True)
rfid = fields.Char('Rfid', compute='_compute_functional_tool_num', store=True)
rfid_dismantle = fields.Char('Rfid(已拆解)', readonly=True)
dismantle_cause = fields.Selection(
[('寿命到期报废', '寿命到期报废'), ('崩刀报废', '崩刀报废'), ('更换为其他刀具', '更换为其他刀具'),
@@ -667,8 +694,10 @@ class FunctionalToolDismantle(models.Model):
dismantle_person = fields.Char('拆解人', readonly=True)
image = fields.Binary('图片', readonly=True)
scrap_id = fields.Char('报废单号')
grinding_id = fields.Char('磨削单号')
scrap_id = fields.Char('报废单号', readonly=True)
grinding_id = fields.Char('磨削单号', readonly=True)
state = fields.Selection([('待拆解', '待拆解'), ('已拆解', '已拆解')], default='待拆解')
# 刀柄
handle_product_id = fields.Many2one('product.product', string='刀柄', compute='_compute_functional_tool_num',
@@ -676,7 +705,7 @@ class FunctionalToolDismantle(models.Model):
handle_type_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀柄型号',
related='handle_product_id.cutting_tool_model_id')
handle_brand_id = fields.Many2one('sf.machine.brand', string='刀柄品牌', related='handle_product_id.brand_id')
handle_rfid = fields.Char(string='刀柄Rfid')
handle_rfid = fields.Char(string='刀柄Rfid', compute='_compute_functional_tool_num', store=True)
scrap_boolean = fields.Boolean(string='刀柄是否报废', default=False)
# 整体式
@@ -686,7 +715,8 @@ class FunctionalToolDismantle(models.Model):
related='integral_product_id.cutting_tool_model_id')
integral_brand_id = fields.Many2one('sf.machine.brand', string='整体式刀具品牌',
related='integral_product_id.brand_id')
integral_freight_barcode = fields.Char('整体式刀具目标货位')
integral_freight_id = fields.Many2one('sf.shelf.location', '整体式刀具目标货位',
domain="[('product_id', 'in', (integral_product_id, False))]")
# 刀片
blade_product_id = fields.Many2one('product.product', string='刀片', compute='_compute_functional_tool_num',
@@ -694,7 +724,8 @@ class FunctionalToolDismantle(models.Model):
blade_type_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号',
related='blade_product_id.cutting_tool_model_id')
blade_brand_id = fields.Many2one('sf.machine.brand', string='刀片品牌', related='blade_product_id.brand_id')
blade_freight_barcode = fields.Char('刀片目标货位')
blade_freight_id = fields.Many2one('sf.shelf.location', '刀片目标货位',
domain="[('product_id', 'in', (blade_product_id, False))]")
# 刀杆
bar_product_id = fields.Many2one('product.product', string='刀杆', compute='_compute_functional_tool_num',
@@ -702,7 +733,8 @@ class FunctionalToolDismantle(models.Model):
bar_type_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号',
related='bar_product_id.cutting_tool_model_id')
bar_brand_id = fields.Many2one('sf.machine.brand', string='刀杆品牌', related='bar_product_id.brand_id')
bar_freight_barcode = fields.Char('刀杆目标货位')
bar_freight_id = fields.Many2one('sf.shelf.location', '刀杆目标货位',
domain="[('product_id', 'in', (bar_product_id, False))]")
# 刀盘
pad_product_id = fields.Many2one('product.product', string='刀盘', compute='_compute_functional_tool_num',
@@ -710,7 +742,8 @@ class FunctionalToolDismantle(models.Model):
pad_type_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号',
related='pad_product_id.cutting_tool_model_id')
pad_brand_id = fields.Many2one('sf.machine.brand', string='刀盘品牌', related='pad_product_id.brand_id')
pad_freight_barcode = fields.Char('刀盘目标货位')
pad_freight_id = fields.Many2one('sf.shelf.location', '刀盘目标货位',
domain="[('product_id', 'in', (pad_product_id, False))]")
# 夹头
chuck_product_id = fields.Many2one('product.product', string='夹头', compute='_compute_functional_tool_num',
@@ -718,7 +751,8 @@ class FunctionalToolDismantle(models.Model):
chuck_type_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号',
related='chuck_product_id.cutting_tool_model_id')
chuck_brand_id = fields.Many2one('sf.machine.brand', string='夹头品牌', related='chuck_product_id.brand_id')
chuck_freight_barcode = fields.Char('夹头目标货位')
chuck_freight_id = fields.Many2one('sf.shelf.location', '夹头目标货位',
domain="[('product_id', 'in', (chuck_product_id, False))]")
@api.depends('functional_tool_id')
def _compute_functional_tool_num(self):
@@ -729,6 +763,7 @@ class FunctionalToolDismantle(models.Model):
item.diameter = item.functional_tool_id.functional_tool_diameter
item.knife_tip_r_angle = item.functional_tool_id.knife_tip_r_angle
item.rfid = item.functional_tool_id.rfid
item.handle_rfid = item.functional_tool_id.rfid
item.handle_product_id = item.functional_tool_id.functional_tool_name_id.handle_product_id.id
item.integral_product_id = item.functional_tool_id.functional_tool_name_id.integral_product_id.id
@@ -742,6 +777,7 @@ class FunctionalToolDismantle(models.Model):
item.diameter = 0
item.knife_tip_r_angle = 0
item.rfid = ''
item.handle_rfid = ''
item.handle_product_id = False
item.integral_product_id = False
@@ -749,3 +785,105 @@ class FunctionalToolDismantle(models.Model):
item.bar_product_id = False
item.pad_product_id = False
item.chuck_product_id = False
def confirmation_disassembly(self):
logging.info('%s刀具确认拆解' % self.dismantle_cause)
location = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
location_dest = self.env['stock.location'].search([('name', '=', '刀具房')])
# =================刀柄是否报废拆解=======
location_dest_scrap = self.env['stock.location'].search([('name', '=', 'Scrap')])
if self.handle_rfid:
lot = self.env['stock.lot'].sudo().search([('name', '=', self.handle_rfid)])
functional_tool_assembly = self.functional_tool_id.functional_tool_name_id
if self.scrap_boolean:
# 刀柄报废 入库到Scrap
lot.create_stock_quant(location, location_dest_scrap, functional_tool_assembly.id, '功能刀具拆解',
functional_tool_assembly)
else:
# 刀柄不报废 入库到刀具房
lot.create_stock_quant(location, location_dest, functional_tool_assembly.id, '功能刀具拆解',
functional_tool_assembly)
# ==============功能刀具报废拆解================
if self.dismantle_cause in ['寿命到期报废', '崩刀报废']:
# 除刀柄外物料报废 入库到Scrap
if self.integral_freight_id:
self.integral_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
elif self.blade_freight_id:
self.blade_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
if self.bar_freight_id:
self.bar_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
elif self.pad_freight_id:
self.pad_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
if self.chuck_freight_id:
self.chuck_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
# ===========功能刀具磨削拆解==============
elif self.dismantle_cause in ['刀具需磨削']:
location_dest = self.env['stock.location'].search([('name', '=', '磨削房')])
# 除刀柄外物料拆解 入库到具体库位
if self.integral_freight_id:
self.integral_product_id.dismantle_stock_moves(False, location, location_dest)
elif self.blade_freight_id:
self.blade_product_id.dismantle_stock_moves(False, location, location_dest)
if self.bar_freight_id:
self.bar_product_id.dismantle_stock_moves(False, location, location_dest)
elif self.pad_freight_id:
self.pad_product_id.dismantle_stock_moves(False, location, location_dest)
if self.chuck_freight_id:
self.chuck_product_id.dismantle_stock_moves(False, location, location_dest)
# ==============功能刀具更换拆解==============
elif self.dismantle_cause in ['更换为其他刀具']:
# 除刀柄外物料拆解 入库到具体库位
if self.integral_freight_id:
self.integral_product_id.dismantle_stock_moves(self.integral_freight_id.barcode, location,
location_dest)
elif self.blade_freight_id:
self.blade_product_id.dismantle_stock_moves(self.blade_freight_id.barcode, location, location_dest)
if self.bar_freight_id:
self.bar_product_id.dismantle_stock_moves(self.bar_freight_id.barcode, location, location_dest)
elif self.pad_freight_id:
self.pad_product_id.dismantle_stock_moves(self.pad_freight_id.barcode, location, location_dest)
if self.chuck_freight_id:
self.chuck_product_id.dismantle_stock_moves(self.chuck_freight_id.barcode, location, location_dest)
# ===============删除功能刀具的Rfid字段的值 赋值给Rfid(已拆解)字段=====
self.functional_tool_id.write({
'rfid_dismantle': self.functional_tool_id.rfid,
'rfid': '',
'functional_tool_status': '已拆除'
})
# 修改拆解单的值
self.write({
'rfid_dismantle': self.rfid,
'rfid': '',
'state': '已拆解'
})
class ProductProduct(models.Model):
_inherit = 'product.product'
def dismantle_stock_moves(self, shelf_location_barcode, location_id, location_dest_id):
# 创建功能刀具拆解单产品库存移动记录
stock_move_id = self.env['stock.move'].sudo().create({
'name': '功能刀具拆解',
'product_id': self.id,
'location_id': location_id.id,
'location_dest_id': location_dest_id.id,
'product_uom_qty': 1.00,
'state': 'done'
})
if shelf_location_barcode:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', shelf_location_barcode)])
location.product_num = location.product_num + 1
else:
location = False
# 创建移动历史记录
stock_move_line_id = self.env['stock.move.line'].sudo().create({
'product_id': self.id,
'move_id': stock_move_id.id,
'current_location_id': location.id or False,
'install_tool_time': fields.Datetime.now(),
'qty_done': 1.0,
'state': 'done',
})
return stock_move_id, stock_move_line_id

View File

@@ -14,6 +14,7 @@ class FunctionalCuttingToolEntity(models.Model):
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', related='functional_tool_name_id.tool_groups_id')
code = fields.Char('编码')
rfid = fields.Char('Rfid', readonly=True)
rfid_dismantle = fields.Char('Rfid(已拆解)', readonly=True)
name = fields.Char('名称')
tool_name_id = fields.Many2one('sf.tool.inventory', '功能刀具名称')
sf_cutting_tool_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀具型号')

View File

@@ -14,77 +14,111 @@
parent="mrp.menu_mrp_root"
sequence="20"/>
<menuitem
id="menu_sf_functional_cutting_tool"
parent="menu_sf_tool_manage"
name="功能刀具"
sequence="2"
action="sf_function_tool_entry_list_view_act"
/>
<menuitem
id="menu_sf_functional_tool_warning"
parent="menu_sf_tool_manage"
name="功能刀具预警"
sequence="5"
action="action_sf_functional_tool_warning"
/>
<menuitem
sequence="10"
name="功能刀具安全库存"
id="menu_sf_functional_tool_real_time_distribution"
action="sf_real_time_distribution_of_functional_tools_view_act"
parent="menu_sf_tool_manage"
/>
<menuitem
sequence="6"
name="功能刀具出入库"
id="menu_sf_function_tool_entry_exit_records"
action="sf_inbound_and_outbound_records_of_functional_tools_view_act"
parent="menu_sf_tool_manage"
/>
<!-- =================计划菜单============== -->
<menuitem
sequence="0"
name="功能刀具计划"
name="计划"
id="menu_sf_function_tool_plan"
parent="menu_sf_tool_manage"
/>
<menuitem
sequence="10"
name="机床换刀申请"
id="menu_sf_machine_table_tool_changing_apply"
action="sf_machine_table_tool_changing_apply_view_act"
parent="menu_sf_function_tool_plan"
/>
<menuitem
sequence="20"
name="CAM工单程序用刀计划"
id="menu_sf_cam_work_order_program_knife_plan"
action="sf_cam_work_order_program_knife_plan_view_act"
parent="menu_sf_function_tool_plan"
/>
<!-- ================功能菜单================= -->
<menuitem
sequence="0"
name="机床换刀申请"
id="menu_sf_machine_table_tool_changing_apply"
action="sf_machine_table_tool_changing_apply_view_act"
parent="menu_sf_function_tool_plan"
sequence="5"
name="功能"
id="menu_sf_function_tool_function"
parent="menu_sf_tool_manage"
/>
<menuitem
sequence="4"
sequence="10"
name="功能刀具组装"
id="menu_sf_functional_tool_assembly"
action="sf_functional_tool_assembly_view_act"
parent="menu_sf_function_tool_function"
/>
<menuitem
sequence="20"
name="功能刀具拆解"
id="menu_sf_functional_tool_dismantle"
action="sf_functional_tool_dismantle_view_act"
parent="menu_sf_function_tool_function"
/>
<!-- ================功能刀具菜单=============== -->
<menuitem
sequence="10"
name="功能刀具"
id="menu_sf_function_tool"
parent="menu_sf_tool_manage"
/>
<menuitem
sequence="5"
name="功能刀具拆解"
id="menu_sf_functional_tool_dismantle"
action="sf_functional_tool_dismantle_view_act"
id="menu_sf_functional_cutting_tool"
parent="menu_sf_function_tool"
name="功能刀具"
sequence="10"
action="sf_function_tool_entry_list_view_act"
/>
<menuitem
id="menu_sf_functional_tool_warning"
parent="menu_sf_function_tool"
name="功能刀具预警"
sequence="20"
action="action_sf_functional_tool_warning"
/>
<menuitem
sequence="30"
name="功能刀具出入库"
id="menu_sf_function_tool_entry_exit_records"
action="sf_inbound_and_outbound_records_of_functional_tools_view_act"
parent="menu_sf_function_tool"
/>
<menuitem
sequence="40"
name="功能刀具安全库存"
id="menu_sf_functional_tool_real_time_distribution"
action="sf_real_time_distribution_of_functional_tools_view_act"
parent="menu_sf_function_tool"
/>
<!-- ===============刀具物料菜单================ -->
<menuitem
sequence="15"
name="刀具物料"
id="menu_sf_tool_material"
parent="menu_sf_tool_manage"
/>
<menuitem
sequence="10"
name="刀具物料查询"
id="menu_sf_tool_material_search"
action="action_sf_tool_material_search"
parent="menu_sf_tool_material"
/>
</data>
</odoo>

View File

@@ -792,11 +792,16 @@
<field name="model">sf.functional.tool.dismantle</field>
<field name="arch" type="xml">
<form>
<header>
<button string="确认拆解" name="confirmation_disassembly" type="object" class="btn-primary"
confirm="是否确认拆解" attrs="{invisible': [('state', '=', '已拆解')]}"/>
<field name="state" widget="statusbar" statusbar_visible="待拆解,已拆解"/>
</header>
<sheet>
<div class="oe_title">
<h1>
<field name="functional_tool_id" placeholder="请选择将要拆解的功能刀具"
options="{'no_create': True}"/>
options="{'no_create': True}" attrs="{readonly': [('state', '=', '已拆解')]}"/>
</h1>
</div>
<field name="_barcode_scanned" widget="barcode_handler"/>
@@ -807,76 +812,103 @@
<field name="tool_groups_id"/>
<field name="diameter"/>
<field name="knife_tip_r_angle"/>
<field name="dismantle_cause" placeholder="请选择拆解原因"/>
</group>
<group>
<field name="image"/>
</group>
</group>
<group>
<group>
<group>
<field name="dismantle_cause" placeholder="请选择拆解原因"/>
</group>
<group>
<field name="scrap_id"
attrs="{'invisible': [('dismantle_cause', 'not in', ['寿命到期报废','崩刀报废'])]}"/>
<field name="grinding_id"
attrs="{'invisible': [('dismantle_cause', 'not in', ['刀具需磨削'])]}"/>
</group>
</group>
</group>
<notebook>
<page string="物料组装信息">
<group string="刀柄">
<group>
<field name="handle_product_id" string="名称"/>
<field name="handle_type_id" string="型号"/>
<field name="handle_brand_id" string="品牌"/>
<group>
<group string="刀柄" attrs="{'invisible': [('handle_product_id', '=', False)]}">
<group>
<field name="handle_product_id" string="名称"/>
<field name="handle_type_id" string="型号"/>
<field name="handle_brand_id" string="品牌"/>
</group>
<group>
<field name="handle_rfid" string="Rfid"/>
<field name="scrap_boolean" string="是否报废"
attrs="{'invisible': [('dismantle_cause', 'not in', ['寿命到期报废','崩刀报废'])]}"/>
</group>
</group>
<group>
<field name="handle_rfid" string="Rfid"/>
</group>
</group>
<group string="整体式刀具">
<group>
<field name="integral_product_id" string="名称"/>
<field name="integral_type_id" string="型号"/>
<field name="integral_brand_id" string="品牌"/>
</group>
<group>
<field name="integral_freight_barcode" string="目标货位"/>
<group string="夹头" attrs="{'invisible': [('chuck_product_id', '=', False)]}">
<group>
<field name="chuck_product_id" string="名称"/>
<field name="chuck_type_id" string="型号"/>
<field name="chuck_brand_id" string="品牌"/>
</group>
<group>
<field name="chuck_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])]}"/>
</group>
</group>
</group>
<group attrs="{'invisible': [('integral_product_id', '=', False)]}">
<group string="整体式刀具">
<group>
<field name="integral_product_id" string="名称"/>
<field name="integral_type_id" string="型号"/>
<field name="integral_brand_id" string="品牌"/>
</group>
<group>
<field name="integral_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])]}"/>
<group string="刀片">
<group>
<field name="blade_product_id" string="名称"/>
<field name="blade_type_id" string="型号"/>
<field name="blade_brand_id" string="品牌"/>
</group>
<group>
<field name="blade_freight_barcode" string="目标货位"/>
</group>
</group>
</group>
<group string="刀">
<group>
<field name="bar_product_id" string="名称"/>
<field name="bar_type_id" string="型号"/>
<field name="bar_brand_id" string="品牌"/>
<group>
<group string="刀片" attrs="{'invisible': [('blade_product_id', '=', False)]}">
<group>
<field name="blade_product_id" string="名称"/>
<field name="blade_type_id" string="型号"/>
<field name="blade_brand_id" string="品牌"/>
</group>
<group>
<field name="blade_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])]}"/>
</group>
</group>
<group>
<field name="bar_freight_barcode" string="目标货位"/>
<group string="刀杆" attrs="{'invisible': [('bar_product_id', '=', False)]}">
<group>
<field name="bar_product_id" string="名称"/>
<field name="bar_type_id" string="型号"/>
<field name="bar_brand_id" string="品牌"/>
</group>
<group>
<field name="bar_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])]}"/>
</group>
</group>
</group>
<group string="刀盘">
<group>
<field name="pad_product_id" string="名称"/>
<field name="pad_type_id" string="型号"/>
<field name="pad_brand_id" string="品牌"/>
</group>
<group>
<field name="pad_freight_barcode" string="目标货位"/>
</group>
</group>
<group string="夹头">
<group>
<field name="chuck_product_id" string="名称"/>
<field name="chuck_type_id" string="型号"/>
<field name="chuck_brand_id" string="品牌"/>
</group>
<group>
<field name="chuck_freight_barcode" string="目标货位"/>
<group string="刀盘" attrs="{'invisible': [('pad_product_id', '=', False)]}">
<group>
<field name="pad_product_id" string="名称"/>
<field name="pad_type_id" string="型号"/>
<field name="pad_brand_id" string="品牌"/>
</group>
<group>
<field name="pad_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])]}"/>
</group>
</group>
</group>
</page>

View File

@@ -94,12 +94,5 @@
<field name="res_model">sf.tool.material.search</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem
sequence="20"
name="刀具物料查询"
id="menu_sf_tool_material_search"
action="action_sf_tool_material_search"
parent="menu_sf_tool_manage"
/>
</data>
</odoo>