From 8a7a90ff0d85c86f3a38845420349d9f27ede209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Mon, 7 Apr 2025 17:04:34 +0800 Subject: [PATCH 01/27] =?UTF-8?q?agv=E9=85=8D=E7=BD=AE=E4=B8=8D=E5=8F=AF?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/views/agv_setting_views.xml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/sf_manufacturing/views/agv_setting_views.xml b/sf_manufacturing/views/agv_setting_views.xml index 62e3c623..b289f4b6 100644 --- a/sf_manufacturing/views/agv_setting_views.xml +++ b/sf_manufacturing/views/agv_setting_views.xml @@ -15,6 +15,23 @@ + + agv.site.form + sf.agv.site + +
+ + + + + + + + +
+
+
+ AGV站点 sf.agv.site @@ -39,7 +56,8 @@ - + From e09226e966d5dc15a240bd384a4ead4c6cbe8d18 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Tue, 8 Apr 2025 09:44:46 +0800 Subject: [PATCH 02/27] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AF=B9=E5=AF=BF?= =?UTF-8?q?=E5=91=BD=E6=9C=AA=E5=88=B0=E6=9C=9F=E4=B8=94=E4=BD=8D=E7=BD=AE?= =?UTF-8?q?=E5=9C=A8=E7=BA=BF=E8=BE=B9=E5=88=80=E5=BA=93=E7=9A=84=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=88=80=E5=85=B7=E8=BF=9B=E8=A1=8C=E6=8B=86=E8=A7=A3?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E4=B8=8D=E7=9B=B4=E6=8E=A5=E6=8A=A5=E9=94=99?= =?UTF-8?q?=EF=BC=8C=E8=80=8C=E6=98=AF=E8=BF=9B=E8=A1=8C=E4=BA=8C=E6=AC=A1?= =?UTF-8?q?=E7=A1=AE=E8=AE=A4=E6=98=AF=E5=90=A6=E8=BF=9B=E8=A1=8C=E6=8B=86?= =?UTF-8?q?=E9=99=A4=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_tool_management/models/base.py | 14 +++++++++++++- sf_tool_management/security/ir.model.access.csv | 5 ++++- sf_tool_management/wizard/wizard.py | 9 +++++++++ sf_tool_management/wizard/wizard_view.xml | 15 +++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py index 40100a93..2fcc40d9 100644 --- a/sf_tool_management/models/base.py +++ b/sf_tool_management/models/base.py @@ -1437,14 +1437,26 @@ class FunctionalToolDismantle(models.Model): def confirmation_disassembly(self): logging.info('%s刀具确认开始拆解' % self.dismantle_cause) code = self.code + context = self.env.context if self.functional_tool_id.functional_tool_status == '已拆除': raise ValidationError('Rfid为【%s】名称为【%s】的功能刀具已经拆解,请勿重复操作!' % ( self.functional_tool_id.rfid_dismantle, self.name)) # 对拆解的功能刀具进行校验,只有在刀具房的功能刀具才能拆解 elif self.functional_tool_id.functional_tool_status != '报警': - if self.functional_tool_id.tool_room_num == 0: + if self.functional_tool_id.current_location == '机内刀库': raise ValidationError('Rfid为【%s】的功能刀具当前位置为【%s】,不能进行拆解!' % ( self.rfid, self.functional_tool_id.current_location)) + elif not context.get('TRUE_DISASSEMBLE') and self.functional_tool_id.current_location == '线边刀库': + return { + 'type': 'ir.actions.act_window', + 'res_model': 'sf.functional.tool.dismantle.wiard', + 'name': '刀具寿命未到期', + 'view_mode': 'form', + 'target': 'new', + 'context': { + 'default_functional_tool_dismantle_id': self.id, + 'TRUE_DISASSEMBLE': True} + } # 目标重复校验 self.location_duplicate_check() datas = {'scrap': [], 'picking': []} diff --git a/sf_tool_management/security/ir.model.access.csv b/sf_tool_management/security/ir.model.access.csv index 8c188464..1ad8a439 100644 --- a/sf_tool_management/security/ir.model.access.csv +++ b/sf_tool_management/security/ir.model.access.csv @@ -40,4 +40,7 @@ access_sf_functional_tool_dismantle_group_sf_tool_user,sf.functional.tool.disman access_sf_functional_tool_dismantle_group_plan_dispatch,sf.functional.tool.dismantle_group_plan_dispatch,model_sf_functional_tool_dismantle,sf_base.group_plan_dispatch,1,0,0,0 access_jikimo_bom,jikimo.bom,model_jikimo_bom,base.group_user,1,1,1,1 -access_jikimo_bom_wizard,jikimo.bom.wizard,model_jikimo_bom_wizard,base.group_user,1,1,1,1 \ No newline at end of file +access_jikimo_bom_wizard,jikimo.bom.wizard,model_jikimo_bom_wizard,base.group_user,1,1,1,1 + +access_sf_functional_tool_dismantle_wiard,sf.functional.tool.dismantle.wiard,model_sf_functional_tool_dismantle_wiard,sf_base.group_sf_tool_user,1,1,1,0 +access_sf_functional_tool_dismantle_wiard_group_plan_dispatch,sf.functional.tool.dismantle.wiard,model_sf_functional_tool_dismantle_wiard,sf_base.group_plan_dispatch,1,0,0,0 diff --git a/sf_tool_management/wizard/wizard.py b/sf_tool_management/wizard/wizard.py index d1797855..633901d8 100644 --- a/sf_tool_management/wizard/wizard.py +++ b/sf_tool_management/wizard/wizard.py @@ -770,3 +770,12 @@ class FunctionalToolAssemblyOrder(models.TransientModel): # } +class FunctionalToolDismantle(models.TransientModel): + _name = 'sf.functional.tool.dismantle.wiard' + _description = '功能刀具拆解二次确认' + + functional_tool_dismantle_id = fields.Many2one('sf.functional.tool.dismantle', '拆解单') + + def confirm(self): + self.functional_tool_dismantle_id.confirmation_disassembly() + return True diff --git a/sf_tool_management/wizard/wizard_view.xml b/sf_tool_management/wizard/wizard_view.xml index 53a45d85..73770342 100644 --- a/sf_tool_management/wizard/wizard_view.xml +++ b/sf_tool_management/wizard/wizard_view.xml @@ -444,4 +444,19 @@ new + + + + 刀具拆解 + sf.functional.tool.dismantle.wiard + +
+
刀具寿命未到期,是否继续拆解?
+
+
+
+
+
\ No newline at end of file From f912a81e7b4246e3e10edd2be21905d6c73776c2 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Tue, 8 Apr 2025 09:48:05 +0800 Subject: [PATCH 03/27] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=E4=BA=A7=E5=93=81=E5=8F=96=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/insepection_report_template.xml | 3 +- tool_service/装夹自动保存检测文件服务/app.py | 114 ++++++++++++++---- 2 files changed, 92 insertions(+), 25 deletions(-) diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index afe7148b..4f28173b 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -73,7 +73,8 @@ - + + diff --git a/tool_service/装夹自动保存检测文件服务/app.py b/tool_service/装夹自动保存检测文件服务/app.py index ba41f666..06a0f2bd 100644 --- a/tool_service/装夹自动保存检测文件服务/app.py +++ b/tool_service/装夹自动保存检测文件服务/app.py @@ -6,10 +6,7 @@ import win32gui import win32con import logging import time - -# 配置日志记录 -logging.basicConfig(filename='service.log', level=logging.INFO, - format='%(asctime)s - %(levelname)s - %(message)s') +import re app = FastAPI() @@ -19,11 +16,11 @@ class FileUploadRequest(BaseModel): # FTP 服务器配置信息 -ftp_host = '110.52.114.162' -ftp_port = 10021 +ftp_host = '47.119.33.43' +ftp_port = 21 ftp_user = 'ftpuser' -ftp_password = '123456' -ftp_directory = '/home/ftp/ftp_root/ThreeTest/XT/Before/' +ftp_password = 'FTPftp123' +ftp_directory = 'ThreeTest/XT/Before/' def find_child_window(parent_hwnd, class_name): @@ -63,25 +60,95 @@ def find_child_window_by_title(parent_hwnd, title): return child_hwnds +# 获取 ComboBox 的句柄 +def get_combobox_handle(parent_handle): + combo_handle = win32gui.FindWindowEx(parent_handle, 0, "ComboBox", None) + if combo_handle == 0: + raise Exception("ComboBox not found") + return combo_handle + + +# 获取 ComboBox 中的所有选项 +def get_combobox_items(combo_handle): + count = win32gui.SendMessage(combo_handle, win32con.CB_GETCOUNT, 0, 0) + items = [] + for i in range(count): + length = win32gui.SendMessage(combo_handle, win32con.CB_GETLBTEXTLEN, i, 0) + buffer = win32gui.PyMakeBuffer(length + 1) + win32gui.SendMessage(combo_handle, win32con.CB_GETLBTEXT, i, buffer) + byte_data = buffer.tobytes() + + # 尝试多种编码方式 + text = None + # 尝试多种编码方式,包括utf-16le + for encoding in ['utf-16le', 'utf-8', 'gbk', 'latin-1']: + try: + decoded_text = byte_data.decode(encoding).rstrip('\x00') + # 如果解码后的文本看起来是合理的,就接受它 + if any(char.isprintable() for char in decoded_text): + text = decoded_text + break + except UnicodeDecodeError: + continue + + # 如果所有解码方式都失败,或者内容仍有大量乱码,显示为十六进制字符串 + if text is None or not all(char.isprintable() or char.isspace() for char in text): + text = byte_data.hex() + + items.append(text) + return items + + +# 获取当前选定项 +def get_combobox_selected(combo_handle): + index = win32gui.SendMessage(combo_handle, win32con.CB_GETCURSEL, 0, 0) + if index == -1: + return None + length = win32gui.SendMessage(combo_handle, win32con.CB_GETLBTEXTLEN, index, 0) + buffer = win32gui.PyMakeBuffer(1024) # 调整缓冲区大小 + win32gui.SendMessage(combo_handle, win32con.CB_GETLBTEXT, index, buffer) + + # 尝试多种编码方式进行解码 + for encoding in ['utf-16le', 'utf-8', 'latin-1']: + try: + # 解码 + raw_text = buffer.tobytes().decode(encoding, errors='ignore').rstrip('\x00') + # 使用正则表达式查找 "数字 + 月" 格式的部分 + match = re.search(r'\d+月', raw_text) + if match: + return match.group() + # 使用正则表达式提取有效字符(中文、数字、字母和常见标点) + filtered_text = re.findall(r'[\w\u4e00-\u9fa5]+', raw_text) + # 返回匹配到的第一个有效部分 + if filtered_text: + return filtered_text[0].strip() + except UnicodeDecodeError: + continue # 尝试下一个编码方式 + + # 如果所有解码方式都失败,返回 None + return None + + +# 设置 ComboBox 的值 +def set_combobox_value(combo_handle, value): + items = get_combobox_items(combo_handle) + try: + index = items.index(value) + win32gui.SendMessage(combo_handle, win32con.CB_SETCURSEL, index, 0) + except ValueError: + raise Exception("Value not found in ComboBox") + + def set_path_and_save(filename): - parent_hwnd = win32gui.FindWindow(None, '另存为') + parent_hwnd = win32gui.FindWindow(None, '保存Excel文件') if parent_hwnd == 0: raise HTTPException(status_code=404, detail="没有找到保存报告的窗口,请检查!") - # 这里假设“地址:”是你需要的部分标题 - address_hwnds = find_child_window_by_partial_title(parent_hwnd, "地址:") - - # 确保找到的窗口句柄有效 - if not address_hwnds: - raise HTTPException(status_code=404, detail="未找到地址框,请联系管理员!") - - # 假设找到的第一个窗口是目标组件 - address_hwnd = address_hwnds[0] - logging.info(f"找到地址框地址: {win32gui.GetWindowText(address_hwnd)}") - - # 设置路径 - local_file_path = os.path.join(win32gui.GetWindowText(address_hwnd).split(' ')[1], filename) + combo_handle = get_combobox_handle(parent_hwnd) + #logging.info(f"ComboBox Items: {get_combobox_items(combo_handle)}") + logging.info(f"Current Selected: {get_combobox_selected(combo_handle)}") + local_file_path = "C:\\RationalDMIS64\\Output\\" + get_combobox_selected(combo_handle) + "\\" + filename logging.info(f"设置路径: {local_file_path}") path_hwnds = find_child_window(parent_hwnd, 'Edit') @@ -115,7 +182,6 @@ def wait_for_file_to_save(filepath, timeout=30): def upload_file_to_ftp(local_file): - if not os.path.isfile(local_file): raise HTTPException(status_code=204, detail="文件未找到") @@ -157,4 +223,4 @@ async def upload_file(request: FileUploadRequest): if __name__ == "__main__": import uvicorn - uvicorn.run(app, host="0.0.0.0", port=8000) + uvicorn.run(app, host="0.0.0.0", port=8999) From d0d1a640d937682858d2053245af55e57aa1be87 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Tue, 8 Apr 2025 10:10:36 +0800 Subject: [PATCH 04/27] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=E9=A1=B5=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/insepection_report_template.xml | 147 +++++++++++++++++- sf_quality/data/report_actions.xml | 2 +- 2 files changed, 147 insertions(+), 2 deletions(-) diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index 4f28173b..d989137c 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -61,6 +61,25 @@ + + + + + \ No newline at end of file diff --git a/sf_quality/data/report_actions.xml b/sf_quality/data/report_actions.xml index 7ee44f63..59338103 100644 --- a/sf_quality/data/report_actions.xml +++ b/sf_quality/data/report_actions.xml @@ -18,7 +18,7 @@ 预览检验报告quality.checkqweb-html - sf_quality.report_quality_inspection + sf_quality.html_report_quality_inspectionreport \ No newline at end of file From 10bea40159373ac09eeb2f9e1004c9b5047e6565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Tue, 8 Apr 2025 10:29:29 +0800 Subject: [PATCH 05/27] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=8D=E5=90=8C?= =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E4=B8=AD=E5=BF=83=E9=85=8D=E7=BD=AE=E7=9B=B8?= =?UTF-8?q?=E5=90=8C=E6=8E=A5=E9=A9=B3=E7=AB=99=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/agv_scheduling.py | 34 +++++++++++++------ sf_manufacturing/models/agv_setting.py | 11 +++--- .../wizard/workpiece_delivery_wizard.py | 33 ++++++++++++------ 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/sf_manufacturing/models/agv_scheduling.py b/sf_manufacturing/models/agv_scheduling.py index cc621727..33522182 100644 --- a/sf_manufacturing/models/agv_scheduling.py +++ b/sf_manufacturing/models/agv_scheduling.py @@ -87,11 +87,12 @@ class AgvScheduling(models.Model): agv_route_type: AGV任务类型 workorders: 工单 """ + scheduling = None _logger.info('创建AGV调度任务\r\n起点为【%s】,任务类型为【%s】,工单为【%s】' % (agv_start_site_name, agv_route_type, workorders)) if not workorders: raise UserError(_('工单不能为空')) - agv_start_site = self.env['sf.agv.site'].sudo().search([('name', '=', agv_start_site_name)], limit=1) - if not agv_start_site: + agv_start_sites = self.env['sf.agv.site'].sudo().search([('name', '=', agv_start_site_name)]) + if not agv_start_sites: raise UserError(_('不存在名称为【%s】的接驳站,请先创建!' % agv_start_site_name)) # 如果存在相同任务类型工单的AGV调度任务,则提示错误 agv_scheduling = self.sudo().search([ @@ -107,24 +108,32 @@ class AgvScheduling(models.Model): (','.join(repetitive_workorders.mapped('production_id.name')), agv_scheduling.name) ) + # 如果只有唯一任务路线,则自动赋予终点接驳站跟任务名称 + agv_routes = self.env['sf.agv.task.route'].sudo().search([ + ('route_type', '=', agv_route_type), + ('start_site_id', 'in', agv_start_sites.ids) + ]) vals = { - 'start_site_id': agv_start_site.id, 'agv_route_type': agv_route_type, 'workorder_ids': workorders.ids, # 'workpiece_delivery_ids': deliveries.mapped('id') if deliveries else [], 'task_create_time': fields.Datetime.now() } - # 如果只有唯一任务路线,则自动赋予终点接驳站跟任务名称 - agv_routes = self.env['sf.agv.task.route'].sudo().search([ - ('route_type', '=', agv_route_type), - ('start_site_id', '=', agv_start_site.id) - ]) if not agv_routes: raise UserError(_('不存在起点为【%s】的【%s】任务路线,请先创建!' % (agv_start_site_name, agv_route_type))) + # 如果路线中包含起点与终点相同的接驳站,则不创建AGV调度任务 + if agv_routes.filtered(lambda r: r.start_site_id.name == r.end_site_id.name): + return True + # 配送类型相同的接驳站为同一个,取第一个即可 + vals.update({ + 'start_site_id': agv_routes[0].start_site_id.id, + }) idle_route = None if len(agv_routes) == 1: idle_route = agv_routes[0] - vals.update({'end_site_id': idle_route.end_site_id.id, 'agv_route_id': idle_route.id}) + vals.update({ + 'end_site_id': idle_route.end_site_id.id, 'agv_route_id': idle_route.id + }) else: # 判断终点接驳站是否为空闲 idle_routes = agv_routes.filtered(lambda r: r.end_site_id.state == '空闲') @@ -132,7 +141,10 @@ class AgvScheduling(models.Model): # 将空闲的路线按照终点接驳站名称排序 idle_routes = sorted(idle_routes, key=lambda r: r.end_site_id.name) idle_route = idle_routes[0] - vals.update({'end_site_id': idle_route.end_site_id.id, 'agv_route_id': idle_route.id}) + vals.update({ + 'end_site_id': idle_route.end_site_id.id, 'agv_route_id': idle_route.id + }) + try: scheduling = self.env['sf.agv.scheduling'].sudo().create(vals) # 触发空闲接驳站状态更新,触发新任务下发 @@ -142,7 +154,7 @@ class AgvScheduling(models.Model): except Exception as e: _logger.error('添加AGV调度任务失败: %s', e) raise UserError(_('添加AGV调度任务失败: %s', e)) - + return scheduling def on_site_state_change(self, agv_site_id, agv_site_state): diff --git a/sf_manufacturing/models/agv_setting.py b/sf_manufacturing/models/agv_setting.py index 820ed539..d33ea9b4 100644 --- a/sf_manufacturing/models/agv_setting.py +++ b/sf_manufacturing/models/agv_setting.py @@ -24,7 +24,7 @@ class AgvSetting(models.Model): # name必须唯一 _sql_constraints = [ - ('name_uniq', 'unique (name)', '站点编号必须唯一!'), + ('name_uniq', 'unique (name, workcenter_id)', '同一工作中心的站点编号必须唯一!'), ] # def update_site_state(self): @@ -68,11 +68,12 @@ class AgvSetting(models.Model): """ if isinstance(agv_site_state_arr, dict): for agv_site_name, is_occupy in agv_site_state_arr.items(): - agv_site = self.env['sf.agv.site'].sudo().search([('name', '=', agv_site_name)]) - if agv_site: - agv_site.state = is_occupy + agv_sites = self.env['sf.agv.site'].sudo().search([('name', '=', agv_site_name)]) + if agv_sites: + agv_sites.state = is_occupy if notify: - self.env['sf.agv.scheduling'].on_site_state_change(agv_site.id, agv_site.state) + for agv_site in agv_sites: + self.env['sf.agv.scheduling'].on_site_state_change(agv_site.id, agv_site.state) else: _logger.error("更新失败:接驳站站点错误!%s" % agv_site_name) raise UserError("更新失败:接驳站站点错误!") diff --git a/sf_manufacturing/wizard/workpiece_delivery_wizard.py b/sf_manufacturing/wizard/workpiece_delivery_wizard.py index c41a7619..b100325e 100644 --- a/sf_manufacturing/wizard/workpiece_delivery_wizard.py +++ b/sf_manufacturing/wizard/workpiece_delivery_wizard.py @@ -117,17 +117,30 @@ class WorkpieceDeliveryWizard(models.TransientModel): item.button_finish() # return scheduling.read()[0] - return { - 'type': 'ir.actions.client', - 'tag': 'display_notification', - 'target': 'new', - 'params': { - 'message': f'任务下发成功!AGV任务调度编号为【{scheduling.name}】', - 'type': 'success', - 'sticky': False, - 'next': {'type': 'ir.actions.act_window_close'}, + if isinstance(scheduling, bool) and scheduling is True: + return{ + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'target': 'new', + 'params': { + 'message': f'解除装夹成功', + 'type': 'success', + 'sticky': False, + 'next': {'type': 'ir.actions.act_window_close'}, + } + } + else: + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'target': 'new', + 'params': { + 'message': f'任务下发成功!AGV任务调度编号为【{scheduling.name}】', + 'type': 'success', + 'sticky': False, + 'next': {'type': 'ir.actions.act_window_close'}, + } } - } except Exception as e: logging.info('%s任务下发失败:%s', self.delivery_type, e) raise UserError(f'{self.delivery_type}任务下发失败:{e}') from e From 315e2aa03d2cdee2b75a423bc5ce8b6baeca37e0 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Tue, 8 Apr 2025 15:56:08 +0800 Subject: [PATCH 06/27] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=88=80=E5=85=B7?= =?UTF-8?q?=E6=8B=86=E8=A7=A3=E5=AF=BF=E5=91=BD=E5=88=B0=E6=9C=9F=E5=88=80?= =?UTF-8?q?=E5=85=B7=E5=88=9B=E5=BB=BA=E6=96=B0=E7=9A=84=E7=BB=84=E8=A3=85?= =?UTF-8?q?=E5=8D=95=E6=97=B6=EF=BC=8C=E6=B7=BB=E5=8A=A0=E5=87=A0=E4=B8=AA?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E7=9A=84=E5=80=BC=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_tool_management/models/base.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py index 2fcc40d9..a9ee08be 100644 --- a/sf_tool_management/models/base.py +++ b/sf_tool_management/models/base.py @@ -1533,6 +1533,10 @@ class FunctionalToolDismantle(models.Model): 'functional_tool_name': self.functional_tool_id.name, 'handle_code_id': self.handle_lot_id.id, 'handle_product_id': self.handle_product_id.id, + 'functional_tool_diameter': self.functional_tool_id.functional_tool_diameter, + 'knife_tip_r_angle': self.functional_tool_id.knife_tip_r_angle, + 'tool_loading_length': self.functional_tool_id.tool_loading_length, + 'functional_tool_length': self.functional_tool_id.functional_tool_length, 'loading_task_source': '3', 'use_tool_time': fields.Datetime.now() + timedelta(hours=4), 'reason_for_applying': '刀具寿命到期' From c40ecfb6cec9e25d426b7c1d3f269d68ae39d39f Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Tue, 8 Apr 2025 17:00:00 +0800 Subject: [PATCH 07/27] =?UTF-8?q?=E5=B0=86=E5=AF=BF=E5=91=BD=E5=88=B0?= =?UTF-8?q?=E6=9C=9F=E6=8B=86=E8=A7=A3=E5=88=9B=E5=BB=BA=E7=9A=84=E7=BB=84?= =?UTF-8?q?=E8=A3=85=E5=8D=95=E6=B7=BB=E5=8A=A0=E5=88=B0=E5=AF=B9=E5=BA=94?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E5=BA=93=E5=AD=98=E7=BB=84=E8=A3=85=E5=8D=95?= =?UTF-8?q?=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_tool_management/models/base.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py index a9ee08be..505ede36 100644 --- a/sf_tool_management/models/base.py +++ b/sf_tool_management/models/base.py @@ -1542,6 +1542,9 @@ class FunctionalToolDismantle(models.Model): 'reason_for_applying': '刀具寿命到期' }) + # 将新的组装单更新到对应的功能刀具安全库存的组装单列表中 + self.functional_tool_id.safe_inventory_id.sudo().sf_functional_tool_assembly_ids = [(4, assembly_id.id)] + return { 'type': 'ir.actions.act_window', 'res_model': 'sf.functional.tool.assembly', From 2bae98950ed46d5ce47cfecf4d48a03d494ff1cf Mon Sep 17 00:00:00 2001 From: hyyy <123@qq.com> Date: Wed, 9 Apr 2025 13:57:48 +0800 Subject: [PATCH 08/27] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=88=80=E5=85=B7?= =?UTF-8?q?=E7=BB=84=E8=A3=85=E4=BC=98=E5=8C=96=E9=9C=80=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_tool_management/__manifest__.py | 1 + .../static/images/replaceIcon.png | Bin 0 -> 785 bytes sf_tool_management/static/src/change.scss | 50 +++++++++++++----- sf_tool_management/views/tool_base_views.xml | 6 +-- 4 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 sf_tool_management/static/images/replaceIcon.png diff --git a/sf_tool_management/__manifest__.py b/sf_tool_management/__manifest__.py index 8baa540f..837a8f2e 100644 --- a/sf_tool_management/__manifest__.py +++ b/sf_tool_management/__manifest__.py @@ -38,6 +38,7 @@ 'web.assets_qweb': [ ], 'web.assets_backend': [ + 'sf_tool_management/static/src/change.scss' ] }, diff --git a/sf_tool_management/static/images/replaceIcon.png b/sf_tool_management/static/images/replaceIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..12d2852f75c99bc654d3f6e25fed6a4766f1a670 GIT binary patch literal 785 zcmV+s1Md8ZP)Px%%Sl8*R9HvFmrqC(Q5?s=Z)Oz=^~t7)_J@)vLRqvtba3qtWPxCNP_e62riR@- z2ah z=e_s){pLLaiwCh-AEp58^Y-%*61fk83IN66IHN3p;1_^Za4d>k{1CVm_-=Gzh5&Ns za_>lj^n!pqG!mGDzZWFoW$?;Bn-U7IumiVF5l0>9O+s^G3tvH$hQSn&-mrf`ibN5R`dY}by96;Xo9qRoLD^Fx! zVyD^7#N#*yKs|IM?K9WgE;%Qhtof)}9DtndT;QMd;+*6=k;vVn)e#4fvyk)7XsM+O zA(v>VD&&g!s{qj^vzBgP+0T{dLO2qJ`?ot~7?Fz?V$DhgpbPXdfY<2)G!-_X|8l?L z-n!C?@y+p6p`NfR_U538MhErKVQ|DHh*6kodo`v?rd0ExA4BL|?M&`YFv6VdSt7tk zaNIL08nbg`IWS#1jr@#!Wy%}!qQTdI(0(WtfSWm4bv(cV{hF%wsg0sAvk=QW%WB|) z%mPf5OrSigT$$VWyMcONJ$zxG-a3|86}w>yV6J=)Wm#nyTpvW2ze^DqyEcZ}yjoSP z(btICfZRZJhX#O$COv{mT8SCQj2dMAP+1R6)6lZ0(& z+t6Fwt0^$BK7ek2w=wYp0F5LxP=&ejV(x%jId_xeco`aPMD6F=(Q~l} zA`!8*w}sL#rP!5rP3dbkA~}N5R$P-;gO;Ke^sV(_J~(emJZUSIqgehkk|8Yp9V>fj z^@T)cu=Yw8O({z+rD|GRc`ZL$Th={H5-QxXr span { + color: #999; + } +} \ 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 8f986858..be0b5a3f 100644 --- a/sf_tool_management/views/tool_base_views.xml +++ b/sf_tool_management/views/tool_base_views.xml @@ -534,7 +534,7 @@ - + @@ -555,14 +555,14 @@ - + - + From cf8c14e7380eaec81b7800c58242ec8e5ffaa46b Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Wed, 9 Apr 2025 15:22:41 +0800 Subject: [PATCH 09/27] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E8=8C=83=E5=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- quality_control/views/quality_views.xml | 2 +- sf_machine_connect/controllers/controllers.py | 25 +++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/quality_control/views/quality_views.xml b/quality_control/views/quality_views.xml index 38de9e4e..528003e3 100644 --- a/quality_control/views/quality_views.xml +++ b/quality_control/views/quality_views.xml @@ -267,7 +267,7 @@ - + diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index 4385937c..0017e2ae 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -567,7 +567,7 @@ class Sf_Dashboard_Connect(http.Controller): """ res = {'status': 1, 'message': '成功', 'data': {}} # plan_obj = request.env['sf.production.plan'].sudo() - plan_obj = request.env['mrp.workorder'].sudo().search([('routing_type', '=', 'CNC加工')]) + # plan_obj = request.env['mrp.workorder'].sudo().search([('routing_type', '=', 'CNC加工')]) line_list = ast.literal_eval(kw['line_list']) begin_time_str = kw['begin_time'].strip('"') end_time_str = kw['end_time'].strip('"') @@ -617,11 +617,19 @@ class Sf_Dashboard_Connect(http.Controller): for time_interval in time_intervals: start_time, end_time = time_interval - orders = plan_obj.search([ - ('production_id.production_line_id.name', '=', line), + # orders = plan_obj.search([ + # ('production_line_id.name', '=', line), + # ('state', 'in', ['done']), + # (date_field_name, '>=', start_time.strftime('%Y-%m-%d %H:%M:%S')), + # (date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) # 包括结束时间 + # ]) + + orders = request.env['mrp.workorder'].sudo().search([ + ('routing_type', '=', 'CNC加工'), # 将第一个条件合并进来 + ('production_line_id.name', '=', line), ('state', 'in', ['done']), (date_field_name, '>=', start_time.strftime('%Y-%m-%d %H:%M:%S')), - (date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) # 包括结束时间 + (date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) ]) # 使用小时和分钟作为键,确保每个小时的数据有独立的键 @@ -638,18 +646,21 @@ class Sf_Dashboard_Connect(http.Controller): for date in date_list: next_day = date + timedelta(days=1) - orders = plan_obj.search([('production_id.production_line_id.name', '=', line), ('state', 'in', ['done']), + orders = request.env['mrp.workorder'].sudo().search([('production_id.production_line_id.name', '=', line), ('state', 'in', ['done']), + ('routing_type', '=', 'CNC加工'), (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) ]) - rework_orders = plan_obj.search( + rework_orders = request.env['mrp.workorder'].sudo().search( [('production_id.production_line_id.name', '=', line), ('state', 'in', ['rework']), + ('routing_type', '=', 'CNC加工'), (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) ]) - not_passed_orders = plan_obj.search( + not_passed_orders = request.env['mrp.workorder'].sudo().search( [('production_id.production_line_id.name', '=', line), ('state', 'in', ['scrap', 'cancel']), + ('routing_type', '=', 'CNC加工'), (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) ]) From ddb0c304b9957630f3aa486ae85dc71bc864fffd Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Wed, 9 Apr 2025 15:57:13 +0800 Subject: [PATCH 10/27] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index 0017e2ae..9fb69303 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -414,7 +414,7 @@ class Sf_Dashboard_Connect(http.Controller): # 工单计划量切换为CNC工单 plan_data_total_counts = work_order_obj.search_count( - [('production_id.production_line_id.name', '=', line), + [('production_line_id.name', '=', line), ('id', '!=', 8061), ('state', 'in', ['ready', 'progress', 'done']), ('routing_type', '=', 'CNC加工')]) # # 工单完成量 @@ -423,13 +423,13 @@ class Sf_Dashboard_Connect(http.Controller): # 工单完成量切换为CNC工单 plan_data_finish_counts = work_order_obj.search_count( - [('production_id.production_line_id.name', '=', line), + [('production_line_id.name', '=', line), ('state', 'in', ['done']), ('routing_type', '=', 'CNC加工')]) # 超期完成量 # 搜索所有已经完成的工单 plan_data_overtime = work_order_obj.search([ - ('production_id.production_line_id.name', '=', line), + ('production_line_id.name', '=', line), ('state', 'in', ['done']), ('routing_type', '=', 'CNC加工') ]) From 6c926bf08103a85af45fafab6d7203a4040ac7e6 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Wed, 9 Apr 2025 16:39:21 +0800 Subject: [PATCH 11/27] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=B4=A8=E6=A3=80?= =?UTF-8?q?=E5=8F=96=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index 9fb69303..ad958485 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -448,9 +448,14 @@ class Sf_Dashboard_Connect(http.Controller): ]) # 过滤出那些检测结果状态为 '返工' 或 '报废' 的记录 - faulty_plans = plan_data.filtered(lambda p: any( - result.test_results in ['返工', '报废'] for result in p.production_id.detection_result_ids - )) + # faulty_plans = plan_data.filtered(lambda p: any( + # result.test_results in ['返工', '报废'] for result in p.production_id.detection_result_ids + # )) + + faulty_plans = request.env['quality.check'].sudo().search([ + ('operation_id.name', '=', 'CNC加工'), + ('quality_state', 'in', ['fail']) + ]) # 查找制造订单取消与归档的数量 cancel_order_count = production_obj.search_count( From bdf4696c089fa49db3f30a9538bfb67e363defa7 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Wed, 9 Apr 2025 16:56:53 +0800 Subject: [PATCH 12/27] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=BE=85=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E5=B7=A5=E5=8D=95=E6=98=8E=E7=BB=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index ad958485..dcfa3ea2 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -767,11 +767,14 @@ class Sf_Dashboard_Connect(http.Controller): for line in line_list: # 未完成订单 - not_done_orders = plan_obj.search( - [('production_line_id.name', '=', line), ('state', 'not in', ['finished']), - ('production_id.state', 'not in', ['cancel', 'done']), ('active', '=', True) + # not_done_orders = plan_obj.search( + # [('production_line_id.name', '=', line), ('state', 'not in', ['finished']), + # ('production_id.state', 'not in', ['cancel', 'done']), ('active', '=', True) + # ]) + not_done_orders = request.env['mrp.workorder'].sudo().search( + [('production_line_id.name', '=', line), ('state', 'in', ['ready', 'progress']), + ('routing_type', '=', 'CNC加工') ]) - # print(not_done_orders) # 完成订单 # 获取当前时间,并计算24小时前的时间 @@ -823,16 +826,18 @@ class Sf_Dashboard_Connect(http.Controller): 'draft': '待排程', 'done': '已排程', 'processing': '生产中', - 'finished': '已完成' + 'finished': '已完成', + 'ready': '待加工', + 'progress': '生产中', } line_dict = { 'sequence': id_to_sequence[order.id], - 'workorder_name': order.name, + 'workorder_name': order.production_id.name, 'blank_name': blank_name, 'material': material, 'dimensions': dimensions, - 'order_qty': order.product_qty, + 'order_qty': 1, 'state': state_dict[order.state], } From 3fb56f15c8398e9870a357485b859668ddadebae Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Thu, 10 Apr 2025 14:24:25 +0800 Subject: [PATCH 13/27] =?UTF-8?q?=E5=A4=84=E7=90=86=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=88=80=E5=85=B7=E7=BB=84=E8=A3=85=E6=97=B6=EF=BC=8C=E6=9C=89?= =?UTF-8?q?=E6=97=B6=E6=89=AB=E6=8F=8F=E8=B4=A7=E4=BD=8D=E7=BC=96=E7=A0=81?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E5=88=80=E5=85=B7=E4=BF=A1=E6=81=AF=E6=89=AB?= =?UTF-8?q?=E4=B8=8D=E5=88=B0=E8=B4=A7=E4=BD=8D=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_tool_management/models/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py index 505ede36..72be50dd 100644 --- a/sf_tool_management/models/base.py +++ b/sf_tool_management/models/base.py @@ -387,7 +387,7 @@ class FunctionalToolAssembly(models.Model): else: raise ValidationError('刀柄选择错误,请重新确认!!!') else: - location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', barcode)]) + location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', barcode.upper())]) if location: if location == record.integral_freight_barcode_id: tool_assembly_id.integral_verify = True From 87786dbd8000cd3e14edb7e1f7f145aad3707a25 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Fri, 11 Apr 2025 14:16:18 +0800 Subject: [PATCH 14/27] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=95=85=E9=9A=9C?= =?UTF-8?q?=E6=97=B6=E9=95=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index dcfa3ea2..19d0f17e 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -926,7 +926,10 @@ class Sf_Dashboard_Connect(http.Controller): for row in result2: alarm_count.append(row[1]) if row[0]: - total_alarm_time += abs(float(row[0])) + if float(row[0]) >= 28800: + continue + # total_alarm_time += abs(float(row[0])) + total_alarm_time += float(row[0]) else: total_alarm_time += 0.0 if len(list(set(alarm_count))) == 1: @@ -1353,7 +1356,7 @@ class Sf_Dashboard_Connect(http.Controller): for result in results: alarm_last_24_nums.append(result[1]) if result[0]: - if float(result[0]) >= 1000: + if float(result[0]) >= 28800: continue alarm_last_24_time += float(result[0]) else: @@ -1371,7 +1374,7 @@ class Sf_Dashboard_Connect(http.Controller): for result in results: alarm_all_nums.append(result[1]) if result[0]: - if float(result[0]) >= 1000: + if float(result[0]) >= 28800: continue alarm_all_time += float(result[0]) else: From cc030957fb0d12d029c6106948494457baa6b6e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Fri, 11 Apr 2025 16:02:24 +0800 Subject: [PATCH 15/27] =?UTF-8?q?=E7=BB=99=E4=BB=93=E5=82=A8=E5=B2=97?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BF=AE=E6=94=B9=E5=B7=A5=E5=8D=95=E7=9A=84?= =?UTF-8?q?=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_warehouse/security/ir.model.access.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_warehouse/security/ir.model.access.csv b/sf_warehouse/security/ir.model.access.csv index 88514fd3..1510e854 100644 --- a/sf_warehouse/security/ir.model.access.csv +++ b/sf_warehouse/security/ir.model.access.csv @@ -150,4 +150,4 @@ access_sf_shelf_lot_group_user,sf.shelf.location.lot.group_user,model_sf_shelf_l access_ir_model_group_sf_stock_user,ir_model_group_sf_stock_user,base.model_ir_model,sf_base.group_sf_stock_user,1,1,0,0 -access_mrp_workorder_group_sf_stock_user,mrp_workorder_group_sf_stock_user,mrp.model_mrp_workorder,sf_base.group_sf_stock_user,1,0,0,0 +access_mrp_workorder_group_sf_stock_user,mrp_workorder_group_sf_stock_user,mrp.model_mrp_workorder,sf_base.group_sf_stock_user,1,1,0,0 From 17fdf20e0371510efd13297bfe44f3e3a3b1aa0b Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Mon, 14 Apr 2025 10:30:51 +0800 Subject: [PATCH 16/27] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=88=80=E5=85=B7?= =?UTF-8?q?=E7=BB=84=E8=A3=85=E8=87=AA=E5=8A=A8=E6=A0=B9=E6=8D=AEBOM?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=88=9D=E5=A7=8B=E7=89=A9=E6=96=99=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_tool_management/models/base.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py index 72be50dd..2fa805b1 100644 --- a/sf_tool_management/models/base.py +++ b/sf_tool_management/models/base.py @@ -782,7 +782,8 @@ class FunctionalToolAssembly(models.Model): """根据BOM对刀具物料进行初始配置""" options = bom.get('options') # 配置刀柄信息 - for handle_id in bom.get('handle_ids'): + handle_ids = self._get_old_tool_material_lot(bom.get('handle_ids')) + for handle_id in handle_ids: if handle_id: if not self.handle_product_id: self.handle_product_id = handle_id.id @@ -820,19 +821,20 @@ class FunctionalToolAssembly(models.Model): location_id = self.env['stock.location'].search([('name', '=', '刀具房')]) stock_quant = self.env['stock.quant'].sudo().search( [('location_id', '=', location_id.id), ('product_id', 'in', material_ids.ids), ('quantity', '>', '0')], - order='lot_id', limit=1) + order='lot_id') if stock_quant: - return stock_quant.lot_id + return [quant.lot_id for quant in stock_quant] else: raise ValidationError(f'【{material_ids[0].cutting_tool_material_id.name}】物料库存不足,请先进行盘点或采购') - def _get_shelf_location_lot(self, lot_id): + def _get_shelf_location_lot(self, lot_ids): """根据所给的刀具物料批次号,返回一个刀具物料货位、批次信息""" - location_lots = self.env['sf.shelf.location.lot'].sudo().search([('lot_id', '=', lot_id.id)]) - if not location_lots: - raise ValidationError(f'没有查询到批次为【{lot_id.name}】物料的货位信息!') - else: - return location_lots[0] + for lot_id in lot_ids: + location_lots = self.env['sf.shelf.location.lot'].sudo().search([('lot_id', '=', lot_id.id)]) + if location_lots: + return location_lots[0] + raise ValidationError(f'【{lot_ids[0].product_id.cutting_tool_material_id.name}】物料在货位库存不足,请先进行盘点入库') + def _get_inventory_bom(self, inventory_id): """获取BOM的刀具物料产品信息""" From 37edc858c2d39739385fc3f43e1b832599f514c9 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Mon, 14 Apr 2025 10:32:26 +0800 Subject: [PATCH 17/27] 1 --- sf_tool_management/models/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py index 2fa805b1..3d9ec5ee 100644 --- a/sf_tool_management/models/base.py +++ b/sf_tool_management/models/base.py @@ -786,7 +786,7 @@ class FunctionalToolAssembly(models.Model): for handle_id in handle_ids: if handle_id: if not self.handle_product_id: - self.handle_product_id = handle_id.id + self.handle_product_id = handle_id.product_id.id break # 刀柄之外的物料配置 From 91d79008e107ea88b68821951be1a76a12c8400b Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Mon, 14 Apr 2025 11:21:24 +0800 Subject: [PATCH 18/27] =?UTF-8?q?=E6=95=85=E9=9A=9C=E6=97=B6=E9=95=BF?= =?UTF-8?q?=E6=8F=90=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 58 ++++++++++++++++--- .../data/insepection_report_template.xml | 4 ++ 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index 19d0f17e..d5c8c7cb 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -18,6 +18,11 @@ db_config = { "host": "172.16.10.131" } +# 基础数据 +TotalAlarmTime = 0 +TodayAlarmTime = 0 +MonthAlarmTime = 0 + def convert_to_seconds(time_str): # 修改正则表达式,使 H、M、S 部分可选 @@ -455,7 +460,7 @@ class Sf_Dashboard_Connect(http.Controller): faulty_plans = request.env['quality.check'].sudo().search([ ('operation_id.name', '=', 'CNC加工'), ('quality_state', 'in', ['fail']) - ]) + ]) # 查找制造订单取消与归档的数量 cancel_order_count = production_obj.search_count( @@ -651,11 +656,12 @@ class Sf_Dashboard_Connect(http.Controller): for date in date_list: next_day = date + timedelta(days=1) - orders = request.env['mrp.workorder'].sudo().search([('production_id.production_line_id.name', '=', line), ('state', 'in', ['done']), - ('routing_type', '=', 'CNC加工'), - (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), - (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) - ]) + orders = request.env['mrp.workorder'].sudo().search( + [('production_id.production_line_id.name', '=', line), ('state', 'in', ['done']), + ('routing_type', '=', 'CNC加工'), + (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), + (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) + ]) rework_orders = request.env['mrp.workorder'].sudo().search( [('production_id.production_line_id.name', '=', line), ('state', 'in', ['rework']), @@ -892,6 +898,8 @@ class Sf_Dashboard_Connect(http.Controller): # 获取请求的机床数据 machine_list = ast.literal_eval(kw['machine_list']) total_alarm_time = 0 + today_alarm_time = 0 + month_alarm_time = 0 alarm_count_num = 0 for item in machine_list: sql = ''' @@ -904,6 +912,11 @@ class Sf_Dashboard_Connect(http.Controller): ) subquery; ''' + # 计算时间范围 + now = datetime.now() + today_start = now.replace(hour=0, minute=0, second=0, microsecond=0) + month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0) + sql2 = ''' SELECT DISTINCT ON (alarm_start_time) alarm_time, alarm_start_time FROM device_data @@ -918,8 +931,16 @@ class Sf_Dashboard_Connect(http.Controller): cur.execute(sql2, (item,)) result2 = cur.fetchall() - # print('result2========', result2) - # + today_data = [] + month_data = [] + + for record in result2: + alarm_start = datetime.strptime(record[1], "%Y-%m-%d %H:%M:%S") + if alarm_start >= today_start: + today_data.append(record) + if alarm_start >= month_start: + month_data.append(record) + for row in result: res['data'][item] = {'idle_count': row[0]} alarm_count = [] @@ -939,7 +960,28 @@ class Sf_Dashboard_Connect(http.Controller): alarm_count_num = 1 else: alarm_count_num = len(list(set(alarm_count))) + + for today in today_data: + if today[0]: + if float(today[0]) >= 28800: + continue + today_alarm_time += float(today[0]) + else: + today_alarm_time += 0.0 + for month in month_data: + if month[0]: + if float(month[0]) >= 28800: + continue + month_alarm_time += float(month[0]) + else: + month_alarm_time += 0.0 + + TotalAlarmTime = total_alarm_time / 3600 + TodayAlarmTime = today_alarm_time / 3600 + MonthAlarmTime = month_alarm_time / 3600 + logging.info('=====AlarmTime===== %s, %s, %s' % (TotalAlarmTime, TodayAlarmTime, MonthAlarmTime)) res['data'][item]['total_alarm_time'] = total_alarm_time / 3600 + logging.info('=======================') res['data'][item]['alarm_count_num'] = alarm_count_num # 返回统计结果 diff --git a/sf_quality/data/insepection_report_template.xml b/sf_quality/data/insepection_report_template.xml index d989137c..14a42065 100644 --- a/sf_quality/data/insepection_report_template.xml +++ b/sf_quality/data/insepection_report_template.xml @@ -78,6 +78,10 @@

公司邮箱:

+ +
+ 1 页/共 1 +
产品名称: 材料: