1、优化功能刀具拆解单拆解原因为更换其他刀具时的扫码录入刀具物料货位信息功能;2、优化功能刀具拆解单确认拆解后的刀具物料拆解流程,及其刀具物料功能刀具的数量统计等;3、功能刀具拆解、功能刀具模块添加动作过滤已拆解状态的记录,并添加筛选方法;4、功能刀具组装流程添加刀具物料货位数量校验;

This commit is contained in:
yuxianghui
2024-04-23 14:15:45 +08:00
parent 080a3d7175
commit 8bc23f5136
8 changed files with 114 additions and 60 deletions

View File

@@ -647,33 +647,56 @@ class FunctionalToolDismantle(models.Model):
"""
# 对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)])
tool_id = self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('rfid', '=', barcode), ('functional_tool_status', '!=', '已拆除')])
if tool_id:
self.functional_tool_id = tool_id.id
else:
raise ValidationError('Rfid为【%s】的功能刀具不存在,请重新扫描!' % barcode)
else:
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
if self.dismantle_cause == '更换为其他刀具':
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', barcode)])
if not location:
raise ValidationError('%s】该货位不存在,请重新扫码!' % barcode)
else:
pass
if not location.product_id:
# 判断功能刀具存在哪些刀具物料需要录入库位
if self.chuck_product_id: # 夹头
if not self.chuck_freight_id:
self.chuck_freight_id = location.id
return True
if self.integral_product_id: # 整体式刀具
if not self.integral_freight_id:
self.integral_freight_id = location.id
return True
elif self.blade_product_id: # 刀片
if not self.blade_freight_id:
self.blade_freight_id = location.id
return True
if self.bar_product_id: # 刀杆
if not self.bar_freight_id:
self.bar_freight_id = location.id
return True
elif self.pad_product_id: # 刀盘
if not self.pad_freight_id:
self.pad_freight_id = location.id
return True
else:
# 判断货位存放的是那个刀具物料产品
if self.integral_product_id == location.product_id: # 整体式刀具
self.integral_freight_id = location.id
elif self.blade_product_id == location.product_id: # 刀片
self.blade_freight_id = location.id
elif self.bar_product_id == location.product_id: # 刀杆
self.bar_freight_id = location.id
elif self.pad_product_id == location.product_id: # 刀盘
self.pad_freight_id = location.id
elif self.chuck_product_id == location.product_id: # 夹头
self.chuck_freight_id = location.id
elif self.dismantle_cause in ['寿命到期报废', '崩刀报废']:
raise ValidationError('该功能刀具因为%s拆解,无需录入库位' % self.dismantle_cause)
else:
raise ValidationError('该功能刀具因为%s拆解,无需录入库位' % self.dismantle_cause)
name = fields.Char('名称', related='functional_tool_id.name')
@@ -698,6 +721,7 @@ class FunctionalToolDismantle(models.Model):
grinding_id = fields.Char('磨削单号', readonly=True)
state = fields.Selection([('待拆解', '待拆解'), ('已拆解', '已拆解')], default='待拆解')
active = fields.Boolean('有效', default=True)
# 刀柄
handle_product_id = fields.Many2one('product.product', string='刀柄', compute='_compute_functional_tool_num',
@@ -787,22 +811,24 @@ class FunctionalToolDismantle(models.Model):
item.chuck_product_id = False
def confirmation_disassembly(self):
logging.info('%s刀具确认拆解' % self.dismantle_cause)
logging.info('%s刀具确认开始拆解' % self.dismantle_cause)
if self.functional_tool_id.functional_tool_status == '已拆除':
raise ValidationError('Rfid为【%s】的功能刀具已经拆解,请勿重复操作!' % self.functional_tool_id.rfid_dismantle)
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)])
lot = self.env['stock.lot'].sudo().search([('rfid', '=', 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)
functional_tool_assembly, functional_tool_assembly.tool_groups_id)
else:
# 刀柄不报废 入库到刀具房
lot.create_stock_quant(location, location_dest, functional_tool_assembly.id, '功能刀具拆解',
functional_tool_assembly)
functional_tool_assembly, functional_tool_assembly.tool_groups_id)
# ==============功能刀具报废拆解================
if self.dismantle_cause in ['寿命到期报废', '崩刀报废']:
# 除刀柄外物料报废 入库到Scrap
@@ -853,9 +879,12 @@ class FunctionalToolDismantle(models.Model):
# 修改拆解单的值
self.write({
'rfid_dismantle': self.rfid,
'dismantle_data': fields.Datetime.now(),
'dismantle_person': self.env.user.name,
'rfid': '',
'state': '已拆解'
})
logging.info('刀具拆解成功!')
class ProductProduct(models.Model):

View File

@@ -45,7 +45,7 @@ class FunctionalCuttingToolEntity(models.Model):
active = fields.Boolean(string='已归档', default=True)
@api.depends('barcode_id.quant_ids')
@api.depends('barcode_id.quant_ids', 'functional_tool_status')
def _compute_current_location_id(self):
for record in self:
if record.barcode_id.quant_ids:
@@ -61,6 +61,12 @@ class FunctionalCuttingToolEntity(models.Model):
else:
record.current_location_id = False
record.current_location = False
if record.functional_tool_status == '已拆除':
record.current_location_id = False
record.current_location = False
record.tool_room_num = 0
record.line_edge_knife_library_num = 0
record.machine_knife_library_num = 0
def get_location_num(self):
"""
@@ -185,7 +191,8 @@ class FunctionalCuttingToolEntity(models.Model):
stock_location_id = self.env['stock.location'].search([('name', '=', '制造前')])
# 创建功能刀具该批次/序列号 库存移动和移动历史
self.barcode_id.create_stock_quant(location_inventory_id, stock_location_id,
self.functional_tool_name_id.id, '机床装刀', self.functional_tool_name_id)
self.functional_tool_name_id.id, '机床装刀', self.functional_tool_name_id,
self.functional_tool_name_id.tool_groups_id)
# ==========刀具组接口==========
# def _register_functional_tool_groups(self, obj):

View File

@@ -112,6 +112,8 @@ class StockLot(models.Model):
record.tool_material_status = '可用'
elif record.quant_ids[-1].location_id.name == '刀具组装位置':
record.tool_material_status = '在用'
elif record.quant_ids[-1].location_id.name == 'Scrap':
record.tool_material_status = '报废'
else:
record.tool_material_status = '未入库'
if record.tool_material_search_id:

View File

@@ -39,9 +39,7 @@ class ToolMaterial(models.Model):
usable_num += quant.quantity
elif location == '刀具组装位置':
have_been_used_num += quant.quantity
elif location == '进货':
pass
elif location != 'Vendors':
elif location == 'Scrap':
scrap_num += quant.quantity
record.usable_num = usable_num
record.have_been_used_num = have_been_used_num

View File

@@ -85,7 +85,10 @@
<group>
<group>
<field name="barcode_id" invisible="1"/>
<field name="rfid" readonly="1"/>
<field name="rfid" readonly="1"
attrs="{'invisible': [('functional_tool_status', '=', '已拆除')]}"/>
<field name="rfid_dismantle" readonly="1"
attrs="{'invisible': [('functional_tool_status', '!=', '已拆除')]}"/>
<field name="tool_name_id" invisible="0"
placeholder="请输入20字以内的名称"/>
<field name="sf_cutting_tool_type_id"/>
@@ -202,6 +205,9 @@
<field name="current_location_id" invisible="True"/>
<field name="sf_cutting_tool_type_id" invisible="True"/>
<filter string="未拆除" name="no_state_removed" domain="[('functional_tool_status', '!=', '已拆除')]"/>
<filter string="已拆除" name="state_removed" domain="[('functional_tool_status', '=', '已拆除')]"/>
<separator/>
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
<searchpanel>
<field name="sf_cutting_tool_type_id" icon="fa-building" enable_counters="1"/>
@@ -218,6 +224,8 @@
<field name="res_model">sf.functional.cutting.tool.entity</field>
<field name="view_mode">tree,form,search</field>
<field name="view_id" ref="view_functional_cutting_tool_list_tree"/>
<field name="search_view_id" ref="view_functional_cutting_tool_list_search"/>
<field name="context">{'search_default_no_state_removed':1}</field>
</record>
<!-- ======================================== 功能刀具预警========================================-->

View File

@@ -783,6 +783,7 @@
<field name="dismantle_cause"/>
<field name="dismantle_data"/>
<field name="dismantle_person"/>
<field name="state" invisible="1"/>
</tree>
</field>
</record>
@@ -794,20 +795,21 @@
<form>
<header>
<button string="确认拆解" name="confirmation_disassembly" type="object" class="btn-primary"
confirm="是否确认拆解" attrs="{invisible': [('state', '=', '已拆解')]}"/>
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}" attrs="{readonly': [('state', '=', '已拆解')]}"/>
options="{'no_create': True}" attrs="{'readonly': [('state', '=', '已拆解')]}"/>
</h1>
</div>
<field name="_barcode_scanned" widget="barcode_handler"/>
<group>
<group>
<field name="rfid"/>
<field name="rfid" attrs="{'invisible': [('state', '=', '已拆解')]}"/>
<field name="rfid_dismantle" attrs="{'invisible': [('state', '!=', '已拆解')]}"/>
<field name="tool_type_id"/>
<field name="tool_groups_id"/>
<field name="diameter"/>
@@ -820,7 +822,8 @@
<group>
<group>
<group>
<field name="dismantle_cause" placeholder="请选择拆解原因"/>
<field name="dismantle_cause" placeholder="请选择拆解原因"
attrs="{'readonly': [('state', '=', '已拆解')]}"/>
</group>
<group>
<field name="scrap_id"
@@ -842,7 +845,7 @@
<group>
<field name="handle_rfid" string="Rfid"/>
<field name="scrap_boolean" string="是否报废"
attrs="{'invisible': [('dismantle_cause', 'not in', ['寿命到期报废','崩刀报废'])]}"/>
attrs="{'invisible': [('dismantle_cause', 'not in', ['寿命到期报废','崩刀报废'])], 'readonly': [('state', '=', '已拆解')]}"/>
</group>
</group>
<group string="夹头" attrs="{'invisible': [('chuck_product_id', '=', False)]}">
@@ -854,7 +857,7 @@
<group>
<field name="chuck_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])]}"/>
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')]}"/>
</group>
</group>
</group>
@@ -868,7 +871,7 @@
<group>
<field name="integral_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])]}"/>
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')]}"/>
</group>
</group>
@@ -883,7 +886,7 @@
<group>
<field name="blade_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])]}"/>
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')]}"/>
</group>
</group>
<group string="刀杆" attrs="{'invisible': [('bar_product_id', '=', False)]}">
@@ -895,7 +898,7 @@
<group>
<field name="bar_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])]}"/>
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')]}"/>
</group>
</group>
<group string="刀盘" attrs="{'invisible': [('pad_product_id', '=', False)]}">
@@ -907,7 +910,7 @@
<group>
<field name="pad_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])]}"/>
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')]}"/>
</group>
</group>
</group>
@@ -923,6 +926,10 @@
<field name="arch" type="xml">
<search>
<field name="functional_tool_id"/>
<filter name="no_dismantle_state" string="未拆解" domain="[('state','!=','已拆解')]"/>
<filter name="dismantle_state" string="已拆解" domain="[('state','=','已拆解')]"/>
<separator/>
<filter name="on_active" string="已归档" domain="[('active','=',False)]"/>
<searchpanel>
<field name="tool_groups_id" enable_counters="1" icon="fa-filter"/>
<field name="tool_type_id" enable_counters="1" icon="fa-filter"/>
@@ -936,8 +943,8 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">sf.functional.tool.dismantle</field>
<field name="view_mode">tree,form,search</field>
<!-- <field name="search_view_id" ref="sf_functional_tool_dismantle_search"/>-->
<!-- <field name="context">{'search_default_no_assemble_status':1}</field>-->
<field name="search_view_id" ref="sf_functional_tool_dismantle_search"/>
<field name="context">{'search_default_no_dismantle_state':1}</field>
</record>

View File

@@ -403,7 +403,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
after_name_id = fields.Many2one('sf.tool.inventory', string='功能刀具名称', required=True)
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号')
rfid = fields.Char('Rfid', compute='_compute_rfid')
tool_code = fields.Char(string='功能刀具编码', compute='_compute_tool_code')
code = fields.Char(string='功能刀具编码', compute='_compute_code')
after_assembly_functional_tool_name = fields.Char(string='组装后功能刀具名称', compute='_compute_name', store=True)
after_assembly_functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model',
string='组装后功能刀具类型')
@@ -448,7 +448,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
@api.depends('after_assembly_functional_tool_type_id', 'integral_specification_id', 'bar_specification_id',
'pad_specification_id', 'handle_specification_id', 'after_assembly_tool_loading_length')
def _compute_tool_code(self):
def _compute_code(self):
for obj in self:
str_1 = 'GNDJ-%s' % obj.after_assembly_functional_tool_type_id.code
str_2 = ''
@@ -467,11 +467,11 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
obj.pad_specification_id.cut_depth_max, obj.handle_specification_id.total_length,
)
else:
obj.tool_code = str_2
obj.code = str_2
return True
obj.tool_code = str_2 + str(self._get_code(str_2))
obj.code = str_2 + str(self._get_code(str_2))
else:
obj.tool_code = str_2
obj.code = str_2
def _get_code(self, str_2):
functional_tool_assembly = self.env['sf.functional.cutting.tool.entity'].sudo().search(
@@ -618,7 +618,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
def get_desc_1(self, stock_lot):
return {
'barcode_id': stock_lot.id,
'code': self.tool_code,
'code': self.code,
'rfid': self.rfid,
'tool_groups_id': self.after_tool_groups_id.id,
'integral_freight_barcode': self.integral_freight_barcode,
@@ -655,7 +655,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
def get_desc_2(self, stock_lot, functional_tool_assembly_id):
return {
'barcode_id': stock_lot.id,
'code': self.tool_code,
'code': self.code,
'name': self.after_name_id.name,
'tool_name_id': self.after_name_id.id,
'rfid': self.rfid,
@@ -718,7 +718,7 @@ class StockPicking(models.Model):
'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.tool_code,
'code': obj.code,
'rfid': obj.rfid,
'functional_tool_name': obj.after_assembly_functional_tool_name,
'tool_groups_id': obj.after_tool_groups_id.id
@@ -762,7 +762,7 @@ class ProductProduct(models.Model):
stock_location_id = self.env['stock.location'].search([('name', '=', '组装后')])
# 创建功能刀具该批次/序列号 库存移动和移动历史
stock_lot.create_stock_quant(location_inventory_id, stock_location_id, functional_tool_assembly.id,
'功能刀具组装', obj)
'功能刀具组装', obj, obj.after_tool_groups_id)
return stock_lot
@@ -796,7 +796,7 @@ class ProductProduct(models.Model):
location_inventory_id = tool_material.quant_ids.location_id[-1]
stock_location_id = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
# 创建功能刀具该批次/序列号 库存移动和移动历史
tool_material.create_stock_quant(location_inventory_id, stock_location_id, None, '功能刀具组装', False)
tool_material.create_stock_quant(location_inventory_id, stock_location_id, None, '功能刀具组装', False, False)
def material_stock_moves(self, shelf_location_barcode):
# 创建库存移动记录
@@ -819,16 +819,19 @@ class ProductProduct(models.Model):
'qty_done': 1.0,
'state': 'done',
})
location.product_num = location.product_num - 1
if location.product_num > 0:
location.product_num = location.product_num - 1
else:
raise ValidationError(
'%s】货位的【%s】产品库存数量为零,请采购入库后再重新组装!' % (location.barcode, location.product_id.name))
return stock_move_id, stock_move_line_id
class StockLot(models.Model):
_inherit = 'stock.lot'
def create_stock_quant(self, location_inventory_id, stock_location_id, functional_tool_assembly_id, name, obj):
def create_stock_quant(self, location_inventory_id, stock_location_id, functional_tool_assembly_id, name, obj,
tool_groups_id):
"""
对功能刀具组装过程的功能刀具和刀具物料进行库存移动,以及创建移动历史
"""
@@ -855,10 +858,10 @@ class StockLot(models.Model):
'functional_tool_type_id': False if not obj else obj.functional_tool_type_id.id,
'diameter': None if not obj else obj.after_assembly_functional_tool_diameter,
'knife_tip_r_angle': None if not obj else obj.after_assembly_knife_tip_r_angle,
'code': '' if not obj else obj.tool_code,
'code': '' if not obj else obj.code,
'rfid': '' if not obj else obj.rfid,
'functional_tool_name': '' if not obj else obj.after_assembly_functional_tool_name,
'tool_groups_id': False if not obj else obj.after_tool_groups_id.id
'tool_groups_id': False if not tool_groups_id else tool_groups_id.id
})
return stock_move_id, stock_move_line_id

View File

@@ -334,7 +334,7 @@
<group>
<group>
<field name="barcode_id" invisible="True"/>
<field name="tool_code" readonly="True"/>
<field name="code" readonly="True"/>
<field name="rfid" class="custom_required"/>
<field name="after_name_id" string="功能刀具名称" placeholder="请选择功能刀具名称"
options="{'no_create': True, 'no_quick_create': True}"/>