diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 9627a0f7..54024fe3 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -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']: diff --git a/sf_sale/views/purchase_order_view.xml b/sf_sale/views/purchase_order_view.xml index f92658fc..90c9bd4b 100644 --- a/sf_sale/views/purchase_order_view.xml +++ b/sf_sale/views/purchase_order_view.xml @@ -94,7 +94,7 @@ {'readonly': ['&',('state', 'in', ['purchase']),('check_status','in', - ['pending','approved'])]} + ['approved'])]} diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py index 235935a0..350658a4 100644 --- a/sf_tool_management/models/base.py +++ b/sf_tool_management/models/base.py @@ -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 diff --git a/sf_tool_management/models/functional_tool.py b/sf_tool_management/models/functional_tool.py index c37d5317..d4718f34 100644 --- a/sf_tool_management/models/functional_tool.py +++ b/sf_tool_management/models/functional_tool.py @@ -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='刀具型号') diff --git a/sf_tool_management/views/menu_view.xml b/sf_tool_management/views/menu_view.xml index eae7532e..8ddee8eb 100644 --- a/sf_tool_management/views/menu_view.xml +++ b/sf_tool_management/views/menu_view.xml @@ -14,77 +14,111 @@ parent="mrp.menu_mrp_root" sequence="20"/> - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/sf_tool_management/views/tool_base_views.xml b/sf_tool_management/views/tool_base_views.xml index 4e1a6fc4..944decd2 100644 --- a/sf_tool_management/views/tool_base_views.xml +++ b/sf_tool_management/views/tool_base_views.xml @@ -792,11 +792,16 @@ sf.functional.tool.dismantle
+
+

+ options="{'no_create': True}" attrs="{‘readonly': [('state', '=', '已拆解')]}"/>

@@ -807,76 +812,103 @@ - + + + + + + + + + + + - - - - - + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - + - - - - - - + + + + + + + + + + - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + diff --git a/sf_tool_management/views/tool_material_search.xml b/sf_tool_management/views/tool_material_search.xml index ee63ba26..d4772244 100644 --- a/sf_tool_management/views/tool_material_search.xml +++ b/sf_tool_management/views/tool_material_search.xml @@ -94,12 +94,5 @@ sf.tool.material.search tree,form -