diff --git a/sf_base/commons/common.py b/sf_base/commons/common.py index 05a2143f..6bf597cc 100644 --- a/sf_base/commons/common.py +++ b/sf_base/commons/common.py @@ -19,3 +19,13 @@ class Common(models.Model): 'TIMESTAMP': str(timestamp), 'checkstr': check_sf_str} return headers + + def get_add_time(self, parse_time): + """ + 把时间增加8小时 + :return: + """ + dt = datetime.datetime.strptime(parse_time, "%Y-%m-%d %H:%M:%S") + d = dt + datetime.timedelta(hours=8) + nTime = d.strftime("%Y-%m-%d %H:%M:%S") + return nTime diff --git a/sf_base/models/tool_base_new.py b/sf_base/models/tool_base_new.py index 474c46f3..8f3eb86f 100644 --- a/sf_base/models/tool_base_new.py +++ b/sf_base/models/tool_base_new.py @@ -1,5 +1,9 @@ # -*- coding: utf-8 -*- +import json +import requests from odoo import fields, models, api +from odoo.exceptions import ValidationError +from odoo.addons.sf_base.commons.common import Common class CuttingToolMaterial(models.Model): @@ -249,3 +253,37 @@ class ToolGroups(models.Model): name = fields.Char('名称') equipment_ids = fields.Many2many('maintenance.equipment', 'ref_maintenance_equipment', string='机台号') remark = fields.Char('备注', size=50) + + # ==========机床刀具组接口========== + def _register_tool_groups(self, obj): + create_url = '/AutoDeviceApi/FeedBackOut' + sf_sync_config = self.env['res.config.settings'].get_values() + token = sf_sync_config['token'] + sf_secret_key = sf_sync_config['sf_secret_key'] + headers = Common.get_headers(obj, token, sf_secret_key) + strurl = sf_sync_config['sf_url'] + create_url + device_id = '' + for equipment_id in obj.equipment_ids: + device_id = '%s,%s' % (device_id, equipment_id.name) + val = { + 'DeviceId': device_id, + 'GroupName': obj.name, + } + kw = json.dumps(val, ensure_ascii=False) + r = requests.post(strurl, json={}, data={'kw': kw, 'token': token}, headers=headers) + ret = r.json() + if r == 200: + return "机床刀具组发送成功" + else: + raise ValidationError("机床刀具组发送失败") + + # def write(self, vals): + # obj = super().write(vals) + # self._register_tool_groups(obj) + # return obj + # + # @api.model_create_multi + # def create(self, vals_list): + # records = super(ToolGroups, self).create(vals_list) + # self._register_tool_groups(records) + # return records diff --git a/sf_base/security/ir.model.access.csv b/sf_base/security/ir.model.access.csv index 978f8ce0..25d384f0 100644 --- a/sf_base/security/ir.model.access.csv +++ b/sf_base/security/ir.model.access.csv @@ -35,6 +35,41 @@ access_sf_feed_per_tooth,sf_feed_per_tooth,model_sf_feed_per_tooth,base.group_us access_sf_ramping_angle,sf_ramping_angle,model_sf_ramping_angle,base.group_user,1,1,1,1 access_sf_cutting_width_depth,sf_cutting_width_depth,model_sf_cutting_width_depth,base.group_user,1,1,1,1 +access_sf_machine_tool,sf_machine_tool,model_sf_machine_tool,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_machine_tool_type,sf_machine_tool_type,model_sf_machine_tool_type,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_machine_brand,sf_machine_brand,model_sf_machine_brand,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_machine_brand_tags,sf_machine_brand_tags,model_sf_machine_brand_tags,base.group_user,1,1,1,1 +access_sf_machine_control_system,sf_machine_control_system,model_sf_machine_control_system,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_processing_order,sf_processing_order,model_sf_processing_order,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_production_process,sf_production_process,model_sf_production_process,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_production_materials,sf_production_materials,model_sf_production_materials,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_materials_model,sf_materials_model,model_sf_materials_model,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_processing_technology,sf_processing_technology,model_sf_processing_technology,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_supplier_sort,sf_supplier_sort,model_sf_supplier_sort,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_production_process_parameter,sf_production_process_parameter,model_sf_production_process_parameter,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_production_process_category,sf_production_process_category,model_sf_production_process_category,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_machine_tool_category,sf_machine_tool_category,model_sf_machine_tool_category,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_cutting_tool_material,sf_cutting_tool_material,model_sf_cutting_tool_material,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_cutting_tool_type,sf_cutting_tool_type,model_sf_cutting_tool_type,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_functional_cutting_tool,sf_functional_cutting_tool,model_sf_functional_cutting_tool,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_functional_cutting_tool_model,sf_functional_cutting_tool_model,model_sf_functional_cutting_tool_model,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_fixture_material,sf_fixture_material,model_sf_fixture_material,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_fixture_materials_basic_parameters,sf_fixture_materials_basic_parameters,model_sf_fixture_materials_basic_parameters,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_multi_mounting_type,sf_multi_mounting_type,model_sf_multi_mounting_type,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_fixture_model,sf_fixture_model,model_sf_fixture_model,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_functional_fixture_type,sf_functional_fixture_type,model_sf_functional_fixture_type,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_functional_fixture,sf_functional_fixture,model_sf_functional_fixture,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_sync_common,sf_sync_common,model_sf_sync_common,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_international_standards,sf_international_standards,model_sf_international_standards,sf_base.group_sf_mrp_user,1,0,0,0 +access_material_apply,material_apply,model_material_apply,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_cutting_tool_standard_library,sf_cutting_tool_standard_library,model_sf_cutting_tool_standard_library,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_tool_groups,sf_tool_groups,model_sf_tool_groups,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_tool_materials_basic_parameters,sf_tool_materials_basic_parameters,model_sf_tool_materials_basic_parameters,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_cutting_speed,sf_cutting_speed,model_sf_cutting_speed,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_feed_per_tooth,sf_feed_per_tooth,model_sf_feed_per_tooth,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_ramping_angle,sf_ramping_angle,model_sf_ramping_angle,sf_base.group_sf_mrp_user,1,0,0,0 +access_sf_cutting_width_depth,sf_cutting_width_depth,model_sf_cutting_width_depth,sf_base.group_sf_mrp_user,1,0,0,0 + access_maintenance_equipment_image,maintenance_equipment_image,model_maintenance_equipment_image,base.group_user,1,1,1,1 access_purchase_order_group_purchase,access_purchase_order_group_purchase,purchase.model_purchase_order,sf_base.group_purchase,1,1,1,0 access_purchase_order_group_purchase_director,access_purchase_order_group_purchase_director,purchase.model_purchase_order,sf_base.group_purchase_director,1,1,1,0 diff --git a/sf_dlm/data/product_data.xml b/sf_dlm/data/product_data.xml index 9b562fbb..95d19c39 100644 --- a/sf_dlm/data/product_data.xml +++ b/sf_dlm/data/product_data.xml @@ -1,6 +1,6 @@ - + 坯料 坯料 @@ -35,10 +35,15 @@ 功能刀具 - - 业务平台 - - + + + + + + + + + 功能刀具 diff --git a/sf_machine_connect/views/default_delivery.xml b/sf_machine_connect/views/default_delivery.xml index 62f1fcdc..b0890981 100644 --- a/sf_machine_connect/views/default_delivery.xml +++ b/sf_machine_connect/views/default_delivery.xml @@ -10,6 +10,7 @@ + diff --git a/sf_maintenance/__manifest__.py b/sf_maintenance/__manifest__.py index e5a4f03b..595a5d25 100644 --- a/sf_maintenance/__manifest__.py +++ b/sf_maintenance/__manifest__.py @@ -12,6 +12,7 @@ 'security/ir.model.access.csv', 'security/ir_rule_data.xml', 'views/maintenance_logs_views.xml', + 'views/maintenance_equipment_oee_views.xml', 'views/maintenance_views.xml', 'views/equipment_maintenance_standards_views.xml', 'views/maintenance_request_views.xml', diff --git a/sf_maintenance/models/__init__.py b/sf_maintenance/models/__init__.py index 0e06b132..b177eb3c 100644 --- a/sf_maintenance/models/__init__.py +++ b/sf_maintenance/models/__init__.py @@ -1,5 +1,6 @@ # -*-coding:utf-8-*- from . import sf_maintenance +from . import sf_maintenance_oee from . import sf_maintenance_logs from . import sf_equipment_maintenance_standards from . import sf_maintenance_requests diff --git a/sf_maintenance/models/sf_equipment_maintenance_standards.py b/sf_maintenance/models/sf_equipment_maintenance_standards.py index 92a94c0e..388199da 100644 --- a/sf_maintenance/models/sf_equipment_maintenance_standards.py +++ b/sf_maintenance/models/sf_equipment_maintenance_standards.py @@ -86,7 +86,7 @@ class SfSaintenanceStandards(models.Model): images = fields.One2many('maintenance.standard.image', 'standard_id', string='反馈图片') maintenance_request_ids = fields.Many2many('maintenance.request', string='维保计划') Period = fields.Integer('周期/频次(天)') - remark = fields.Char('备注说明') + remark = fields.Char('维保记录') class MaintenanceStandardImage(models.Model): diff --git a/sf_maintenance/models/sf_maintenance_logs.py b/sf_maintenance/models/sf_maintenance_logs.py index 791f66f8..2dc26f7e 100644 --- a/sf_maintenance/models/sf_maintenance_logs.py +++ b/sf_maintenance/models/sf_maintenance_logs.py @@ -11,6 +11,7 @@ class SfMaintenanceLogs(models.Model): type = fields.Selection([('type1', '类型1'), ('type2', '类型2')], string='类型') brand = fields.Many2one('sf.machine.brand', related='maintenance_equipment_id.brand_id', string='品牌') maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='设备') + maintenance_equipment_oee_id = fields.Many2one('maintenance.equipment.oee', string='设备oee') code_location = fields.Char(string='编码位置') fault_type = fields.Selection( [('电气类', '电气类'), ('机械类', '机械类'), ('程序类', '程序类'), ('系统类', '系统类')], string='故障类型') diff --git a/sf_maintenance/models/sf_maintenance_oee.py b/sf_maintenance/models/sf_maintenance_oee.py new file mode 100644 index 00000000..71802fda --- /dev/null +++ b/sf_maintenance/models/sf_maintenance_oee.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +from odoo import api, fields, models, _ + + +class SfMaintenanceEquipmentOEE(models.Model): + _name = 'maintenance.equipment.oee' + _description = '设备OEE' + + name = fields.Char('设备oee') + equipment_id = fields.Many2one('maintenance.equipment', '设备', + domain="[('category_id.equipment_type', '=', '机床'),('state_zc', '=', '已注册')]") + type_id = fields.Many2one('sf.machine_tool.type', '型号', related='equipment_id.type_id') + machine_tool_picture = fields.Binary('设备图片', related='equipment_id.machine_tool_picture') + state = fields.Selection( + [("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"), ("空闲", "空闲"), + ("封存(报废)", "封存(报废)")], + default='正常', string="机床状态", related='equipment_id.state') + run_time = fields.Float('正常运行总时长(h)') + equipment_time = fields.Float('总时长(h)') + done_nums = fields.Integer('累计加工总件数') + utilization_rate = fields.Char('开动率') + fault_time = fields.Float('故障停机总时长(h)') + fault_nums = fields.Integer('故障次数') + sf_maintenance_logs_ids = fields.One2many('sf.maintenance.logs', 'maintenance_equipment_oee_id', '设备故障日志', + related='equipment_id.sf_maintenance_logs_ids') + + def name_get(self): + result = [] + for parameter in self: + if parameter.equipment_id: + name = parameter.equipment_id.name + result.append((parameter.id, name)) + return result \ No newline at end of file diff --git a/sf_maintenance/security/ir.model.access.csv b/sf_maintenance/security/ir.model.access.csv index 1ff4f5e0..0853ee77 100644 --- a/sf_maintenance/security/ir.model.access.csv +++ b/sf_maintenance/security/ir.model.access.csv @@ -4,6 +4,9 @@ access_sf_maintenance_logs,sf_maintenance_logs,model_sf_maintenance_logs,sf_grou access_sf_maintenance_logs,sf_maintenance_logs,model_sf_maintenance_logs,sf_group_equipment_manager,1,1,1,0 access_maintenance_equipment,maintenance_equipment,model_maintenance_equipment,sf_group_equipment_user,1,0,0,0 access_maintenance_equipment,maintenance_equipment,model_maintenance_equipment,sf_group_equipment_manager,1,1,1,0 +access_maintenance_equipment_oee,maintenance_equipment_oee,model_maintenance_equipment_oee,sf_group_equipment_user,1,0,0,0 +access_maintenance_equipment_oee,maintenance_equipment_oee,model_maintenance_equipment_oee,sf_group_equipment_manager,1,1,1,0 +access_maintenance_equipment_oee,maintenance_equipment_oee,model_maintenance_equipment_oee,base.group_user,1,1,1,1 access_maintenance_standards,maintenance_standards,model_maintenance_standards,sf_group_equipment_user,1,0,0,0 access_maintenance_standards,maintenance_standards,model_maintenance_standards,sf_group_equipment_manager,1,1,1,0 access_maintenance_standard_image,maintenance_standard_image,model_maintenance_standard_image,sf_group_equipment_user,1,0,0,0 diff --git a/sf_maintenance/views/maintenance_equipment_oee_views.xml b/sf_maintenance/views/maintenance_equipment_oee_views.xml new file mode 100644 index 00000000..60055631 --- /dev/null +++ b/sf_maintenance/views/maintenance_equipment_oee_views.xml @@ -0,0 +1,118 @@ + + + + + + maintenance.oee.tree + maintenance.equipment.oee + + + + + + + + + + + + + + + + maintenance.oee.form + maintenance.equipment.oee + +
+
+ +
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + +
+
+
+
+ + + + maintenance.oee.search + maintenance.equipment.oee + + + + + + + + + + + + + + 设备OEE + ir.actions.act_window + maintenance.equipment.oee + + tree,form + + +

