This commit is contained in:
李鹏宇
2026-01-06 18:34:21 +08:00
27 changed files with 424 additions and 177 deletions
@@ -85,6 +85,7 @@ class SoongWorkflowLog2(models.Model):
approval_state = fields.Selection([('0', '未读'), ('1', '已读')], string='状态', default='0')
document_ids = fields.Many2many('ir.attachment', string="附件")
lase_click_date = fields.Datetime(string="操作时间")
commit = fields.Char(string="意见")
@api.depends("workflow_id", "node_id", "node_btn_id")
+12 -17
View File
@@ -22,9 +22,7 @@ class SoongWorkflowMixin(models.AbstractModel):
for rec in self:
if rec.log_ids:
current_user = self.env.user
target_logs = rec.log_ids.filtered(
lambda l: l.done_by.id == current_user.id and l.approval_state == '0'
)
target_logs = rec.log_ids.filtered(lambda l: l.done_by.id == current_user.id and l.approval_state == '0')
if target_logs:
target_logs.write({'approval_state': '1'})
return super(SoongWorkflowMixin, self).read(fields=fields, load=load)
@@ -813,33 +811,33 @@ class SoongWorkflowMixin(models.AbstractModel):
('employee_id.user_role_ids', 'in', role_ids)
]
# 如果有角色条件,添加到可见性条件中
# if role_domain:
# allowed_user_ids = self.env['res.users'].search(role_domain).ids
# invisible += f" or uid not in {allowed_user_ids}"
if role_domain:
allowed_user_ids = self.env['res.users'].search(role_domain).ids
invisible += f" or uid not in {allowed_user_ids}"
# 如果有隐藏条件的话,启用隐藏
if button.is_review_invisible and button.invisible_expression:
domain = eval(button.invisible_expression)
btn_invisible = self.sudo().env[button.workflow_id.model_id.model].search(domain).ids
invisible += " or id not in {0} ".format(str(btn_invisible))
# 如果是加签确认
if is_apostille:
id_el = etree.Element("field")
id_el.set("name", "approval_sign_ids")
id_el.set("invisible", "1")
invisible += " or uid not in approval_sign_ids"
# if is_apostille:
# id_el = etree.Element("field")
# id_el.set("name", "approval_sign_ids")
# id_el.set("invisible", "1")
# invisible += " or uid not in approval_sign_ids"
if button.name in ["退回", "结束"]:
id_el = etree.Element("field")
id_el.set("name", "log_ids")
id_el.set("invisible", "1")
invisible += " or not log_ids "
if button.name == "分发":
invisible += " or not is_send"
if button.name == "收回":
id_el = etree.Element("field")
id_el.set("name", "log_ids")
id_el.set("invisible", "1")
invisible += " or not log_ids or not is_back"
# if button.name == "结束":
# invisible += " or True"
invisible += " or work_end"
if model == 'purchase.order':
@@ -1090,11 +1088,8 @@ class SoongWorkflowMixin(models.AbstractModel):
has_group = user_rec.has_group(ext_id)
if not has_group:
flag_show = False
if not flag_show and (
field_attrs.group_ids or field_attrs.user_ids
):
if not flag_show and (field_attrs.group_ids or field_attrs.user_ids):
invisible_arr.append(node.node_name)
read_num = ''
if readonly_arr:
id_el = etree.Element("field")
id_el.set("name", "log_ids")
@@ -57,6 +57,7 @@ class SoongWorkflowRecord(models.Model):
# 人力资源流程的发生日期
workflow_happen_date = fields.Date(string="发生日期")
is_unlink = fields.Boolean(string="是否可删", compute='_compute_is_unlink')
@api.depends_context('uid', 'company')
@api.depends('department_id', 'employee_ids')
@@ -77,6 +78,14 @@ class SoongWorkflowRecord(models.Model):
has_valid_employee = bool(record.employee_ids & valid_employee_ids)
record.member_of_department = has_valid_employee
@api.depends('create_uid', 'employee_ids')
def _compute_is_unlink(self):
for record in self:
if len(record.employee_ids) == 1 and record.employee_ids.user_id.id == record.create_uid.id:
record.is_unlink = True
else:
record.is_unlink = False
def _get_valid_employee_for_user(self):
user = self.env.user
employee = user.employee_ids
@@ -322,6 +331,17 @@ class SoongWorkflowRecord(models.Model):
# ids += c_id
# return [('id', 'in', ids)]
# 后台
def backend(self):
form_id = self.env.ref("soong_workflow.soong_workflow_record_form").id
return {
"type": "ir.actions.act_window",
"name": "后台",
"res_model": "soong.workflow.record",
"views": [[form_id, "form"]],
"res_id": self.id
}
# 撤销
def revoke_record(self):
wizard = self.env.ref("soong_workflow.view_soong_workflow_record_revoke_wizard")
@@ -36,7 +36,8 @@
<field name="log_ids2" style="width:100%; margin-top: 10px;">
<tree editable="bottom">
<field name="done_by" string=""/>
<field name="name" string=""/>
<field name="commit" string=""/>
<!-- <field name="name" string=""/>-->
<field name="approval_state" string=""/>
<field name="lase_click_date" string=""/>
</tree>
@@ -99,7 +100,8 @@
<field name="log_ids2" style="width:100%%; margin-top: 10px;">
<tree create="false" edit="false" delete="false" editable="bottom">
<field name="done_by" string=""/>
<field name="name" string=""/>
<field name="commit" string=""/>
<!-- <field name="name" string=""/>-->
<field name="approval_state" string=""/>
<field name="lase_click_date" string=""/>
</tree>
+16 -6
View File
@@ -11,7 +11,17 @@
parent="menu_soong_workflow_root"
action="action_kklw_workflow_approval_request"
sequence="1"/>
<menuitem id="menu_soong_workflow_other_record"
<menuitem id="menu_soong_workflow_todo_record_first"
name="待办"
parent="menu_soong_workflow_root"
action="soong_workflow.soong_workflow_record_todo_action"
sequence="2"/>
<menuitem id="menu_soong_workflow_done_record_first"
name="已办"
parent="menu_soong_workflow_root"
action="soong_workflow.soong_workflow_record_done_action"
sequence="3"/>
<menuitem id="menu_soong_workflow_other_record"
name="流程查询"
parent="menu_soong_workflow_root"
action="soong_workflow_other_record_action"
@@ -66,11 +76,11 @@
parent="menu_soong_other_setting"
action="view_soong_workflow_node_button_action"
sequence="2"/>
<!-- <menuitem id="menu_trans_link_action_setting"-->
<!-- name="工作流节点配置(后台测试)"-->
<!-- parent="menu_soong_other_setting"-->
<!-- action="trans_link_action"-->
<!-- sequence="3"/>-->
<!-- <menuitem id="menu_trans_link_action_setting"-->
<!-- name="工作流节点配置(后台测试)"-->
<!-- parent="menu_soong_other_setting"-->
<!-- action="trans_link_action"-->
<!-- sequence="3"/>-->
<menuitem id="menu_soong_approval_note"
name="常用审批意见"
parent="menu_soong_other_setting"
+47 -4
View File
@@ -101,9 +101,8 @@
<field name="is_manager" column_invisible="1"/>
<field name="meal" column_invisible="1"/>
<field name="workflow_happen_date" string="发生日期" column_invisible="1"/>
<button name="delete_record" type="object" string="删除" class="btn-primary" confirm="你确定要删除吗?"
groups="soong_workflow.group_soong_workflow_manager"/>
<button name="backend" type="object" string="后台" class="btn-primary" groups="soong_workflow.group_soong_workflow_manager"/>
<button name="delete_record" type="object" string="删除" class="btn-primary" confirm="你确定要删除吗?" groups="soong_workflow.group_soong_workflow_manager"/>
<button name="reminders_record" type="object" string="催办" class="btn-primary"
groups="soong_workflow.group_soong_workflow_manager" invisible="approve_state in ['start', 'end']"/>
<button name="revoke_record" type="object" string="撤销" class="btn-primary"
@@ -113,6 +112,49 @@
</tree>
</field>
</record>
<record id="soong_workflow_record_form" model="ir.ui.view">
<field name="name">soong.workflow.record.form</field>
<field name="model">soong.workflow.record</field>
<field name="arch" type="xml">
<form string="流程监控">
<group>
<group>
<field name="code"/>
<field name="workflow_id" string="审批类型"/>
<field name="name"/>
<field name="approve_state" string="审批状态"/>
<field name="create_uid"/>
<field name="employee_ids" widget="many2many_tags" string="当前经办人"/>
<field name="soong_state"/>
<field name="member_of_department"/>
<field name="node_id" string="当前节点"/>
</group>
<group>
<field name="documents_ids" widget="preview_many2many"/>
<field name="approvals_group_id"/>
<field name="department_id"/>
<field name="users_ids" string="用户" widget="many2many_tags"/>
<field name="write_date2"/>
<field name="company_id"/>
</group>
</group>
<group>
<group>
<field name="text"/>
<field name="reclaim_state"/>
</group>
<group>
<field name="is_manager"/>
<field name="meal"/>
<field name="workflow_happen_date" string="发生日期"/>
</group>
</group>
</form>
</field>
</record>
<!--我的流程-->
<record id="soong_workflow_record_my_tree" model="ir.ui.view">
<field name="name">soong.workflow.my.record.tree</field>
@@ -133,8 +175,9 @@
<field name="employee_ids" widget="many2many_tags" string="当前经办人" class="list_ids_width"/>
<field name="soong_state"/>
<field name="is_manager" column_invisible="1"/>
<field name="is_unlink" column_invisible="1"/>
<button name="delete_record" type="object" string="删除" class="btn-primary" confirm="你确定要删除吗?"
invisible="approve_state != 'start'"/>
invisible="not is_unlink"/>
<button name="reminders_record" type="object" string="催办" class="btn-primary" invisible="soong_state != 'done' or create_uid != uid or approve_state == 'end'"/>
<button name="revoke_record" type="object" string="撤销" class="btn-primary"
groups="soong_workflow.group_soong_workflow_manager"/>
@@ -24,19 +24,23 @@ class SoongBouncedWizard(models.Model):
if invalid_logs:
raise UserError('当前状态不可以收回')
prev_log = None
total_log_count = len(log_ids)
deleted_log_count = len(log_to_delete)
prev_log_index = (total_log_count - deleted_log_count) - 1
other_log_index = total_log_count - deleted_log_count
if prev_log_index < 0 or prev_log_index >= len(log_ids):
raise UserError('无有效的上一级审批明细行,无法执行收回操作')
prev_log = log_ids[prev_log_index]
related_record = self.env[self.res_model].browse(self.res_id)
done_by_list = []
for index in range(other_log_index):
done_by_list.append(log_ids[index].done_by.id)
if hasattr(related_record, 'self_users_ids'):
related_record.self_users_ids = [(6, 0, [prev_log.done_by.id])]
self.env['soong.workflow.record'].search([('code', '=', record.code)]).write({"employee_ids": [(6, 0, [prev_log.done_by.employee_ids.id])],
"users_ids": [(6, 0, [prev_log.done_by.id])],
"users_ids": [(6, 0, done_by_list)],
'soong_state': 'to_do'
})
log_to_delete.unlink()
@@ -331,7 +331,6 @@ class SoongWorkflowCommentWizard(models.TransientModel):
cx = self.env.context.copy() or {}
record_id = self.env[self.res_model].search([('id', '=', self.res_id)])
is_admin = self.env.user.has_group('soong_workflow.group_soong_workflow_manager')
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)])
@@ -441,7 +440,6 @@ class SoongWorkflowCommentWizard(models.TransientModel):
hours=8)),
url=url, btntxt="查看详情")
# next_node_employee_log.msg_id = result_data[1]['msgid']
else: # 串审模式 (沿用原有逻辑)
# 查找下一个节点
next_node_id = record_id.workflow_id.node_ids.search([
@@ -468,41 +466,6 @@ class SoongWorkflowCommentWizard(models.TransientModel):
user_ids = [employee.user_id.id for employee in self.employee_ids if employee.user_id]
related_record.self_users_ids = [(6, 0, user_ids)] if user_ids else [(5,)]
record_id.write({'state': self.trans_link_id.name})
# if self.node_btn_name == '结束':
# # 抄送传阅日志
# if self_node_id.is_carbon_copy:
# for employee in self_node_id.employee_ids:
# if not employee.wecom_userid:
# raise ("请同步{}的企业微信".format(employee.name))
# record_id = self.env[self.res_model].search([('id', '=', self.res_id)])
# self.sudo().env["soong.workflow.record.copy"].create({
# "code": record_id.code,
# "name": record_id.name,
# "res_model": self.res_model,
# "workflow_id": self.node_btn_id.workflow_id.id,
# "res_id": self.res_id,
# "done_by": employee.user_id.id,
# "approval_state_copy": "0",
# })
# self.sudo().env["soong.workflow.log2"].create({
# "model": self.res_model,
# "res_id": self.res_id,
# "node_id": self.node_btn_id.node_id.id,
# "workflow_id": self.node_btn_id.workflow_id.id,
# "done_by": employee.user_id.id,
# "node_btn_id": self.node_btn_id.id,
# "approval_state": "0",
# })
# url = f'https://oa.thtzjt.com/web#id={self.id}&cids=2&action={record_id.action.id}&model={self.res_model}&view_type=from&menu_id={record_id.id}'
# description = "标题: {}\n".format(record_id.name) + self.env.user.name + ' ' + str(
# fields.Datetime.now() + timedelta(hours=8))
# self.sudo().env["wecom.apps"].sync_send_message_textcard(category='oa',
# user_id=employee.wecom_userid,
# title=record_id._description + "传阅/抄送",
# description=description, url=url,
# btntxt="查看详情")
# self.env['soong.workflow.record'].search([('code', '=', record_id.code)]).write({'approve_state': 'pending'})
# return self.node_btn_id.with_context(cx).run()
for employee in self.circulated_employee_ids:
record_id = self.env[self.res_model].search([('id', '=', self.res_id)])
self.sudo().env["soong.workflow.record.copy"].create({
@@ -554,71 +517,57 @@ class SoongWorkflowCommentWizard(models.TransientModel):
if hasattr(related_record, 'self_users_ids'):
related_record.self_users_ids = [(6, 0, user_ids)] if user_ids else [(5,)]
workflow_record_id.users_ids = [(6, 0, user_ids)]
return self.node_btn_id.with_context(cx).run()
if self.node_btn_name == '结束':
current_user = self.env.user
current_datetime = fields.Datetime.now()
is_admin = current_user.has_group('soong_workflow.group_soong_workflow_manager')
if is_admin:
write_vals = {
record_id.log_ids[-1].sudo().write({
'comment': self.comment,
'approval_state': "3",
'approval_state': "2",
'lase_click_date': fields.Datetime.now() - timedelta(hours=8),
'document_ids': [(6, 0, self.document_ids.ids)] # Many2many 替换语法
}
record_id.log_ids[-1].sudo().write(write_vals)
record_id.work_end = True
'document_ids': [(6, 0, self.document_ids.ids)]
})
self.env['soong.workflow.record'].search([('code', '=', record_id.code)]).write({'approve_state': 'end',
"employee_ids": False,
"node_id": False, })
else:
log_records = record_id.log_ids
if record_id.log_ids2:
log_records = record_id.log_ids2
elif record_id.log_ids:
log_records = record_id.log_ids
if log_records:
# 查找当前用户的日志记录并更新
user_log = log_records.filtered(lambda log: log.done_by == current_user)
if record_id.log_ids:
user_log = record_id.log_ids.filtered(lambda log: log.done_by == current_user)
if user_log:
user_log.write({
'comment': self.comment,
'approval_state': "3",
'approval_state': "2",
'lase_click_date': current_datetime,
'document_ids': [(6, 0, self.document_ids.ids)]
})
last_log = log_records[-1] if log_records else None
if last_log:
same_name_logs = log_records.filtered(
lambda log: log.name == last_log.name
and log.node_btn_name == '4'
and log.id != last_log.id
)
# 判断是否需要更新工作流状态
if same_name_logs:
all_approved = all(log.approval_state == '3' for log in same_name_logs)
all_approved = all_approved and (last_log.approval_state == '3')
if all_approved:
# 所有符合条件的记录都已批准,更新工作流状态
self.env['soong.workflow.record'].search([
('code', '=', record_id.code)
]).write({
'approve_state': 'end',
'employee_ids': False,
'node_id': False,
})
record_id.work_end = True
else:
self.env['soong.workflow.record'].search([
('code', '=', record_id.code)
]).write({
'approve_state': 'end',
'employee_ids': False,
'node_id': False,
})
record_id.work_end = True
if not record_id.log_ids.search([('approval_state', 'in', ['0', '1'])]) and not record_id.log_ids2.search([('approval_state', '=', '0')]):
record_id.work_end = True
# last_log = log_records[-1] if log_records else None
# if last_log:
# same_name_logs = log_records.filtered(lambda log: log.name == last_log.name and log.node_btn_name == '4' and log.id != last_log.id)
#
# # 判断是否需要更新工作流状态
# if same_name_logs:
# all_approved = all(log.approval_state == '3' for log in same_name_logs)
# all_approved = all_approved and (last_log.approval_state == '3')
# if all_approved:
# # 所有符合条件的记录都已批准,更新工作流状态
# self.env['soong.workflow.record'].search([('code', '=', record_id.code)]).write({
# 'approve_state': 'end',
# 'employee_ids': False,
# 'node_id': False,
# })
# record_id.work_end = True
# else:
# self.env['soong.workflow.record'].search([
# ('code', '=', record_id.code)
# ]).write({
# 'approve_state': 'end',
# 'employee_ids': False,
# 'node_id': False,
# })
# record_id.work_end = True
# 给申请人发消息
biz_record = self.env[self.res_model].browse(self.res_id)
@@ -660,7 +609,40 @@ class SoongWorkflowCommentWizard(models.TransientModel):
title=record_id._description,
description=f"编号为{record_id.code}的{record_id._description}已结束,请归档",
url=url, btntxt="查看详情")
return self.node_btn_id.with_context(cx).run()
if self.node_btn_name == '确认':
log_rec_id = record_id.log_ids2.filtered(lambda log: log.done_by == self.env.user)
log_rec_id.write({
'comment': self.comment,
'approval_state': "1",
'lase_click_date': fields.datetime.now(),
'document_ids': [(6, 0, self.document_ids.ids)]
})
for employee in self.circulated_employee_ids:
workflow_record_id = self.env['soong.workflow.record'].search([('code', '=', record_id.code)])
workflow_record_id.users_ids = [(4, employee.user_id.id) for employee in self.circulated_employee_ids if employee.user_id]
workflow_record_id.employee_ids = [(4, self.circulated_employee_ids.ids)]
record_id = self.env[self.res_model].search([('id', '=', self.res_id)])
self.sudo().env["soong.workflow.record.copy"].create({
"code": record_id.code,
"name": record_id.name,
"res_model": self.res_model,
"workflow_id": self.node_btn_id.workflow_id.id,
"res_id": self.res_id,
"done_by": employee.user_id.id,
"approval_state_copy": "0",
})
self.sudo().env["soong.workflow.log2"].create({
"model": self.res_model,
"res_id": self.res_id,
"node_id": self.node_btn_id.node_id.id,
"workflow_id": self.node_btn_id.workflow_id.id,
"done_by": employee.user_id.id,
"node_btn_id": self.node_btn_id.id,
"approval_state": "0",
})
if self.node_btn_name == "分发":
self.is_send = True
workflow_record_id = self.env['soong.workflow.record'].search([('code', '=', record_id.code)])
action_id = self.env['ir.actions.act_window'].search([('res_model', '=', self.res_model)])[0]
url = f'https://oa.thtzjt.com/web#id={record_id.id}&cids=2&action={action_id.id}&model={self.res_model}&view_type=from&menu_id={record_id.id}'
@@ -681,7 +663,7 @@ class SoongWorkflowCommentWizard(models.TransientModel):
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='oa', user_id=self.employee_ids.wecom_userid, title=record_id._description, description=description, url=url, btntxt="查看详情")
for emp in self.dep_manager_employee_ids:
workflow_record_id.users_ids = [(4, employee.user_id.id) for employee in self.dep_manager_employee_ids if employee.user_id]
next_node_id = record_id.workflow_id.node_ids.search([('name', '=', '承办'),('workflow_id', '=', record_id.workflow_id.id)])
next_node_id = record_id.workflow_id.node_ids.search([('name', '=', '承办'), ('workflow_id', '=', record_id.workflow_id.id)])
record_id.log_ids[-1].write({"comment": self.comment, "approval_state": "2", "lase_click_date": fields.Datetime.now()})
self.sudo().env["soong.workflow.log"].create({
"code": self.code,
@@ -693,8 +675,8 @@ class SoongWorkflowCommentWizard(models.TransientModel):
"node_btn_name": "0",
})
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='oa', user_id=emp.wecom_userid, title=record_id._description + "承办", description=description, url=url, btntxt="查看详情")
workflow_record_id.employee_ids = self.dep_manager_employee_ids + self.employee_ids
for employee in self.circulated_employee_ids:
workflow_record_id.users_ids = [(4, employee.user_id.id) for employee in self.circulated_employee_ids if employee.user_id]
record_id = self.env[self.res_model].search([('id', '=', self.res_id)])
self.sudo().env["soong.workflow.record.copy"].create({
"code": record_id.code,
@@ -715,6 +697,7 @@ class SoongWorkflowCommentWizard(models.TransientModel):
"approval_state": "0",
})
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='oa', user_id=employee.wecom_userid, title=record_id._description + "传阅/抄送",description=description, url=url, btntxt="查看详情")
workflow_record_id.employee_ids = self.dep_manager_employee_ids + self.employee_ids + self.circulated_employee_ids
if self.node_btn_name == "收回":
# recall_url = f'https://qyapi.weixin.qq.com/cgi-bin/message/recall?access_token={access_token}'
record = self.env[self.res_model].search([('id', '=', self.res_id)])
@@ -736,7 +719,15 @@ class SoongWorkflowCommentWizard(models.TransientModel):
record.write({'state': 'draft', 'work_end': False})
else:
record.write({'state': log_ids[-2].name, 'work_end': False})
return self.node_btn_id.with_context(cx).run()
if self.node_btn_name != "收回":
menu_id = self.env.ref("soong_workflow.menu_soong_workflow_todo_record_first").id
return {
"type": "ir.actions.client",
"tag": "reload",
"params": {"menu_id": menu_id,}
}
def update_self_users_ids(self):
@@ -23,12 +23,17 @@
</div>
</group>
<group invisible="node_btn_name != '结束'">
<div>
<h2>当前流程是否结束,请确认</h2>
</div>
<div class="oe_comment_block" style=" width:1200%; border: 1px solid #dee2e6; border-radius: 4px; padding: 12px; margin-bottom: 16px;">
<label for="comment_note_id" string="结束意见"
style="font-weight: bold; margin-bottom: 8px; display: block;"/>
<label for="comment_note_id" string="结束意见" style="font-weight: bold; margin-bottom: 8px; display: block;"/>
<field name="comment_note_id" class="mb-3" style="width: 100%;" options="{'no_create': True}" domain="[('note_setting_id.users_role_ids', 'in', user_role_ids)]"/>
<field name="comment_note" placeholder="请输入意见内容..." style="width: 100%;"/>
</div>
<group>
<field name="circulated_employee_ids" widget="many2many_tags" options="{'no_create': True}"/>
</group>
</group>
<group invisible="node_btn_name != '分发'">
<div class="oe_comment_block" style=" width:1200%; border: 1px solid #dee2e6; border-radius: 4px; padding: 12px; margin-bottom: 16px;">
@@ -64,15 +69,12 @@
<field name="employee_ids1" widget="many2many_tags" string="人员范围" invisible="1"/>
<field name="employee_ids" widget="many2many_tags" string="人员范围" domain = "[('company_id', '=', company_id), ('id', 'in', employee_ids1)] if is_this_company else [('id', 'in', employee_ids1)]" options="{'no_create': True}"/>
<field name="circulated_employee_ids" invisible="node_btn_name == '退回'" widget="many2many_tags" options="{'no_create': True}"/>
<field name="add_employee_ids" invisible="node_btn_name == '退回'" widget="many2many_tags" options="{'no_create': True}"/>
<!-- <field name="add_employee_ids" invisible="node_btn_name == '退回'" widget="many2many_tags" options="{'no_create': True}"/>-->
</group>
</group>
<group invisible="node_btn_name != '结束'">
<field name="document_ids" widget="preview_many2many" force_save="1"/>
</group>
<div invisible="node_btn_name != '结束'">
<h2>当前流程是否结束,请确认</h2>
</div>
<div invisible="node_btn_name != '收回'">
<h2>当前流程是否收回,请确认</h2>
</div>
@@ -333,6 +333,9 @@ class OvertimeApprovals(models.Model):
existing_line.workday += workday
existing_line.legal_day += legal_day
existing_line.public_holidays += public_holidays
existing_line.year_holiday += public_holidays
existing_line.year_workday += workday
start_date = fields.Date.to_date(self.start_time)
end_date = fields.Date.to_date(self.end_time)
attendance_records = self.env['hr.attendance'].search([
@@ -31,7 +31,7 @@ class YuthonVacationReports(models.Model):
year_holiday = fields.Float(string="本年公休日", digits=(16, 3))
year_workday = fields.Float(string="本年工作日", digits=(16, 3))
year_sum = fields.Float(string="本年应休合计", digits=(16, 3), compute="_compute_year_sum")
used_this_year1 = fields.Float(string="本年已休", digits=(16, 3), compute="_compute_year_sum")
used_this_year1 = fields.Float(string="本年已休", digits=(16, 3))
remainder_year1 = fields.Float(string="本年剩余(补休)", digits=(16, 3), compute="_compute_year_sum")
company_id = fields.Many2one(related="employee_id.company_id", string="公司", store=True)
@@ -875,6 +875,34 @@ class VacationLeaveLine(models.Model):
vacation_main = self.env['yuthon.vacation.reports'].browse(vals['vacation_id'])
if vacation_main.vacation_state == 'confirmed':
vals['is_confirm'] = True
if vals.get('update_type') == 'reduce' and vals.get('vacation_id'):
vacation_main = self.env['yuthon.vacation.reports'].browse(vals['vacation_id'])
deduct_amount = vals.get('update_lines', 0.0) / 8
if vacation_main:
used_this_year_new = vacation_main.used_this_year + deduct_amount
vacation_main.write({'used_this_year': used_this_year_new})
#处理跨年场景:查找下月1号的假期记录并扣减previous_year
if vacation_main.vacation_date:
current_vacation_date = vacation_main.vacation_date
next_month_first_day = current_vacation_date + relativedelta(months=+1, day=1)
# 判断是否跨年
is_cross_year = current_vacation_date.year != next_month_first_day.year
if is_cross_year:
next_month_vacation = self.env['yuthon.vacation.reports'].search([
('employee_id', '=', vacation_main.employee_id.id),
('vacation_date', '=', next_month_first_day),
('vacation_state', 'in', ['not_sent', 'pending']),
], limit=1)
if next_month_vacation:
previous_year_new = next_month_vacation.previous_year- deduct_amount
previous_year_new = max(previous_year_new, 0.0)
next_month_vacation.write({'previous_year': previous_year_new})
return super(VacationLeaveLine, self).create(vals)
def _sync_to_employee(self, reverse=False):
@@ -930,32 +958,6 @@ class VacationOverline(models.Model):
'view_mode': 'form',
}
# def _sync_to_employee(self, reverse=False):
# """将数据同步到关联员工
# :param reverse: 是否反向操作(用于删除场景)
# """
# employee = self.vacation_id.employee_id
# employee.meal_number -= self.meal_number
# # 根据操作类型确定计算方式
# sign = -1 if reverse else 1
# if self.update_type == 'add':
# employee.write({
# 'normal_overtime_hours': employee.normal_overtime_hours + (self.workday * sign),
# 'holiday_overtime_hours': employee.holiday_overtime_hours + (self.legal_day * sign),
# 'weekend_overtime_hours': employee.weekend_overtime_hours + (self.public_holidays * sign)
# })
# elif self.update_type == 'reduce':
# employee.write({
# 'normal_overtime_hours': employee.normal_overtime_hours - (self.workday * sign),
# 'holiday_overtime_hours': employee.holiday_overtime_hours - (self.legal_day * sign),
# 'weekend_overtime_hours': employee.weekend_overtime_hours - (self.public_holidays * sign)
# })
#
# @api.model
# def create(self, vals):
# record = super(VacationOverline, self).create(vals)
# record._sync_to_employee()
# return record
@api.model
def create(self, vals):
if vals.get('vacation_id'):
@@ -967,30 +969,69 @@ class VacationOverline(models.Model):
vacation_main = self.env['yuthon.vacation.reports'].browse(vals['vacation_id'])
deduct_workday = vals.get('workday', 0.0)
deduct_public = vals.get('public_holidays', 0.0)
deduct_legal = vals.get('legal_day', 0.0)
deduct_workday_convert = deduct_workday / 8
deduct_public_convert = deduct_public / 8
deduct_legal_convert = deduct_legal / 8
deduct_total = deduct_workday_convert + deduct_public_convert + deduct_legal_convert
if vacation_main:
vacation_deduct_vals = {
'year_workday': vacation_main.year_workday - deduct_workday/8,
'year_holiday': vacation_main.year_holiday - deduct_public/8,
vacation_used_vals = {
'used_this_year1': (vacation_main.used_this_year1 or 0.0) + deduct_total
}
vacation_main.write(vacation_deduct_vals)
vacation_main.write(vacation_used_vals)
is_cross_year = False
# 计算下月1号并判断是否跨年
if vacation_main.vacation_date:
current_vacation_date = vacation_main.vacation_date
next_month_first_day = current_vacation_date + relativedelta(months=+1, day=1)
# 必须是跨年才写入上年工作日
is_cross_year = current_vacation_date.year != next_month_first_day.year
# 跨年场景
if is_cross_year:
# 查找下月1号的未确认假期记录并扣减上年额度
next_month_vacation = self.env['yuthon.vacation.reports'].search([
('employee_id', '=', vacation_main.employee_id.id),
('vacation_date', '=', next_month_first_day),
('vacation_state', 'in', ['not_sent', 'pending']),
], limit=1)
if is_cross_year:
if next_month_vacation:
next_month_deduct_vals = {
'last_workday': next_month_vacation.last_workday - deduct_workday/8,
'last_holiday': next_month_vacation.last_holiday - deduct_public/8,
'last_workday': next_month_vacation.last_workday - deduct_workday_convert,
'last_holiday': next_month_vacation.last_holiday - deduct_public_convert,
}
next_month_vacation.write(next_month_deduct_vals)
if vals.get('update_type') == 'add' and vals.get('vacation_id'):
current_text = vals.get('text', '').strip()
if current_text != '上月额度继承':
vacation_main = self.env['yuthon.vacation.reports'].browse(vals['vacation_id'])
add_workday = vals.get('workday', 0.0)
add_public = vals.get('public_holidays', 0.0)
if vacation_main:
vacation_add_vals = {
'year_workday': vacation_main.year_workday + add_workday / 8,
'year_holiday': vacation_main.year_holiday + add_public / 8,
}
vacation_main.write(vacation_add_vals)
if vacation_main.vacation_date:
current_vacation_date = vacation_main.vacation_date
next_month_first_day = current_vacation_date + relativedelta(months=+1, day=1)
# 必须是跨年才写入上年工作日
is_cross_year = current_vacation_date.year != next_month_first_day.year
next_month_vacation = self.env['yuthon.vacation.reports'].search([
('employee_id', '=', vacation_main.employee_id.id),
('vacation_date', '=', next_month_first_day),
('vacation_state', 'in', ['not_sent', 'pending']),
], limit=1)
if is_cross_year:
next_month_deduct_vals = {
'last_workday': next_month_vacation.last_workday + add_workday / 8,
'last_holiday': next_month_vacation.last_holiday + add_public / 8,
}
next_month_vacation.write(next_month_deduct_vals)
return super(VacationOverline, self).create(vals)
# def unlink(self):
@@ -58,8 +58,14 @@ class RoomBooking(models.Model):
return res
for idx, (main_record, vals) in enumerate(zip(res, vals_list)):
issue_meeting_lines = vals.get('issue_meeting_line_ids', [])
if not isinstance(issue_meeting_lines, list):
continue
for line_triple in issue_meeting_lines:
if not (isinstance(line_triple, (list, tuple)) and len(line_triple) == 3):
continue
line_state, line_id, line_vals = line_triple
if line_state != 0 or not isinstance(line_vals, dict):
continue
issue_library_id = line_vals.get('issue_library_id')
room_id = vals.get('room_id')
meeting_type_id = vals.get('meeting_type_id')
@@ -99,9 +105,12 @@ class IssueMeetingLine(models.Model):
if self.decision_results == 'agree':
is_agree = 'pass'
agree_name = '通过'
issue_state = 'on_meet'
else:
is_agree = 'reject'
agree_name = '未通过'
issue_state = 'will'
self.issue_library_id.issue_state = issue_state
if '党' in meeting_type_name:
self.issue_library_id.is_party_passed = is_agree
original_party_char = self.issue_library_id.party_char or ""
+1 -1
View File
@@ -244,7 +244,7 @@ class IssueLibrary(models.Model):
self.issue_approval_id = issue_approval_id
return {
"type": "ir.actions.act_window",
"name": "批量提交",
"name": "提交议题审批",
"res_model": "issue.approval",
"views": [[form_id, "form"]],
"res_id": issue_approval_id.id,
+3 -3
View File
@@ -45,9 +45,9 @@
decoration-info="issue_state == 'will'"
decoration-success="issue_state == 'done'"
decoration-muted="issue_state == 'cancel'">
<!-- <header>-->
<!-- <button name="all_issue_pull" string="批量提交上会审批" type="object"/>-->
<!-- </header>-->
<header>
<button name="all_issue_pull" string="提交议题审批" type="object"/>
</header>
<field name="name" column_invisible="1"/>
<field name="name_text" class="list_width"/>
<field name="is_party" groups="yuthon_salary.group_jtbb_user" string="党总支"/>
+1
View File
@@ -23,6 +23,7 @@
'views/yuthon_official_incoming_labor_views.xml',
'views/yuthon_official_party_views.xml',
'views/yuthon_file_processing_views.xml',
'views/yuthon_sub_enterprises_view.xml',
'views/yuthon_official_incoming_party_views.xml',
'views/yuthon_cross_departmental_views.xml',
# 'views/inherit_soong_workflow_insector_views.xml',
@@ -1,6 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data>
<record id="sub_enterprises_sequence" model="ir.sequence">
<field name="name">文件处理(子企业)</field>
<field name="code">sub_enterprises_code</field>
<field name="prefix">WZQ%(y)s%(month)s%(day)s</field>
<field name="padding">3</field>
<field name="company_id" eval="False"/>
</record>
<record id="file_code_sequence" model="ir.sequence">
<field name="name">文件处理</field>
<field name="code">file_code</field>
+1
View File
@@ -13,3 +13,4 @@ from . import inherit_room_booking
from . import inherit_issue_library
from . import yuthon_cross_departmental
from . import yuthon_file_processing
from . import yuthon_sub_enterprises
+17 -1
View File
@@ -34,7 +34,7 @@ class YuthonOfficial(models.Model):
date = fields.Datetime(string="拟稿日期", default=fields.Datetime.now)
official_statu = fields.Selection([('done', '办结'), ('approval', '审核')], string="公文环节")
users_id = fields.Many2one('res.users', string="拟稿人", default=lambda self: self.env.user)
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="拟稿部门")
department_id = fields.Many2one(related='users_id.employee_ids.department_id', string="拟稿部门")
company_id = fields.Many2one(related='users_id.company_id', string="公司")
company_id1 = fields.Many2one('res.company', string="公司前缀", default=lambda self: self.env.company)
is_meet = fields.Boolean(string="是否上会")
@@ -57,6 +57,7 @@ class YuthonOfficial(models.Model):
issue_library_ids = fields.One2many('issue.library', 'yuthon_official_id', string="议题关联")
work_end = fields.Boolean(string="结束")
official_state = fields.Selection([('to_do', '待转'), ('done', '已转')], string="状态")
sub_id = fields.Many2one('yuthon.sub.enterprises', string="文件处理流程")
def _get_default_name_title(self):
return self._description if self._description else self._name
@@ -64,6 +65,21 @@ class YuthonOfficial(models.Model):
name_title = fields.Char(default=_get_default_name_title)
self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
def end_approval(self):
self.write({'work_end': True})
if self.main_flats_id.name == '广州市天河投资集团有限公司':
process_id = self.env['yuthon.sub.enterprises'].search([('issuance_process_id', '=', self.id)])
if not process_id:
official_partner_id = self.env['official.partner'].search([('name', '=', '广州市天河投资集团有限公司')])
sub_id = self.env['yuthon.sub.enterprises'].create({
'name': '广州市天河投资集团有限公司文件处理',
'users_id': self.users_id.id,
'official_partner_id': official_partner_id.id,
'issuance_process_id': self.id,
})
self.write({'sub_id': sub_id.id})
@api.onchange('is_cold')
def onchange_is_cold(self):
if self.is_cold:
@@ -31,6 +31,7 @@ class YuthonOfficialIncomingNormal(models.Model):
active = fields.Boolean('Active', default=True, tracking=True)
work_end = fields.Boolean(string="结束")
is_send = fields.Boolean(string="是否分发")
is_issues = fields.Boolean(string="是否上会")
issues_result = fields.Html(string="会议结果")
is_supervising = fields.Boolean(string="是否督办")
@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models, tools
from odoo.exceptions import ValidationError, UserError
class YuthonSubEnterprises(models.Model):
_name = 'yuthon.sub.enterprises'
_description = '文件处理(子企业)'
_inherit = ['mail.thread.main.attachment', 'mail.activity.mixin', 'soong.workflow.mixin']
_rec_name = 'name'
name = fields.Char(string="名称")
code = fields.Char(string="流水号", default=lambda self: self.env['ir.sequence'].next_by_code('sub_enterprises_code'))
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
company_id = fields.Many2one(related='users_id.employee_id.company_id', string="公司")
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
issuance_process_id = fields.Many2one('yuthon.official', string="发文流程")
come_file_id = fields.Char(string="来文编号")
reason_application = fields.Text(string="事由")
official_partner_id = fields.Many2one('official.partner', string="来文单位")
document_ids = fields.Many2many('ir.attachment', string="附件")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
work_end = fields.Boolean(string="结束")
def _get_default_name_title(self):
return self._description if self._description else self._name
name_title = fields.Char(default=_get_default_name_title)
self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
+2 -1
View File
@@ -10,4 +10,5 @@ access_yuthon_official_incoming_normal,yuthon_official_incoming_normal,model_yut
access_yuthon_cross_departmental, yuthon_cross_departmental,model_yuthon_cross_departmental,base.group_user,1,1,1,1
access_yuthon_file_processing,yuthon_file_processing,model_yuthon_file_processing,base.group_user,1,1,1,1
access_main_flats,main_flats,model_main_flats,base.group_user,1,1,1,1
access_copy_flats,copy_flats,model_copy_flats,base.group_user,1,1,1,1
access_copy_flats,copy_flats,model_copy_flats,base.group_user,1,1,1,1
access_yuthon_sub_enterprises,yuthon_sub_enterprises,model_yuthon_sub_enterprises,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
10 access_yuthon_cross_departmental yuthon_cross_departmental model_yuthon_cross_departmental base.group_user 1 1 1 1
11 access_yuthon_file_processing yuthon_file_processing model_yuthon_file_processing base.group_user 1 1 1 1
12 access_main_flats main_flats model_main_flats base.group_user 1 1 1 1
13 access_copy_flats copy_flats model_copy_flats base.group_user 1 1 1 1
14 access_yuthon_sub_enterprises yuthon_sub_enterprises model_yuthon_sub_enterprises base.group_user 1 1 1 1
+6
View File
@@ -66,6 +66,12 @@
name="工会发文"
action="yuthon_official_labor_action"
sequence="10"/>
<menuitem
id="yuthon_sub_enterprises"
parent="yuthon_official_labor_management_menu"
name="文件处理(子企业)"
action="view_yuthon_sub_enterprises_action"
sequence="10"/>
<menuitem id="trade_project_approval_board"
name="立项"
parent="administrative_offices_root_board"
@@ -43,6 +43,7 @@
</h1>
</div>
<group string="审批事项">
<field name="is_send" invisible="1"/>
<field name="is_back" invisible="1"/>
<field name="users_id"/>
<field name="company_id" invisible="1"/>
@@ -81,6 +81,7 @@
<group col="2" string="拟稿信息">
<group>
<field name="users_id"/>
<field name="sub_id" invisible="not sub_id"/>
<field name="official_documents_ids" widget="preview_many2many"/>
</group>
<group>
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_yuthon_sub_enterprises_tree" model="ir.ui.view">
<field name="name">yuthon.sub.enterprises.tree</field>
<field name="model">yuthon.sub.enterprises</field>
<field name="arch" type="xml">
<tree string="文件处理(子企业)">
<field name="name"/>
<field name="users_id"/>
<field name="come_file_id"/>
<field name="official_partner_id"/>
</tree>
</field>
</record>
<record id="view_yuthon_sub_enterprises_form" model="ir.ui.view">
<field name="name">yuthon.sub.enterprises.form</field>
<field name="model">yuthon.sub.enterprises</field>
<field name="arch" type="xml">
<form string="文件处理(子企业)">
<sheet>
<widget name="web_ribbon" title="普件" bg_color="text-bg-success"
invisible="urgency_level != 'normal'"/>
<widget name="web_ribbon" title="急件" bg_color="text-bg-warning"
invisible="urgency_level != 'urgent'"/>
<widget name="web_ribbon" title="特级" bg_color="text-bg-danger"
invisible="urgency_level != 'emergency'"/>
<group col="3">
<group>
<field name="code" string="流水号" readonly="1"/>
</group>
<group>
<field name="urgency_level" readonly="1"/>
</group>
<group/>
</group>
<div class="col-12 text-center">
<h1>
<field name="name_title" readonly="1"/>
</h1>
</div>
<group string="审批信息">
<field name="name"/>
<field name="users_id"/>
<field name="work_end" invisible="1"/>
<field name="come_file_id"/>
<field name="official_partner_id"/>
<field name="reason_application"/>
<field name="issuance_process_id" invisible="not issuance_process_id"/>
<field name="document_ids" widget="preview_many2many"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_yuthon_sub_enterprises_action" model="ir.actions.act_window">
<field name="name">文件处理(子企业)</field>
<field name="res_model">yuthon.sub.enterprises</field>
<field name="view_mode">tree,form</field>
</record>
</odoo>
@@ -17,10 +17,10 @@ class InheritPurchaseOrder(models.Model):
)
name_title = fields.Char(string="默认标题", default='采购申请单', readonly=True)
code = fields.Char(string="流水号", default=lambda self: self.env['ir.sequence'].next_by_code('purchase_workflow_approval_code'))
state = fields.Selection(selection_add=[('部门经理', '部门经理'),
state = fields.Selection(selection_add=[('部门经理', '部门经理'), ('工会主席', '工会主席'),
('协办', '协办'),
('分管领导', '分管领导'),
('总经理', '总经理')], default='draft')
('总经理', '总经理'), ('归档', '归档')], default='draft')
work_end = fields.Boolean(string="结束")
user_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user)
company_id = fields.Many2one(related='user_id.employee_ids.company_id', string="公司")
+10 -10
View File
@@ -719,16 +719,16 @@
parent="holiday_manage_menu_root_board"
action="soong_workflow.soong_workflow_department_record_action"
sequence="4"/>
<menuitem id="menu_soong_workflow_department_record_copy"
name="抄送/传阅流程"
parent="holiday_manage_menu_root_board"
action="soong_workflow.soong_workflow_record_action_copy"
sequence="5"/>
<menuitem id="menu_soong_workflow_department_record_add"
name="加签流程"
parent="holiday_manage_menu_root_board"
action="soong_workflow.soong_workflow_record_action_add"
sequence="6"/>
<!-- <menuitem id="menu_soong_workflow_department_record_copy"-->
<!-- name="抄送/传阅流程"-->
<!-- parent="holiday_manage_menu_root_board"-->
<!-- action="soong_workflow.soong_workflow_record_action_copy"-->
<!-- sequence="5"/>-->
<!-- <menuitem id="menu_soong_workflow_department_record_add"-->
<!-- name="加签流程"-->
<!-- parent="holiday_manage_menu_root_board"-->
<!-- action="soong_workflow.soong_workflow_record_action_add"-->
<!-- sequence="6"/>-->
<menuitem id="property_device_repair_action_brand"
parent="holiday_manage_menu_root_board"
name="报事报修"