1
This commit is contained in:
@@ -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
|
||||
|
||||
+155
-3
@@ -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`);
|
||||
|
||||
+66
-34
@@ -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; // 允许长单词换行
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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="用户")
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<template id="soong_workflow_log">
|
||||
<field name="log_ids" invisible="not log_ids" style="width:100%%; margin-top: 10px;">
|
||||
<tree create="false" edit="false" delete="false" editable="bottom">
|
||||
<field name="sequence" string=""/>
|
||||
<field name="name" string=""/>
|
||||
|
||||
<!-- <field name="node_btn_id" />-->
|
||||
<field name="done_by" string=""/>
|
||||
<field name="lase_click_date" string=""/>
|
||||
<field name="comment" string=""/>
|
||||
<field name="approval_state" string=""/>
|
||||
<field name="node_btn_name" string=""/>
|
||||
</tree>
|
||||
</field>
|
||||
<group string="审批详情" invisible="not log_ids">
|
||||
<field name="log_ids" invisible="not log_ids" style="width:100%%; margin-top: 10px;">
|
||||
<tree create="false" edit="false" delete="false" editable="bottom">
|
||||
<field name="sequence" string=""/>
|
||||
<field name="name" string=""/>
|
||||
<field name="done_by" string=""/>
|
||||
<field name="lase_click_date" string=""/>
|
||||
<field name="comment" string=""/>
|
||||
<field name="approval_state" string=""/>
|
||||
<field name="node_btn_name" string=""/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -14,17 +14,27 @@
|
||||
sequence="3"/>
|
||||
|
||||
<menuitem id="menu_workflow_approval_request_my"
|
||||
name="我的流程"
|
||||
name="待办流程"
|
||||
parent="menu_soong_workflow_root"
|
||||
action="soong_workflow_record_action"
|
||||
sequence="1"/>
|
||||
<menuitem id="menu_workflow_approval_request_copy"
|
||||
name="抄送/传阅流程"
|
||||
parent="menu_soong_workflow_root"
|
||||
action="soong_workflow_record_action"
|
||||
sequence="2"/>
|
||||
<menuitem id="menu_workflow_approval_request_entrust"
|
||||
name="委托流程"
|
||||
parent="menu_soong_workflow_root"
|
||||
action="soong_workflow_record_action"
|
||||
sequence="3"/>
|
||||
|
||||
<menuitem id="menu_workflow_approval_request_all"
|
||||
name="流程查询"
|
||||
parent="menu_soong_workflow_root"
|
||||
action="soong_workflow_record_action_all"
|
||||
sequence="2"/>
|
||||
日程
|
||||
sequence="4"/>
|
||||
|
||||
<menuitem id="menu_soong_workflow_entrust"
|
||||
sequence="5"
|
||||
name="流程委托"
|
||||
@@ -38,30 +48,13 @@
|
||||
sequence="7"/>
|
||||
|
||||
<menuitem id="menu_soong_workflow_inspector_approval"
|
||||
sequence="4"
|
||||
name="督察审批"
|
||||
sequence="5"
|
||||
name="督办审批"
|
||||
action="soong_workflow_inspector_action"
|
||||
parent="menu_soong_workflow_root"/>
|
||||
|
||||
<!-- <menuitem id="menu_soong_workflow_inspector_transact"-->
|
||||
<!-- sequence="3"-->
|
||||
<!-- name="督察办理"-->
|
||||
<!-- parent="menu_soong_workflow_inspector"/>-->
|
||||
<!-- 督办事项的表单 -->
|
||||
<!-- <menuitem id="menu_soong_workflow_inspector_transact_sth"-->
|
||||
<!-- sequence="1"-->
|
||||
<!-- name="督察事项"-->
|
||||
<!-- action="soong_workflow_inspector_line_action"-->
|
||||
<!-- parent="menu_soong_workflow_inspector_transact"/>-->
|
||||
|
||||
<!-- <menuitem id="menu_soong_workflow_inspector_transact_my"-->
|
||||
<!-- sequence="3"-->
|
||||
<!-- name="我的任务"-->
|
||||
<!-- action="soong_workflow_inspector_line_action"-->
|
||||
<!-- parent="menu_soong_workflow_inspector_transact"/>-->
|
||||
|
||||
<menuitem id="menu_soong_other_setting"
|
||||
sequence="5"
|
||||
sequence="6"
|
||||
name="其他配置"
|
||||
parent="menu_soong_workflow_root"
|
||||
action="soong_note_action"/>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<field name="model">soong.workflow.log</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="工作流日志" default_order="lase_click_date desc">
|
||||
<field name="sequence"/>
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<!-- <field name="model"/>-->
|
||||
|
||||
@@ -149,6 +149,7 @@
|
||||
<field name="sequence" required="1"/>
|
||||
<field name="name" required="1"/>
|
||||
<field name="is_highlight"/>
|
||||
<!-- <field name="is_high_red"/>-->
|
||||
<field name="has_comment"/>
|
||||
<field name="is_automatic"/>
|
||||
</group>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<tree string="WorkFollow Record" action="open_record" delete="false" type="object"
|
||||
decoration-muted="approve_state == 'end'" decoration-warning="approve_state != 'end'"
|
||||
create="false" default_order="write_date desc">
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
<field name="workflow_id" string="审批类型"/>
|
||||
<field name="node_id" string="当前节点"/>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<field name="reason_application"/>
|
||||
<field name="documents_ids" widget="preview_many2many"/>
|
||||
</group>
|
||||
<group string="个人信息" col="4">
|
||||
<group col="4">
|
||||
<group>
|
||||
<field name="users_id"/>
|
||||
<field name="employee_id" invisible="1"/>
|
||||
@@ -36,7 +36,7 @@
|
||||
<field name="attendance_id" domain="[('employee_id', '=', employee_id), ('is_abnormal', '=', 1)]"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="replacement_time" readonly='0'/>
|
||||
<field name="replacement_time"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="shift_id" invisible="1"/>
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user