+ 设备OEE +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + diff --git a/sf_maintenance/views/maintenance_logs_views.xml b/sf_maintenance/views/maintenance_logs_views.xml index b0d6af79..087f6ffb 100644 --- a/sf_maintenance/views/maintenance_logs_views.xml +++ b/sf_maintenance/views/maintenance_logs_views.xml @@ -8,7 +8,6 @@ - diff --git a/sf_manufacturing/controllers/controllers.py b/sf_manufacturing/controllers/controllers.py index c4fd6b87..42b166b1 100644 --- a/sf_manufacturing/controllers/controllers.py +++ b/sf_manufacturing/controllers/controllers.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import logging import json -import base64 from odoo import http from odoo.http import request @@ -21,9 +20,9 @@ class Manufacturing_Connect(http.Controller): res = {'Succeed': True, 'Datas': []} datas = request.httprequest.data ret = json.loads(datas) - ret = json.loads(ret['result']) logging.info('RfidCode:%s' % ret) - workorder = request.env['mrp.workorder'].sudo().search([('name', '=', ret['RfidCode'])]) + workorder = request.env['mrp.workorder'].sudo().search( + [('production_id.name', '=', 'WH/MO/00071'), ('routing_type', '=', '装夹')]) if workorder: for item in workorder: res['Datas'].append({ @@ -33,10 +32,186 @@ class Manufacturing_Connect(http.Controller): 'Quantity': 1, 'MaterialId': item.product_id.default_code, 'MaterialName': item.product_id.name, - # 'Spec':item.mat, - 'Material': item.materials_type_id.name + 'Spec': '%s×%s×%s' % (item.move_raw_ids.materiel_length, item.move_raw_ids.materiel_width, + item.move_raw_ids.materiel_height), + 'Material': item.product_id.materials_type_id.name }) except Exception as e: res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} logging.info('get_Work_Info error:%s' % e) return json.JSONEncoder().encode(res) + + @http.route('/AutoDeviceApi/GetShiftPlan', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False, + cors="*") + def get_ShiftPlan(self, **kw): + """ + 自动化每天获取机台日计划 + :param kw: + :return: + """ + logging.info('get_ShiftPlan:%s' % kw) + try: + res = {'Succeed': True, 'Datas': []} + datas = request.httprequest.data + ret = json.loads(datas) + ret = json.loads(ret['result']) + logging.info('RfidCode:%s' % ret) + workorder = request.env['mrp.workorder'].sudo().search([('name', '=', ret['ProductionLine'])]) + if workorder: + for item in workorder: + date_planned_start = '' + date_planned_finished = '' + if item.date_planned_start is not False: + planned_start = item.date_planned_start.strftime("%Y-%m-%d %H:%M:%S") + date_planned_start = request.env['sf.sync.common'].sudo().get_add_time(planned_start) + if item.date_planned_finished is not False: + planned_finished = item.date_planned_finished.strftime("%Y-%m-%d %H:%M:%S") + date_planned_finished = request.env['sf.sync.common'].sudo().get_add_time(planned_finished) + res['Datas'].append({ + 'BillId': item.production_id.name, + 'RfidCode': item.RfidCode, + 'CraftName': item.name, + 'Quantity': 1, + 'WortkStart': date_planned_start, + 'WorkEnd': date_planned_finished, + 'MaterialId': item.product_id.default_code, + 'MaterialName': item.product_id.name, + # 'Spec':item.mat, + 'Material': item.materials_type_id.name + }) + except Exception as e: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} + logging.info('get_ShiftPlan error:%s' % e) + return json.JSONEncoder().encode(res) + + @http.route('/AutoDeviceApi/QcCheck', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False, + cors="*") + def get_qcCheck(self, **kw): + """ + 工件预调(前置三元检测) + 1、前置三元检测在产线外:三元检测设备把测量信息上传给MES, + MES生成检测定位数据。中控系统传递RFID编号给MES获取测量偏置结果。(来源为三元检测工单上的字段) + :param kw: + :return: + """ + logging.info('get_qcCheck:%s' % kw) + try: + res = {'Succeed': True, 'Datas': []} + datas = request.httprequest.data + ret = json.loads(datas) + ret = json.loads(ret['result']) + logging.info('RfidCode:%s' % ret) + workorder = request.env['mrp.workorder'].sudo().search([('routing_type', '=', '前置三元定位检测')]) + if workorder: + for item in workorder: + res['Datas'].append({ + 'XOffset': item.production_id.name, + 'YOffset': item.RfidCode, + 'ZOffet': item.name, + 'COffset': 1 + }) + except Exception as e: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} + logging.info('get_qcCheck error:%s' % e) + return json.JSONEncoder().encode(res) + + @http.route('/AutoDeviceApi/FeedBackStart', type='json', auth='none', methods=['GET', 'POST'], csrf=False, + cors="*") + def button_Work_START(self, **kw): + """ + 工单任务开始 + :param kw: + :return: + """ + logging.info('button_Work_START:%s' % kw) + try: + res = {'Succeed': True, 'Datas': []} + datas = request.httprequest.data + ret = json.loads(datas) + if not ret['BillId']: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传制造订单号'} + return json.JSONEncoder().encode(res) + if not ret['CraftId']: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传工序名称'} + return json.JSONEncoder().encode(res) + if not ret['DeviceId']: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传设备号'} + return json.JSONEncoder().encode(res) + production_id = ret['BillId'] + routing_type = ret['CraftId'] + workorder = request.env['mrp.workorder'].sudo().search( + [('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1) + workorder.button_start() + except Exception as e: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} + logging.info('button_Work_START error:%s' % e) + return json.JSONEncoder().encode(res) + + @http.route('/AutoDeviceApi/FeedBackEnd', type='json', auth='none', methods=['GET', 'POST'], csrf=False, + cors="*") + def button_Work_End(self, **kw): + """ + 工单任务结束 + :param kw: + :return: + """ + logging.info('button_Work_End:%s' % kw) + try: + res = {'Succeed': True, 'Datas': []} + datas = request.httprequest.data + ret = json.loads(datas) + if not ret['BillId']: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传制造订单号'} + return json.JSONEncoder().encode(res) + if not ret['CraftId']: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传工序名称'} + return json.JSONEncoder().encode(res) + if not ret['DeviceId']: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传设备号'} + return json.JSONEncoder().encode(res) + production_id = ret['BillId'] + routing_type = ret['CraftId'] + workorder = request.env['mrp.workorder'].sudo().search( + [('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1) + workorder.button_finish() + except Exception as e: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} + logging.info('button_Work_End error:%s' % e) + return json.JSONEncoder().encode(res) + + @http.route('/AutoDeviceApi/QcCheck', type='json', auth='none', methods=['GET', 'POST'], csrf=False, + cors="*") + def Workorder_QcCheck(self, **kw): + """ + 零件质检 + :param kw: + :return: + """ + logging.info('Workorder_QcCheck:%s' % kw) + try: + res = {'Succeed': True, 'Datas': []} + datas = request.httprequest.data + ret = json.loads(datas) + if not ret['BillId']: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传制造订单号'} + return json.JSONEncoder().encode(res) + if not ret['CraftId']: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传工序名称'} + return json.JSONEncoder().encode(res) + if not ret['DeviceId']: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传设备号'} + return json.JSONEncoder().encode(res) + if not ret['Quality']: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传检测结果'} + return json.JSONEncoder().encode(res) + if not ret['ReportPaht']: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传检查报告文件(地址)'} + return json.JSONEncoder().encode(res) + production_id = ret['BillId'] + routing_type = ret['CraftId'] + request.env['mrp.workorder'].sudo().search( + [('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1) + except Exception as e: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} + logging.info('Workorder_QcCheck error:%s' % e) + return json.JSONEncoder().encode(res) diff --git a/sf_manufacturing/data/stock_data.xml b/sf_manufacturing/data/stock_data.xml index 74d02b4a..6bd0fe53 100644 --- a/sf_manufacturing/data/stock_data.xml +++ b/sf_manufacturing/data/stock_data.xml @@ -1,6 +1,13 @@ + + 工序编码规则 + mrp.routing.workcenter + 4 + + + YourCompany Sequence ocout WH/OCOUT/ diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index cb326ee8..8eb17dfd 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -450,10 +450,10 @@ class MrpProduction(models.Model): for route in routingworkcenter: - if route.routing_type == '后置三元质量检测': - workorders_values.append( - self.env['mrp.workorder'].json_workorder_str1(k, production, route) - ) + # if route.routing_type == '后置三元质量检测': + # workorders_values.append( + # self.env['mrp.workorder'].json_workorder_str1(k, production, route) + # ) if route.routing_type == 'CNC加工': workorders_values.append( self.env['mrp.workorder'].json_workorder_str1(k, production, route)) diff --git a/sf_manufacturing/models/mrp_routing_workcenter.py b/sf_manufacturing/models/mrp_routing_workcenter.py index c8e7d8aa..8bb9733b 100644 --- a/sf_manufacturing/models/mrp_routing_workcenter.py +++ b/sf_manufacturing/models/mrp_routing_workcenter.py @@ -1,5 +1,6 @@ import logging -from odoo import fields, models +from odoo import fields, models, api +from odoo.exceptions import UserError class ResMrpRoutingWorkcenter(models.Model): @@ -10,7 +11,7 @@ class ResMrpRoutingWorkcenter(models.Model): ('装夹预调', '装夹预调'), # ('前置三元定位检测', '前置三元定位检测'), ('CNC加工', 'CNC加工'), - ('后置三元质量检测', '后置三元质量检测'), + # ('后置三元质量检测', '后置三元质量检测'), ('解除装夹', '解除装夹'), ('切割', '切割'), ('表面工艺', '表面工艺') @@ -21,13 +22,17 @@ class ResMrpRoutingWorkcenter(models.Model): bom_id = fields.Many2one('mrp.bom', required=False) surface_technics_id = fields.Many2one('sf.production.process', string="表面工艺") + def generate_code(self): + return self.env['ir.sequence'].next_by_code('mrp.routing.workcenter') + + code = fields.Char('编码', default=generate_code) + # 获得当前登陆者公司 def get_company_id(self): self.company_id = self.env.user.company_id.id company_id = fields.Many2one('res.company', compute="get_company_id", related=False) - # 排产的时候, 根据坯料的长宽高比对一下机床的最大加工尺寸.不符合就不要分配给这个加工中心(机床). # 工单对应的工作中心,根据工序中的工作中心去匹配, # 如果只配置了一个工作中心,则默认采用该工作中心; diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index feb37787..eabdff95 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -35,7 +35,7 @@ class ResMrpWorkOrder(models.Model): ('装夹预调', '装夹预调'), # ('前置三元定位检测', '前置三元定位检测'), ('CNC加工', 'CNC加工'), - ('后置三元质量检测', '后置三元质量检测'), + # ('后置三元质量检测', '后置三元质量检测'), ('解除装夹', '解除装夹'), ('切割', '切割'), ('表面工艺', '表面工艺') ], string="工序类型") @@ -216,9 +216,9 @@ class ResMrpWorkOrder(models.Model): elif route.routing_type == 'CNC加工': duration_expected = self.env['mrp.routing.workcenter'].sudo().search( [('name', '=', 'CNC加工')]).time_cycle - elif route.routing_type == '后置三元质量检测': - duration_expected = self.env['mrp.routing.workcenter'].sudo().search( - [('name', '=', '后置三元质量检测')]).time_cycle + # elif route.routing_type == '后置三元质量检测': + # duration_expected = self.env['mrp.routing.workcenter'].sudo().search( + # [('name', '=', '后置三元质量检测')]).time_cycle elif route.routing_type == '解除装夹': duration_expected = self.env['mrp.routing.workcenter'].sudo().search( [('name', '=', '解除装夹')]).time_cycle @@ -232,7 +232,7 @@ class ResMrpWorkOrder(models.Model): 'processing_panel': k, 'quality_point_ids': route.route_workcenter_id.quality_point_ids, 'routing_type': route.routing_type, - 'work_state': '' if not route.routing_type == '获取CNC加工程序' else '待发起', + 'work_state': '待发起', 'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids, route.routing_type, production.product_id), @@ -597,6 +597,7 @@ class CNCprocessing(models.Model): cnc_id = fields.Many2one('ir.attachment') sequence_number = fields.Char('序号') program_name = fields.Char('程序名') + functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型') cutting_tool_name = fields.Char('刀具名称') cutting_tool_no = fields.Char('刀号') processing_type = fields.Char('加工类型') diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py index 42a392e2..b9209d57 100644 --- a/sf_manufacturing/models/product_template.py +++ b/sf_manufacturing/models/product_template.py @@ -870,6 +870,11 @@ class SfMaintenanceEquipmentTool(models.Model): _description = '机床刀位' equipment_id = fields.Many2one('maintenance.equipment', string='设备') + + code = fields.Char('机床刀位号') + name = fields.Char('刀位号', compute='_compute_name') + + # 待删除字段 product_template_id = fields.Many2one('product.template', string='功能刀具名称', domain="[('categ_type', '=', '刀具')]") image_1920 = fields.Binary('图片', related='product_template_id.image_1920') @@ -882,9 +887,6 @@ class SfMaintenanceEquipmentTool(models.Model): life_value_max = fields.Char('最大寿命值') alarm_value = fields.Char('报警值') used_value = fields.Char('已使用值') - code = fields.Char('机床刀位号') - - name = fields.Char('', compute='_compute_name') @api.depends('code') def _compute_name(self): diff --git a/sf_manufacturing/views/mrp_routing_workcenter_view.xml b/sf_manufacturing/views/mrp_routing_workcenter_view.xml index d0db3a7b..5ab745db 100644 --- a/sf_manufacturing/views/mrp_routing_workcenter_view.xml +++ b/sf_manufacturing/views/mrp_routing_workcenter_view.xml @@ -6,6 +6,9 @@ mrp.routing.workcenter + + + + + + + + + + + +
+
+
+
@@ -423,20 +438,6 @@ - - - - - - - -
-
-
-
diff --git a/sf_manufacturing/views/sf_maintenance_equipment.xml b/sf_manufacturing/views/sf_maintenance_equipment.xml index a2d9437d..b398f994 100644 --- a/sf_manufacturing/views/sf_maintenance_equipment.xml +++ b/sf_manufacturing/views/sf_maintenance_equipment.xml @@ -1,7 +1,7 @@ - + 设备增加刀具库位table sf_manufacturing_equipment.form maintenance.equipment @@ -13,17 +13,6 @@ - - - - - - - - - - - diff --git a/sf_quality/models/__init__.py b/sf_quality/models/__init__.py index 79a87b7d..71468786 100644 --- a/sf_quality/models/__init__.py +++ b/sf_quality/models/__init__.py @@ -2,3 +2,4 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from . import custom_quality +from . import quality diff --git a/sf_quality/models/quality.py b/sf_quality/models/quality.py new file mode 100644 index 00000000..ace40ff9 --- /dev/null +++ b/sf_quality/models/quality.py @@ -0,0 +1,34 @@ +import json +import requests +from odoo import fields, models, api +from odoo.exceptions import ValidationError +from odoo.addons.sf_base.commons.common import Common + + +class QualityCheck(models.Model): + _inherit = "quality.check" + _description = '零件特采' + + # ==========零件特采接口========== + def _register_tool_groups(self): + create_url = '/AutoDeviceApi/FeedBackOut' + sf_sync_config = self.env['res.config.settings'].get_values() + token = sf_sync_config['token'] + sf_secret_key = sf_sync_config['sf_secret_key'] + headers = Common.get_headers(self, token, sf_secret_key) + strurl = sf_sync_config['sf_url'] + create_url + val = { + 'RfidCode': None, + } + kw = json.dumps(val, ensure_ascii=False) + r = requests.post(strurl, json={}, data={'kw': kw, 'token': token}, headers=headers) + ret = r.json() + if r == 200: + return "零件特采发送成功" + else: + raise ValidationError("零件特采发送失败") + + # @api.onchange('quality_state') + # def _onchange_quality_state(self): + # if self.quality_state in ['pass', 'fail']: + # self._register_tool_groups() diff --git a/sf_sale/models/sale_order.py b/sf_sale/models/sale_order.py index 6cbd1fd7..96103530 100644 --- a/sf_sale/models/sale_order.py +++ b/sf_sale/models/sale_order.py @@ -8,6 +8,18 @@ class ReSaleOrder(models.Model): _inherit = 'sale.order' logistics_way = fields.Selection([('自提', '自提'), ('到付', '到付'), ('在线支付', '在线支付')], string='物流方式') + state = fields.Selection( + selection=[ + ('draft', "报价"), + ('sent', "报价已发送"), + ('sale', "销售订单"), + ('done', "已锁定"), + ('cancel', '已废弃'), + ], + string="状态", + readonly=True, copy=False, index=True, + tracking=3, + default='draft') deadline_of_delivery = fields.Date('订单交期', tracking=True) person_of_delivery = fields.Char('交货人') telephone_of_delivery = fields.Char('交货人电话号码') @@ -38,7 +50,8 @@ class ReSaleOrder(models.Model): 'name': self.env['ir.sequence'].next_by_code('sale.order', sequence_date=now_time), 'partner_id': partner.id, 'check_status': 'approved', - 'state': 'draft', + 'state': 'sale', + 'user_id': partner.user_id.id, 'person_of_delivery': delivery_name, 'telephone_of_delivery': delivery_telephone, 'address_of_delivery': delivery_address, @@ -60,11 +73,12 @@ class ReSaleOrder(models.Model): self.check_status = 'pending' def get_customer(self): - customer = self.env['res.partner'].search([('name', '=', '业务平台')]) + customer = self.env['res.partner'].search([('name', '=', '业务平台')], limit=1, order='id asc') if customer: return customer else: partner = self.env['res.partner'].create({'name': '业务平台'}) + self.env['res.users'].create({'name': '业务平台', 'partner_id': partner.id}) return partner # 业务平台分配工厂时在创建完产品后再创建销售明细信息 @@ -80,7 +94,7 @@ class ReSaleOrder(models.Model): 'product_uom_qty': item['number'], 'model_glb_file': base64.b64decode(item['model_file']), } - return self.env['sale.order.line'].create(vals) + return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals) @api.constrains('order_line') def check_order_line(self): @@ -114,10 +128,22 @@ class RePurchaseOrder(models.Model): check_status = fields.Selection([('pending', '待审核'), ('approved', '已审核'), ('fail', '不通过')], '审核状态') remark = fields.Text('备注') + user_id = fields.Many2one( + 'res.users', string='买家', index=True, tracking=True, + compute='_compute_user_id', + store=True) def button_confirming(self): self.write({'state': 'purchase', 'check_status': 'pending'}) + @api.depends('partner_id') + def _compute_user_id(self): + if not self.user_id: + if self.partner_id: + self.user_id = self.partner_id.purchase_user_id.id + else: + self.user_id = self.env.user.id + @api.constrains('order_line') def check_order_line(self): for item in self: diff --git a/sf_sale/security/ir.model.access.csv b/sf_sale/security/ir.model.access.csv index 7e893864..25b2dce0 100644 --- a/sf_sale/security/ir.model.access.csv +++ b/sf_sale/security/ir.model.access.csv @@ -12,7 +12,7 @@ access_product_product_group_sale_salemanager,product_product_group_sale_saleman access_product_product_group_sale_director,product_product_group_sale_director,product.model_product_product,sf_base.group_sale_director,1,1,1,0 access_product_product_group_purchase,product_product_group_purchase,product.model_product_product,sf_base.group_purchase,1,0,0,0 access_product_product_group_purchase_director,product_product_group_purchase_director,product.model_product_product,sf_base.group_purchase_director,1,1,1,0 -access_product_template_group_sale_salemanager,product_product_group_sale_salemanager,product.model_product_template,sf_base.group_sale_salemanager,1,0,0,0 +access_product_template_group_sale_salemanager,product_template_group_sale_salemanager,product.model_product_template,sf_base.group_sale_salemanager,1,0,0,0 access_product_template_group_sale_director,product_template_group_sale_director,product.model_product_template,sf_base.group_sale_director,1,1,1,0 access_product_template_group_purchase,product_template_group_purchase,product.model_product_template,sf_base.group_purchase,1,0,0,0 access_product_template_group_purchase_director,product_template_group_purchase_director,product.model_product_template,sf_base.group_purchase_director,1,1,1,0 @@ -20,8 +20,8 @@ access_product_template_group_plan_dispatch,product_template_group_plan_dispatch access_product_template_group_plan_director,product_template_group_plan_director,product.model_product_template,sf_base.group_plan_director,1,1,1,0 access_stock_picking_group_sale_salemanager,stock_picking_group_sale_salemanager,stock.model_stock_picking,sf_base.group_sale_salemanager,1,0,0,0 access_stock_picking_group_sale_director,stock_picking_group_sale_director,stock.model_stock_picking,sf_base.group_sale_director,1,0,0,0 -access_stock_picking_group_purchase,stock_picking_group_purchase,stock.model_stock_picking,sf_base.group_purchase,1,0,0,0 -access_stock_picking_group_purchase_director,stock_picking_group_purchase_director,stock.model_stock_picking,sf_base.group_purchase_director,1,0,0,0 +access_stock_picking_group_purchase,stock_picking_group_purchase,stock.model_stock_picking,sf_base.group_purchase,1,1,1,0 +access_stock_picking_group_purchase_director,stock_picking_group_purchase_director,stock.model_stock_picking,sf_base.group_purchase_director,1,1,1,0 access_account_move_group_sale_salemanager,account_move_group_sale_salemanager,account.model_account_move,sf_base.group_sale_salemanager,1,0,0,0 access_account_move_group_sale_director,account_move_group_sale_director,account.model_account_move,sf_base.group_sale_director,1,0,0,0 access_resource_resource_group_sale_director,resource_resource_group_sale_director,resource.model_resource_resource,sf_base.group_sale_director,1,1,1,0 @@ -33,8 +33,8 @@ access_mrp_bom_group_quality,mrp_bom_group_quality,mrp.model_mrp_bom,sf_base.gro access_mrp_bom_group_quality_director,mrp_bom_group_quality_director,mrp.model_mrp_bom,sf_base.group_quality_director,1,0,0,0 access_stock_move_group_sale_salemanager,stock_move_group_sale_salemanager,stock.model_stock_move,sf_base.group_sale_salemanager,1,0,0,0 access_stock_move_group_sale_director,stock_move_group_sale_director,stock.model_stock_move,sf_base.group_sale_director,1,0,0,0 -access_stock_move_group_purchase,stock_move_group_purchase,stock.model_stock_move,sf_base.group_purchase,1,0,0,0 -access_stock_move_group_purchase_director,stock_move_group_purchase_director,stock.model_stock_move,sf_base.group_purchase_director,1,0,0,0 +access_stock_move_group_purchase,stock_move_group_purchase,stock.model_stock_move,sf_base.group_purchase,1,1,1,0 +access_stock_move_group_purchase_director,stock_move_group_purchase_director,stock.model_stock_move,sf_base.group_purchase_director,1,1,1,0 access_stock_warehouse_orderpoint_group_sale_salemanager,stock_warehouse_orderpoint_group_sale_salemanager,stock.model_stock_warehouse_orderpoint,sf_base.group_sale_salemanager,1,0,0,0 access_stock_warehouse_orderpoint_group_sale_director,stock_warehouse_orderpoint_group_sale_director,stock.model_stock_warehouse_orderpoint,sf_base.group_sale_director,1,0,0,0 access_stock_warehouse_orderpoint_group_purchase,stock_warehouse_orderpoint_group_purchase,stock.model_stock_warehouse_orderpoint,sf_base.group_purchase,1,1,0,0 diff --git a/sf_sale/views/purchase_order_view.xml b/sf_sale/views/purchase_order_view.xml index b22bb584..423742b8 100644 --- a/sf_sale/views/purchase_order_view.xml +++ b/sf_sale/views/purchase_order_view.xml @@ -11,14 +11,14 @@
- +