From 941b8c0be71ac4dc986606c3539ca4cb799d058e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Thu, 13 Feb 2025 11:31:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=B5=8B=E8=AF=95=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=B8=85=E7=90=86=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jikimo_test_assistant/__init__.py | 3 + jikimo_test_assistant/__manifest__.py | 32 ++++++ jikimo_test_assistant/controllers/__init__.py | 2 + jikimo_test_assistant/controllers/main.py | 86 ++++++++++++++++ jikimo_test_assistant/models/__init__.py | 1 + .../security/ir.model.access.csv | 2 + .../static/src/js/data_clean_confirm.js | 50 ++++++++++ jikimo_test_assistant/wizards/__init__.py | 2 + .../wizards/jikimo_data_clean_wizard.py | 99 +++++++++++++++++++ .../wizards/jikimo_data_clean_wizard.xml | 47 +++++++++ sf_quality/views/quality_check_view.xml | 10 +- 11 files changed, 330 insertions(+), 4 deletions(-) create mode 100644 jikimo_test_assistant/__init__.py create mode 100644 jikimo_test_assistant/__manifest__.py create mode 100644 jikimo_test_assistant/controllers/__init__.py create mode 100644 jikimo_test_assistant/controllers/main.py create mode 100644 jikimo_test_assistant/models/__init__.py create mode 100644 jikimo_test_assistant/security/ir.model.access.csv create mode 100644 jikimo_test_assistant/static/src/js/data_clean_confirm.js create mode 100644 jikimo_test_assistant/wizards/__init__.py create mode 100644 jikimo_test_assistant/wizards/jikimo_data_clean_wizard.py create mode 100644 jikimo_test_assistant/wizards/jikimo_data_clean_wizard.xml diff --git a/jikimo_test_assistant/__init__.py b/jikimo_test_assistant/__init__.py new file mode 100644 index 00000000..b6de2276 --- /dev/null +++ b/jikimo_test_assistant/__init__.py @@ -0,0 +1,3 @@ +from . import models +from . import controllers +from . import wizards diff --git a/jikimo_test_assistant/__manifest__.py b/jikimo_test_assistant/__manifest__.py new file mode 100644 index 00000000..f9902300 --- /dev/null +++ b/jikimo_test_assistant/__manifest__.py @@ -0,0 +1,32 @@ +{ + 'name': '机企猫 测试助手', + 'version': '16.0.1.0.0', + 'category': 'Technical', + 'summary': '测试数据初始化工具', + 'description': """ + 用于初始化测试环境数据的工具模块 + """, + 'author': 'Jikimo', + 'website': 'www.jikimo.com', + 'depends': [ + 'base', + 'sale_management', + 'purchase', + 'mrp', + 'stock', + 'account' + ], + 'data': [ + 'security/ir.model.access.csv', + 'wizards/jikimo_data_clean_wizard.xml', + ], + 'assets': { + 'web.assets_backend': [ + 'jikimo_test_assistant/static/src/js/data_clean_confirm.js', + ], + }, + 'installable': True, + 'application': False, + 'auto_install': False, + 'license': 'LGPL-3', +} \ No newline at end of file diff --git a/jikimo_test_assistant/controllers/__init__.py b/jikimo_test_assistant/controllers/__init__.py new file mode 100644 index 00000000..cd4d6a8b --- /dev/null +++ b/jikimo_test_assistant/controllers/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import main \ No newline at end of file diff --git a/jikimo_test_assistant/controllers/main.py b/jikimo_test_assistant/controllers/main.py new file mode 100644 index 00000000..b2ef6810 --- /dev/null +++ b/jikimo_test_assistant/controllers/main.py @@ -0,0 +1,86 @@ +from odoo import http +import logging +import os +import json +import sys + +_logger = logging.getLogger(__name__) + +class Main(http.Controller): + @http.route('/api/pdf2image', type='http', auth='public', methods=['POST'], csrf=False) + def convert_pdf_to_image(self, **kwargs): + """将PDF文件转换为图片文件 + + Returns: + dict: 包含转换后图片url的字典 + """ + res = {} + try: + # 检查poppler是否可用 + # if sys.platform.startswith('win'): + # if not os.environ.get('POPPLER_PATH'): + # return { + # 'code': 400, + # 'msg': '请先配置POPPLER_PATH环境变量' + # } + # else: + # import shutil + # if not shutil.which('pdftoppm'): + # return { + # 'code': 400, + # 'msg': '请先安装poppler-utils' + # } + + # 获取上传的PDF文件 + pdf_file = kwargs.get('file') + if not pdf_file: + res = {'code': 400, 'msg': '未找到上传的PDF文件'} + + # 检查文件类型 + if not pdf_file.filename.lower().endswith('.pdf'): + res = {'code': 400, 'msg': '请上传PDF格式的文件'} + + # 读取PDF文件内容 + pdf_content = pdf_file.read() + + # 使用pdf2image转换 + from pdf2image import convert_from_bytes + import tempfile + + # 转换PDF + with tempfile.TemporaryDirectory() as path: + images = convert_from_bytes(pdf_content) + image_urls = [] + + # 保存每一页为图片 + for i, image in enumerate(images): + image_path = os.path.join(path, f'page_{i+1}.jpg') + image.save(image_path, 'JPEG') + + # 将图片保存到ir.attachment + with open(image_path, 'rb') as img_file: + attachment = http.request.env['ir.attachment'].sudo().create({ + 'name': f'page_{i+1}.jpg', + 'datas': img_file.read(), + 'type': 'binary', + 'access_token': kwargs.get('access_token') or '123' + }) + image_urls.append({ + 'page': i+1, + 'url': f'/web/content/{attachment.id}' + }) + + res = { + 'code': 200, + 'msg': '转换成功', + 'data': image_urls + } + + except Exception as e: + _logger.error('PDF转换失败: %s', str(e)) + res = { + 'code': 500, + 'msg': f'转换失败: {str(e)}' + } + return json.JSONEncoder().encode(res) + diff --git a/jikimo_test_assistant/models/__init__.py b/jikimo_test_assistant/models/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/jikimo_test_assistant/models/__init__.py @@ -0,0 +1 @@ + diff --git a/jikimo_test_assistant/security/ir.model.access.csv b/jikimo_test_assistant/security/ir.model.access.csv new file mode 100644 index 00000000..2e334571 --- /dev/null +++ b/jikimo_test_assistant/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_jikimo_data_clean_wizard,jikimo_test_assistant.jikimo_data_clean_wizard,model_jikimo_data_clean_wizard,base.group_system,1,1,1,1 \ No newline at end of file diff --git a/jikimo_test_assistant/static/src/js/data_clean_confirm.js b/jikimo_test_assistant/static/src/js/data_clean_confirm.js new file mode 100644 index 00000000..a4cd07ec --- /dev/null +++ b/jikimo_test_assistant/static/src/js/data_clean_confirm.js @@ -0,0 +1,50 @@ +odoo.define('jikimo_test_assistant.action_clean_data_confirm', function (require) { + const core = require('web.core'); + const ajax = require('web.ajax'); + const Dialog = require('web.Dialog'); + var rpc = require('web.rpc'); + var _t = core._t; + + async function action_clean_data_confirm(parent, {params}) { + let message = "确认清理数据?
" + message += "日期:"+ params.date + "以前
" + message += "模型:" + params.model_names.join(',') + const dialog = new Dialog(parent, { + title: "确认", + $content: $('
').append(message), + buttons: [ + { text: "确认", classes: 'btn-primary jikimo_button_confirm', close: true, click: () => actionCleanDataConfirm(parent, params) }, + { text: "取消", close: true }, + ], + }); + dialog.open(); + + + async function actionCleanDataConfirm(parent, params) { + rpc.query({ + model: 'jikimo.data.clean.wizard', + method: 'action_clean_data', + args: [params.active_id], + kwargs: { + context: params.context, + } + }).then(res => { + parent.services.action.doAction({ + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'target': 'new', + 'params': { + 'message': '数据清理成功!', + 'type': 'success', + 'sticky': false, + 'next': {'type': 'ir.actions.act_window_close'}, + } + }); + }) + + } + } + + core.action_registry.add('action_clean_data_confirm', action_clean_data_confirm); + return action_clean_data_confirm; +}); diff --git a/jikimo_test_assistant/wizards/__init__.py b/jikimo_test_assistant/wizards/__init__.py new file mode 100644 index 00000000..2dadb00b --- /dev/null +++ b/jikimo_test_assistant/wizards/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import jikimo_data_clean_wizard \ No newline at end of file diff --git a/jikimo_test_assistant/wizards/jikimo_data_clean_wizard.py b/jikimo_test_assistant/wizards/jikimo_data_clean_wizard.py new file mode 100644 index 00000000..f08b114e --- /dev/null +++ b/jikimo_test_assistant/wizards/jikimo_data_clean_wizard.py @@ -0,0 +1,99 @@ +from odoo import models, fields, api +from datetime import datetime + +import logging + +_logger = logging.getLogger(__name__) + +class JikimoDataCleanWizard(models.TransientModel): + _name = 'jikimo.data.clean.wizard' + _description = '业务数据清理' + + date = fields.Date(string='截止日期', required=True, default=fields.Date.context_today) + model_ids = fields.Many2many('ir.model', string='业务模型', domain=[ + ('model', 'in', [ + 'sale.order', # 销售订单 + 'purchase.order', # 采购订单 + 'mrp.production', # 生产订单 + 'stock.picking', # 库存调拨 + 'account.move', # 会计凭证 + ]) + ]) + + def action_clean_data(self): + self.ensure_one() + model_list = self.model_ids.mapped('model') + + # 销售订单清理(排除已交付,已锁定,已取消) + if 'sale.order' in model_list: + self.model_cancel('sale.order', except_states=['delivered', 'done', 'cancel']) + + # 采购订单清理(排除采购订单,已锁定,已取消) + if 'purchase.order' in model_list: + self.model_cancel('purchase.order', except_states=['purchase', 'done', 'cancel']) + + # 生产订单清理(排除返工,报废,完成,已取消) + if 'mrp.production' in model_list: + self.model_cancel('mrp.production', except_states=['rework', 'scrap', 'done', 'cancel']) + + # 工单清理 (排除返工,完成,已取消) + if 'mrp.workorder' in model_list: + self.model_cancel('mrp.production', except_states=['rework', 'done', 'cancel']) + + # 排程单清理 (排除已完成,已取消) + if 'mrp.workorder' in model_list: + self.model_cancel('mrp.production', except_states=['finished', 'cancel']) + + # 工单库存移动 (排除完成,已取消) + if 'stock.move' in model_list: + self.model_cancel('stock.move') + + # 库存调拨清理 (排除完成,已取消) + if 'stock.picking' in model_list: + self.model_cancel('stock.picking') + + # 会计凭证清理 (排除已过账,已取消) + if 'account.move' in model_list: + self.model_cancel('account.move', except_states=['posted', 'cancel']) + + return True + + def model_cancel(self, model_name, state_field='state', to_state='cancel',except_states=('done', 'cancel')): + table = self.env[model_name]._table + if isinstance(except_states, list): + except_states = tuple(except_states) + sql = """ + UPDATE + %s SET %s = '%s' + WHERE + create_date < '%s' + AND state NOT IN %s +""" % (table, state_field, to_state, self.date.strftime('%Y-%m-%d'), except_states) + self.env.cr.execute(sql) + self.env.cr.commit() + + @api.model + def get_confirm_message(self): + date_str = self.date.strftime('%Y-%m-%d') if self.date else '' + model_names = ', '.join([model.name for model in self.model_ids]) + return { + 'date': date_str, + 'model_names': model_names + } + + def action_clean_data_confirm(self): + model_names = self.model_ids.mapped('display_name') + return { + 'type': 'ir.actions.client', + 'tag': 'action_clean_data_confirm', + 'params': { + 'model_names': model_names, + 'date': self.date, + 'active_id': self.id, + 'context': self.env.context + } + } + + + + diff --git a/jikimo_test_assistant/wizards/jikimo_data_clean_wizard.xml b/jikimo_test_assistant/wizards/jikimo_data_clean_wizard.xml new file mode 100644 index 00000000..d297bb3c --- /dev/null +++ b/jikimo_test_assistant/wizards/jikimo_data_clean_wizard.xml @@ -0,0 +1,47 @@ + + + + + jikimo.data.clean.wizard.form + jikimo.data.clean.wizard + +
+ + + + + + +
+
+
+
+
+ + + + 业务数据清理 + jikimo.data.clean.wizard + form + new + + + + + + +
\ No newline at end of file diff --git a/sf_quality/views/quality_check_view.xml b/sf_quality/views/quality_check_view.xml index 2b8143e6..00b139de 100644 --- a/sf_quality/views/quality_check_view.xml +++ b/sf_quality/views/quality_check_view.xml @@ -91,12 +91,14 @@ - - - - {'is_web_request': True, 'search_default_waiting': 1} + { + 'is_web_request': True, + 'search_default_progress': 1, + 'search_default_passed': 1, + 'search_default_failed': 1, + } \ No newline at end of file