From 6caae0325a5cc96b208caae9ed1a0832ee70b0cf Mon Sep 17 00:00:00 2001 From: yuxianghui <1608204036@qq.com> Date: Tue, 20 Jun 2023 16:51:06 +0800 Subject: [PATCH 01/15] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=88=80=E5=85=B7?= =?UTF-8?q?=E8=AE=A1=E5=88=92=EF=BC=88=E6=8D=A2=E5=88=80=E7=94=B3=E8=AF=B7?= =?UTF-8?q?=E5=92=8CCAM=E5=B7=A5=E5=8D=95=E7=A8=8B=E5=BA=8F=E7=94=A8?= =?UTF-8?q?=E5=88=80=E8=AE=A1=E5=88=92=EF=BC=89=E8=A7=86=E5=9B=BE=E5=B7=B2?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_tool_management/models/base.py | 101 +++++++++++++++++- .../security/ir.model.access.csv | 2 + sf_tool_management/views/menu_view.xml | 23 ++++ sf_tool_management/views/tool_base_views.xml | 85 ++++++++++++++- 4 files changed, 208 insertions(+), 3 deletions(-) diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py index ae13cb56..8932b3a3 100644 --- a/sf_tool_management/models/base.py +++ b/sf_tool_management/models/base.py @@ -26,7 +26,7 @@ class FunctionalCuttingToolEntity(models.Model): remark = fields.Char('备注') # 功能刀具出入库记录 特有字段 - thickness = fields.Selection([('1', '粗'), ('2', '中'), ('3', '细')], string='粗/中/细') + thickness = fields.Selection([('1', '粗'), ('2', '中'), ('3', '精')], string='粗/中/精') max_life_span = fields.Char(string='最大寿命值') # alarm_value = fields.Char(string='报警值') # used_value = fields.Char(string='已使用值') @@ -56,7 +56,8 @@ class FunctionalCuttingToolEntity(models.Model): return_processing_num = fields.Text(string='归还需磨削数量') return_total = fields.Text(string='合计') total = fields.Text(string='总计') - # remark = fields.Text(string='备注/说明') + + # remark = fields.Char(string='备注/说明') # @api.onchange('functional_cutting_tool_id') # def get_functional_cutting_tool_info(self): @@ -97,3 +98,99 @@ class FunctionalCuttingToolEntity(models.Model): else: new_code = '001' return new_code + + +class MachineTableToolChangingApply(models.Model): + _name = 'sf.machine.table.tool.changing.apply' + _description = '机床换刀申请' + + CNC_machine_table = fields.Char(string='CNC机床') + # todo 机床类型和刀位号 为 Many2one + machine_table_type = fields.Char(string='机床类型') + cutter_spacing_code = fields.Char(string='刀位号') + functional_tool_code = fields.Char(string='功能刀具编码') + functional_tool_name = fields.Char(string='功能刀具名称') + # todo 功能刀具类型为 Many2one + functional_tool_type = fields.Char(string='功能刀具类型') + diameter = fields.Char(string='直径') + coarse_middle_thin = fields.Selection([("1", "粗"), ('2', '中'), ('3', '精')], string='粗/中/精') + hilt_name = fields.Char(string='刀柄名称') + hilt_code = fields.Char(string='刀柄编号') + max_lifetime_value = fields.Char(string='最大寿命值') + alarm_value = fields.Char(string='报警值') + used_value = fields.Char(string='已使用值') + functional_tool_status = fields.Selection([("0", "正常"), ('1', '异常')], string='功能刀具状态') + + replacement_tool_code = fields.Char(string='待换刀具编码') + replacement_tool_name = fields.Char(string='待换刀具名称') + replacement_tool_type = fields.Char(string='待换刀具类型') + replacement_tool_coarse_middle_thin = fields.Selection([("1", "粗"), ('2', '中'), ('3', '精')], + string='粗/中/精') + new_former = fields.Selection([('0', '新'), ('1', '旧')], string='新/旧') + applicant = fields.Char(string='申请人') + used_tool_time = fields.Datetime(string='用刀时间') + reason_for_applying = fields.Char(string='申请原因') + remark = fields.Char(string='备注说明') + + def sync_tool_entity_from_tool_changing_apply_table(self): + """ + ‘功能刀具预警’数据同步到‘机床换刀申请’ + """ + # 获取源表中的所有记录 + source_records = self.env['sf.functional.cutting.tool.entity'].search([]) + + # 循环遍历每个记录 + for source_record in source_records: + # 检查目标表中是否存在相同的记录 + destination_record = self.search([('CNC_machine_table', '=', source_record.machine_tool_code)]) + if destination_record: + # 如果目标表中已经存在相同的记录,则更新该记录 + # todo + destination_record.name = source_record.name + else: + # 如果目标表中不存在相同的记录,则创建一个新记录 + destination_record = self.create({ + # todo + # 'name': source_record.name, + }) + + # todo + def tool_changing_apply(self): + """ + 换刀申请(按键) + """ + + # todo + def transfer(self): + """ + 转移(按键) + """ + + +class CAMWorkOrderProgramKnifePlan(models.Model): + _name = 'sf.cam.work.order.program.knife.plan' + _description = 'CAM工单程序用刀计划' + + CAM_cutter_spacing_code = fields.Char(string='CAM刀位号') + functional_tool_code = fields.Char(string='功能刀具编码') + functional_tool_name = fields.Char(string='功能刀具名称') + functional_tool_type = fields.Char(string='功能刀具类型') + machine_table_name = fields.Char(string='机台名称') + diameter = fields.Char(string='直径(程式)') + tool_loading_length = fields.Char(string='装刀长') + clearance_length = fields.Char(string='避空长') + tool_included_angle = fields.Char(string='刀尖角(R角)') + L_D = fields.Char(string='L/D') + coarse_middle_thin = fields.Selection([("1", "粗"), ('2', '中'), ('3', '精')], string='粗/中/精') + required_cutting_time = fields.Char(string='需要切割时间') + whether_standard_tool = fields.Boolean(string='是否标准刀') + need_knife_time = fields.Datetime(string='需要用刀时间') + applicant = fields.Char(string='申请人') + reason_for_applying = fields.Char(string='申请原因') + remark = fields.Char(string='备注说明') + + # todo + def tool_loading_apply(self): + """ + 装刀申请(按键) + """ diff --git a/sf_tool_management/security/ir.model.access.csv b/sf_tool_management/security/ir.model.access.csv index 3156f716..7b514b89 100644 --- a/sf_tool_management/security/ir.model.access.csv +++ b/sf_tool_management/security/ir.model.access.csv @@ -1,5 +1,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_sf_functional_cutting_tool_entity,sf.functional.cutting.tool.entity,model_sf_functional_cutting_tool_entity,base.group_user,1,1,1,1 +access_sf_cam_work_order_program_knife_plan,sf.cam.work.order.program.knife.plan,model_sf_cam_work_order_program_knife_plan,base.group_user,1,1,1,1 +access_sf_machine_table_tool_changing_apply,sf.machine.table.tool.changing.apply,model_sf_machine_table_tool_changing_apply,base.group_user,1,1,1,1 diff --git a/sf_tool_management/views/menu_view.xml b/sf_tool_management/views/menu_view.xml index 2abf6a11..b0fc131c 100644 --- a/sf_tool_management/views/menu_view.xml +++ b/sf_tool_management/views/menu_view.xml @@ -49,5 +49,28 @@ parent="menu_sf_tool_manage" /> + + + + + + \ No newline at end of file diff --git a/sf_tool_management/views/tool_base_views.xml b/sf_tool_management/views/tool_base_views.xml index 962759f4..baeb0882 100644 --- a/sf_tool_management/views/tool_base_views.xml +++ b/sf_tool_management/views/tool_base_views.xml @@ -36,7 +36,7 @@ - + 功能刀具出入库记录 sf.functional.cutting.tool.entity @@ -142,5 +142,88 @@ + + + + CAM工单程序用刀计划 + sf.cam.work.order.program.knife.plan + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mrp_maintenance/tests/__init__.py b/mrp_maintenance/tests/__init__.py new file mode 100644 index 00000000..461aff90 --- /dev/null +++ b/mrp_maintenance/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import test_mrp_maintenance diff --git a/mrp_maintenance/tests/test_mrp_maintenance.py b/mrp_maintenance/tests/test_mrp_maintenance.py new file mode 100644 index 00000000..9b2b9ada --- /dev/null +++ b/mrp_maintenance/tests/test_mrp_maintenance.py @@ -0,0 +1,263 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import time +from datetime import datetime, timedelta +from odoo.tests import common, Form + + +class TestMrpMaintenance(common.TransactionCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + + # Relative models + cls.ResUsers = cls.env['res.users'] + cls.equipment = cls.env['maintenance.equipment'] + + # User references + cls.main_company = cls.env.ref('base.main_company') + cls.technician_user_id = cls.env.ref('base.user_root') + cls.maintenance_team_id = cls.env.ref('maintenance.equipment_team_maintenance') + cls.stage_repaired_id = cls.env.ref('maintenance.stage_3').id + cls.stage_id = cls.env.ref('maintenance.stage_0').id + cls.category_id = cls.env['maintenance.equipment.category'].create({ + 'name': 'Monitors - Test', + 'technician_user_id': cls.env.ref('base.user_admin').id, + 'color': 3, + }) + + # Create user + cls.user = cls.ResUsers.create({ + 'name': "employee", + 'company_id': cls.main_company.id, + 'login': "employee", + 'email': "employee@yourcompany.example.com", + 'groups_id': [(6, 0, [cls.env.ref('base.group_user').id])] + }) + + # Create user with extra rights + cls.manager = cls.ResUsers.create({ + 'name': "Equipment Manager", + 'company_id': cls.main_company.id, + 'login': "manager", + 'email': "eqmanager@yourcompany.example.com", + 'groups_id': [(6, 0, [cls.env.ref('maintenance.group_equipment_manager').id])] + }) + + # Create method for create a maintenance request + def _create_request(self, name, request_date, equipment_id, maintenance_type): + values = { + 'name': name, + 'request_date': request_date, + 'user_id': self.user.id, + 'owner_user_id': self.user.id, + 'equipment_id': equipment_id.id, + 'maintenance_type': maintenance_type, + 'stage_id': self.stage_id, + 'maintenance_team_id': self.maintenance_team_id.id, + } + return self.env['maintenance.request'].create(values) + + def test_00_mrp_maintenance(self): + + """ In order to check Next preventive maintenance date""" + """ + ex: equipment = Acer Laptop + effective_date = 25-04-2018 + period = 5 + + preventive maintenance date = effective date + period + 30-04-2018 = 25-04-2018 + 5 days + + create maintenance request + request_date = effective date + period + 30-04-2018 = 25-04-2018 + 5 days + + close maintenance request and calculate preventive maintenance date + close_date = 05-05-2018 + + preventive maintenance date = close_date + period + 10-05-2018 = 05-05-2018 + 5day + """ + + # Required for `assign_date` to be visible in the view + with self.debug_mode(): + # Create a new equipment + equipment_form = Form(self.equipment) + equipment_form.name = 'Acer Laptop' + equipment_form.maintenance_team_id = self.maintenance_team_id + equipment_form.category_id = self.category_id + equipment_form.technician_user_id = self.technician_user_id + equipment_form.assign_date = time.strftime('%Y-%m-%d') + equipment_form.serial_no = 'MT/127/18291015' + equipment_form.expected_mtbf = 2 + equipment_form.effective_date = (datetime.now().date() + timedelta(days=5)).strftime("%Y-%m-%d") + equipment_form.period = 5 + equipment_01 = equipment_form.save() + + # Check that equipment is created or not + self.assertTrue(equipment_01, 'Equipment not created') + + # Check next preventive maintenance date = effective date + period + self.assertEqual(equipment_01.next_action_date, datetime.now().date() + timedelta(days=10), 'Wrong next preventive maintenance date.') + + # Create a maintenance request + maintenance_request_01 = self._create_request(name='Display not working', request_date=datetime.now().date() + timedelta(days=10), equipment_id=equipment_01, maintenance_type="preventive") + + # check that maintenance_request is created or not + self.assertTrue(maintenance_request_01, 'Maintenance Request not created') + + # Check next preventive maintenance date when there is only one maintenance request created + self.assertEqual(equipment_01.next_action_date, datetime.now().date() + timedelta(days=10), 'Wrong next preventive maintenance calculated when there is maintenance todo') + + # check maintenance request date. + self.assertEqual(maintenance_request_01.request_date, datetime.now().date() + timedelta(days=10), 'maintenance request_date is wrong') + + # Updating maintenance to Done stage and its close date + maintenance_request_01.write({'stage_id': self.stage_repaired_id}) + maintenance_request_01.close_date = datetime.now().date() + timedelta(days=15) + + # Now next preventive maintenance date = close date + period + self.assertEqual(equipment_01.next_action_date, datetime.now().date() + timedelta(days=20), 'Wrong next preventive maintenance calculated when there is maintenance done') + + # Create another request which would be in maintenance todo stage + maintenance_request_02 = self._create_request(name='Display not working', request_date=datetime.now().date() + timedelta(days=25), equipment_id=equipment_01, maintenance_type="preventive") + + # check that maintenance_request is created or not + self.assertTrue(maintenance_request_02, 'Maintenance Request not created') + + # Check next preventive maintenance date + self.assertEqual(equipment_01.next_action_date, datetime.now().date() + timedelta(days=25), 'Wrong next preventive maintenance calculated when there is one maintenance is done and another todo') + + def test_01_mrp_maintenance(self): + """ In order to check MTBF,MTTR,estimated next failure and estimated + latest failure equipment requests. + """ + + # Required for `assign_date` to be visible in the view + with self.debug_mode(): + # Create a new equipment + equipment_form = Form(self.equipment) + equipment_form.name = 'Acer Laptop' + equipment_form.maintenance_team_id = self.maintenance_team_id + equipment_form.category_id = self.category_id + equipment_form.technician_user_id = self.technician_user_id + equipment_form.assign_date = time.strftime('%Y-%m-%d') + equipment_form.serial_no = 'MT/127/18291015' + equipment_form.expected_mtbf = 2 + equipment_form.effective_date = '2017-04-13' + equipment_form.period = 5 + equipment_01 = equipment_form.save() + + # Check that equipment is created or not + self.assertTrue(equipment_01, 'Equipment not created') + + # Create maintenance requests + + # Maintenance Request Request Date + # 1) 2017-05-03 + # 2) 2017-05-23 + # 3) 2017-06-11 + + maintenance_request_01 = self._create_request(name='Some keys are not working', request_date=datetime(2017, 5, 3).date(), equipment_id=equipment_01, maintenance_type="corrective") + maintenance_request_02 = self._create_request(name='Touchpad not working', request_date=datetime(2017, 5, 23).date(), equipment_id=equipment_01, maintenance_type="corrective") + maintenance_request_03 = self._create_request(name='Battery drains fast', request_date=datetime(2017, 6, 11).date(), equipment_id=equipment_01, maintenance_type="corrective") + + # check that maintenance_request is created or not + self.assertTrue(maintenance_request_01, 'Maintenance Request not created') + self.assertTrue(maintenance_request_02, 'Maintenance Request not created') + self.assertTrue(maintenance_request_03, 'Maintenance Request not created') + + # Request Request Date Close Date diff_days + # 1) 2017-05-03 2017-05-13 10 + # 2) 2017-05-23 2017-05-28 5 + # 3) 2017-06-11 2017-06-11 0 + + # MTTR = Day used to handle maintenance request / No of request + # 5 = (10+5+0)15 / 3 + + # MTBF = Gap in days of between effective date and last request / No of request + # 19 = (2017-06-11 - 2017-04-13) 59 / 3 + + # estimated next failure = latest failure date + MTBF + # 2017-06-30 00:00:00 = 2017-06-11 + 19 + + # maintenance_request_01 write stage_id and close_date. + maintenance_request_01.write({'stage_id': self.stage_repaired_id}) + maintenance_request_01.close_date = datetime(2017, 5, 3).date() + timedelta(days=10) + self.assertEqual(maintenance_request_01.close_date, datetime(2017, 5, 13).date(), 'Wrong close date on maintenance request.') + + # maintenance_request_02 write stage_id and close_date. + maintenance_request_02.write({'stage_id': self.stage_repaired_id}) + maintenance_request_02.close_date = datetime(2017, 5, 23).date() + timedelta(days=5) + self.assertEqual(maintenance_request_02.close_date, datetime(2017, 5, 28).date(), 'Wrong close date on maintenance request.') + + # maintenance_request_03 write stage_id and close_date. + maintenance_request_03.write({'stage_id': self.stage_repaired_id}) + maintenance_request_03.close_date = maintenance_request_03.request_date + self.assertEqual(maintenance_request_03.close_date, datetime(2017, 6, 11).date(), 'Wrong close date on maintenance request.') + + # Check MTTR = Day used to handle maintenance request / No of request (15 / 3) + self.assertEqual(equipment_01.mttr, 5, 'Maintenance Equipment MTTR(Mean Time To Repair) should be 5 days') + + # Check MTBF = Gap in days of between effective date and last request / No of request + self.assertEqual(equipment_01.mtbf, 19, 'Maintenance Equipment MTBF(Mean Time Between Failure) should be 19 days') + + # Check calculation of latest failure date (should be 11-06-2017) + latest_failure_date = equipment_01.latest_failure_date + self.assertEqual(maintenance_request_03.request_date, datetime(2017, 6, 11).date(), 'Wrong request_date on maintenance request.') + self.assertEqual(latest_failure_date, maintenance_request_03.request_date, 'Wrong latest_failure_date on maintenance request.') + + # Check calculation of estimated next failure (should be 30-06-2017) + # Step-1: latest failure date + MTBF + estimated_next_failure = equipment_01.latest_failure_date + timedelta(days=equipment_01.mtbf) + self.assertEqual(estimated_next_failure, datetime(2017, 6, 30).date(), 'Wrong latest_failure_date on maintenance request.') + + def test_02_mrp_maintenance(self): + + """ In order to check cron job to create preventive request (_cron_generate_requests)""" + """ + EX: + equipment = Acer Laptop + effective_date = 25-04-2018 + period = 5 + + maintenance request + request_date = effective_date + period + 30-04-2018 = 25-04-2018 + 5 days + """ + + # Required for `assign_date` to be visible in the view + with self.debug_mode(): + # Create a new equipment + equipment_form = Form(self.equipment) + equipment_form.name = 'Acer Laptop' + equipment_form.maintenance_team_id = self.maintenance_team_id + equipment_form.category_id = self.category_id + equipment_form.technician_user_id = self.technician_user_id + equipment_form.assign_date = time.strftime('%Y-%m-%d') + equipment_form.serial_no = 'MT/127/18291015' + equipment_form.expected_mtbf = 2 + equipment_form.effective_date = datetime.now().date() + timedelta(days=5) + equipment_form.period = 5 + equipment_01 = equipment_form.save() + + # Check that equipment is created or not + self.assertTrue(equipment_01, 'Equipment not created') + + # Execute cron job. + self.equipment._cron_generate_requests() + + # Get maintenence request. + maintenance_requests = self.env['maintenance.request'].search([('equipment_id', '=', equipment_01.id)]) + + # Check whether request is created or not. + self.assertEqual(len(maintenance_requests), 1, 'Cron job execution failure or request is not created.') + + # check maintenence request request_date + self.assertEqual(maintenance_requests.request_date, equipment_01.next_action_date, "wrong request_date in maintenence request") + + # Check whether Next preventive date is changed after execution of cron job. + self.assertEqual(equipment_01.next_action_date, datetime.now().date() + timedelta(days=10), 'Wrong next preventive maintenance date after cron job execution.') diff --git a/mrp_maintenance/views/maintenance_views.xml b/mrp_maintenance/views/maintenance_views.xml new file mode 100644 index 00000000..28eb251b --- /dev/null +++ b/mrp_maintenance/views/maintenance_views.xml @@ -0,0 +1,95 @@ + + + + maintenance.equipment.view.form.inherit.mrp + maintenance.equipment + + + + + + + + + + + + + + + + + maintenance.request.view.form.inherit.mrp + maintenance.request + + + + + + + + + + +
+
+
+
+
+ + ['|', (not workorder_id and 1 or 0, '=', 1), '|', ('workcenter_id', '=', False), ('workcenter_id.order_ids', 'in', workorder_id)] + +
+
+ + + maintenence.request.view.search.inherit.mrp + maintenance.request + + + + + + + + + + + + +
diff --git a/mrp_maintenance/views/mrp_views.xml b/mrp_maintenance/views/mrp_views.xml new file mode 100644 index 00000000..e611a59a --- /dev/null +++ b/mrp_maintenance/views/mrp_views.xml @@ -0,0 +1,58 @@ + + + + + mrp.workcenter.form.inherit.maintenance + mrp.workcenter + + + + + + + + + + + + + + + + + + + + + mrp.workcenter.view.kanban.inherit.maintenance + mrp.workcenter + + + + + + + + + + + mrp.production.view.form.inherit.maintenance + mrp.production + + + +
+ +
+
+
+
diff --git a/sf_base/views/base_view.xml b/sf_base/views/base_view.xml index 1b51900c..2ddc055e 100644 --- a/sf_base/views/base_view.xml +++ b/sf_base/views/base_view.xml @@ -302,8 +302,6 @@ - - + + + + + equipment.maintenance.standards.form + equipment.maintenance.standards + +
+ + + + + + + + + + + + + +
+
+
+ + + equipment.maintenance.standards.tree + equipment.maintenance.standards + + + + + + + + + + + + + + + + + + equipment.maintenance.standards.search + equipment.maintenance.standards + + + + + + + + + + + + + + + + + + + + 设备维保标准 + ir.actions.act_window + equipment.maintenance.standards + tree,form + + +

+ 点击下方的创建按钮来添加设备维保标准。 +

+
+
+ + + + +
\ No newline at end of file diff --git a/sf_maintenance/views/maintenance_request_views.xml b/sf_maintenance/views/maintenance_request_views.xml new file mode 100644 index 00000000..de631cf6 --- /dev/null +++ b/sf_maintenance/views/maintenance_request_views.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sf_maintenance/views/maintenance_views.xml b/sf_maintenance/views/maintenance_views.xml new file mode 100644 index 00000000..1f3b8b07 --- /dev/null +++ b/sf_maintenance/views/maintenance_views.xml @@ -0,0 +1,156 @@ + + + + + sf.maintenance.equipment.category + maintenance.equipment.category + + + + + + + + + + sf_equipment.form + maintenance.equipment + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +