1297 lines
57 KiB
Python
1297 lines
57 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from odoo import models, fields, api, _
|
|
from odoo.tools.safe_eval import safe_eval
|
|
from odoo.exceptions import ValidationError, UserError
|
|
from datetime import datetime, date, time, timedelta
|
|
import random
|
|
import string
|
|
import logging
|
|
from lxml import etree
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
CONDITION_CODE_TEMP = """# Available locals:
|
|
# - time, date, datetime, timedelta: Python libraries.
|
|
# - env: Odoo Environement.
|
|
# - model: Model of the record on which the action is triggered.
|
|
# - obj: Record on which the action is triggered if there is one, otherwise None.
|
|
# - user, Current user object.
|
|
# - workflow: Workflow engine.
|
|
# - syslog : syslog(message), function to log debug information to Odoo logging file or console.
|
|
# - warning: warning(message), Warning Exception to use with raise.
|
|
# - To return an user, assign:
|
|
|
|
|
|
user = env.user"""
|
|
PYTHON_CODE_TEMP = """# Available locals:
|
|
# - time, date, datetime, timedelta: Python libraries.
|
|
# - env: Odoo Environement.
|
|
# - model: Model of the record on which the action is triggered.
|
|
# - obj: Record on which the action is triggered if there is one, otherwise None.
|
|
# - user, Current user object.
|
|
# - workflow: Workflow engine.
|
|
# - syslog : syslog(message), function to log debug information to Odoo logging file or console.
|
|
# - warning: warning(message), Warning Exception to use with raise.
|
|
# To return an action, assign: action = {...}
|
|
|
|
|
|
"""
|
|
DEFAULT_BG_COLOR = "rgb(255, 255, 255,1)"
|
|
DEFAULT_LABEL_COLOR = "rgb(81, 81, 81,1)"
|
|
START_BG_COLOR = "rgba(120,120,120,1)"
|
|
START_LABEL_COLOR = "rgba(255,255,255,1)"
|
|
END_BG_COLOR = "rgba(120,120,120,1)"
|
|
END_LABEL_COLOR = "rgba(255,255,255,1)"
|
|
END_BG_COLOR_1 = "rgba(0,255,30,1)"
|
|
|
|
|
|
class SoongWorkflowNode(models.Model):
|
|
_name = "soong.workflow.node"
|
|
_description = "Soong Workflow Nodes"
|
|
_order = "sequence"
|
|
|
|
_sql_constraints = [
|
|
(
|
|
"uniq_node_name",
|
|
"unique(workflow_id,node_name)",
|
|
_("Workflow and Technical Name must be unique."),
|
|
),
|
|
]
|
|
|
|
sequence = fields.Integer(string="Sequence", default=10, help="Arrange node by defining sequence.")
|
|
name = fields.Char(string="Name", translate=True, help="Enter string name of the node.")
|
|
node_name = fields.Char(string="Technical Name", help="Generated technical name which used by backend code.", )
|
|
workflow_id = fields.Many2one(comodel_name="soong.workflow", string="Workflow Ref.", ondelete="cascade",
|
|
required=True, )
|
|
model_id = fields.Many2one("ir.model", string="Model Ref.", domain="[('state','=','base')]",
|
|
related="workflow_id.model_id", required=True, )
|
|
flow_start = fields.Boolean(string="Flow Start", help="Check it if this node is the starting node.")
|
|
flow_end = fields.Boolean(string="Flow End", help="Check it if this node is the ending node.")
|
|
is_visible = fields.Boolean(string="Appear in Statusbar", default=True,
|
|
help="Control visiability of the node/state in view.", )
|
|
out_link_ids = fields.One2many(comodel_name="soong.workflow.link", inverse_name="node_from",
|
|
string="Outgoing Transitions", )
|
|
in_link_ids = fields.One2many(comodel_name="soong.workflow.link", inverse_name="node_to",
|
|
string="Incoming Transitions", )
|
|
field_ids = fields.One2many(comodel_name="soong.workflow.node.field", inverse_name="node_id", string="Fields", )
|
|
button_ids = fields.One2many(comodel_name="soong.workflow.node.button", inverse_name="node_id", string="Buttons", )
|
|
diagram_position = fields.Char(readonly=True, string="Diagram Position")
|
|
bg_color = fields.Char(default=DEFAULT_BG_COLOR, string="Background Color")
|
|
label_color = fields.Char(default=DEFAULT_LABEL_COLOR, string="Label Color")
|
|
use_custom_colors = fields.Boolean(help="Select colors from the palette manually", string="Use Custom Colors")
|
|
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_archive = fields.Boolean(string="归档")
|
|
illustrate = fields.Text(string="说明")
|
|
is_apostille = fields.Boolean(string="加签", default=False)
|
|
is_end = fields.Boolean(string="结束", default=False)
|
|
is_confirm = fields.Boolean(string="确认", default=False)
|
|
department_id = fields.Many2many(
|
|
'hr.department',
|
|
string='部门转入范围',
|
|
relation="soong_workflow_node_transfer_department_rel",
|
|
column1="node_id",
|
|
column2="transfer_department_id"
|
|
)
|
|
transfer_comment_id = fields.Many2one('soong.note', string="转交固定意见")
|
|
return_comment_id = fields.Many2one('soong.note', string="退回固定意见")
|
|
confirm_comment_id = fields.Many2one('soong.note', string="确认固定意见")
|
|
end_comment_id = fields.Many2one('soong.note', string="结束固定意见")
|
|
approval_concatenation = fields.Selection([('chuan', '串申'), ('bing', '并申')], string="审批形式", default="bing",
|
|
help='并:任何人均给意见,最后一个完成的人转交到下一节点.'
|
|
'串:都会收到消息,但任意一个人转交后,即到下一节点,其他人将不再显示,相当于收回.')
|
|
same_user_skip_type = fields.Selection([
|
|
('none', '不跳过'),
|
|
('next', '跳过下一个相同人员节点'),
|
|
('prev', '跳过上一个相同人员节点'),
|
|
], string='相同人员节点处理', default='none')
|
|
is_mandatory_node = fields.Boolean(string="必经节点", default=False)
|
|
|
|
@api.onchange("is_apostille")
|
|
def onchange_is_apostille(self):
|
|
for record in self:
|
|
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, {
|
|
"name": _("加签"),
|
|
# "workflow_id": record.workflow_id.ids[0] if record.workflow_id.ids else None,
|
|
"node_id": record.id,
|
|
"sequence": sequence + 1,
|
|
"action_type": "apostille",
|
|
"btn_hide": False # 对所有人显示
|
|
}),
|
|
(0, 0, {
|
|
"name": _("加签确认"),
|
|
# "workflow_id": record.workflow_id.ids[0] if record.workflow_id.ids else None,
|
|
"node_id": record.id,
|
|
"sequence": sequence + 2,
|
|
"action_type": "apostille",
|
|
"btn_hide": True, # 仅对加签人员显示
|
|
"review_type": "apostille",
|
|
})
|
|
]
|
|
else:
|
|
remove_ids = record.button_ids.filtered(lambda r: r.name in ["加签", "加签确认"])
|
|
record.button_ids = [(3, remove_id.id) for remove_id in remove_ids]
|
|
|
|
@api.onchange("is_end")
|
|
def onchange_is_end(self):
|
|
for record in self:
|
|
current_buttons = record.button_ids
|
|
if record.is_end:
|
|
record.use_custom_colors = True
|
|
record.bg_color = END_BG_COLOR_1
|
|
record.res_bg_color = END_BG_COLOR_1
|
|
end_btns = current_buttons.filtered(lambda r: r.name == _("结束"))
|
|
archive_btns = current_buttons.filtered(lambda r: r.name == _("归档"))
|
|
remove_commands = [(3, btn.id) for btn in end_btns + archive_btns]
|
|
sequence = max([r.sequence for r in current_buttons] if current_buttons else [1])
|
|
add_end = (0, 0, {
|
|
"name": _("结束"),
|
|
"node_id": record.id,
|
|
"sequence": sequence + 1,
|
|
"action_type": "end",
|
|
"btn_hide": False,
|
|
"has_comment": True,
|
|
"review_type": "end",
|
|
})
|
|
add_archive = (0, 0, {
|
|
"name": _("归档"),
|
|
"node_id": record.id,
|
|
"sequence": sequence + 2,
|
|
"action_type": "code",
|
|
"btn_hide": False,
|
|
"has_comment": True,
|
|
})
|
|
record.button_ids = remove_commands + [add_end, add_archive]
|
|
|
|
else:
|
|
record.use_custom_colors = True
|
|
record.bg_color = DEFAULT_BG_COLOR
|
|
record.res_bg_color = DEFAULT_BG_COLOR
|
|
end_btns = current_buttons.filtered(lambda r: r.name == _("结束"))
|
|
archive_btns = current_buttons.filtered(lambda r: r.name == _("归档"))
|
|
record.button_ids = [(3, btn.id) for btn in end_btns + archive_btns]
|
|
|
|
@api.onchange("is_confirm")
|
|
def onchange_is_confirm(self):
|
|
for record in self:
|
|
if record.is_confirm:
|
|
record.use_custom_colors = True
|
|
sequence = max([r.sequence for r in record.button_ids] if record.button_ids else [1])
|
|
record.button_ids = [
|
|
(0, 0, {
|
|
"name": _("确认"),
|
|
# "workflow_id": record.workflow_id.ids[0] if record.workflow_id.ids else None,
|
|
"node_id": record.id,
|
|
"sequence": sequence + 1,
|
|
"action_type": "confirm",
|
|
"btn_hide": False, # 对所有人显示
|
|
"has_comment": True, # 对所有人显示
|
|
"review_type": "confirm",
|
|
}),
|
|
]
|
|
else:
|
|
record.use_custom_colors = True
|
|
record.bg_color = DEFAULT_BG_COLOR
|
|
record.res_bg_color = DEFAULT_BG_COLOR
|
|
remove_ids = record.button_ids.filtered(lambda r: r.name in ["确认"])
|
|
record.button_ids = [(3, remove_id.id) for remove_id in remove_ids]
|
|
|
|
def btn_role_sync(self):
|
|
for record in self:
|
|
now_btn = record.button_ids.filtered(lambda r: r.name in ["转交"])
|
|
for btn in now_btn:
|
|
other_btn = record.button_ids.filtered(lambda r: r.name not in ["转交", "收回", "加签", "加签确认", '确认', '归档'])
|
|
other_btn.write({
|
|
"btn_hide": btn.btn_hide,
|
|
"review_type": btn.review_type,
|
|
"reviewer_id": btn.reviewer_id.id,
|
|
"reviewer_group_id": btn.reviewer_group_id.id,
|
|
"users_role_id": btn.users_role_id.id,
|
|
"users_role_group_ids": btn.users_role_group_ids.ids,
|
|
})
|
|
|
|
@api.model_create_multi
|
|
def create(self, values):
|
|
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": record.workflow_id.id,
|
|
"sequence": 1}),
|
|
(0, 0, {
|
|
"name": _("收回"),
|
|
"workflow_id": record.workflow_id.id,
|
|
"sequence": 2,
|
|
"btn_hide": True,
|
|
"review_type": "withdraw",
|
|
"action_type": "code",
|
|
"code": "obj.action_withdraw()",
|
|
})
|
|
]})
|
|
elif '分发' in 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:
|
|
record.write({"button_ids": [
|
|
(0, 0, {
|
|
"name": _("转交"),
|
|
"workflow_id": record.workflow_id.id,
|
|
"sequence": 1,
|
|
"action_type": "code",
|
|
"has_comment": True}),
|
|
(0, 0, {
|
|
"name": _("收回"),
|
|
"workflow_id": record.workflow_id.id,
|
|
"sequence": 2,
|
|
"btn_hide": True,
|
|
"review_type": "withdraw",
|
|
"action_type": "code",
|
|
"code": "obj.action_withdraw()"}),
|
|
(0, 0, {
|
|
"name": _("退回"),
|
|
"workflow_id": record.workflow_id.id,
|
|
"sequence": 2,
|
|
"action_type": "code",
|
|
"has_comment": True}),
|
|
(0, 0, {
|
|
"name": _("确认"),
|
|
"workflow_id": record.workflow_id.id,
|
|
"sequence": 2,
|
|
"action_type": "code",
|
|
"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,
|
|
})
|
|
return records
|
|
|
|
@api.depends("bg_color", "label_color", "use_custom_colors", "flow_start", "flow_end")
|
|
def _compute_custom_colors(self):
|
|
for rec in self:
|
|
if rec.use_custom_colors:
|
|
rec.res_bg_color = rec.bg_color
|
|
rec.res_label_color = rec.label_color
|
|
elif rec.flow_start:
|
|
rec.res_bg_color = START_BG_COLOR
|
|
rec.res_label_color = START_LABEL_COLOR
|
|
elif rec.flow_end:
|
|
rec.res_bg_color = END_BG_COLOR
|
|
rec.res_label_color = END_LABEL_COLOR
|
|
else:
|
|
rec.res_bg_color = DEFAULT_BG_COLOR
|
|
rec.res_label_color = DEFAULT_LABEL_COLOR
|
|
|
|
@api.constrains("flow_start", "flow_end")
|
|
def _check_flow_start_end(self):
|
|
for rec in self:
|
|
if rec.flow_start and rec.flow_end:
|
|
raise UserError(_("Start and end cannot be selected for the node"))
|
|
|
|
@api.onchange("name")
|
|
def _compute_node_name(self):
|
|
for rec in self:
|
|
if rec and rec.name:
|
|
name = rec.name.lower().strip().replace(" ", "_")
|
|
rec.node_name = name
|
|
|
|
def btn_load_fields(self):
|
|
# 加载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)
|
|
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 and field_name != "name_title":
|
|
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))]):
|
|
rec.field_ids.create({
|
|
"model_id": rec.model_id.id,
|
|
"node_id": rec.id,
|
|
"name": field.id,
|
|
})
|
|
else:
|
|
raise UserError('该模型未找到form视图')
|
|
|
|
def all_readonly_fields(self):
|
|
self.field_ids.write({"readonly": True})
|
|
|
|
def all_required_fields(self):
|
|
self.field_ids.write({"required": True})
|
|
|
|
def all_invisible_fields(self):
|
|
self.field_ids.write({"invisible": True})
|
|
|
|
def all_false_fields(self):
|
|
self.field_ids.write({"invisible": False, "required": False, "readonly": False})
|
|
|
|
|
|
class SoongWorkflowNodeButton(models.Model):
|
|
_name = "soong.workflow.node.button"
|
|
_description = "Soong Workflow Node Buttons"
|
|
_order = "sequence"
|
|
|
|
def _generate_key(self):
|
|
return "".join(
|
|
random.SystemRandom().choice(string.ascii_uppercase + string.digits)
|
|
for _ in range(10)
|
|
)
|
|
|
|
name = fields.Char(
|
|
string="Button String",
|
|
translate=True,
|
|
help="Enter button string name that will appear in the view.",
|
|
)
|
|
sequence = fields.Integer(
|
|
string="Sequence", default=10, help="Arrange buttons by defining sequence."
|
|
)
|
|
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."
|
|
)
|
|
icon = fields.Char(string="Icon",
|
|
help="Enter icon name like: fa-print, it's recommended to use FontAwesome Icons.", )
|
|
has_comment = fields.Boolean(string="意见/弹窗", default=True)
|
|
btn_key = fields.Char(string="Button Key", default=_generate_key)
|
|
btn_hide = fields.Boolean(
|
|
string="Hide Button if Condition isn't fulfilled",
|
|
help="If condition is false the button will be hidden.",
|
|
)
|
|
review_type = fields.Selection(
|
|
string="审批类型",
|
|
default="user_role",
|
|
selection=[
|
|
("individual", "Specific user"),
|
|
("group", "Any user in a specific group"),
|
|
("expression", "Python Expression"),
|
|
('user_role', '角色'),
|
|
# ('invisible', '隐藏条件'),
|
|
('apostille', '加签确认'),
|
|
('end', "结束"),
|
|
('confirm', "确认"),
|
|
('withdraw', '收回'),
|
|
],
|
|
)
|
|
is_review_invisible = fields.Boolean(string="使用范围", default=False)
|
|
is_node_automatic = fields.Boolean('是否自动选择所有人员', help='默认否,选择是之后,前节点转交是会自动带出本节点的所有匹配的人员。', default=False)
|
|
illustrate = fields.Text(string="说明")
|
|
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="主角色",)
|
|
users_role_group_ids = fields.Many2many(comodel_name="soong.user.role.group", string="角色组")
|
|
reviewer_expression = fields.Text(
|
|
string="Review Expression",
|
|
default=CONDITION_CODE_TEMP,
|
|
help="Write Python code that defines the reviewer. "
|
|
"The result of executing the expression must be a res.users "
|
|
"recordset.",
|
|
)
|
|
invisible_expression = fields.Char(
|
|
string="隐藏条件",
|
|
default="",
|
|
)
|
|
# todo 找翻译文件改变状态
|
|
action_type = fields.Selection(
|
|
[
|
|
("link", "Trigger Link"),
|
|
("link_start_statu", "Trigger Link Start Statu"),
|
|
("link_action", "Trigger Link Action"),
|
|
("link_action_approve", "Trigger Link Action Approve"),
|
|
("link_action_refuse", "Trigger Link Action Refuse"),
|
|
("code", "Python Code"),
|
|
("action", "Server Action"),
|
|
("win_act", "Window Action"),
|
|
("apostille", "加签按钮"),
|
|
('end', "结束"),
|
|
('confirm', "确认"),
|
|
],
|
|
string="Action Type",
|
|
default="link",
|
|
help="Choose type of action to be trigger by the button.",
|
|
)
|
|
link_id = fields.Many2one(comodel_name="soong.workflow.link", string="Link")
|
|
code = fields.Text(string="Python Code", default=PYTHON_CODE_TEMP)
|
|
server_action_id = fields.Many2one(
|
|
comodel_name="ir.actions.server", string="Server Action"
|
|
)
|
|
win_act_id = fields.Many2one(
|
|
comodel_name="ir.actions.act_window", string="Window Action"
|
|
)
|
|
node_id = fields.Many2one(
|
|
comodel_name="soong.workflow.node",
|
|
string="Workflow Node Ref.",
|
|
ondelete="cascade",
|
|
required=True,
|
|
)
|
|
workflow_id = fields.Many2one(
|
|
"soong.workflow",
|
|
string="Workflow Ref.",
|
|
# required=True,
|
|
store=True,
|
|
related="node_id.workflow_id",
|
|
ondelete="cascade",
|
|
)
|
|
invisible_expression_model = fields.Char(related="workflow_id.model_id.model", store=True)
|
|
is_automatic = fields.Boolean('发起人部门')
|
|
is_automatic_company = fields.Boolean('发起人公司', default=True)
|
|
is_automatic_group = fields.Boolean('发起人集团')
|
|
|
|
is_logged_by = fields.Boolean('登录人部门')
|
|
is_logged_company = fields.Boolean('登录人公司')
|
|
is_logged_group = fields.Boolean('登录人集团')
|
|
|
|
is_dep = fields.Boolean('按指定部门')
|
|
role_id = fields.Many2one(comodel_name="soong.user.role.group", string="角色")
|
|
specify_field_id = fields.Many2one(comodel_name="ir.model.fields", string="指定字段")
|
|
is_carbon_copy = fields.Boolean(string="抄送/传阅")
|
|
department1_ids = fields.Many2many(
|
|
"hr.department",
|
|
string="抄送部门",
|
|
relation="soong_workflow_node_department_rel",
|
|
column1="node_id",
|
|
column2="department_id"
|
|
)
|
|
user_role_ids = fields.Many2many("soong.user.role", string="抄送角色", )
|
|
cc_users_role_group_ids = fields.Many2many(
|
|
'soong.user.role.group',
|
|
'soong_workflow_node_button_cc_groups_rel',
|
|
'button_id',
|
|
'group_id',
|
|
string='抄送角色组'
|
|
)
|
|
employee_ids = fields.Many2many('hr.employee', string='抄送/传阅人员')
|
|
|
|
@api.onchange('department1_ids', 'user_role_ids', 'cc_users_role_group_ids', 'employee1_ids')
|
|
def _onchange_sync_employee_ids(self):
|
|
for record in self:
|
|
final_employees = self.env['hr.employee']
|
|
role_group_roles = record.cc_users_role_group_ids.mapped('user_role_ids')
|
|
all_target_roles = record.user_role_ids | role_group_roles
|
|
if all_target_roles:
|
|
role_employees = self.env['hr.employee'].search([
|
|
'|',
|
|
('user_role_id', 'in', all_target_roles.ids),
|
|
('user_role_ids', 'in', all_target_roles.ids)
|
|
])
|
|
final_employees |= role_employees
|
|
|
|
if record.department1_ids:
|
|
dept_employees = self.env['hr.employee'].search([
|
|
('department_id', 'in', record.department1_ids.ids)
|
|
])
|
|
final_employees |= dept_employees
|
|
record.employee_ids = final_employees if final_employees else [(5, 0, 0)]
|
|
|
|
def update_user_id(self):
|
|
button_ids = self.env["soong.workflow.node.button"].browse(
|
|
self._context.get('active_ids', self._context.get('active_id')))
|
|
for button_id in button_ids:
|
|
button_id.write({'reviewer_id': False})
|
|
|
|
@api.onchange('is_automatic')
|
|
def _onchange_is_automatic(self):
|
|
if self.is_automatic:
|
|
self.is_automatic_company = False
|
|
self.is_automatic_group = False
|
|
self.is_logged_by = False
|
|
self.is_logged_company = False
|
|
self.specify_field_id = None
|
|
self.is_dep = False
|
|
self.is_logged_group = False
|
|
|
|
@api.onchange('is_automatic_company')
|
|
def _onchange_is_automatic_company(self):
|
|
if self.is_automatic_company:
|
|
self.is_automatic = False
|
|
self.is_automatic_group = False
|
|
self.is_logged_by = False
|
|
self.is_dep = False
|
|
self.specify_field_id = None
|
|
self.is_logged_company = False
|
|
self.is_logged_group = False
|
|
|
|
@api.onchange('is_automatic_group')
|
|
def _onchange_is_automatic_group(self):
|
|
if self.is_automatic_group:
|
|
self.is_automatic = False
|
|
self.is_automatic_company = False
|
|
self.is_logged_by = False
|
|
self.is_dep = False
|
|
self.specify_field_id = None
|
|
self.is_logged_company = False
|
|
self.is_logged_group = False
|
|
|
|
@api.onchange('is_logged_by')
|
|
def _onchange_is_logged_by(self):
|
|
if self.is_logged_by:
|
|
self.is_automatic = False
|
|
self.is_automatic_company = False
|
|
self.is_automatic_group = False
|
|
self.specify_field_id = None
|
|
self.is_dep = False
|
|
self.is_logged_company = False
|
|
self.is_logged_group = False
|
|
|
|
@api.onchange('is_logged_company')
|
|
def _onchange_is_logged_company(self):
|
|
if self.is_logged_company:
|
|
self.is_automatic = False
|
|
self.is_automatic_company = False
|
|
self.is_automatic_group = False
|
|
self.is_logged_by = False
|
|
self.is_dep = False
|
|
self.specify_field_id = None
|
|
self.is_logged_group = False
|
|
|
|
@api.onchange('is_logged_group')
|
|
def _onchange_is_logged_group(self):
|
|
if self.is_logged_group:
|
|
self.is_automatic = False
|
|
self.is_automatic_company = False
|
|
self.is_automatic_group = False
|
|
self.is_logged_by = False
|
|
self.is_dep = False
|
|
self.specify_field_id = None
|
|
self.is_logged_company = False
|
|
|
|
@api.onchange('specify_field_id')
|
|
def _onchange_specify_field_id(self):
|
|
if self.specify_field_id:
|
|
self.is_automatic = False
|
|
self.is_automatic_company = False
|
|
self.is_automatic_group = False
|
|
self.is_logged_by = False
|
|
self.is_dep = False
|
|
self.is_logged_company = False
|
|
self.is_logged_group = False
|
|
|
|
@api.onchange('is_dep')
|
|
def _onchange_is_dep(self):
|
|
if self.is_dep:
|
|
self.is_automatic = False
|
|
self.is_automatic_company = False
|
|
self.is_automatic_group = False
|
|
self.is_logged_by = False
|
|
self.specify_field_id = None
|
|
self.is_logged_company = False
|
|
self.is_logged_group = False
|
|
|
|
@api.onchange('users_role_id', 'users_role_group_ids')
|
|
def _onchange_role_selection(self):
|
|
if self.users_role_id and self.users_role_group_ids:
|
|
self.users_role_id = False
|
|
self.users_role_group_ids = [(5, 0, 0)]
|
|
return {
|
|
'warning': {
|
|
'title': _('输入错误'),
|
|
'message': _('只能选择主角色或者角色组中的一个,不能同时选择。')
|
|
}
|
|
}
|
|
|
|
|
|
@api.onchange("node_id")
|
|
def change_workflow(self):
|
|
for rec in self:
|
|
if isinstance(rec.id, int) and rec.node_id and rec.node_id.workflow_id:
|
|
rec.workflow_id = rec.node_id.workflow_id.id
|
|
elif self.env.context.get("default_node_id", 0):
|
|
model_id = (
|
|
self.env["soong.workflow.node"]
|
|
.sudo()
|
|
.browse(self.env.context.get("default_node_id"))
|
|
.model_id.id
|
|
)
|
|
rec.workflow_id = (
|
|
self.env["soong.workflow"]
|
|
.sudo()
|
|
.search([("model_id", "=", model_id), ('is_enable', '=', True)])
|
|
)
|
|
|
|
@api.constrains("btn_key")
|
|
def validation(self):
|
|
for rec in self:
|
|
# Check if there is no duplicate button key
|
|
res = self.search_count(
|
|
[
|
|
("id", "!=", rec.id),
|
|
("btn_key", "=", rec.btn_key),
|
|
]
|
|
)
|
|
if res:
|
|
rec.btn_key = self._generate_key()
|
|
|
|
def log(self):
|
|
cx = self.env.context.copy() or {}
|
|
query_user_id = self.env.user.id
|
|
is_admin = self.env.user.has_group('soong_workflow.group_soong_workflow_manager')
|
|
res_model = cx.get("active_model", False)
|
|
res_id = cx.get("active_id", 0)
|
|
record_id = self.env[res_model].search([('id', '=', res_id)])
|
|
log = self.env['soong.workflow.log'].search([("model", "=", res_model),
|
|
("res_id", "=", res_id)])
|
|
employee_user_role_ids = self._get_approvers_for_link(record_id)
|
|
if is_admin and record_id:
|
|
if hasattr(record_id, 'user_id') and record_id.user_id:
|
|
query_user_id = record_id.user_id.id
|
|
elif hasattr(record_id, 'users_id') and record_id.users_id:
|
|
query_user_id = record_id.users_id.id
|
|
|
|
if len(log) > 1 and is_admin:
|
|
current_node_log = self.sudo().env["soong.workflow.log"].search(
|
|
[("model", "=", res_model),
|
|
("res_id", "=", res_id),
|
|
("node_id", "=", self.node_id.id)])
|
|
else:
|
|
current_node_log = self.sudo().env["soong.workflow.log"].search(
|
|
[("model", "=", res_model),
|
|
("res_id", "=", res_id),
|
|
("done_by", "=", query_user_id),
|
|
("node_id", "=", self.node_id.id)])
|
|
# 创建或更新当前用户的审批记录
|
|
if not current_node_log:
|
|
self.sudo().env["soong.workflow.log"].create({
|
|
"model": res_model,
|
|
"res_id": res_id,
|
|
"node_id": self.node_id.id,
|
|
"workflow_id": self.workflow_id.id,
|
|
"done_by": query_user_id,
|
|
"node_btn_name": "0",
|
|
"node_btn_id": self.id,
|
|
"lase_click_date": fields.Datetime.now(),
|
|
"approval_state": "2", # 已完成
|
|
"comment": '同意',
|
|
})
|
|
else:
|
|
current_node_log.write({
|
|
"comment": '同意',
|
|
"approval_state": "2", # 已完成
|
|
"lase_click_date": fields.Datetime.now()
|
|
})
|
|
|
|
expected_employees = employee_user_role_ids
|
|
|
|
# 查找下一个节点
|
|
next_node_id = record_id.workflow_id.node_ids.search([
|
|
('name', '=', self.link_id.node_to.name),
|
|
('workflow_id', '=', self.workflow_id.id)
|
|
])
|
|
|
|
completed_logs = self.sudo().env["soong.workflow.log"].search([
|
|
("model", "=", res_model),
|
|
("res_id", "=", res_id),
|
|
("node_id", "=", self.node_id.id),
|
|
("node_btn_name", "=", "4"),
|
|
("approval_state", "!=", "2")
|
|
])
|
|
all_completed = len(completed_logs) == 0
|
|
if all_completed:
|
|
for employee in expected_employees:
|
|
# 检查该员工在下一节点是否已有记录
|
|
next_node_employee_log = self.sudo().env["soong.workflow.log"].search([
|
|
("model", "=", res_model),
|
|
("res_id", "=",res_id),
|
|
("node_id", "=", next_node_id.id),
|
|
('node_btn_name', '!=', '1'),
|
|
("done_by", "=", employee.user_id.id)
|
|
])
|
|
|
|
if not next_node_employee_log:
|
|
# 创建初步记录,状态为"待审批"
|
|
self.sudo().env["soong.workflow.log"].create({
|
|
"model": res_model,
|
|
"res_id":res_id,
|
|
"node_id": next_node_id.id,
|
|
"workflow_id": self.workflow_id.id,
|
|
"done_by": employee.user_id.id,
|
|
"node_btn_name": "4",
|
|
"approval_state": "0", # 待审批
|
|
})
|
|
workflow_record_id = self.env['soong.workflow.record'].search([('code', '=', record_id.code)])
|
|
if employee_user_role_ids:
|
|
workflow_record_id.users_ids = [(4, employee.user_id.id) for employee in employee_user_role_ids if
|
|
employee.user_id]
|
|
workflow_record_id.employee_ids = employee_user_role_ids
|
|
workflow_record_id.approve_state = "pending" # 待审批
|
|
related_record = self.env[res_model].browse(res_id)
|
|
if hasattr(related_record, 'self_users_ids'):
|
|
user_ids = [employee.user_id.id for employee in employee_user_role_ids if employee.user_id]
|
|
related_record.self_users_ids = [(6, 0, user_ids)] if user_ids else [(5,)]
|
|
record_id.write({'state': self.link_id.node_to.name})
|
|
|
|
for employee in employee_user_role_ids:
|
|
action_id = self.env['ir.actions.act_window'].search([('res_model', '=', res_model)])[0]
|
|
# url = f'https://oa.thtzjt.com/web?login={employee.user_id.login}&oauth_uid={employee.wecom_userid}#id={record_id.id}&cids=2&action={action_id.id}&model={record_id._name}&view_type=form&menu_id=10104'
|
|
# 生成目标URL(不使用login参数,避免session冲突)
|
|
target_url = f'https://oa.thtzjt.com/web#id={record_id.id}&cids=2&action={action_id.id}&model={record_id._name}&view_type=form&menu_id=10104'
|
|
# 使用OAuth登录链接,避免session冲突
|
|
url = self.sudo().env["wecom.apps"].generate_oauth_login_url(target_url)
|
|
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='oa',
|
|
user_id=employee.wecom_userid,
|
|
title=record_id._description,
|
|
description="标题: {}\n".format(
|
|
record_id.name) + self.env.user.name + ' ' + str(
|
|
fields.Datetime.now() + timedelta(
|
|
hours=8)),
|
|
url=url, btntxt="查看详情")
|
|
|
|
def _get_approvers_for_link(self, record_id=None):
|
|
node = self.workflow_id.node_ids.search([
|
|
('name', '=', self.link_id.node_to.name),
|
|
('workflow_id', '=', self.workflow_id.id)
|
|
])
|
|
button = False
|
|
if node.button_ids:
|
|
# 1. 优先找“分发”按钮
|
|
distribute_btn = next((btn for btn in node.button_ids if btn.name == '分发'), None)
|
|
if distribute_btn:
|
|
button = distribute_btn
|
|
else:
|
|
# 2. 找不到“分发”再找“转交”
|
|
transfer_btn = next((btn for btn in node.button_ids if btn.name == '转交'), None)
|
|
if transfer_btn:
|
|
button = transfer_btn
|
|
else:
|
|
# 3. 最后找“结束”
|
|
button = next((btn for btn in node.button_ids if btn.name == '结束'), None)
|
|
|
|
if not button:
|
|
return self.env['hr.employee']
|
|
|
|
link_users_id = button.users_role_id
|
|
link_users_group_ids = button.users_role_group_ids
|
|
is_automatic = button.is_automatic
|
|
is_automatic_company = button.is_automatic_company
|
|
is_automatic_group = button.is_automatic_group
|
|
is_logged_by = button.is_logged_by
|
|
is_logged_company = button.is_logged_company
|
|
is_logged_group = button.is_logged_group
|
|
is_dep = button.is_dep
|
|
is_field = button.specify_field_id
|
|
|
|
if button.reviewer_id:
|
|
employee = self.env['hr.employee'].search([
|
|
('user_id', '=', button.reviewer_id.id),
|
|
], limit=1)
|
|
return employee
|
|
|
|
# 部门和公司筛选条件
|
|
department_domain = []
|
|
company_domain = []
|
|
user_role_domain = []
|
|
|
|
if record_id:
|
|
# 获取当前用户和申请人的相关信息
|
|
current_user = self.env.user
|
|
applicant = None
|
|
|
|
# 获取申请人的用户对象
|
|
for field_name in ['user_id', 'users_id']:
|
|
if hasattr(record_id, field_name):
|
|
applicant = getattr(record_id, field_name)
|
|
if applicant:
|
|
break
|
|
|
|
# 根据勾选的条件设置域条件(只勾选一个)
|
|
if is_automatic and record_id.department_id:
|
|
# 按当前申请人自动匹配-本部门(保留部门和公司条件)
|
|
department_domain = ['|', ('department_id', '=', record_id.department_id.id),
|
|
('department_ids', 'in', record_id.department_id.id)]
|
|
company_domain = [('company_id', '=', applicant.company_id.id)]
|
|
|
|
elif is_automatic_company and applicant and hasattr(applicant, 'company_id'):
|
|
# 按当前申请人自动匹配-本公司(仅保留公司条件)
|
|
company_id = applicant.company_id.id
|
|
company_domain = [('company_id', '=', company_id)]
|
|
|
|
elif is_automatic_group and applicant and hasattr(applicant, 'company_id'):
|
|
# 按当前申请人自动匹配-本集团(仅保留公司条件)
|
|
parent_company = applicant.company_id.parent_id
|
|
if parent_company:
|
|
group_company_ids = self.env['res.company'].search([('id', 'child_of', parent_company.id)]).ids
|
|
company_domain = [('company_id', 'in', group_company_ids)]
|
|
|
|
elif is_dep and hasattr(record_id, 'department_id1') and record_id.department_id1:
|
|
department_id1 = record_id.department_id1.id
|
|
department_domain = ['|', ('department_id', '=', department_id1),
|
|
('department_ids', 'in', department_id1)]
|
|
user_role_domain = ['|', ('user_role_id', '=', button.role_id.user_role_ids.ids),
|
|
('user_role_ids', 'in', button.role_id.user_role_ids.ids)]
|
|
|
|
elif is_logged_by and current_user.department_id:
|
|
# 按当前登录人自动匹配-本部门(保留部门和公司条件)
|
|
department_domain = ['|', ('department_id', '=', current_user.department_id.id),
|
|
('department_ids', 'in', current_user.department_id.id)]
|
|
company_domain = [('company_id', '=', current_user.company_id.id)]
|
|
|
|
elif is_logged_company:
|
|
# 按当前登录人自动匹配-本公司(仅保留公司条件)
|
|
company_id = current_user.company_id.id
|
|
company_domain = [('company_id', '=', company_id)]
|
|
|
|
elif is_logged_group:
|
|
# 按当前登录人自动匹配-本集团(仅保留公司条件)
|
|
parent_company = current_user.company_id.parent_id
|
|
if parent_company:
|
|
group_company_ids = self.env['res.company'].search([('id', 'child_of', parent_company.id)]).ids
|
|
company_domain = [('company_id', 'in', group_company_ids)]
|
|
elif is_field:
|
|
field_name = button.specify_field_id.name
|
|
# 目前只会有入职
|
|
field_value = record_id[field_name]
|
|
department_domain = ['|', ('department_id', '=', field_value.id),
|
|
('department_ids', 'in', field_value.id)]
|
|
|
|
if link_users_id:
|
|
role_domain = ['|', ('user_role_id', '=', link_users_id.id), ('user_role_ids', 'in', link_users_id.id)]
|
|
if user_role_domain:
|
|
role_domain = ['|'] + role_domain + user_role_domain
|
|
domain = role_domain + company_domain + department_domain
|
|
return self.env['hr.employee'].sudo().search(domain)
|
|
|
|
elif link_users_group_ids:
|
|
role_domain = ['|', ('user_role_id', 'in', link_users_group_ids.user_role_ids.ids),
|
|
('user_role_ids', 'in', link_users_group_ids.user_role_ids.ids)]
|
|
if user_role_domain:
|
|
role_domain = ['|'] + role_domain + user_role_domain
|
|
domain = role_domain + company_domain + department_domain
|
|
return self.env['hr.employee'].sudo().search(domain)
|
|
|
|
# 特殊分发按钮
|
|
if '分发' in link.name and record_id and hasattr(record_id, 'users_id'):
|
|
return record_id.users_id.employee_id
|
|
return self.env['hr.employee']
|
|
|
|
|
|
def run(self):
|
|
for rec in self:
|
|
# Check Condition Before Executing Action
|
|
result = False
|
|
cx = self.env.context.copy() or {}
|
|
locals_dict = {
|
|
"env": self.env,
|
|
"model": self.env[cx.get("active_model", False)],
|
|
"obj": self.env[cx.get("active_model", False)].browse(cx.get("active_id", 0)),
|
|
"user": self.env.user,
|
|
"datetime": datetime,
|
|
"time": time,
|
|
"date": date,
|
|
"timedelta": timedelta,
|
|
"workflow": self.env["soong.workflow"],
|
|
"warning": self.warning,
|
|
"syslog": self.syslog,
|
|
}
|
|
if rec.btn_hide:
|
|
if rec.review_type == "individual":
|
|
if rec.reviewer_id == self.env.user:
|
|
result = True
|
|
elif rec.review_type == "group":
|
|
if self.env.user in self.reviewer_group_id.users:
|
|
result = True
|
|
else:
|
|
try:
|
|
safe_eval(
|
|
rec.reviewer_expression,
|
|
locals_dict=locals_dict,
|
|
mode="exec",
|
|
nocopy=True,
|
|
)
|
|
user = "user" in locals_dict and locals_dict["user"] or False
|
|
if user and self.env.user in user:
|
|
result = True
|
|
except ValidationError as ex:
|
|
raise ex
|
|
except SyntaxError as ex:
|
|
raise UserError(
|
|
_(
|
|
"Wrong python code defined.\n\nError: %s\nLine: %s, Column: %s\n\n%s"
|
|
% (
|
|
ex.args[0],
|
|
ex.args[1][1],
|
|
ex.args[1][2],
|
|
ex.args[1][3],
|
|
)
|
|
)
|
|
)
|
|
else:
|
|
result = True
|
|
if result:
|
|
# Run Proper Action
|
|
if rec.action_type == 'confirm':
|
|
rec.action_type = 'code'
|
|
func = getattr(self, "_run_%s" % rec.action_type)
|
|
func_result = func()
|
|
try:
|
|
user_ids = []
|
|
button_ids = rec.link_id.node_to.button_ids
|
|
for button_id in button_ids:
|
|
# 根据每个按钮状态判断当前应该的查看人员
|
|
if button_id.review_type == "individual":
|
|
user_ids.append(button_id.reviewer_id.id)
|
|
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_ids += user_role_id.ids
|
|
# # 发送信息提醒
|
|
# partner_ids = self.sudo().env['res.users'].search([('id', 'in', user_ids)]).mapped('partner_id').ids
|
|
# self.sudo().with_context(lang=self.env.lang)._message_auto_subscribe_notify(partner_ids, 'soong_workflow.message_yuthon_workflow_btn_approval_data')
|
|
|
|
except Exception as e:
|
|
pass
|
|
return func_result
|
|
|
|
def _run_win_act(self):
|
|
# Variables
|
|
cx = self.env.context.copy() or {}
|
|
win_act_obj = self.env["ir.actions.act_window"]
|
|
# Run Window Action
|
|
for rec in self:
|
|
action = win_act_obj.with_context(cx).browse(rec.win_act_id.id).read()[0]
|
|
action["context"] = cx
|
|
return action
|
|
return False
|
|
|
|
def _run_action(self):
|
|
# Variables
|
|
srv_act_obj = self.env["ir.actions.server"]
|
|
# Run Server Action
|
|
for rec in self:
|
|
srv_act_rec = srv_act_obj.browse(rec.server_action_id.id)
|
|
return srv_act_rec.run()
|
|
|
|
def _run_code(self):
|
|
# Variables
|
|
cx = self.env.context.copy() or {}
|
|
locals_dict = {
|
|
"env": self.env,
|
|
"model": self.env[cx.get("active_model", False)],
|
|
"obj": self.env[cx.get("active_model", False)].browse(
|
|
cx.get("active_id", 0)
|
|
),
|
|
"user": self.env.user,
|
|
"datetime": datetime,
|
|
"time": time,
|
|
"date": date,
|
|
"timedelta": timedelta,
|
|
"workflow": self.env["soong.workflow"],
|
|
"warning": self.warning,
|
|
"syslog": self.syslog,
|
|
}
|
|
# Run Code
|
|
for rec in self:
|
|
try:
|
|
safe_eval(rec.code, locals_dict=locals_dict, mode="exec", nocopy=True)
|
|
action = "action" in locals_dict and locals_dict["action"] or False
|
|
if action:
|
|
return action
|
|
except Warning as ex:
|
|
raise ex
|
|
except SyntaxError as ex:
|
|
raise UserError(
|
|
_(
|
|
"Wrong python code defined.\n\nError: %s\nLine: %s, Column: %s\n\n%s"
|
|
% (ex.args[0], ex.args[1][1], ex.args[1][2], ex.args[1][3])
|
|
)
|
|
)
|
|
return True
|
|
|
|
def _run_link(self):
|
|
for rec in self:
|
|
# Check Condition Before Executing Action
|
|
result = False
|
|
cx = self.env.context.copy() or {}
|
|
locals_dict = {
|
|
"env": self.env,
|
|
"model": self.env[cx.get("active_model", False)],
|
|
"obj": self.env[cx.get("active_model", False)].browse(
|
|
cx.get("active_id", 0)
|
|
),
|
|
"user": self.env.user,
|
|
"datetime": datetime,
|
|
"time": time,
|
|
"date": date,
|
|
"timedelta": timedelta,
|
|
"workflow": self.env["soong.workflow"],
|
|
"warning": self.warning,
|
|
"syslog": self.syslog,
|
|
}
|
|
try:
|
|
safe_eval(
|
|
rec.link_id.condition_code,
|
|
locals_dict=locals_dict,
|
|
mode="exec",
|
|
nocopy=True,
|
|
)
|
|
result = "result" in locals_dict and locals_dict["result"] or False
|
|
except ValidationError as ex:
|
|
raise ex
|
|
except SyntaxError as ex:
|
|
raise UserError(
|
|
_(
|
|
"Wrong python code defined.\n\nError: %s\nLine: %s, Column: %s\n\n%s"
|
|
% (ex.args[0], ex.args[1][1], ex.args[1][2], ex.args[1][3])
|
|
)
|
|
)
|
|
if result:
|
|
# Trigger link function
|
|
return rec.link_id.trigger_link()
|
|
|
|
def _run_link_start_statu(self):
|
|
for rec in self:
|
|
# Check Condition Before Executing Action
|
|
result = False
|
|
cx = self.env.context.copy() or {}
|
|
locals_dict = {
|
|
"env": self.env,
|
|
"model": self.env[cx.get("active_model", False)],
|
|
"obj": self.env[cx.get("active_model", False)].browse(
|
|
cx.get("active_id", 0)
|
|
),
|
|
"user": self.env.user,
|
|
"datetime": datetime,
|
|
"time": time,
|
|
"date": date,
|
|
"timedelta": timedelta,
|
|
"workflow": self.env["soong.workflow"],
|
|
"warning": self.warning,
|
|
"syslog": self.syslog,
|
|
}
|
|
try:
|
|
safe_eval(
|
|
rec.link_id.condition_code,
|
|
locals_dict=locals_dict,
|
|
mode="exec",
|
|
nocopy=True,
|
|
)
|
|
result = "result" in locals_dict and locals_dict["result"] or False
|
|
except ValidationError as ex:
|
|
raise ex
|
|
except SyntaxError as ex:
|
|
raise UserError(
|
|
_(
|
|
"Wrong python code defined.\n\nError: %s\nLine: %s, Column: %s\n\n%s"
|
|
% (ex.args[0], ex.args[1][1], ex.args[1][2], ex.args[1][3])
|
|
)
|
|
)
|
|
if result:
|
|
# todo 更改业务数据的状态,成品不建议这样玩
|
|
try:
|
|
active_id = cx.get("active_id", 0)
|
|
active_model = cx.get("active_model", False)
|
|
obj = self.env[active_model].browse(active_id)
|
|
if obj.exists():
|
|
obj.write({'statu': 'approval'})
|
|
except Exception as e:
|
|
pass
|
|
# Trigger link function
|
|
return rec.link_id.trigger_link()
|
|
|
|
def _run_link_action(self):
|
|
for rec in self:
|
|
# Check Condition Before Executing Action
|
|
result = False
|
|
cx = self.env.context.copy() or {}
|
|
locals_dict = {
|
|
"env": self.env,
|
|
"model": self.env[cx.get("active_model", False)],
|
|
"obj": self.env[cx.get("active_model", False)].browse(
|
|
cx.get("active_id", 0)
|
|
),
|
|
"user": self.env.user,
|
|
"datetime": datetime,
|
|
"time": time,
|
|
"date": date,
|
|
"timedelta": timedelta,
|
|
"workflow": self.env["soong.workflow"],
|
|
"warning": self.warning,
|
|
"syslog": self.syslog,
|
|
}
|
|
try:
|
|
safe_eval(
|
|
rec.link_id.condition_code,
|
|
locals_dict=locals_dict,
|
|
mode="exec",
|
|
nocopy=True,
|
|
)
|
|
result = "result" in locals_dict and locals_dict["result"] or False
|
|
except ValidationError as ex:
|
|
raise ex
|
|
except SyntaxError as ex:
|
|
raise UserError(
|
|
_(
|
|
"Wrong python code defined.\n\nError: %s\nLine: %s, Column: %s\n\n%s"
|
|
% (ex.args[0], ex.args[1][1], ex.args[1][2], ex.args[1][3])
|
|
)
|
|
)
|
|
if result:
|
|
win_act_obj = self.env["ir.actions.act_window"]
|
|
# Run Window Action
|
|
action = win_act_obj.with_context(cx).browse(
|
|
self.env.ref('soong_workflow.soong_approval_notice_wizard_action').id).read()[0]
|
|
action["context"] = cx
|
|
action["context"].update({"default_approval_notice_state": '0'})
|
|
# Trigger link function
|
|
return action
|
|
|
|
def _run_link_action_approve(self):
|
|
for rec in self:
|
|
# Check Condition Before Executing Action
|
|
result = False
|
|
cx = self.env.context.copy() or {}
|
|
locals_dict = {
|
|
"env": self.env,
|
|
"model": self.env[cx.get("active_model", False)],
|
|
"obj": self.env[cx.get("active_model", False)].browse(
|
|
cx.get("active_id", 0)
|
|
),
|
|
"user": self.env.user,
|
|
"datetime": datetime,
|
|
"time": time,
|
|
"date": date,
|
|
"timedelta": timedelta,
|
|
"workflow": self.env["soong.workflow"],
|
|
"warning": self.warning,
|
|
"syslog": self.syslog,
|
|
}
|
|
try:
|
|
safe_eval(
|
|
rec.link_id.condition_code,
|
|
locals_dict=locals_dict,
|
|
mode="exec",
|
|
nocopy=True,
|
|
)
|
|
result = "result" in locals_dict and locals_dict["result"] or False
|
|
except ValidationError as ex:
|
|
raise ex
|
|
except SyntaxError as ex:
|
|
raise UserError(
|
|
_(
|
|
"Wrong python code defined.\n\nError: %s\nLine: %s, Column: %s\n\n%s"
|
|
% (ex.args[0], ex.args[1][1], ex.args[1][2], ex.args[1][3])
|
|
)
|
|
)
|
|
if result:
|
|
win_act_obj = self.env["ir.actions.act_window"]
|
|
# Run Window Action
|
|
action = win_act_obj.with_context(cx).browse(
|
|
self.env.ref('soong_workflow.soong_approval_approve_notice_wizard_action').id).read()[0]
|
|
action["context"] = cx
|
|
action["context"].update({"default_approval_notice_state": '1'})
|
|
# Trigger link function
|
|
return action
|
|
|
|
def _run_link_action_refuse(self):
|
|
for rec in self:
|
|
# Check Condition Before Executing Action
|
|
result = False
|
|
cx = self.env.context.copy() or {}
|
|
locals_dict = {
|
|
"env": self.env,
|
|
"model": self.env[cx.get("active_model", False)],
|
|
"obj": self.env[cx.get("active_model", False)].browse(
|
|
cx.get("active_id", 0)
|
|
),
|
|
"user": self.env.user,
|
|
"datetime": datetime,
|
|
"time": time,
|
|
"date": date,
|
|
"timedelta": timedelta,
|
|
"workflow": self.env["soong.workflow"],
|
|
"warning": self.warning,
|
|
"syslog": self.syslog,
|
|
}
|
|
try:
|
|
safe_eval(
|
|
rec.link_id.condition_code,
|
|
locals_dict=locals_dict,
|
|
mode="exec",
|
|
nocopy=True,
|
|
)
|
|
result = "result" in locals_dict and locals_dict["result"] or False
|
|
except ValidationError as ex:
|
|
raise ex
|
|
except SyntaxError as ex:
|
|
raise UserError(
|
|
_(
|
|
"Wrong python code defined.\n\nError: %s\nLine: %s, Column: %s\n\n%s"
|
|
% (ex.args[0], ex.args[1][1], ex.args[1][2], ex.args[1][3])
|
|
)
|
|
)
|
|
if result:
|
|
win_act_obj = self.env["ir.actions.act_window"]
|
|
# Run Window Action
|
|
action = win_act_obj.with_context(cx).browse(
|
|
self.env.ref('soong_workflow.soong_approval_refuse_notice_wizard_action').id).read()[0]
|
|
action["context"] = cx
|
|
action["context"].update({"default_approval_notice_state": '2'})
|
|
# Trigger link function
|
|
return action
|
|
|
|
def warning(self, msg):
|
|
if not isinstance(msg, str):
|
|
msg = str(msg)
|
|
raise UserError(msg)
|
|
|
|
def syslog(self, msg):
|
|
if not isinstance(msg, str):
|
|
msg = str(msg)
|
|
_logger.info(msg)
|
|
|
|
|
|
class SoongWorkflowNodeField(models.Model):
|
|
_name = "soong.workflow.node.field"
|
|
_description = "Soong Workflow Node Fields"
|
|
|
|
name = fields.Many2one(comodel_name="ir.model.fields", string="Field")
|
|
model_id = fields.Many2one(
|
|
comodel_name="ir.model", string="Model", domain="[('state','=','base')]"
|
|
)
|
|
readonly = fields.Boolean(string="Readonly")
|
|
required = fields.Boolean(string="Required")
|
|
invisible = fields.Boolean(string="Invisible")
|
|
group_ids = fields.Many2many(comodel_name="res.groups", string="Groups")
|
|
user_ids = fields.Many2many(comodel_name="res.users", string="Users")
|
|
node_id = fields.Many2one(
|
|
comodel_name="soong.workflow.node",
|
|
string="Node Ref.",
|
|
ondelete="cascade",
|
|
required=True,
|
|
)
|