diff --git a/jikimo_frontend/views/bye_odoo.xml b/jikimo_frontend/views/bye_odoo.xml index 75136cc1..14fd211b 100644 --- a/jikimo_frontend/views/bye_odoo.xml +++ b/jikimo_frontend/views/bye_odoo.xml @@ -16,7 +16,7 @@ diff --git a/jikimo_sale_order_message_notify/__init__.py b/jikimo_sale_order_message_notify/__init__.py deleted file mode 100644 index 9a7e03ed..00000000 --- a/jikimo_sale_order_message_notify/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import models \ No newline at end of file diff --git a/jikimo_sale_order_message_notify/__manifest__.py b/jikimo_sale_order_message_notify/__manifest__.py deleted file mode 100644 index 45570c08..00000000 --- a/jikimo_sale_order_message_notify/__manifest__.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -{ - 'name': '机企猫智能工厂 消息提醒', - 'version': '1.0', - 'summary': '智能工厂消息提醒模块', - 'sequence': 1, - 'description': """ - - """, - 'category': 'sf', - 'website': 'https://www.sf.jikimo.com', - 'depends': ['jikimo_message_notify'], - 'data': [ - 'security/ir.model.access.csv', - 'data/bussiness_node.xml', - # 'views/sf_message_template_view.xml', - ], - 'test': [ - ], - 'license': 'LGPL-3', - 'installable': True, - 'auto_install': False, - 'application': False, -} diff --git a/jikimo_sale_order_message_notify/data/bussiness_node.xml b/jikimo_sale_order_message_notify/data/bussiness_node.xml deleted file mode 100644 index e6800a48..00000000 --- a/jikimo_sale_order_message_notify/data/bussiness_node.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - 订单确认 - sale.order - - - \ No newline at end of file diff --git a/jikimo_sale_order_message_notify/models/__init__.py b/jikimo_sale_order_message_notify/models/__init__.py deleted file mode 100644 index c0462bbd..00000000 --- a/jikimo_sale_order_message_notify/models/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from . import jikimo_message_template -from . import sale_order diff --git a/jikimo_sale_order_message_notify/models/jikimo_message_template.py b/jikimo_sale_order_message_notify/models/jikimo_message_template.py deleted file mode 100644 index 4c2530f5..00000000 --- a/jikimo_sale_order_message_notify/models/jikimo_message_template.py +++ /dev/null @@ -1,10 +0,0 @@ -from odoo import models, fields, api - -class JikimoMessageTemplate(models.Model): - _inherit = "jikimo.message.template" - - def _get_message_model(self): - res = super(JikimoMessageTemplate, self)._get_message_model() - res.append("sale.order") - return res - diff --git a/jikimo_sale_order_message_notify/models/sale_order.py b/jikimo_sale_order_message_notify/models/sale_order.py deleted file mode 100644 index 4883fedd..00000000 --- a/jikimo_sale_order_message_notify/models/sale_order.py +++ /dev/null @@ -1,12 +0,0 @@ -from odoo import models, fields, api - - -class SaleOrder(models.Model): - _name = "sale.order" - _description = "销售订单" - _inherit = ["sale.order", "jikimo.message.dispatch"] - - def create(self, vals_list): - res = super(SaleOrder, self).create(vals_list) - res.add_queue('订单确认') - return res diff --git a/jikimo_sale_order_message_notify/security/group_security.xml b/jikimo_sale_order_message_notify/security/group_security.xml deleted file mode 100644 index fdbc3ae5..00000000 --- a/jikimo_sale_order_message_notify/security/group_security.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/jikimo_sale_order_message_notify/security/ir.model.access.csv b/jikimo_sale_order_message_notify/security/ir.model.access.csv deleted file mode 100644 index 0b7f9c7b..00000000 --- a/jikimo_sale_order_message_notify/security/ir.model.access.csv +++ /dev/null @@ -1,6 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink - - - - - diff --git a/jikimo_sale_order_message_notify/views/sf_message_template_view.xml b/jikimo_sale_order_message_notify/views/sf_message_template_view.xml deleted file mode 100644 index 21920b64..00000000 --- a/jikimo_sale_order_message_notify/views/sf_message_template_view.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - sf.message.template.view.form - message.template - -
- -
-
- - - - - - - - - -
-
-
-
- - - sf.message.template.view.tree - message.template - - - - - - - - - - - - - - - sf.message.template.search.view - message.template - - - - - - - - - - - - 消息模板 - message.template - tree,form - - - - - -
-
\ No newline at end of file diff --git a/sf_base/static/src/scss/test.scss b/sf_base/static/src/scss/test.scss index c91a8a77..565e7956 100644 --- a/sf_base/static/src/scss/test.scss +++ b/sf_base/static/src/scss/test.scss @@ -159,9 +159,6 @@ td.o_required_modifier { display:inline; } .diameter{ - display: flex !important; - justify-content: flex-start !important; - align-items: center !important; } .o_address_format { display: flex !important; diff --git a/sf_base/views/tool_views.xml b/sf_base/views/tool_views.xml index 8b429f89..6b97f0ec 100644 --- a/sf_base/views/tool_views.xml +++ b/sf_base/views/tool_views.xml @@ -578,7 +578,7 @@ - + sf.tool.inventory.search sf.tool.inventory diff --git a/sf_hr/__manifest__.py b/sf_hr/__manifest__.py index c0bd63ef..b3e21ab3 100644 --- a/sf_hr/__manifest__.py +++ b/sf_hr/__manifest__.py @@ -7,10 +7,11 @@ 'sequence': 1, 'category': 'sf', 'website': 'https://www.sf.jikimo.com', - 'depends': ['hr'], + 'depends': ['base', 'hr'], 'data': [ 'views/hr_employee.xml', 'views/res_config_settings_views.xml', + 'views/res_users_view.xml', 'data/cron_data.xml', ], 'demo': [ diff --git a/sf_hr/models/__init__.py b/sf_hr/models/__init__.py index ffe76391..9744f0cc 100644 --- a/sf_hr/models/__init__.py +++ b/sf_hr/models/__init__.py @@ -2,3 +2,4 @@ from . import hr_employee from . import res_config_setting +from . import res_users diff --git a/sf_hr/models/hr_employee.py b/sf_hr/models/hr_employee.py index 8cf5595d..e9826f29 100644 --- a/sf_hr/models/hr_employee.py +++ b/sf_hr/models/hr_employee.py @@ -20,7 +20,9 @@ class JkmPracticeEmployee(models.Model): if result['employee_list']: for employee_info in result['employee_list']: if employee_info['work_email']: - self.sudo().search([('work_email', '=', employee_info['work_email'])]).write( - {'we_id': employee_info['we_id']}) + hr_employee = self.sudo().search([('work_email', '=', employee_info['work_email'])]) + hr_employee.write({'we_id': employee_info['we_id']}) + if hr_employee.user_id: + hr_employee.user_id.write({'we_employee_id': employee_info['we_id']}) else: logging.info('_employee_info_sync error:%s' % result['message']) diff --git a/sf_hr/models/res_users.py b/sf_hr/models/res_users.py new file mode 100644 index 00000000..392c297a --- /dev/null +++ b/sf_hr/models/res_users.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +from odoo import models, fields, api + +import logging + +_logger = logging.getLogger(__name__) + + +class ResUsers(models.Model): + _inherit = 'res.users' + + we_employee_id = fields.Char(string=u'企业微信账号', default="") diff --git a/sf_hr/views/res_users_view.xml b/sf_hr/views/res_users_view.xml new file mode 100644 index 00000000..c65d8e46 --- /dev/null +++ b/sf_hr/views/res_users_view.xml @@ -0,0 +1,20 @@ + + + + + res.users.account.form + res.users + + + + + + + + + + + + + + diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index 23452b43..1f65c884 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -231,6 +231,95 @@ class Sf_Dashboard_Connect(http.Controller): res['message'] = '前端请求日志数据失败,原因:%s' % e return json.dumps(res) + @http.route('/api/logs/page_data', type='http', auth='public', methods=['GET', 'POST'], + csrf=False, cors="*") + def logs_page_data(self, **kw): + """ + 拿到日志数据返回给大屏展示(支持时间戳分页) + :param kw: + :return: + """ + res = {'status': 1, 'message': '成功', 'data': {}} + logging.info('前端请求日志数据的参数为:%s' % kw) + + try: + # 连接数据库 + conn = psycopg2.connect(**db_config) + cur = conn.cursor() + + # 获取并解析传递的参数 + machine_list = ast.literal_eval(kw.get('machine_list', '[]')) + begin_time_str = kw.get('begin_time', '').strip('"') + end_time_str = kw.get('end_time', '').strip('"') + page = int(kw.get('page', 1)) # 默认页码为1 + page_size = int(kw.get('page_size', 80)) # 默认每页条数为10 + + 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') + + # 计算分页的 offset + offset = (page - 1) * page_size + + # 先查询符合条件的总记录数 + total_records = 0 + for item in machine_list: + count_sql = ''' + SELECT COUNT(*) + FROM device_data + WHERE device_name = %s AND time >= %s AND time <= %s; + ''' + # 执行总记录数查询 + cur.execute(count_sql, (item, begin_time, end_time)) + record_count = cur.fetchone()[0] # 获取总记录数 + total_records += record_count + + # 计算总页数 + if total_records > 0: + total_pages = (total_records + page_size - 1) // page_size # 向上取整 + else: + total_pages = 0 + + # 将总页数和总记录数返回到响应中 + res['total_records'] = total_records + res['total_pages'] = total_pages + + for item in machine_list: + sql = ''' + SELECT time, device_state, program_name + FROM device_data + WHERE device_name = %s AND time >= %s AND time <= %s + ORDER BY time DESC + LIMIT %s OFFSET %s; + ''' + # 执行SQL命令,使用参数绑定 + cur.execute(sql, (item, begin_time, end_time, page_size, offset)) + results = cur.fetchall() + + # 将数据按照 equipment_code 进行分组 + if item not in res['data']: + res['data'][item] = [] + + for result in results: + res['data'][item].append({ + 'time': result[0].strftime('%Y-%m-%d %H:%M:%S'), + 'state': result[1], + 'production_name': result[2], + }) + + return json.dumps(res) # 返回分页数据 + + except Exception as e: + logging.info('前端请求日志数据失败,原因:%s' % e) + res['status'] = -1 + res['message'] = '前端请求日志数据失败,原因:%s' % e + return json.dumps(res) + + finally: + if cur: + cur.close() + if conn: + conn.close() + # 返回CNC机床列表 @http.route('/api/CNCList', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") @@ -378,7 +467,8 @@ class Sf_Dashboard_Connect(http.Controller): pass_rate = 1 if pass_nums: pass_rate = round( - (len(pass_nums) / detection_data if len(plan_data_finish_orders) > 0 else 0), 3) + # (len(pass_nums) / detection_data if len(plan_data_finish_orders) > 0 else 0), 3) + (len(pass_nums) / len(plan_data_finish_orders) if len(plan_data_finish_orders) > 0 else 0), 3) # 返工率 rework_rate = round( @@ -418,8 +508,9 @@ class Sf_Dashboard_Connect(http.Controller): 'plan_data_progress_deviation': plan_data_progress_deviation, 'plan_data_rework_counts': plan_data_rework_counts, 'on_time_rate': on_time_rate, - 'detection_data': detection_data, - 'pass_rate': pass_rate + # 'detection_data': detection_data, + 'detection_data': plan_data_finish_counts, + 'pass_rate': (plan_data_finish_counts - plan_data_fault_counts) / plan_data_finish_counts } res['data'][line] = data @@ -489,11 +580,14 @@ class Sf_Dashboard_Connect(http.Controller): for time_interval in time_intervals: start_time, end_time = time_interval - # print(start_time, end_time) - orders = plan_obj.search([('production_line_id.name', '=', line), ('state', 'in', ['finished']), - (date_field_name, '>=', start_time.strftime('%Y-%m-%d 00:00:00')), - (date_field_name, '<', end_time.strftime('%Y-%m-%d 00:00:00')) - ]) + + orders = plan_obj.search([ + ('production_line_id.name', '=', line), + ('state', 'in', ['finished']), + (date_field_name, '>=', start_time.strftime('%Y-%m-%d %H:%M:%S')), + (date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) # 包括结束时间 + ]) + # 使用小时和分钟作为键,确保每个小时的数据有独立的键 key = start_time.strftime('%H:%M:%S') # 只取小时:分钟:秒作为键 time_count_dict[key] = len(orders) @@ -715,7 +809,8 @@ class Sf_Dashboard_Connect(http.Controller): 'material': material, 'dimensions': dimensions, 'order_qty': finish_order.product_qty, - 'finish_time': finish_order.actual_end_time.strftime('%Y-%m-%d %H:%M:%S') if finish_order.actual_end_time else ' ' + 'finish_time': finish_order.actual_end_time.strftime( + '%Y-%m-%d %H:%M:%S') if finish_order.actual_end_time else ' ' } done_data.append(line_dict) @@ -799,54 +894,27 @@ class Sf_Dashboard_Connect(http.Controller): """ 查询设备的异常情况 """ - res = {'status': 1, 'message': '成功', 'data': {}} + res = {'status': 1, 'message': '成功', 'data': []} logging.info('前端请求机床数据的参数为:%s' % kw) - # 连接数据库 - conn = psycopg2.connect(**db_config) - cur = conn.cursor() try: - # 获取请求的机床数据 + maintenance_logs_obj = request.env['sf.maintenance.logs'].sudo() + # # 获取请求的机床数据 # machine_list = ast.literal_eval(kw['machine_list']) - # idle_times = [] - # idle_dict = {} - # for item in machine_list: - sql = ''' - SELECT DISTINCT ON (alarm_time) alarm_time, alarm_message, system_date, system_time, alarm_repair_time - FROM device_data - WHERE alarm_time IS NOT NULL - ORDER BY alarm_time, time; + # machine_data = equipment_obj.search([('code', '=', item)]) + for log in maintenance_logs_obj.search([]): + res['data'].append({ + 'name': log.name, + 'alarm_time': log.alarm_time.strftime('%Y-%m-%d %H:%M:%S'), + 'fault_alarm_info': log.fault_alarm_info if log.fault_alarm_info else ' ', + 'fault_process': log.fault_process if log.fault_process else ' ', + }) - ''' - # 执行SQL命令 - cur.execute(sql) - result = cur.fetchall() - # print('result', result) - - # 将查询结果转换为字典列表 - data = [] - for row in result: - record = { - 'alarm_time': row[0], - 'alarm_message': row[1], - 'system_date': row[2], - 'system_time': row[3], - 'alarm_repair_time': row[4] - } - data.append(record) - - # 将数据填充到返回结果中 - res['data'] = data - - # 返回统计结果 - return json.dumps(res, ensure_ascii=False) except Exception as e: - print(f"An error occurred: {e}") - return json.dumps(res) - finally: - cur.close() - conn.close() + logging.error(f"An error occurred: {e}") + + return json.dumps(res) # 设备oee @http.route('/api/OEE', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") @@ -1163,6 +1231,7 @@ class Sf_Dashboard_Connect(http.Controller): conn = psycopg2.connect(**db_config) # 获取请求的机床数据 machine_list = ast.literal_eval(kw['machine_list']) + time_threshold = datetime.now() - timedelta(days=1) def fetch_result_as_dict(cursor): """辅助函数:将查询结果转为字典""" @@ -1172,18 +1241,29 @@ class Sf_Dashboard_Connect(http.Controller): for item in machine_list: with conn.cursor() as cur: cur.execute(""" - SELECT * FROM device_data - WHERE device_name = %s - AND device_state != '离线' - ORDER BY time DESC - LIMIT 1; - """, (item,)) + SELECT * FROM device_data + WHERE device_name = %s + AND device_state != '离线' + ORDER BY time DESC + LIMIT 1; + """, (item,)) last_all_time = fetch_result_as_dict(cur) + with conn.cursor() as cur: + cur.execute(""" + SELECT * FROM device_data + WHERE device_name = %s + AND device_state != '离线' AND time >= %s + ORDER BY time ASC + LIMIT 1; + """, (item, time_threshold)) + last_24_time = fetch_result_as_dict(cur) # 返回数据 res['data'][item] = { 'wait_time': last_all_time['run_time'] if last_all_time['run_time'] is not None else 0, 'cut_time': last_all_time['process_time'] if last_all_time['process_time'] is not None else 0, - 'power_on_time': last_all_time['power_on_time'] if last_all_time['power_on_time'] is not None else 0 + 'cut_24_time': last_24_time['process_time'] if last_24_time['process_time'] is not None else 0, + 'power_on_time': last_all_time['power_on_time'] if last_all_time['power_on_time'] is not None else 0, + 'power_on_24_time': last_24_time['power_on_time'] if last_24_time['power_on_time'] is not None else 0 } conn.close() diff --git a/sf_maintenance/models/sf_maintenance_logs.py b/sf_maintenance/models/sf_maintenance_logs.py index 7f80e163..c1a82a1b 100644 --- a/sf_maintenance/models/sf_maintenance_logs.py +++ b/sf_maintenance/models/sf_maintenance_logs.py @@ -1,13 +1,14 @@ # -*-coding:utf-8-*- -from odoo import fields, models +from odoo import fields, models, api class SfMaintenanceLogs(models.Model): _name = 'sf.maintenance.logs' _description = '设备故障日志' + _order = 'alarm_time desc' - code = fields.Char(string='编码') - name = fields.Char(string='名称') + code = fields.Char(string='编码', readonly=True) + name = fields.Char(string='名称', compute='_compute_name') 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='机台号') @@ -28,3 +29,13 @@ class SfMaintenanceLogs(models.Model): fault_duration = fields.Float(string='故障时长') note = fields.Text(string='备注') active = fields.Boolean('Active', default=True) + + @api.depends('code') + def _compute_name(self): + for record in self: + if record.code: + record.name = self.env['maintenance.equipment'].sudo().search([('code', '=', record.code), ('active', '=', True)]).name + record.maintenance_equipment_id = self.env['maintenance.equipment'].sudo().search([('code', '=', record.code), ('active', '=', True)]).id + else: + record.name = '' + diff --git a/sf_maintenance/models/sf_maintenance_oee.py b/sf_maintenance/models/sf_maintenance_oee.py index 1a2e4f10..ee2c209c 100644 --- a/sf_maintenance/models/sf_maintenance_oee.py +++ b/sf_maintenance/models/sf_maintenance_oee.py @@ -66,11 +66,14 @@ class SfMaintenanceEquipmentOEE(models.Model): if result['status'] == 1: logs_list = result['data'][self.equipment_code] logs_detail = '' + log_state = '' for log in logs_list: - print('loooooooooooooooooooogs', log) - production_name = log['production_name'] if log['production_name'] else ' ' - logs_detail += '' + log['time'] + '' + log[ - 'state'] + '' + production_name + '' + if log['state'] != log_state: + print('loooooooooooooooooooogs', log) + production_name = log['production_name'] if log['production_name'] else ' ' + logs_detail += '' + log['time'] + '' + log[ + 'state'] + '' + production_name + '' + log_state = log['state'] # self.day_logs_detail = '' + logs_detail + '
时间事件/状态加工工单
' self.day_logs_detail = ''' @@ -119,10 +122,13 @@ class SfMaintenanceEquipmentOEE(models.Model): if result['status'] == 1: logs_list = result['data'][self.equipment_code] logs_detail = '' + log_state = '' for log in logs_list: - production_name = log['production_name'] if log['production_name'] else ' ' - logs_detail += '' + if log['state'] != log_state: + production_name = log['production_name'] if log['production_name'] else ' ' + logs_detail += '' + log_state = log['state'] # self.day_logs_detail = '
' + log['time'] + '' + log[ - 'state'] + '' + production_name + '
' + log['time'] + '' + log[ + 'state'] + '' + production_name + '
' + logs_detail + '
时间事件/状态加工工单
' self.history_logs_detail = ''' diff --git a/sf_maintenance/views/maintenance_equipment_oee_views.xml b/sf_maintenance/views/maintenance_equipment_oee_views.xml index 33749809..b798b0ab 100644 --- a/sf_maintenance/views/maintenance_equipment_oee_views.xml +++ b/sf_maintenance/views/maintenance_equipment_oee_views.xml @@ -55,7 +55,31 @@