diff --git a/attendance_iot/controllers/kaoqin_test.py b/attendance_iot/controllers/kaoqin_test.py index 8f0199e1d..5413e1781 100644 --- a/attendance_iot/controllers/kaoqin_test.py +++ b/attendance_iot/controllers/kaoqin_test.py @@ -58,7 +58,7 @@ class BusController(Controller): if employee_id: request.env(user=SUPERUSER_ID)["hr.attendance.detail"].create({ 'employee_id': employee_id.id, # 员工 - 'checkin_time': fields.Datetime.now(), # 打卡时间 + 'checkin_time': fields.Datetime.now(), 'source': 'iot', # 打卡来源 'attendance_iot_id': attendance_iot_id.id, # 打卡设备 }) diff --git a/soong_workflow/models/soong_workflow_log.py b/soong_workflow/models/soong_workflow_log.py index a424be823..71330f18a 100644 --- a/soong_workflow/models/soong_workflow_log.py +++ b/soong_workflow/models/soong_workflow_log.py @@ -45,12 +45,12 @@ class SoongWorkflowLog(models.Model): @api.depends("workflow_id", "node_id", "node_btn_id") def _compute_name(self): for rec in self: - # rec.name = "%(workflow_id_name)s - %(node_id_name)s - %(node_btn_name)s" % { - # "workflow_id_name": rec.workflow_id.name, - # "node_id_name": rec.node_id.name, - # "node_btn_name": rec.node_btn_id.name, - # } - rec.name = "%(node_id_name)s" % {"node_id_name": rec.node_id.name} + if rec.name == '归档': + pass + if rec.node_id: + rec.name = "%(node_id_name)s" % {"node_id_name": rec.node_id.name} + else: + rec.name = "" @api.depends("workflow_id") def _compute_sequence(self): @@ -91,7 +91,10 @@ class SoongWorkflowLog2(models.Model): @api.depends("workflow_id", "node_id", "node_btn_id") def _compute_name(self): for rec in self: - rec.name = "%(node_id_name)s" % {"node_id_name": rec.node_id.name} + if rec.node_id and rec.node_btn_id: + rec.name = "%(node_id_name)s" % {"node_id_name": rec.node_id.name} + else: + rec.name = None @api.depends("workflow_id") def _compute_sequence(self): diff --git a/soong_workflow/models/soong_workflow_mixin.py b/soong_workflow/models/soong_workflow_mixin.py index c26a71edc..0f4d365bf 100644 --- a/soong_workflow/models/soong_workflow_mixin.py +++ b/soong_workflow/models/soong_workflow_mixin.py @@ -96,17 +96,24 @@ class SoongWorkflowMixin(models.AbstractModel): if matched_logs and all(log.approval_state == '0' for log in matched_logs): record.is_back = True if record._name == 'yuthon.official.incoming.normal': - has_handling_log = any( - log.name == '承办' and log.approval_state == '1' - for log in record.log_ids - ) - has_handling_log2 = any( - log.approval_state == '1' + current_user_in_logs2 = any( + log.done_by.id == self.env.uid for log in record.log_ids2 ) - if has_handling_log or has_handling_log2: - record.is_back = False - else: + organizer_user_in_logs = any( + log.done_by.id == self.env.user.id + for log in record.log_ids.filtered(lambda l: l.name == '承办') + ) + all_handling_logs_approval_0 = all( + log.approval_state == '0' + for log in record.log_ids.filtered(lambda l: l.name == '承办') + ) + all_logs2_approval_0 = all( + log.approval_state == '0' + for log in record.log_ids2 + ) + + if all_logs2_approval_0 and all_handling_logs_approval_0 and not current_user_in_logs2 and not organizer_user_in_logs: record.is_back = True def _compute_is_active(self): @@ -115,7 +122,7 @@ class SoongWorkflowMixin(models.AbstractModel): query_user_id = self.user_id.id elif hasattr(self, 'users_id') and self.users_id: query_user_id = self.users_id.id - if query_user_id == current_user_id and self.work_end: + if query_user_id == current_user_id and self.work_end and self.log_ids[-1].approval_state in ['0', '1']: self.is_active = True else: self.is_active = False @@ -128,9 +135,9 @@ class SoongWorkflowMixin(models.AbstractModel): ('res_id', '=', record.id), ('approval_state', 'in', ['0', '1'])] lg2 = record.log_ids2.search(domain) lg1 = record.log_ids.search(domain) - if lg2: + if lg2 or lg1: record.is_confirm = False - if lg1: + if not lg1 and not lg2: record.is_end = False @api.depends("node_id", "log_ids") @@ -215,7 +222,7 @@ class SoongWorkflowMixin(models.AbstractModel): def _create_update_logs(self, btn_rec): log_obj = self.env["soong.workflow.log"] - if btn_rec.name not in ['转交', '分发', '加签', '加签确认', '退回', '收回', '结束']: + if btn_rec.name not in ['转交', '分发', '加签', '加签确认', '退回', '收回', '结束', '归档', '确认']: record_obj = log_obj.search( [("model", "=", self._name), ("res_id", "=", self.id), @@ -508,7 +515,6 @@ class SoongWorkflowMixin(models.AbstractModel): 'default_comment_note_id': comment_note_id, "default_code": self.code, "default_res_model": self._name, - "default_log_ids": logs.ids, "default_node_btn_id": btn_rec.id, "default_is_supervising": is_supervising, "default_trans_link_id": self.env['trans.link'].search(trans_domain, limit=1).id if btn_rec.name == '转交' else False, diff --git a/soong_workflow/models/soong_workflow_node.py b/soong_workflow/models/soong_workflow_node.py index 291d40c0e..84486ad5b 100644 --- a/soong_workflow/models/soong_workflow_node.py +++ b/soong_workflow/models/soong_workflow_node.py @@ -126,49 +126,41 @@ class SoongWorkflowNode(models.Model): @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 - 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": "end", - "btn_hide": False, # 对所有人显示 - "has_comment": False, # 对所有人显示 - "review_type": "end", - }), - ] + 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": False, + "review_type": "end", + }) + add_archive = (0, 0, { + "name": _("归档"), + "node_id": record.id, + "sequence": sequence + 2, + "action_type": "code", + "btn_hide": False, + "has_comment": False, + }) + 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 - 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_archive") - def onchange_is_archive(self): - for record in self: - if record.is_archive: - sequence = max([r.sequence for r in record.button_ids] if record.button_ids else [1]) - record.button_ids = [ - (0, 0, { - "name": _('归档'), - "node_id": record.id, - "sequence": sequence + 1, - "action_type": "code", - "btn_hide": False, - "has_comment": False, - }), - ] - 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] - + 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): diff --git a/soong_workflow/models/soong_workflow_record.py b/soong_workflow/models/soong_workflow_record.py index 3b1fce815..b499f953b 100644 --- a/soong_workflow/models/soong_workflow_record.py +++ b/soong_workflow/models/soong_workflow_record.py @@ -67,7 +67,7 @@ class SoongWorkflowRecord(models.Model): done_by = fields.Many2one(comodel_name="res.users", string="发起人") active = fields.Boolean(string="归档", default=True) is_manager = fields.Boolean(string="是否管理员", compute='_compute_is_manager') - soong_state = fields.Selection([('to_do', '待办'), ('done', '已办'), ('active', '已归档')], string="流程状态", default="to_do") + soong_state = fields.Selection([('to_do', '待办'), ('done', '已办'),('to_active', '待归档'), ('active', '已归档')], string="流程状态", default="to_do") member_of_department = fields.Boolean("是否是本部门数据", compute='_compute_part_of_department', search='_search_part_of_department') @@ -336,7 +336,7 @@ class SoongWorkflowRecord(models.Model): def get_view(self, view_id=None, view_type='form', **options): all_records = self.search([ ('users_ids', 'in', self.env.user.id), - ('soong_state', '!=', 'active') + ('soong_state', '!=', 'active'), ]) for record in all_records: record_id = self.env[record.res_model].browse(record.res_id) @@ -345,11 +345,22 @@ class SoongWorkflowRecord(models.Model): continue for log in record_id.log_ids: if log.done_by.name == self.env.user.name: - if log.approval_state == '0'or log.approval_state == '1': + if log.name == '归档' and (log.approval_state == '0' or log.approval_state == '1'): + record.write({'soong_state': 'to_active'}) + elif log.name == '归档' and log.approval_state == '2': + record.write({'soong_state': 'active'}) + elif log.approval_state == '0' or log.approval_state == '1': record.write({'soong_state': 'to_do'}) else: record.write({'soong_state': 'done'}) + for log2 in record_id.log_ids2: + if log2.done_by.name == self.env.user.name: + if log2.approval_state == '2': + record.write({'soong_state': 'done'}) + elif log2.approval_state in ['0', '1']: + record.write({'soong_state': 'to_do'}) + return super(SoongWorkflowRecord, self).get_view(view_id, view_type, **options) # def get_department_employees(self, department_id): diff --git a/soong_workflow/views/soong_workflow_node_views.xml b/soong_workflow/views/soong_workflow_node_views.xml index d9420fcf8..a61f21220 100644 --- a/soong_workflow/views/soong_workflow_node_views.xml +++ b/soong_workflow/views/soong_workflow_node_views.xml @@ -41,7 +41,6 @@ options="{'no_create': True}"/> - @@ -154,7 +153,7 @@ soong.workflow.node.button
- + diff --git a/soong_workflow/views/soong_workflow_record.xml b/soong_workflow/views/soong_workflow_record.xml index 5a0297801..4e63e02c6 100644 --- a/soong_workflow/views/soong_workflow_record.xml +++ b/soong_workflow/views/soong_workflow_record.xml @@ -317,7 +317,7 @@ soong.workflow.record tree,kanban,search {'header_search_default_approve_state': 1, 'header_search_default_to_do':1, 'check_employee': 1} - [('users_ids', 'in', uid), ('reclaim_state', '=', False), ('soong_state', 'in', ['to_do', 'active'])] + [('users_ids', 'in', uid), ('reclaim_state', '=', False), ('soong_state', 'in', ['to_do', 'to_active'])] @@ -327,7 +327,7 @@ soong.workflow.record tree,kanban,search {'header_search_default_approve_state': 1, 'header_search_default_to_do':1, 'check_employee': 1} - [('users_ids', 'in', uid), ('reclaim_state', '=', False), ('soong_state', '=', 'done')] + [('users_ids', 'in', uid), ('reclaim_state', '=', False), ('soong_state', 'in', ['done', 'active'])] diff --git a/soong_workflow/wizard/soong_workflow_comment_wizard.py b/soong_workflow/wizard/soong_workflow_comment_wizard.py index 265b0d526..e46a62dab 100644 --- a/soong_workflow/wizard/soong_workflow_comment_wizard.py +++ b/soong_workflow/wizard/soong_workflow_comment_wizard.py @@ -456,10 +456,18 @@ class SoongWorkflowCommentWizard(models.TransientModel): fields.Datetime.now() + timedelta( hours=8)), url=url, btntxt="查看详情") - msg_id = result_data[-1]['msgid'] - target_logs = next_node_log_records.filtered(lambda l: l.done_by.id == employee.user_id.id) - if target_logs: - target_logs.msg_id = msg_id + msg_id = None + try: + if result_data and isinstance(result_data, list) and len(result_data) > 0: + last_item = result_data[-1] + if isinstance(last_item, dict) and 'msgid' in last_item: + msg_id = last_item['msgid'] + except (IndexError, KeyError, TypeError): + msg_id = None + if msg_id: + target_logs = next_node_log_records.filtered(lambda l: l.done_by.id == employee.user_id.id) + if target_logs: + target_logs.msg_id = msg_id else: # 串审模式 (沿用原有逻辑) # 查找下一个节点 @@ -606,12 +614,16 @@ class SoongWorkflowCommentWizard(models.TransientModel): # if not record_id.log_ids2.search([('approval_state', '=', '0')]) or record_id.log_ids2: last_log = record_id.log_ids[-1] if record_id.log_ids else None if last_log: + 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 same_name_logs = record_id.log_ids.filtered( lambda log: log.name == last_log.name and log.node_btn_name == '4' and log.id != last_log.id ) - all_approved = all(log.approval_state == '3' for log in same_name_logs) - all_approved = all_approved and (last_log.approval_state == '3') - + all_approved = all(log.approval_state == '3' for log in same_name_logs) or not same_name_logs log2_ids_all_qualified = True if record_id.log_ids2: log2_ids_all_qualified = all(log2.approval_state == '2' for log2 in record_id.log_ids2) @@ -622,19 +634,25 @@ class SoongWorkflowCommentWizard(models.TransientModel): if workflow_record: workflow_record.write({ 'approve_state': 'end', - 'employee_ids': False, + 'employee_ids': [(6, 0, [applicant.employee_ids.id])], + 'soong_state': 'to_active', 'node_id': False, }) + log_id = record_id.log_ids.filtered(lambda l: l.comment in ['归档', '待归档']) + if not log_id: + self.env["soong.workflow.log"].create({ + 'name': '归档', + "code": self.code, + "model": self.res_model, + "res_id": self.res_id, + "workflow_id": self.node_btn_id.workflow_id.id, + "lase_click_date": fields.Datetime.now(), + "done_by": applicant.id, + "approval_state": "0", + "node_btn_id": self.node_btn_id.id, + }) 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) if hasattr(biz_record, 'user_id') and biz_record.user_id: @@ -696,8 +714,12 @@ class SoongWorkflowCommentWizard(models.TransientModel): "done_by": self.employee_ids.user_id.id, "node_btn_name": "0", }) - result_data = self.sudo().env["wecom.apps"].sync_send_message_textcard(category='oa', user_id='18562027762', title=record_id._description, description=description, url=url, btntxt="查看详情") - msg_id = result_data[-1]['msgid'] + result_data = 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="查看详情") + msg_id = None + if result_data and isinstance(result_data, list) and len(result_data) > 0: + last_item = result_data[-1] + if isinstance(last_item, dict) and 'msgid' in last_item: + msg_id = last_item['msgid'] or "" log_id.msg_id = msg_id 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] @@ -712,7 +734,11 @@ class SoongWorkflowCommentWizard(models.TransientModel): "node_btn_name": "4", }) result_data = 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="查看详情") - msg_id = result_data[-1]['msgid'] + msg_id = None + if result_data and isinstance(result_data, list) and len(result_data) > 0: + last_item = result_data[-1] + if isinstance(last_item, dict) and 'msgid' in last_item: + msg_id = last_item['msgid'] or "" log_id.msg_id = msg_id 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] @@ -736,8 +762,12 @@ class SoongWorkflowCommentWizard(models.TransientModel): "node_btn_id": self.node_btn_id.id, "approval_state": "0", }) - result_data = self.sudo().env["wecom.apps"].sync_send_message_textcard(category='oa', user_id='18562027762', title=record_id._description + "传阅/抄送",description=description, url=url, btntxt="查看详情") - msg_id = result_data[-1]['msgid'] + result_data = 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="查看详情") + msg_id = None + if result_data and isinstance(result_data, list) and len(result_data) > 0: + last_item = result_data[-1] + if isinstance(last_item, dict) and 'msgid' in last_item: + msg_id = last_item['msgid'] or "" log2_id.msg_id = msg_id workflow_record_id.employee_ids = self.dep_manager_employee_ids + self.employee_ids + self.circulated_employee_ids record_id.log_ids[-1].write({"comment": self.comment, "approval_state": "2", "lase_click_date": fields.Datetime.now()}) @@ -766,8 +796,14 @@ class SoongWorkflowCommentWizard(models.TransientModel): self.node_btn_id.with_context(cx).run() if self.node_btn_name == '归档': + record = self.env[self.res_model].search([('id', '=', self.res_id)]) + record.log_ids[-1].write({'approval_state': '2'}) + if self.document_ids: + record.log_ids[-1].write({'document_ids': [(6, 0, self.document_ids.ids)]}) workflow_record_id = self.env['soong.workflow.record'].search([('code', '=', record_id.code)]) - workflow_record_id.write({'soong_state': 'active'}) + workflow_record_id.write({'soong_state': 'active', + 'employee_ids':False + }) if self.node_btn_name != "收回": diff --git a/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml b/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml index 3041e611f..defa2ff85 100644 --- a/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml +++ b/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml @@ -24,6 +24,9 @@

