From e1a47840921b1040dd58ed858ead01d7173835a5 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Mon, 26 Aug 2024 17:20:46 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=AE=BE=E5=A4=87oee?= =?UTF-8?q?=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 108 ++++++++++++++++++ sf_manufacturing/models/mrp_workcenter.py | 1 + sf_manufacturing/models/mrp_workorder.py | 4 +- 3 files changed, 111 insertions(+), 2 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index 94c0fdcb..fc0347c3 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -764,3 +764,111 @@ class Sf_Dashboard_Connect(http.Controller): finally: cur.close() conn.close() + + # 设备oee + @http.route('/api/OEE', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") + def OEE(self, **kw): + """ + 获取产线等oee + """ + res = {'status': 1, 'message': '成功', 'data': {}} + logging.info('前端请求oee数据的参数为:%s' % kw) + + try: + count_oee = 1 + workcenter_obj = request.env['mrp.workcenter'].sudo() + workcenter_list = ast.literal_eval(kw['workcenter_list']) + print('workcenter_list: %s' % workcenter_list) + for line in workcenter_list: + res['data'][line] = workcenter_obj.search([('name', '=', line)]).oee + count_oee *= workcenter_obj.search([('name', '=', line)]).oee + res['data']['综合oee'] = count_oee / 1000000 + except Exception as e: + print(f"An error occurred: {e}") + + return json.dumps(res) + + # # 查询某段时间的设备oee + # @http.route('/api/OEEByTime', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") + # def OEEByTime(self, **kw): + # """ + # 获取某段时间的oee + # """ + # res = {'status': 1, 'message': '成功', 'data': {}} + # logging.info('前端请求获取某段时间的oee的参数为:%s' % kw) + # workcenter_list = ast.literal_eval(kw['workcenter_list']) + # begin_time_str = kw['begin_time'].strip('"') + # end_time_str = kw['end_time'].strip('"') + # begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S') + # end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S') + # print('workcenter_list: %s' % workcenter_list) + # # 连接数据库 + # conn = psycopg2.connect(**db_config) + # cur = conn.cursor() + # # 查询并计算OEE平均值 + # oee_data = {} + # for workcenter in workcenter_list: + # cur.execute(""" + # SELECT AVG(oee) as avg_oee + # FROM oee_data + # WHERE workcenter_name = %s + # AND time BETWEEN %s AND %s + # """, (workcenter, begin_time, end_time)) + # + # result = cur.fetchone() + # avg_oee = result[0] if result else 0.0 + # oee_data[workcenter] = avg_oee + # + # # 返回数据 + # res['data'] = oee_data + # return json.dumps(res) + + @http.route('/api/OEEByTime', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") + def OEEByTime(self, **kw): + """ + 获取某段时间的oee,根据用户指定的时间单位(day或hour)返回对应的平均值 + """ + res = {'status': 1, 'message': '成功', 'data': {}} + logging.info('前端请求获取某段时间的oee的参数为:%s' % kw) + + # 获取并解析参数 + workcenter_list = ast.literal_eval(kw['workcenter_list']) + begin_time_str = kw['begin_time'].strip('"') + end_time_str = kw['end_time'].strip('"') + time_unit = kw.get('time_unit', 'day') # 默认单位为天 + begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S') + end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S') + + # 连接数据库 + conn = psycopg2.connect(**db_config) + cur = conn.cursor() + + # 根据时间单位选择不同的时间格式 + if time_unit == 'hour': + time_format = 'YYYY-MM-DD HH24:00:00' + else: # 默认为'day' + time_format = 'YYYY-MM-DD' + + # 查询并计算OEE平均值 + oee_data = {} + for workcenter in workcenter_list: + cur.execute(f""" + SELECT to_char(time, '{time_format}') as time_unit, AVG(oee) as avg_oee + FROM oee_data + WHERE workcenter_name = %s + AND time BETWEEN %s AND %s + GROUP BY time_unit + ORDER BY time_unit + """, (workcenter, begin_time, end_time)) + + results = cur.fetchall() + oee_data[workcenter] = {row[0]: row[1] for row in results} + + # 关闭数据库连接 + cur.close() + conn.close() + + # 返回数据 + res['data'] = oee_data + return json.dumps(res) + diff --git a/sf_manufacturing/models/mrp_workcenter.py b/sf_manufacturing/models/mrp_workcenter.py index 461ef6ad..03597980 100644 --- a/sf_manufacturing/models/mrp_workcenter.py +++ b/sf_manufacturing/models/mrp_workcenter.py @@ -41,6 +41,7 @@ class ResWorkcenter(models.Model): oee_target = fields.Float( string='OEE Target', help="Overall Effective Efficiency Target in percentage", default=90, tracking=True) + oee = fields.Float(compute='_compute_oee', help='Overall Equipment Effectiveness, based on the last month', store=True) time_start = fields.Float('Setup Time', tracking=True) time_stop = fields.Float('Cleanup Time', tracking=True) diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 095c1ab1..10c733d9 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -1154,10 +1154,10 @@ class ResMrpWorkOrder(models.Model): def button_finish(self): for record in self: if record.routing_type == '装夹预调': - if not record.material_center_point or record.X_deviation_angle <= 0: - raise UserError("请对前置三元检测定位参数进行计算定位") if not record.rfid_code and record.is_rework is False: raise UserError("请扫RFID码进行绑定") + if not record.material_center_point or record.X_deviation_angle <= 0: + raise UserError("请对前置三元检测定位参数进行计算定位") record.process_state = '待加工' # record.write({'process_state': '待加工'}) record.production_id.process_state = '待加工' From 937ea42af35a7db6d5571c72b3444ea9a4489870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Tue, 27 Aug 2024 08:54:33 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=BA=E5=B7=A5?= =?UTF-8?q?=E6=8A=A5=E4=BB=B7=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_production.py | 7 ++++++- sf_manufacturing/models/mrp_workorder.py | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 8e1f7199..7da6cbbb 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -123,7 +123,12 @@ class MrpProduction(models.Model): # 上传零件图纸 part_drawing = fields.Binary('零件图纸') - manual_quotation = fields.Boolean('人工编程', default=False, readonly=True) + @api.depends('product_id.manual_quotation') + def _compute_manual_quotation(self): + for item in self: + item.manual_quotation = item.product_id.manual_quotation + + manual_quotation = fields.Boolean('人工编程', default=False, compute=_compute_manual_quotation) is_scrap = fields.Boolean('是否报废', default=False) is_remanufacture = fields.Boolean('是否重新制造', default=False) diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index e19887ac..2cfaaccd 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -60,7 +60,12 @@ class ResMrpWorkOrder(models.Model): default='pending', copy=False, readonly=True, recursive=True, index=True, tracking=True) # state = fields.Selection(selection_add=[('to be detected', "待检测"), ('rework', '返工')], tracking=True) - manual_quotation = fields.Boolean('人工编程', default=False, readonly=True) + @api.depends('production_id.manual_quotation') + def _compute_manual_quotation(self): + for item in self: + item.manual_quotation = item.production_id.manual_quotation + + manual_quotation = fields.Boolean('人工编程', default=False, compute=_compute_manual_quotation) def _compute_working_users(self): super()._compute_working_users() From 26ad5b5b3f70a43c173f9eff0ee05f3155c99299 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Tue, 27 Aug 2024 08:55:01 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E6=8E=A5=E5=8F=A3=E3=80=81=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=AC=A1=E6=95=B0=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 165 ++++++------------ 1 file changed, 54 insertions(+), 111 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index fc0347c3..96708dd8 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -173,49 +173,6 @@ class Sf_Dashboard_Connect(http.Controller): res['message'] = '前端请求机床数据失败,原因:%s' % e return json.JSONEncoder().encode(res) - # @http.route('/api/logs/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False, - # cors="*") - # def logs_list(self, **kw): - # """ - # 拿到日志数据返回给大屏展示 - # :param kw: - # :return: - # """ - # res = {'status': 1, 'message': '成功', 'data': []} - # logging.info('前端请求日志数据的参数为:%s' % kw) - # - # try: - # # 获取请求的日志数据 - # logs_obj = request.env['maintenance.equipment.oee.log.detail'].sudo() - # # 获取请求的机床数据 - # machine_list = ast.literal_eval(kw['machine_list']) - # begin_time_str = kw['begin_time'].strip('"') - # end_time_str = kw['end_time'].strip('"') - # - # begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S') - # end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S') - # - # print('begin_time: %s' % begin_time) - # for item in machine_list: - # log_datas = logs_obj.search( - # [('equipment_code', '=', item), ('time', '>=', begin_time), ('time', '<=', end_time)]) - # print('log_datas: %s' % log_datas) - # for log_data in log_datas: - # res['data'].append({ - # 'equipment_code': log_data.equipment_code, - # 'time': log_data.time.strftime('%Y-%m-%d %H:%M:%S'), - # 'state': log_data.state - # - # }) - # - # return json.JSONEncoder().encode(res) - # - # except Exception as e: - # logging.info('前端请求日志数据失败,原因:%s' % e) - # res['status'] = -1 - # res['message'] = '前端请求日志数据失败,原因:%s' % e - # return json.JSONEncoder().encode(res) - @http.route('/api/logs/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") def logs_list(self, **kw): """ @@ -227,9 +184,9 @@ class Sf_Dashboard_Connect(http.Controller): logging.info('前端请求日志数据的参数为:%s' % kw) try: - # 获取请求的日志数据 - logs_obj = request.env['maintenance.equipment.oee.log.detail'].sudo() - # 获取请求的机床数据 + # 连接数据库 + conn = psycopg2.connect(**db_config) + cur = conn.cursor() machine_list = ast.literal_eval(kw['machine_list']) begin_time_str = kw['begin_time'].strip('"') end_time_str = kw['end_time'].strip('"') @@ -240,19 +197,25 @@ class Sf_Dashboard_Connect(http.Controller): print('begin_time: %s' % begin_time) for item in machine_list: - log_datas = logs_obj.search( - [('equipment_code', '=', item), ('time', '>=', begin_time), ('time', '<=', end_time)]) - print('log_datas: %s' % log_datas) + sql = ''' + SELECT time, device_state, program_name + FROM device_data + WHERE device_name = %s AND time >= %s AND time <= %s + ORDER BY time ASC; + ''' + # 执行SQL命令,使用参数绑定 + cur.execute(sql, (item, begin_time, end_time)) + results = cur.fetchall() # 将数据按照 equipment_code 进行分组 if item not in res['data']: res['data'][item] = [] - for log_data in log_datas: + for result in results: res['data'][item].append({ - 'time': log_data.time.strftime('%Y-%m-%d %H:%M:%S'), - 'state': log_data.state, - 'production_name': log_data.production_name, + 'time': result[0].strftime('%Y-%m-%d %H:%M:%S'), + 'state': result[1], + 'production_name': result[2], }) return json.dumps(res) # 注意使用 json.dumps 而不是直接用 json.JSONEncoder().encode() @@ -624,7 +587,7 @@ class Sf_Dashboard_Connect(http.Controller): # 查询pg库来获得待机次数 @http.route('/api/IdleAlarmCount', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") - def idle_count(self, **kw): + def idle_alarm_count(self, **kw): """ 查询设备的待机次数 """ @@ -637,69 +600,50 @@ class Sf_Dashboard_Connect(http.Controller): try: # 获取请求的机床数据 machine_list = ast.literal_eval(kw['machine_list']) - idle_times = [] - idle_dict = {} - + total_alarm_time = 0 + alarm_count_num = 0 for item in machine_list: sql = ''' - SELECT idle_start_time,alarm_time,alarm_repair_time FROM device_data WHERE device_name = %s; + SELECT COUNT(*) + FROM ( + SELECT DISTINCT ON (idle_start_time) idle_start_time + FROM device_data + WHERE device_name = %s AND idle_start_time IS NOT NULL + ORDER BY idle_start_time, time + ) subquery; + ''' + + sql2 = ''' + SELECT DISTINCT ON (alarm_time) alarm_time, alarm_repair_time + FROM device_data + WHERE device_name = %s AND alarm_time IS NOT NULL + ORDER BY alarm_time, time; + ''' # 执行SQL命令 cur.execute(sql, (item,)) result = cur.fetchall() - # # print('result', result) - # - # # 将查询结果添加到idle_times列表中 - # idle_times = [row[0] for row in result if row[0] is not None] - # - # # 对结果去重 - # unique_idle_times = set(idle_times) - # # print('unique_idle_times', unique_idle_times) - # - # # 统计去重后的数量 - # idle_count = len(unique_idle_times) - # # idle_dict[item] = idle_count - # - # res['data'][item] = idle_count - - total_alarm_time = 0 - alarm_count = 0 - alarm_time_list = [] - idle_times = [] - alarm_times = [] + print('result========', result) + cur.execute(sql2, (item,)) + result2 = cur.fetchall() + print('result2========', result2) + # for row in result: - idle_start_time = row[0] - alarm_time = row[1] - alarm_repair_time = row[2] - - alarm_time_list.append(alarm_time) # 将时长累加,以秒为单位 - idle_times.append(idle_start_time) - # if alarm_repair_time is not None: - # alarm_times.append(alarm_repair_time) - alarm_times.append(alarm_repair_time) - - # 对结果去重 - unique_total_alarm_time = set(alarm_time_list) - unique_idle_times = set(idle_times) - unique_alarm_times = set(alarm_times) - - # 统计去重后的数量 - idle_count = len(unique_idle_times) - - for alarm_time in unique_total_alarm_time: - if alarm_time is not None: - total_alarm_time += abs(float(alarm_time)) - - alarm_count = len(unique_alarm_times) if unique_alarm_times else 0 - alarm_count = alarm_count if total_alarm_time else 0 - - # 存储待机次数和总待机时长(单位:秒) - res['data'][item] = { - 'idle_count': idle_count, - 'total_alarm_time': total_alarm_time / 3600, # 以秒为单位 - 'alarm_count': alarm_count - } + res['data'][item] = {'idle_count': row[0]} + alarm_count = [] + for row in result2: + alarm_count.append(row[0]) + total_alarm_time += abs(float(row[0])) + if len(list(set(alarm_count))) == 1: + if list(set(alarm_count))[0] is None: + alarm_count_num = 0 + else: + alarm_count_num = 1 + else: + alarm_count_num = len(list(set(alarm_count))) + res['data'][item]['total_alarm_time'] = total_alarm_time / 3600 + res['data'][item]['alarm_count_num'] = alarm_count_num # 返回统计结果 return json.dumps(res) @@ -712,7 +656,7 @@ class Sf_Dashboard_Connect(http.Controller): # 查询pg库来获得异常情况 @http.route('/api/alarm/logs', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") - def idle_count(self, **kw): + def alarm_logs(self, **kw): """ 查询设备的异常情况 """ @@ -871,4 +815,3 @@ class Sf_Dashboard_Connect(http.Controller): # 返回数据 res['data'] = oee_data return json.dumps(res) - From b35f444e49998d369724ab1befbeaca7366e3219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Tue, 27 Aug 2024 09:23:18 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=BA=E5=B7=A5?= =?UTF-8?q?=E6=8A=A5=E4=BB=B7=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_production.py | 2 +- sf_manufacturing/models/mrp_workorder.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 7da6cbbb..322dff15 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -128,7 +128,7 @@ class MrpProduction(models.Model): for item in self: item.manual_quotation = item.product_id.manual_quotation - manual_quotation = fields.Boolean('人工编程', default=False, compute=_compute_manual_quotation) + manual_quotation = fields.Boolean('人工编程', default=False, compute=_compute_manual_quotation, store=True) is_scrap = fields.Boolean('是否报废', default=False) is_remanufacture = fields.Boolean('是否重新制造', default=False) diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 2cfaaccd..6adec1de 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -65,7 +65,7 @@ class ResMrpWorkOrder(models.Model): for item in self: item.manual_quotation = item.production_id.manual_quotation - manual_quotation = fields.Boolean('人工编程', default=False, compute=_compute_manual_quotation) + manual_quotation = fields.Boolean('人工编程', default=False, compute=_compute_manual_quotation, store=True) def _compute_working_users(self): super()._compute_working_users() From ebb800754991f785233bc448b77a72beeca7fe7c Mon Sep 17 00:00:00 2001 From: hujiaying Date: Tue, 27 Aug 2024 09:46:34 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E9=94=80=E5=94=AE=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E5=86=85=E2=80=9D=E5=8F=96=E6=B6=88=E2=80=9C=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E5=8F=98=E4=B8=BA=E2=80=9D=E6=8B=92=E7=BB=9D=E6=8E=A5=E5=8D=95?= =?UTF-8?q?=E2=80=9C=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_sale/views/sale_order_view.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sf_sale/views/sale_order_view.xml b/sf_sale/views/sale_order_view.xml index d5af8ebd..ee34fc3e 100644 --- a/sf_sale/views/sale_order_view.xml +++ b/sf_sale/views/sale_order_view.xml @@ -129,6 +129,9 @@ {'readonly': [('state', 'in', ['cancel','sale'])]} + + 拒绝接单 + From 324ed283c4bbe6787208683896ee4e83a263e1b3 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Tue, 27 Aug 2024 10:01:22 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E5=91=98=E5=B7=A5=E5=AF=B9=E8=B1=A1?= =?UTF-8?q?=E5=86=85=E2=80=9D=E5=B7=A5=E4=BD=9C=E7=94=B5=E5=AD=90=E9=82=AE?= =?UTF-8?q?=E4=BB=B6=E2=80=9C=E5=AD=97=E6=AE=B5=E5=8F=98=E4=B8=BA=E5=BF=85?= =?UTF-8?q?=E5=A1=AB=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_hr/__init__.py | 3 +++ sf_hr/__manifest__.py | 22 ++++++++++++++++++++++ sf_hr/models/__init__.py | 2 ++ sf_hr/security/ir.model.access.csv | 0 sf_hr/views/hr_employee.xml | 15 +++++++++++++++ 5 files changed, 42 insertions(+) create mode 100644 sf_hr/__init__.py create mode 100644 sf_hr/__manifest__.py create mode 100644 sf_hr/models/__init__.py create mode 100644 sf_hr/security/ir.model.access.csv create mode 100644 sf_hr/views/hr_employee.xml diff --git a/sf_hr/__init__.py b/sf_hr/__init__.py new file mode 100644 index 00000000..cde864ba --- /dev/null +++ b/sf_hr/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models diff --git a/sf_hr/__manifest__.py b/sf_hr/__manifest__.py new file mode 100644 index 00000000..aaf9cfc7 --- /dev/null +++ b/sf_hr/__manifest__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +{ + 'name': '机企猫智能工厂 员工管理', + 'version': '1.0', + 'summary': '智能工厂员工模块', + 'sequence': 1, + 'category': 'sf', + 'website': 'https://www.sf.jikimo.com', + 'depends': ['hr'], + 'data': [ + 'views/hr_employee.xml', + ], + 'demo': [ + ], + 'qweb': [ + ], + 'license': 'LGPL-3', + 'installable': True, + 'application': False, + 'auto_install': False, +} diff --git a/sf_hr/models/__init__.py b/sf_hr/models/__init__.py new file mode 100644 index 00000000..633f8661 --- /dev/null +++ b/sf_hr/models/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- + diff --git a/sf_hr/security/ir.model.access.csv b/sf_hr/security/ir.model.access.csv new file mode 100644 index 00000000..e69de29b diff --git a/sf_hr/views/hr_employee.xml b/sf_hr/views/hr_employee.xml new file mode 100644 index 00000000..a3db9076 --- /dev/null +++ b/sf_hr/views/hr_employee.xml @@ -0,0 +1,15 @@ + + + + + employee_form + hr.employee + + + + 1 + + + + + \ No newline at end of file From c6f6927d57bc8d20f0e02f7677d5dffb58c5460b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Tue, 27 Aug 2024 10:42:24 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B7=A5=E4=BB=B6?= =?UTF-8?q?=E9=85=8D=E9=80=81=E5=90=8E=E6=B2=A1=E6=9C=89=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E4=B8=8B=E5=8F=91=E6=97=B6=E9=97=B4=E7=9A=84?= =?UTF-8?q?bug=EF=BC=8CAGV=E9=85=8D=E7=BD=AE=E4=B8=AD=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E4=B8=8B=E5=8F=91AGV=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/__manifest__.py | 1 + sf_manufacturing/models/__init__.py | 1 + sf_manufacturing/models/agv_scheduling.py | 4 +++- sf_manufacturing/models/res_config_setting.py | 22 +++++++++++++++++ .../views/res_config_settings_views.xml | 24 +++++++++++++++++++ .../wizard/workpiece_delivery_wizard.py | 12 ++++++++-- .../views/res_config_settings_views.xml | 2 +- 7 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 sf_manufacturing/models/res_config_setting.py create mode 100644 sf_manufacturing/views/res_config_settings_views.xml diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py index e84b34cc..35501367 100644 --- a/sf_manufacturing/__manifest__.py +++ b/sf_manufacturing/__manifest__.py @@ -32,6 +32,7 @@ 'views/model_type_view.xml', 'views/agv_setting_views.xml', 'views/sf_maintenance_equipment.xml', + 'views/res_config_settings_views.xml', ], 'assets': { diff --git a/sf_manufacturing/models/__init__.py b/sf_manufacturing/models/__init__.py index b93d613e..7d6aa8ae 100644 --- a/sf_manufacturing/models/__init__.py +++ b/sf_manufacturing/models/__init__.py @@ -10,3 +10,4 @@ from . import res_user from . import production_line_base from . import agv_setting from . import agv_scheduling +from . import res_config_setting diff --git a/sf_manufacturing/models/agv_scheduling.py b/sf_manufacturing/models/agv_scheduling.py index 237038ba..d232c643 100644 --- a/sf_manufacturing/models/agv_scheduling.py +++ b/sf_manufacturing/models/agv_scheduling.py @@ -231,7 +231,9 @@ class AgvScheduling(models.Model): rec.site_state = '空闲' rec.end_site_id = agv_task_route.end_site_id.id rec.agv_route_id = agv_task_route.id - # rec._delivery_avg() + is_agv_task_dispatch = self.env['ir.config_parameter'].sudo().get_param('is_agv_task_dispatch') + if is_agv_task_dispatch: + rec._delivery_avg() # 更新接驳站状态 rec.env['sf.agv.site'].update_site_state({rec.end_site_id.name: '占用'}, False) diff --git a/sf_manufacturing/models/res_config_setting.py b/sf_manufacturing/models/res_config_setting.py new file mode 100644 index 00000000..d6b029c6 --- /dev/null +++ b/sf_manufacturing/models/res_config_setting.py @@ -0,0 +1,22 @@ +from odoo import models, fields, api + + +class ResConfigSettings(models.TransientModel): + _inherit = 'res.config.settings' + + is_agv_task_dispatch = fields.Boolean('是否下发AGV任务', default=False) + + @api.model + def get_values(self): + values = super(ResConfigSettings, self).get_values() + config = self.env['ir.config_parameter'].sudo() + is_agv_task_dispatch = config.get_param('is_agv_task_dispatch') + values.update( + is_agv_task_dispatch=is_agv_task_dispatch, + ) + return values + + def set_values(self): + super(ResConfigSettings, self).set_values() + config = self.env['ir.config_parameter'].sudo() + config.set_param("is_agv_task_dispatch", self.is_agv_task_dispatch or False) diff --git a/sf_manufacturing/views/res_config_settings_views.xml b/sf_manufacturing/views/res_config_settings_views.xml new file mode 100644 index 00000000..89738492 --- /dev/null +++ b/sf_manufacturing/views/res_config_settings_views.xml @@ -0,0 +1,24 @@ + + + + + res.config.settings.view.form.inherit.sf_sync + res.config.settings + + + +
+
+ +
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/sf_manufacturing/wizard/workpiece_delivery_wizard.py b/sf_manufacturing/wizard/workpiece_delivery_wizard.py index 8e7f47f8..5d5dc889 100644 --- a/sf_manufacturing/wizard/workpiece_delivery_wizard.py +++ b/sf_manufacturing/wizard/workpiece_delivery_wizard.py @@ -109,11 +109,19 @@ class WorkpieceDeliveryWizard(models.TransientModel): ) # 如果关联了工件配送单,则修改状态为已下发 if self.delivery_ids: - self.delivery_ids.write({ + val = { 'status': '已下发', 'agv_scheduling_id': scheduling.id, 'feeder_station_start_id': scheduling.start_site_id.id, - }) + } + # 如果agv任务已经下发,则修改工件配送单信息 + if scheduling.state == '配送中': + val.update({ + 'feeder_station_destination_id': scheduling.end_site_id.id, + 'route_id': scheduling.agv_route_id.id, + 'task_delivery_time': fields.Datetime.now() + }) + self.delivery_ids.write(val) # 如果是解除装夹工单,则需要处理工单逻辑 for item in self.workorder_ids: diff --git a/sf_mrs_connect/views/res_config_settings_views.xml b/sf_mrs_connect/views/res_config_settings_views.xml index 08e9560f..05e5be41 100644 --- a/sf_mrs_connect/views/res_config_settings_views.xml +++ b/sf_mrs_connect/views/res_config_settings_views.xml @@ -76,7 +76,7 @@

AGV参数配置

-
+