diff --git a/list_view_sticky_header_and_column/README.rst b/list_view_sticky_header_and_column/README.rst index fd8816471..236e8a22b 100644 --- a/list_view_sticky_header_and_column/README.rst +++ b/list_view_sticky_header_and_column/README.rst @@ -1,3 +1,14 @@ + +.. image:: https://tools.huo15.com/uploads/images/system/logo-colours.png + :width: 100 + :alt: logo + +辉火云企业套件社区版 - 附加模块 +=========================== +HuihuoYun Business Suite Community addons +----------------------------------------- + + .. image:: https://img.shields.io/badge/license-LGPL--3-green.svg :target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html :alt: License: LGPL-3 diff --git a/list_view_sticky_header_and_column/static/src/js/list_view_sticky_header_and_column.js b/list_view_sticky_header_and_column/static/src/js/list_view_sticky_header_and_column.js index 3ab2197b4..b88965677 100644 --- a/list_view_sticky_header_and_column/static/src/js/list_view_sticky_header_and_column.js +++ b/list_view_sticky_header_and_column/static/src/js/list_view_sticky_header_and_column.js @@ -1,22 +1,173 @@ /** @odoo-module **/ /** This file will used to stick the selected header and column in the list view **/ -import { patch } from "@web/core/utils/patch"; -import { ListRenderer } from "@web/views/list/list_renderer"; +import {patch} from "@web/core/utils/patch"; +import {ListRenderer} from "@web/views/list/list_renderer"; +import {onMounted, onWillUnmount} from "@odoo/owl"; + +/** + * @file list_view_sticky_header_and_column.js + * @description 辉火云企业套件 + * @author Job Zhao - 青岛火一五信息科技有限公司 + * @contact postmaster@huo15.com | 18554898815 + * @date 2025/1/28 + * @copyright 青岛火一五信息科技有限公司 保留所有权利 + * @see https://www.huo15.com + */ patch(ListRenderer.prototype, { /** super the setup function **/ setup() { super.setup(); + // >>> 青岛火一五信息科技有限公司 - JobZhao - postmaster@huo15.com - 2025/1/28 + onMounted(() => { + this.root = this.__owl__.bdom.parentEl; + this._adjustColumnWidths(); + const $thead = $(this.__owl__.bdom.parentEl.querySelectorAll('.o_list_table thead')[0]); + $thead.css('z-index', '100000') + //移除现有的粘性列和选中标记 + const $clickedHeader = $(this.__owl__.bdom.parentEl.querySelectorAll('.o_list_table th')[1]); + $(this.__owl__.bdom.parentEl.querySelectorAll('.sticky-column')).removeClass('sticky-column'); + console.log($(this.__owl__.bdom.parentEl.querySelectorAll('.sticky-column')).removeClass('sticky-column')); + $(this.__owl__.bdom.parentEl.querySelectorAll('.clicked-header')).removeClass('clicked-header'); + $clickedHeader.addClass('clicked-header'); + const columnIndex = $clickedHeader.index(); + + //获取表头、表行和表尾的元素 + const $tableHeaders = $(this.__owl__.bdom.parentEl.querySelectorAll('.o_list_table th')); + const $tableRows = $(this.__owl__.bdom.parentEl.querySelectorAll('.o_list_table tr')); + const $tfootRow = $(this.__owl__.bdom.parentEl.querySelectorAll('.o_list_table tfoot tr')[0].children); + //为选中的列和表头添加粘性效果 + const $selectedFooterCells = $tfootRow.filter(`td:nth-child(-n+${columnIndex + 1})`); + $selectedFooterCells.addClass('sticky-column'); + const $selectedColumns = $(this.__owl__.bdom.parentEl.querySelectorAll(`.o_data_row td:nth-child(-n+${columnIndex + 1})`)); + const $selectedHeaderCells = $tableHeaders.filter(`th:nth-child(-n+${columnIndex + 1})`); + $tableHeaders.removeClass('sticky-column').css('left', ''); + $(this.__owl__.bdom.parentEl.querySelectorAll('.o_data_row td')).removeClass('sticky-column').css('left', ''); + $selectedColumns.addClass('sticky-column'); + $selectedHeaderCells.addClass('sticky-column'); + $tableHeaders.filter('.sticky-column').css('top', '0'); + + // 调整列的 left 位置 + const $targetColumn = $selectedColumns.eq(columnIndex); + const targetLeftPosition = $targetColumn.position().left; + const columnsToAdjust = columnIndex + 1; + $tableRows.each(function (index, row) { + const $headerCells = $(row).find('th'); + const $rowCells = $(row).find('td'); + for (let i = 0; i < columnsToAdjust; i++) { + if ($headerCells.eq(i).length > 0) { + $headerCells.eq(i).css('left', `${$headerCells.eq(i).position().left}px`); + } + if ($rowCells.eq(i).length > 0) { + $rowCells.eq(i).css('left', `${$rowCells.eq(i).position().left}px`); + } + } + }); + + // 监听窗口缩放事件 + this.resizeObserver = new ResizeObserver(() => { + this._adjustColumnWidths(); + }); + this.resizeObserver.observe(this.root); + }); + // 在组件卸载时停止监听 + onWillUnmount(() => { + if (this.resizeObserver) { + this.resizeObserver.disconnect(); + } + }); + }, + /** + * 调整列宽和换行逻辑 + */ + _adjustColumnWidths() { + // >>> 青岛火一五信息科技有限公司 - JobZhao - postmaster@huo15.com - 2025/1/28 + this.root = this.__owl__.bdom.parentEl; + + const table = this.root.querySelector(".o_list_table"); // 获取表格元素 + if (!table) return; + + const columns = table.querySelectorAll("th"); // 获取所有表头 + const rows = table.querySelectorAll(".o_data_row"); // 获取所有数据行 + + columns.forEach((column, colIndex) => { + let maxWidth = 0; + let maxContent = ""; + const thContent = column.textContent.trim(); + + console.log('th length:', thContent.length) + // 遍历每一行,找到最长的单元格内容 + rows.forEach((row) => { + const cell = row.querySelector(`td:nth-child(${colIndex + 1})`); + if (cell) { + const content = cell.textContent.trim(); + let isChinese = /[\u4e00-\u9fa5]/.test(thContent); // 判断是否包含汉字 + + let contentLength = content.length; + let thContentLength = thContent.length; + if (thContentLength<=2){ + thContentLength*=1.5; + } + if (isChinese) { + thContentLength *= 2.5; + } + if (contentLength <= thContentLength) { + contentLength = thContentLength; + } + isChinese = /[\u4e00-\u9fa5]/.test(content); // 判断是否包含汉字 + if (isChinese) { + contentLength *= 2; + } + // 更新最大宽度和最长内容 + if (contentLength > maxWidth) { + maxWidth = contentLength; + maxContent = content; + } + // 更新最大宽度和最长内容 + if (contentLength > maxWidth) { + maxWidth = contentLength; + maxContent = content; + } + } + }); + + // 设置列宽 + if (maxWidth > 0 && maxWidth < 30) { + const columnWidth = maxWidth * 1; // 假设每个字符占 8px + column.style.minWidth = `${columnWidth}ch`; + column.style.maxWidth = `${columnWidth}ch`; + column.style.width = `${columnWidth}ch`; + } else if (maxWidth >= 30) { + column.style.minWidth = `240px`; + column.style.maxWidth = `240px`; + column.style.width = `240px`; + } + + + // 如果最长内容超过 30 个字符,设置换行 + if (maxWidth > 30) { + rows.forEach((row) => { + const cell = row.querySelector(`td:nth-child(${colIndex + 1})`); + if (cell) { + console.log('cell:', cell) + cell.style.whiteSpace = "normal"; // 允许换行 + cell.style.wordWrap = "break-word"; // 允许长单词换行 + + } + }); + } + }); }, /** * function defining the button having t-on-click _onClick */ _onClickIcon(ev, record) { + ev.preventDefault(); ev.stopPropagation() + console.log('target current:', $(ev.currentTarget)) const $clickedHeader = $(ev.currentTarget).closest('th'); const columnIndex = $clickedHeader.index(); - console.log(this.__owl__.bdom.parentEl) $(this.__owl__.bdom.parentEl.querySelectorAll('.sticky-column')).removeClass('sticky-column'); console.log($(this.__owl__.bdom.parentEl.querySelectorAll('.sticky-column')).removeClass('sticky-column')) $(this.__owl__.bdom.parentEl.querySelectorAll('.clicked-header')).removeClass('clicked-header'); @@ -42,6 +193,7 @@ patch(ListRenderer.prototype, { for (let i = 0; i < columnsToAdjust; i++) { if ($headerCells.eq(i).length > 0) { $headerCells.eq(i).css('left', `${$headerCells.eq(i).position().left}px`); + } if ($rowCells.eq(i).length > 0) { $rowCells.eq(i).css('left', `${$rowCells.eq(i).position().left}px`); diff --git a/list_view_sticky_header_and_column/static/src/scss/list_view_sticky_header_and_column.scss b/list_view_sticky_header_and_column/static/src/scss/list_view_sticky_header_and_column.scss index 72dc1ebfa..dd90a4e9d 100644 --- a/list_view_sticky_header_and_column/static/src/scss/list_view_sticky_header_and_column.scss +++ b/list_view_sticky_header_and_column/static/src/scss/list_view_sticky_header_and_column.scss @@ -1,67 +1,99 @@ .o_action .o_content { - z-index: 1; + z-index: 1; } .sticky-column { - position: sticky !important; - background-color: white; - z-index: 2; + position: sticky !important; + background-color: white; + z-index: 2; } + .o_list_view .o_list_table td.sticky-column { - z-index: 4; - background-color: white; + z-index: 4; + background-color: white; } + .o_list_view .o_list_table thead { - position: sticky; - top: 0; - z-index: 3; - background-color: white; + position: sticky; + top: 0; + z-index: 3; + background-color: white; } + .o_list_view .o_list_table th.sticky-column { - z-index: 4; - background-color: white; + z-index: 4; + background-color: white; } + .o_account_reports_page .table-responsive { - overflow-x: auto; - overflow-y: visible; + overflow-x: auto; + overflow-y: visible; } + .table-responsive { - overflow: visible; + overflow: visible; } + .o_list_view .table-responsive .table thead { - z-index: 1; + z-index: 1; } + .o_form_view:not(.o_field_highlight) .o_field_widget:not(.o_field_invalid):not(.o_field_highlight) .o_input:not(:hover):not(:focus) { - --o-input-border-color: transparent; - //border-style: solid; - //border-color: #000; - //border-width: 0px; - //border-bottom-width: 1px; + --o-input-border-color: transparent; + //border-style: solid; + //border-color: #000; + //border-width: 0px; + //border-bottom-width: 1px; } + body.white .table { - width: -webkit-fill-available !important; + width: -webkit-fill-available !important; } + .o_list_renderer .o_list_table thead { - position: sticky; - top: 0; - z-index: 6; + position: sticky; + top: 0; + z-index: 6; } + th.sticky-column::before { - content: ""; - position: absolute; - width: 5px; - height: 100%; - background: white; - top: 0; - left: -4px; + content: ""; + position: absolute; + width: 5px; + height: 100%; + background: white; + top: 0; + left: -4px; } + .fa-thumb-tack { - display: none; + display: none; } th:hover .fa-thumb-tack, th.clicked-header .fa-thumb-tack { - display: block; + display: block; } //.o_input:hover{background: #b3c8df!important;} + + +// >>> 青岛火一五信息科技有限公司 - JobZhao - postmaster@huo15.com - 2025/1/28 +// 解决宽度调整 +.o_list_view { + .o_list_table { + table-layout: auto; // 让表格宽度根据内容自动调整 + width: 100%; // 确保表格宽度占满容器 + + th, td { + white-space: nowrap; // 默认不换行 + overflow: hidden; // 超出部分隐藏 + text-overflow: ellipsis; // 超出部分显示省略号 + } + + td.long-text { + white-space: normal; // 允许换行 + word-wrap: break-word; // 允许长单词换行 + } + } +} \ No newline at end of file diff --git a/soong_workflow/models/soong_workflow_log.py b/soong_workflow/models/soong_workflow_log.py index c506f6dfe..098850c5a 100644 --- a/soong_workflow/models/soong_workflow_log.py +++ b/soong_workflow/models/soong_workflow_log.py @@ -38,9 +38,9 @@ class SoongWorkflowLog(models.Model): done_by = fields.Many2one(comodel_name="res.users", string="审批人") lase_click_date = fields.Datetime(string="操作时间") approval_state = fields.Selection([ - ('0', '待审批'), - ('1', '审批中'), - ('2', '已审批'), + ('0', '待办'), + ('1', '办理中'), + ('2', '已办结'), ], string='审批状态', default='0') comment = fields.Char(string="意见") date_create = fields.Datetime(string="时间", default=lambda self: fields.Datetime.now()) diff --git a/soong_workflow/models/soong_workflow_mixin.py b/soong_workflow/models/soong_workflow_mixin.py index 9bf63e307..53439c51a 100644 --- a/soong_workflow/models/soong_workflow_mixin.py +++ b/soong_workflow/models/soong_workflow_mixin.py @@ -155,7 +155,7 @@ class SoongWorkflowMixin(models.AbstractModel): log_ids = fields.One2many( comodel_name="soong.workflow.log", inverse_name="res_id", - string="Logs", + string=" ", domain=lambda self: [("model", "=", self._name)], auto_join=True, ) @@ -716,6 +716,8 @@ class SoongWorkflowMixin(models.AbstractModel): if button.is_highlight: btn_exec_action_el.set("class", "oe_highlight") + # if button.is_high_red: + # btn_exec_action_el.set("style", "background-color: red !important;color: white !important;") if button.has_icon: btn_exec_action_el.set("icon", button.icon) if is_review_type_invisible: diff --git a/soong_workflow/models/soong_workflow_node.py b/soong_workflow/models/soong_workflow_node.py index dcf96f447..bb5189ed2 100644 --- a/soong_workflow/models/soong_workflow_node.py +++ b/soong_workflow/models/soong_workflow_node.py @@ -84,10 +84,9 @@ class SoongWorkflowNode(models.Model): res_bg_color = fields.Char(compute="_compute_custom_colors", readonly=True, string="Backgroung Color") res_label_color = fields.Char(compute="_compute_custom_colors", readonly=True, string="Label Color") - is_carbon_copy = fields.Boolean(string="抄送") + is_carbon_copy = fields.Boolean(string="抄送/传阅") is_apostille = fields.Boolean(string="加签", default=False) - employee_ids = fields.Many2many('hr.employee', string='抄送人员') - + employee_ids = fields.Many2many('hr.employee', string='抄送/传阅人员') @api.onchange("is_apostille") def onchange_is_apostille(self): @@ -95,7 +94,7 @@ class SoongWorkflowNode(models.Model): if record.is_apostille: sequence = max([r.sequence for r in record.button_ids] if record.button_ids else [1]) record.button_ids = [ - (0, 0, { + (0, 0, { "name": _("加签"), "workflow_id": record.workflow_id, "node_id": record.id, @@ -117,60 +116,76 @@ class SoongWorkflowNode(models.Model): else: record.button_ids.filtered(lambda r: r.name in ["加签", "加签确认"]).unlink() - @api.model_create_multi def create(self, values): - for val in values: - if val['node_name'] != 'end': - if not val["button_ids"]: - if val['node_name'] == 'start': - val["button_ids"] = [ + records = super().create(values) + for record in records: + if record.node_name != 'end': + if not record.button_ids: + if record.node_name == 'start': + record.write({"button_ids": [ (0, 0, { "name": _("转交"), - "workflow_id": val['workflow_id'], - "sequence": 1, - },), + "workflow_id": record.workflow_id.id, + "sequence": 1}), (0, 0, { "name": _("收回"), - "workflow_id": val['workflow_id'], + "workflow_id": record.workflow_id.id, "sequence": 2, "action_type": "code", "code": "obj.action_withdraw()", - },)] - elif val['node_name'] == '分发': - val["button_ids"] = [ - (0, 0, { - "name": _("分发"), - "workflow_id": val['workflow_id'], - "sequence": 1, - "action_type": "code", - "has_comment": True, - },)] + }) + ]}) + elif record.node_name == '分发': + record.write({"button_ids": [(0, 0, { + "name": _("分发"), + "workflow_id": record.workflow_id.id, + "sequence": 1, + "action_type": "code", + "has_comment": True, + })]}) else: - val["button_ids"] = [ + record.write({"button_ids": [ (0, 0, { "name": _("转交"), - "workflow_id": val['workflow_id'], + "workflow_id": record.workflow_id.id, "sequence": 1, "action_type": "code", - "has_comment": True, - },), + "has_comment": True}), (0, 0, { "name": _("收回"), - "workflow_id": val['workflow_id'], + "workflow_id": record.workflow_id.id, "sequence": 2, "action_type": "code", - "code": "obj.action_withdraw()", - },), + "code": "obj.action_withdraw()"}), (0, 0, { "name": _("退回"), - "workflow_id": val['workflow_id'], + "workflow_id": record.workflow_id.id, "sequence": 2, "action_type": "code", - "has_comment": True, - },)] - - return super().create(values) + "has_comment": True}) + ]}) + # 运行时执行加载所有form,并且只读 + model_id = self.env['soong.workflow'].search([('id', '=', record.workflow_id.id), ('is_enable', '=', True)]).model_id + form_view = self.env["ir.ui.view"].search([("model", "=", model_id.model), ("type", "=", "form")], limit=1) + if form_view: + xml_tree = etree.fromstring(form_view.arch) + field_names = set() + for field_node in xml_tree.xpath("//field"): + field_name = field_node.get("name") + if field_name: + field_names.add(field_name) + for field in self.env["ir.model.fields"].search( + [("model_id", "=", model_id.id), ("name", "in", list(field_names))]): + self.field_ids.create({ + "model_id": model_id.id, + "node_id": record.id, + "name": field.id, + "readonly": True, + }) + else: + raise UserError('该模型未找到form视图') + return records @api.depends("bg_color", "label_color", "use_custom_colors", "flow_start", "flow_end") def _compute_custom_colors(self): @@ -205,7 +220,8 @@ class SoongWorkflowNode(models.Model): # 加载form视图中的字段 for rec in self: rec.field_ids.unlink() - form_view = self.env["ir.ui.view"].search([("model", "=", rec.model_id.model), ("type", "=", "form")], limit=1) + form_view = self.env["ir.ui.view"].search([("model", "=", rec.model_id.model), ("type", "=", "form")], + limit=1) if form_view: xml_tree = etree.fromstring(form_view.arch) field_names = set() @@ -213,12 +229,13 @@ class SoongWorkflowNode(models.Model): field_name = field_node.get("name") if field_name: field_names.add(field_name) - for field in self.env["ir.model.fields"].search([("model_id", "=", rec.model_id.id), ("name", "in", list(field_names))]): + for field in self.env["ir.model.fields"].search( + [("model_id", "=", rec.model_id.id), ("name", "in", list(field_names))]): rec.field_ids.create({ - "model_id": rec.model_id.id, - "node_id": rec.id, - "name": field.id, - }) + "model_id": rec.model_id.id, + "node_id": rec.id, + "name": field.id, + }) else: raise UserError('该模型未找到form视图') @@ -256,6 +273,7 @@ class SoongWorkflowNodeButton(models.Model): ) is_highlight = fields.Boolean(string="Is Highlighted", default=True, help="Control highlighting of the button if needs user attention..", ) + # is_high_red = fields.Boolean(string="红色突出") has_icon = fields.Boolean( string="Has Icon", help="Enable it to add icon to the button." ) @@ -281,7 +299,8 @@ class SoongWorkflowNodeButton(models.Model): ) reviewer_id = fields.Many2one(comodel_name="res.users", string="Reviewer") reviewer_group_id = fields.Many2one(comodel_name="res.groups", string="Reviewer group") - users_role_id = fields.Many2one(comodel_name="soong.user.role", string="主角色", domain=[('user_type', '!=', 'lv_role')]) + users_role_id = fields.Many2one(comodel_name="soong.user.role", string="主角色", + domain=[('user_type', '!=', 'lv_role')]) reviewer_expression = fields.Text( string="Review Expression", default=CONDITION_CODE_TEMP, @@ -331,7 +350,8 @@ class SoongWorkflowNodeButton(models.Model): ondelete="cascade", ) invisible_expression_model = fields.Char(related="workflow_id.model_id.model") - is_automatic = fields.Boolean('是否自动匹配', default=True, help='该节点默认拟办人员的部门相应人员。必须是系统全局角色') + is_automatic = fields.Boolean('是否自动匹配', default=True, + help='该节点默认拟办人员的部门相应人员。必须是系统全局角色') @api.onchange("node_id") def change_workflow(self): @@ -430,7 +450,8 @@ class SoongWorkflowNodeButton(models.Model): elif button_id.review_type == "group": user_ids += button_id.reviewer_group_id.users.ids elif button_id.review_type == "user_role": - user_role_id = self.env['res.users'].search([('employee_id.user_role_id', '=', button_id.users_role_id.id)]) + user_role_id = self.env['res.users'].search( + [('employee_id.user_role_id', '=', button_id.users_role_id.id)]) user_ids += user_role_id.ids # # 发送信息提醒 # partner_ids = self.sudo().env['res.users'].search([('id', 'in', user_ids)]).mapped('partner_id').ids diff --git a/soong_workflow/models/soong_workflow_record.py b/soong_workflow/models/soong_workflow_record.py index b4a6692b1..af3af7c3c 100644 --- a/soong_workflow/models/soong_workflow_record.py +++ b/soong_workflow/models/soong_workflow_record.py @@ -24,6 +24,7 @@ class SoongWorkflowRecord(models.Model): rec.name = False name = fields.Char(string="Name", compute="compute_name", store=True) + code = fields.Char(string="流水号") res_model = fields.Char(string="Res Model", required=True) res_id = fields.Integer(string="Res ID", required=True) users_ids = fields.Many2many('res.users', string="用户") diff --git a/soong_workflow/templates/soong_workflow_templates.xml b/soong_workflow/templates/soong_workflow_templates.xml index ea87beaad..72c7cd16d 100644 --- a/soong_workflow/templates/soong_workflow_templates.xml +++ b/soong_workflow/templates/soong_workflow_templates.xml @@ -1,19 +1,18 @@ - diff --git a/soong_workflow/views/menuitem.xml b/soong_workflow/views/menuitem.xml index 502c546c7..347eb848d 100644 --- a/soong_workflow/views/menuitem.xml +++ b/soong_workflow/views/menuitem.xml @@ -14,17 +14,27 @@ sequence="3"/> + + -日程 + sequence="4"/> + - - - - - - - - - - - - - - - - - diff --git a/soong_workflow/views/soong_workflow_log_views.xml b/soong_workflow/views/soong_workflow_log_views.xml index 0cb6aac18..166b3d2b1 100644 --- a/soong_workflow/views/soong_workflow_log_views.xml +++ b/soong_workflow/views/soong_workflow_log_views.xml @@ -6,6 +6,7 @@ soong.workflow.log + diff --git a/soong_workflow/views/soong_workflow_node_views.xml b/soong_workflow/views/soong_workflow_node_views.xml index b64ad6f62..0dccdf720 100644 --- a/soong_workflow/views/soong_workflow_node_views.xml +++ b/soong_workflow/views/soong_workflow_node_views.xml @@ -149,6 +149,7 @@ + diff --git a/soong_workflow/views/soong_workflow_record.xml b/soong_workflow/views/soong_workflow_record.xml index 5b8c28c11..3f29695e9 100644 --- a/soong_workflow/views/soong_workflow_record.xml +++ b/soong_workflow/views/soong_workflow_record.xml @@ -20,6 +20,7 @@ + diff --git a/soong_workflow/wizard/soong_workflow_comment_wizard.py b/soong_workflow/wizard/soong_workflow_comment_wizard.py index 79512f52b..659c01328 100644 --- a/soong_workflow/wizard/soong_workflow_comment_wizard.py +++ b/soong_workflow/wizard/soong_workflow_comment_wizard.py @@ -115,10 +115,10 @@ class SoongWorkflowCommentWizard(models.TransientModel): self.ensure_one() cx = self.env.context.copy() or {} record_id = self.env[self.res_model].search([('id', '=', self.res_id)]) - # 抄送人员 if self.node_btn_name == '转交': - self_node_id = record_id.workflow_id.node_ids.search( - [('name', '=', record_id.state), ('workflow_id', '=', record_id.workflow_id.id)]) + self_node_id = record_id.workflow_id.node_ids.search([('name', '=', record_id.state), ('workflow_id', '=', record_id.workflow_id.id)]) + # 工作流更新,转交节点日志记录。 + now_record_obj = self.sudo().env["soong.workflow.log"].search( [("model", "=", self.res_model), ("res_id", "=", self.res_id), @@ -128,8 +128,7 @@ class SoongWorkflowCommentWizard(models.TransientModel): ("node_btn_id", "=", self.node_btn_id.id), ], order="lase_click_date DESC", limit=1) if not now_record_obj: - now_record_obj = self.sudo().env["soong.workflow.log"].create( - { + now_record_obj = self.sudo().env["soong.workflow.log"].create({ "model": self.res_model, "res_id": self.res_id, "node_id": self.node_btn_id.node_id.id, @@ -139,8 +138,7 @@ class SoongWorkflowCommentWizard(models.TransientModel): "node_btn_id": self.node_btn_id.id, "lase_click_date": fields.Datetime.now(), "approval_state": "2" - } - ) + }) now_record_obj.write({"comment": self.comment_note_id.name, "approval_state": "2"}) if self_node_id.is_carbon_copy: for employee in self_node_id.employee_ids: @@ -191,14 +189,14 @@ class SoongWorkflowCommentWizard(models.TransientModel): ('department_id', '=', record_id.department_id.id), ('department_ids', 'in', record_id.department_id.id)]) employee_ids = employee_user_role_ids if not is_automatic else employee_user_role_id - record_obj = self.sudo().env["soong.workflow.log"].search([("model", "=", self.res_model), - ("res_id", "=", self.res_id), - ("node_id", "=", next_node_id.id), - ("workflow_id", "=", record_id.workflow_id.id), - ("node_btn_name", "=", "0"), + record_obj = self.sudo().env["soong.workflow.log"].search([("model", "=", self.res_model), ("res_id", "=", self.res_id)])[-1] + # ("node_id", "=", next_node_id.id), + # ("workflow_id", "=", record_id.workflow_id.id), + # ("node_btn_name", "=", "0"), # ("node_btn_id", "=", record_id.node_btn_id.id), - ], order="lase_click_date DESC", limit=1) - if not record_obj: + # ], order="lase_click_date DESC", limit=1) + # 生成下一个节点的数据。如果当前节点不等于当前状态创建新数据 + if record_id.state != record_obj.name: record_obj = self.sudo().env["soong.workflow.log"].create( { "model": self.res_model, @@ -262,12 +260,6 @@ class SoongWorkflowCommentWizard(models.TransientModel): } ) return self.node_btn_id.with_context(cx).run() - # # 填写审批记录 - # if self.node_btn_name != '加签': - # self.log_ids.write({"comment": self.comment_note_id.name}) - # # 加签人员写入 - # if self.node_btn_name == '加签': - # record_id.approval_sign_ids = self.approval_users_ids # if self.node_btn_name == '分发': # if self.circulated_employee_ids: # url = 'https://oa.thtzjt.com/mail/view?model={}&res_id={}'.format(self.res_model, self.res_id) @@ -282,7 +274,7 @@ class SoongWorkflowCommentWizard(models.TransientModel): # url=url, btntxt="查看详情") # partner_ids = self.circulated_employee_ids.user_id.partner_id.ids # self.with_context(lang=self.env.lang)._message_auto_subscribe_notify(partner_ids,'soong_workflow.message_soong_workflow_distribute') - if self.employee_ids: - state = self.node_btn_id.node_id.out_link_ids.name.split('-> ')[-1] - record_id.write({'state': 'end' if state == '结束' else state}) + if self.employee_ids: + state = self.node_btn_id.node_id.out_link_ids.name.split('-> ')[-1] + record_id.write({'state': 'end' if state == '结束' else state}) return self.node_btn_id.with_context(cx).run() diff --git a/yuthon_hr_attendance/models/card_approval.py b/yuthon_hr_attendance/models/card_approval.py index 621512f71..735cb1ef4 100644 --- a/yuthon_hr_attendance/models/card_approval.py +++ b/yuthon_hr_attendance/models/card_approval.py @@ -25,11 +25,10 @@ class CardApprovals(models.Model): reason_application = fields.Html(string="申请事由") documents_ids = fields.Many2many('ir.attachment', string="附件") attendance_id = fields.Many2one('hr.attendance', string="补卡日期") - replacement_time = fields.Selection([('work', '上班卡'), ('quitting', '下班卡'), ('all', '全天卡')], string="补卡", - compute='_compute_replacement_time') + replacement_time = fields.Selection([('work', '上班卡'), ('quitting', '下班卡'), ('all', '全天卡')], string="补卡") - @api.depends('attendance_id') - def _compute_replacement_time(self): + @api.onchange('attendance_id') + def onchange_replacement_time(self): for rep in self: rep.replacement_time = None if rep.attendance_id.is_early_card and not rep.attendance_id.is_late_card: diff --git a/yuthon_hr_attendance/views/card_approval.xml b/yuthon_hr_attendance/views/card_approval.xml index 8943bfa40..ecfd374fb 100644 --- a/yuthon_hr_attendance/views/card_approval.xml +++ b/yuthon_hr_attendance/views/card_approval.xml @@ -26,7 +26,7 @@ - + @@ -36,7 +36,7 @@ - + diff --git a/yuthon_will_task/models/yuthon_will_task.py b/yuthon_will_task/models/yuthon_will_task.py index 760150d49..46dd505af 100644 --- a/yuthon_will_task/models/yuthon_will_task.py +++ b/yuthon_will_task/models/yuthon_will_task.py @@ -52,8 +52,8 @@ class YuthonWillTask(models.Model): def will_task_time(self): for i in self.search([('state', '=', 'will')]): - if datetime.now() + timedelta(hours=8) > self.start_time: - i.write({'state', 'done'}) + if datetime.now() + timedelta(hours=8) > i.start_time: + i.write({'state': 'done'}) for task in self.search([('state', '=', 'will')]): now = datetime.now() + timedelta(hours=8) start_time = task.start_time + timedelta(hours=8)