From 019e79124dcab771a3db45f9ebe3e6d0a77ef6c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= Date: Sat, 7 Dec 2024 15:22:33 +0800 Subject: [PATCH] pengyuthon wechat --- soong_workflow/models/soong_user_role.py | 7 ++ soong_workflow/models/soong_workflow_mixin.py | 24 ++++-- .../views/soong_user_role_views.xml | 9 ++- .../views/soong_workflow_record.xml | 2 +- .../wizard/soong_workflow_comment_wizard.py | 71 ++++++++-------- yuthon_hr_attendance/__manifest__.py | 3 + .../src/planning_gantt/gantt_popover.js | 32 ++++++++ .../src/planning_gantt/gantt_popover.xml | 54 +++++++++++++ .../planning_gantt/planning_gantt_renderer.js | 81 +++++++++++++++++++ yuthon_hr_employee/models/inherit_hr_job.py | 7 ++ .../models/yuthon_hr_employee.py | 22 +---- .../views/inherit_hr_job_views.xml | 8 ++ .../views/yuthon_hr_employee_views.xml | 6 +- .../static/scss/issue_library_scss.scss | 4 +- 14 files changed, 260 insertions(+), 70 deletions(-) create mode 100644 yuthon_hr_attendance/static/src/planning_gantt/gantt_popover.js create mode 100644 yuthon_hr_attendance/static/src/planning_gantt/gantt_popover.xml create mode 100644 yuthon_hr_attendance/static/src/planning_gantt/planning_gantt_renderer.js diff --git a/soong_workflow/models/soong_user_role.py b/soong_workflow/models/soong_user_role.py index 111578cb7..b0de204a2 100644 --- a/soong_workflow/models/soong_user_role.py +++ b/soong_workflow/models/soong_user_role.py @@ -56,3 +56,10 @@ class YuthonUserRole(models.Model): search_domain = ['|', ('pinyin_name', operator, input_pinyin), ('name', operator, name)] domain = expression.AND([search_domain, domain]) return self._search(domain, limit=limit, order=order) + + def f5_new(self): + job_ids = self.env["soong.user.role"].browse(self._context.get('active_ids', self._context.get('active_id'))) + for job in job_ids: + department_id = self.env['hr.department'].search([('name', '=', job.department_id.name)]) + if department_id: + job.sudo().write({'department_id': department_id.id if len(department_id) == 1 else department_id[0].id}) diff --git a/soong_workflow/models/soong_workflow_mixin.py b/soong_workflow/models/soong_workflow_mixin.py index e083273d4..436056551 100644 --- a/soong_workflow/models/soong_workflow_mixin.py +++ b/soong_workflow/models/soong_workflow_mixin.py @@ -205,10 +205,9 @@ class SoongWorkflowMixin(models.AbstractModel): # 自动匹配 employee_user_role_id = self.env['hr.employee'].search( ['|', ('user_role_id', '=', next_state.users_role_id.id), - ('user_role_ids', 'in', next_state.users_role_id.id), '|', '&', + ('user_role_ids', 'in', next_state.users_role_id.id), '|', ('department_id', '=', self.department_id.id), - ('department_ids', 'in', self.department_id.id), - ('yuthon_company', '=', self.create_uid.employee_id.yuthon_company)]) + ('department_ids', 'in', self.department_id.id)]) employee_ids = employee_user_role_ids if not next_state.is_automatic else employee_user_role_id url = 'https://oa.thtzjt.com/mail/view?model={}&res_id={}'.format(self._name, self.id) for employee in employee_ids: @@ -308,9 +307,18 @@ class SoongWorkflowMixin(models.AbstractModel): @api.constrains("state") def _update_wkf_records(self): for rec in self: - record_obj = self.env["soong.workflow.record"].search( - [("res_model", "=", rec._name), ("res_id", "=", rec.id)]) + record_obj = self.env["soong.workflow.record"].search([("res_model", "=", rec._name), ("res_id", "=", rec.id)]) current_user_id = self.env.user.id + self_state = self.workflow_id.node_ids.search([('name', '=', self.state), ('workflow_id', '=', self.workflow_id.id)]).button_ids[0] + employee_user_role_ids = self.env['hr.employee'].search( + ['|', ('user_role_id', '=', self_state.users_role_id.id), + ('user_role_ids', 'in', self_state.users_role_id.id)]) + employee_user_role_id = self.env['hr.employee'].search( + ['|', ('user_role_id', '=', self_state.users_role_id.id), + ('user_role_ids', 'in', self_state.users_role_id.id), '|', + ('department_id', '=', self.department_id.id), + ('department_ids', 'in', self.department_id.id)]) + employee_ids = employee_user_role_ids if not self_state.is_automatic else employee_user_role_id if not record_obj: record_obj = self.env["soong.workflow.record"].create({ "res_model": rec._name, @@ -319,9 +327,13 @@ class SoongWorkflowMixin(models.AbstractModel): "node_id": rec.node_id.id, "users_ids": [(4, current_user_id)], }) + user_ids_list = [] + for employee in employee_ids: + if employee.user_id: + user_ids_list.append((4, employee.user_id.id)) record_obj.update({"workflow_id": rec.workflow_id.id, "node_id": rec.node_id.id, - "users_ids": [(4, current_user_id)], + "users_ids": user_ids_list, }) def unlink(self): diff --git a/soong_workflow/views/soong_user_role_views.xml b/soong_workflow/views/soong_user_role_views.xml index c938cbf15..0a81368e8 100644 --- a/soong_workflow/views/soong_user_role_views.xml +++ b/soong_workflow/views/soong_user_role_views.xml @@ -1,6 +1,13 @@ - + + 刷新部门 + + + code + action = model.f5_new() + + soong.user.role.tree soong.user.role diff --git a/soong_workflow/views/soong_workflow_record.xml b/soong_workflow/views/soong_workflow_record.xml index 7ae09bb9a..ba3386038 100644 --- a/soong_workflow/views/soong_workflow_record.xml +++ b/soong_workflow/views/soong_workflow_record.xml @@ -49,7 +49,7 @@ - WorkFollow Record + 工作流记录 ir.actions.act_window soong.workflow.record tree,form diff --git a/soong_workflow/wizard/soong_workflow_comment_wizard.py b/soong_workflow/wizard/soong_workflow_comment_wizard.py index 43476fa0a..1b794e1fa 100644 --- a/soong_workflow/wizard/soong_workflow_comment_wizard.py +++ b/soong_workflow/wizard/soong_workflow_comment_wizard.py @@ -6,11 +6,6 @@ from odoo.exceptions import UserError, ValidationError from datetime import datetime, date, time, timedelta -class SoongApprovalNoticeWizard(models.TransientModel): - _name = "soong.approval.notice.wizard" - _description = "Soong Workflow Comment Wizard" - - class SoongWorkflowCommentWizard(models.TransientModel): _name = "soong.workflow.comment.wizard" _description = "Soong Workflow Comment Wizard" @@ -126,13 +121,13 @@ class SoongWorkflowCommentWizard(models.TransientModel): if not employee.wecom_userid: raise ("请同步{}的企业微信".format(employee.name)) url = "https://oa.thtzjt.com/mail/view?model={}&res_id={}".format(self.res_model, record_id.id) - 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="查看详情") + # 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="查看详情") # partner_ids = self_node_id.employee_ids.user_id.partner_id.ids # self.with_context(lang=self.env.lang)._message_auto_subscribe_notify(partner_ids, 'soong_workflow.message_soong_workflow_distribute') # 转交逻辑--单线 @@ -143,30 +138,30 @@ class SoongWorkflowCommentWizard(models.TransientModel): if self.node_link_len: record_id.write({'state': 'end' if self.trans_link_id.name == '结束' else self.trans_link_id.name}) url = 'https://oa.thtzjt.com/mail/view?model={}&res_id={}'.format(self.res_model, self.res_id) - for employee in self.employee_ids: - 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="查看详情") + # for employee in self.employee_ids: + # 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="查看详情") # partner_ids = self.employee_ids.user_id.partner_id.ids # self.with_context(lang=self.env.lang)._message_auto_subscribe_notify(partner_ids, 'soong_workflow.message_soong_workflow_distribute') return self.node_btn_id.with_context(cx).run() if self.node_btn_name == '退回': record_id.write({'state': 'start' if self.return_link_id.name == '拟办' else self.return_link_id.name}) url = 'https://oa.thtzjt.com/mail/view?model={}&res_id={}'.format(self.res_model, self.res_id) - for employee in self.employee_ids: - 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="查看详情") + # for employee in self.employee_ids: + # 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="查看详情") # partner_ids = self.employee_ids.user_id.partner_id.ids # self.with_context(lang=self.env.lang)._message_auto_subscribe_notify(partner_ids, 'soong_workflow.message_soong_workflow_distribute') return self.node_btn_id.with_context(cx).run() @@ -179,14 +174,14 @@ class SoongWorkflowCommentWizard(models.TransientModel): if self.node_btn_name == '分发': if self.circulated_employee_ids: url = 'https://oa.thtzjt.com/mail/view?model={}&res_id={}'.format(self.res_model, self.res_id) - for employee in self.circulated_employee_ids: - 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="查看详情") + # for employee in self.circulated_employee_ids: + # 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="查看详情") # partner_ids = self.circulated_employee_ids.user_id.partner_id.ids # self.with_context(lang=self.env.lang)._message_auto_subscribe_notify(partner_ids,'soong_workflow.message_soong_workflow_distribute') if self.employee_ids: diff --git a/yuthon_hr_attendance/__manifest__.py b/yuthon_hr_attendance/__manifest__.py index df6442b52..1825561f9 100644 --- a/yuthon_hr_attendance/__manifest__.py +++ b/yuthon_hr_attendance/__manifest__.py @@ -40,6 +40,9 @@ 'assets': { 'web.assets_backend': [ 'yuthon_hr_attendance/static/scss/hr_attendance_scss.scss', + 'yuthon_hr_attendance/static/src/planning_gantt/gantt_popover.js', + 'yuthon_hr_attendance/static/src/planning_gantt/gantt_popover.xml', + 'yuthon_hr_attendance/static/src/planning_gantt/planning_gantt_renderer.js', ], }, 'installable': True, diff --git a/yuthon_hr_attendance/static/src/planning_gantt/gantt_popover.js b/yuthon_hr_attendance/static/src/planning_gantt/gantt_popover.js new file mode 100644 index 000000000..5204c572f --- /dev/null +++ b/yuthon_hr_attendance/static/src/planning_gantt/gantt_popover.js @@ -0,0 +1,32 @@ +/** @odoo-module **/ + +import { GanttPopover } from "@web_gantt/gantt_popover"; +import { patch } from "@web/core/utils/patch"; +import { onMounted } from "@odoo/owl"; + +patch(GanttPopover.prototype, { + + setup() { + super.setup(); + + onMounted(() => { + // super.onMounted(); + if (this.props.slotTemplate) + $('#selectTemplate').val(this.props.slotTemplate.template_id? this.props.slotTemplate.template_id.toString() : '') + }) + + }, + + onDelete() { + this.props.delButton.onDelete(); + this.props.close(); + }, + async onTemplateChange(ev) { + await this.props.slotTemplate.onTemplateChange(ev) + } +}) +GanttPopover.props = [ + ...GanttPopover.props, + 'delButton?', + 'slotTemplate?', +] \ No newline at end of file diff --git a/yuthon_hr_attendance/static/src/planning_gantt/gantt_popover.xml b/yuthon_hr_attendance/static/src/planning_gantt/gantt_popover.xml new file mode 100644 index 000000000..64fd7538c --- /dev/null +++ b/yuthon_hr_attendance/static/src/planning_gantt/gantt_popover.xml @@ -0,0 +1,54 @@ + + + + +
+
+ 班次 + + +
+
+ + + + + + + + + + +
+ + +
\ No newline at end of file diff --git a/yuthon_hr_attendance/static/src/planning_gantt/planning_gantt_renderer.js b/yuthon_hr_attendance/static/src/planning_gantt/planning_gantt_renderer.js new file mode 100644 index 000000000..44e651880 --- /dev/null +++ b/yuthon_hr_attendance/static/src/planning_gantt/planning_gantt_renderer.js @@ -0,0 +1,81 @@ +/** @odoo-module **/ + +import {PlanningGanttRenderer} from "@planning/views/planning_gantt/planning_gantt_renderer"; +import {patch} from "@web/core/utils/patch"; +import {_t} from "@web/core/l10n/translation"; +// const { strftimeToLuxonFormat } = require("@web/core/l10n/dates"); +patch(PlanningGanttRenderer.prototype, { + + // onTemplateChange: async (ev) => { + // debugger + // const template_id = parseInt(ev.target.value); + // const planning_slot = await this.model.orm.searchRead('planning.slot', [['id', '=', record.id]], ['display_name']) + // record.display_name = planning_slot[0].display_name + // pill.displayName = this.getDisplayName(pill) + // this.model.orm.write('planning.slot', [record.id], {template_id}) + // $(`[data-pill-id="${pill.id}"]`).val(pill.displayName) + // }, + + async getPopoverProps(pill) { + const {canDelete} = this.model.metaData; + const popoverProps = super.getPopoverProps(pill) + // if (this.popoverTemplate) { + // const { record } = pill; + // const planning_slot = await this.model.orm.searchRead('planning.slot', [['id', '=', record.id]], {}) + // const resourceList = await this.model.orm.searchRead('resource.resource', [], ['id', 'name']) + // const onResourceChange = this.onResourceChange + + // Object.assign(popoverProps.context, { + // resourceList, + // onResourceChange, + // }); + // } + const { record } = pill; + const planning_slot = await this.model.orm.searchRead('planning.slot', [['id', '=', record.id]], ['role_id', 'template_id']) + const role_id = planning_slot[0].role_id ? planning_slot[0].role_id[0] : false, + template_id = planning_slot[0].template_id ? planning_slot[0].template_id[0] : false + const templateList = await this.model.orm.searchRead('planning.slot.template', [['role_id', '=', role_id]], ['id', 'name']) + // const resourceList = await this.model.orm.searchRead('resource.resource', [], ['id', 'name']) + + + popoverProps['slotTemplate'] = { + template_id: template_id, + templateList: templateList, + onTemplateChange: async (ev) => { + debugger + const template_id = parseInt(ev.target.value); + this.model.orm.write('planning.slot', [record.id], {template_id}) + const planning_slot = await this.model.orm.searchRead('planning.slot', [['id', '=', record.id]], ['start_datetime', 'end_datetime']) + record.start_datetime = luxon.DateTime.fromFormat(planning_slot[0].start_datetime, 'yyyy-MM-dd HH:mm:ss').plus({'hours':8}) + record.end_datetime = luxon.DateTime.fromFormat(planning_slot[0].end_datetime, 'yyyy-MM-dd HH:mm:ss').plus({'hours':8}) + pill.displayName = this.getDisplayName(pill) + $(`[data-pill-id="${pill.id}"] div span`).text(pill.displayName) + }, + } + + popoverProps['delButton'] = { + text: canDelete ? _t("Delete") : _t("View"), + onDelete: () => { + if (canDelete) { + // this.model.orm.unlink('planning.slot', [record.id]) + this.model.orm.call('planning.slot', 'unlink', [record.id]) + + $(`[data-pill-id="${pill.id}"]`).remove() + + // location.reload() + // this.model.data.records = this.model.data.records.filter(rec => rec != record) + // // this.model.load(this.model.searchParams) + } + } + } + return popoverProps + }, + + async onPillClicked(ev, pill) { + if (this.popover.isOpen) { + return; + } + const popoverTarget = ev.target.closest(".o_gantt_pill_wrapper"); + this.popover.open(popoverTarget, await this.getPopoverProps(pill)); + }, +}) diff --git a/yuthon_hr_employee/models/inherit_hr_job.py b/yuthon_hr_employee/models/inherit_hr_job.py index 17d8989c6..0d1184b01 100644 --- a/yuthon_hr_employee/models/inherit_hr_job.py +++ b/yuthon_hr_employee/models/inherit_hr_job.py @@ -81,6 +81,13 @@ class HrJob(models.Model): if record.end_date < fields.Date.today(): record.is_enable = False + def f5_new(self): + job_ids = self.env["hr.job"].browse(self._context.get('active_ids', self._context.get('active_id'))) + for job in job_ids: + department_id = self.env['hr.department'].search([('name', '=', job.department_id.name)]) + if department_id: + job.sudo().write({'department_id': department_id.id if len(department_id) == 1 else department_id[0].id}) + class HrJobType(models.Model): _name = "hr.job.type" diff --git a/yuthon_hr_employee/models/yuthon_hr_employee.py b/yuthon_hr_employee/models/yuthon_hr_employee.py index 390fde949..e8eaea114 100644 --- a/yuthon_hr_employee/models/yuthon_hr_employee.py +++ b/yuthon_hr_employee/models/yuthon_hr_employee.py @@ -47,7 +47,7 @@ class YuthonHrEmployee(models.Model): user_sex = fields.Selection([('girl', '女'), ('boy', '男')], string="性别") user_state = fields.Selection([('in', '在职'), ('leave', '离职'), ('withdraw', '退休'), ('borrow', '借调'), ('expatriate', '外派'), ('adjunct', '在职(兼职)')], - string="员工状态", compute='_compute_user_state') + string="员工状态") user_number_start_time = fields.Date(string="身份证开始时间") user_number_end_time = fields.Date(string="身份证到期时间") nation = fields.Selection(nation_list, string="民族") @@ -66,8 +66,8 @@ class YuthonHrEmployee(models.Model): ('part_time', '外地农业'), ('practice', '外地非农业')], string="户籍类型") duty_replacement_card = fields.Integer(string="值班补卡次数(月)") # 工作信息 - new_start_contract_data = fields.Date(string="合同开始日期") - new_end_contract_data = fields.Date(string="合同终止日期") + # new_start_contract_data = fields.Date(string="合同开始日期") + # new_end_contract_data = fields.Date(string="合同终止日期") open_start_time = fields.Date(string="参加工作时间") social_insurance_date = fields.Date(string="缴纳社保日期") social_insurance_time = fields.Char(string="社保时长", compute='_compute_social_insurance_info', store=True) @@ -274,22 +274,6 @@ class YuthonHrEmployee(models.Model): else: record.retire_years = 0 - @api.depends('new_start_contract_data', 'new_end_contract_data') - def _compute_user_state(self): - for record in self: - today = datetime.now().date() - start_time = record.new_start_contract_data - end_time = record.new_end_contract_data - if start_time and end_time: - if start_time >= end_time: - raise ValidationError('合同开始日期不能大于合同结束日期') - if start_time <= today <= end_time: - record.user_state = 'in' - else: - record.user_state = 'leave' - else: - record.user_state = '' - @api.depends('normal_overtime_hours', 'weekend_overtime_hours', 'holiday_overtime_hours') def _compute_all_overtime_hours(self): for record in self: diff --git a/yuthon_hr_employee/views/inherit_hr_job_views.xml b/yuthon_hr_employee/views/inherit_hr_job_views.xml index 9b524f82c..5e3c70412 100644 --- a/yuthon_hr_employee/views/inherit_hr_job_views.xml +++ b/yuthon_hr_employee/views/inherit_hr_job_views.xml @@ -1,5 +1,13 @@ + + 刷新部门 + + + code + action = model.f5_new() + + hr.job.inherit hr.job diff --git a/yuthon_hr_employee/views/yuthon_hr_employee_views.xml b/yuthon_hr_employee/views/yuthon_hr_employee_views.xml index 5e4c827b5..f0be4f43c 100644 --- a/yuthon_hr_employee/views/yuthon_hr_employee_views.xml +++ b/yuthon_hr_employee/views/yuthon_hr_employee_views.xml @@ -115,8 +115,8 @@ - - + + @@ -237,7 +237,7 @@ - + diff --git a/yuthon_issue/static/scss/issue_library_scss.scss b/yuthon_issue/static/scss/issue_library_scss.scss index f96dfdb8a..62875c58a 100644 --- a/yuthon_issue/static/scss/issue_library_scss.scss +++ b/yuthon_issue/static/scss/issue_library_scss.scss @@ -1,6 +1,6 @@ .list_width{ - width: 240px; - max-width: 240px; + width: 400px !important; + max-width: 400px !important; } .list_ids_width{ width: 500px !important;