From 080a3d717535d230365517781391a8355921429e Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Mon, 22 Apr 2024 17:59:48 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E4=BC=98=E5=8C=96=E6=89=AB=E7=A0=81?= =?UTF-8?q?=E7=9A=84=E6=89=98=E7=9B=98=E5=B7=B2=E7=BB=91=E5=AE=9A=E5=B7=A5?= =?UTF-8?q?=E5=8D=95=E7=9A=84=E6=8F=90=E7=A4=BA=E4=BF=A1=E6=81=AF=EF=BC=9B?= =?UTF-8?q?2=E3=80=81=E4=BC=98=E5=8C=96=E9=87=87=E8=B4=AD=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E6=9C=AA=E5=AE=A1=E6=A0=B8=E6=97=B6=EF=BC=8C=E9=87=91?= =?UTF-8?q?=E9=A2=9D=E6=95=B0=E6=8D=AE=E4=B8=8D=E8=83=BD=E6=94=B9=E5=8F=98?= =?UTF-8?q?=E7=9A=84bug=EF=BC=9B3=E3=80=81=E5=8A=9F=E8=83=BD=E5=88=80?= =?UTF-8?q?=E5=85=B7=E6=8B=86=E8=A7=A3=E5=8D=95=E6=96=B0=E5=A2=9E=E6=A0=B9?= =?UTF-8?q?=E6=8D=AE=E4=B8=8D=E5=90=8C=E6=83=85=E5=86=B5=E6=89=AB=E5=BA=93?= =?UTF-8?q?=E4=BD=8D=E7=A0=81=E5=BD=95=E5=85=A5=E4=BA=94=E7=A7=8D=E7=89=A9?= =?UTF-8?q?=E6=96=99=E7=9A=84=E7=9B=AE=E7=9A=84=E5=BA=93=E4=BD=8D=E7=9A=84?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=EF=BC=9B4=E3=80=81=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=88=80=E5=85=B7=E6=8B=86=E8=A7=A3=E5=8D=95=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=8B=86=E8=A7=A3=E5=90=8E=E7=9A=84Rfid=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=8B=86=E8=A7=A3=E5=8D=95=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E5=AD=97=E6=AE=B5=EF=BC=8C=E6=96=B0=E5=A2=9E=E5=88=80?= =?UTF-8?q?=E5=85=B7=E7=89=A9=E6=96=99=E5=BA=93=E4=BD=8D=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E8=BF=87=E6=BB=A4=EF=BC=9B5=E3=80=81?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=88=80=E5=85=B7=E6=8B=86=E8=A7=A3=E5=8D=95?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=A1=AE=E8=AE=A4=E6=8B=86=E8=A7=A3=E6=8C=89?= =?UTF-8?q?=E9=92=AE=EF=BC=8C=E5=AE=8C=E6=88=90=E7=82=B9=E5=87=BB=E7=A1=AE?= =?UTF-8?q?=E8=AE=A4=E6=8B=86=E8=A7=A3=E5=90=8E=E7=9A=84=E5=88=80=E5=85=B7?= =?UTF-8?q?=E7=89=A9=E6=96=99=E6=98=AF=E5=90=A6=E6=8A=A5=E5=BA=9F=E3=80=81?= =?UTF-8?q?=E7=A3=A8=E5=89=8A=E6=88=96=E8=80=85=E6=9B=B4=E6=8D=A2=E7=9A=84?= =?UTF-8?q?=E4=B8=8D=E5=90=8C=E6=9D=A1=E4=BB=B6=E8=BF=9B=E8=A1=8C=E6=8B=86?= =?UTF-8?q?=E8=A7=A3=E5=90=8E=E7=89=A9=E6=96=99=E7=9A=84=E4=B8=8D=E5=90=8C?= =?UTF-8?q?=E5=8E=BB=E5=90=91=E7=9A=84=E5=8A=9F=E8=83=BD=E5=8F=8A=E7=94=9F?= =?UTF-8?q?=E6=88=90=E7=A7=BB=E5=8A=A8=E5=8E=86=E5=8F=B2=EF=BC=8C=E8=A7=A3?= =?UTF-8?q?=E9=99=A4=E5=8A=9F=E8=83=BD=E5=88=80=E5=85=B7Rfid=E7=9A=84?= =?UTF-8?q?=E7=BB=91=E5=AE=9A=E5=B9=B6=E6=9B=B4=E6=94=B9=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E7=AD=89=E3=80=826=E3=80=81=E4=BC=98=E5=8C=96=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=88=80=E5=85=B7=E7=AE=A1=E7=90=86=E4=B8=8B=E7=9A=84?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E7=9B=AE=E5=BD=95=E5=B8=83=E5=B1=80=EF=BC=9B?= =?UTF-8?q?7=E3=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_workorder.py | 2 +- sf_sale/views/purchase_order_view.xml | 2 +- sf_tool_management/models/base.py | 162 ++++++++++++++++-- sf_tool_management/models/functional_tool.py | 1 + sf_tool_management/views/menu_view.xml | 120 ++++++++----- sf_tool_management/views/tool_base_views.xml | 144 ++++++++++------ .../views/tool_material_search.xml | 7 - 7 files changed, 318 insertions(+), 120 deletions(-) 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 -