你确认要归档吗?

+ + +
@@ -69,7 +72,7 @@ - + diff --git a/yuthon_holiday/views/yuthon_fixes_approval_views.xml b/yuthon_holiday/views/yuthon_fixes_approval_views.xml index 8fd88e3fa..30ddc8827 100644 --- a/yuthon_holiday/views/yuthon_fixes_approval_views.xml +++ b/yuthon_holiday/views/yuthon_fixes_approval_views.xml @@ -53,9 +53,12 @@ - + + + + diff --git a/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py b/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py index e56b5542b..b52e2a806 100644 --- a/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py +++ b/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py @@ -414,6 +414,10 @@ class HrAttendanceDetail(models.Model): start_datetime = datetime.combine(date, datetime.min.time()).replace( hour=start_hour, minute=start_minute, second=0, microsecond=0 ) - timedelta(hours=8) + if template.planning_name == '厨卫(集团本部)': + start_datetime = datetime.combine(date, datetime.min.time()).replace( + hour=start_hour, minute=start_minute, second=0, microsecond=0 + ) - timedelta(hours=6) if template.day2 == '次日': end_datetime = datetime.combine(date, datetime.min.time()).replace( hour=end_hour, minute=end_minute, second=0, microsecond=0 diff --git a/yuthon_hr_attendance/views/card_approval.xml b/yuthon_hr_attendance/views/card_approval.xml index a31b78ae1..d1872014b 100644 --- a/yuthon_hr_attendance/views/card_approval.xml +++ b/yuthon_hr_attendance/views/card_approval.xml @@ -55,10 +55,13 @@ - + + + + diff --git a/yuthon_hr_attendance/views/go_approval.xml b/yuthon_hr_attendance/views/go_approval.xml index ba490ee9e..40673ff83 100644 --- a/yuthon_hr_attendance/views/go_approval.xml +++ b/yuthon_hr_attendance/views/go_approval.xml @@ -98,6 +98,9 @@ + + + diff --git a/yuthon_hr_attendance/views/overtime_approval.xml b/yuthon_hr_attendance/views/overtime_approval.xml index c4211f22c..be8b8741d 100644 --- a/yuthon_hr_attendance/views/overtime_approval.xml +++ b/yuthon_hr_attendance/views/overtime_approval.xml @@ -62,10 +62,13 @@ - + + + + diff --git a/yuthon_hr_attendance/views/yuthon_adjustments_approval_views.xml b/yuthon_hr_attendance/views/yuthon_adjustments_approval_views.xml index 8cbf7664e..a9e04448c 100644 --- a/yuthon_hr_attendance/views/yuthon_adjustments_approval_views.xml +++ b/yuthon_hr_attendance/views/yuthon_adjustments_approval_views.xml @@ -50,9 +50,12 @@ - + + + + diff --git a/yuthon_hr_attendance/views/yuthon_shift_approval_views.xml b/yuthon_hr_attendance/views/yuthon_shift_approval_views.xml index f8a1408b9..4ba973976 100644 --- a/yuthon_hr_attendance/views/yuthon_shift_approval_views.xml +++ b/yuthon_hr_attendance/views/yuthon_shift_approval_views.xml @@ -54,12 +54,15 @@ - + + + +