pengyuthon wechat

This commit is contained in:
李鹏宇
2024-12-07 15:22:33 +08:00
parent cc83ba4f62
commit 019e79124d
14 changed files with 260 additions and 70 deletions
+7
View File
@@ -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})
+18 -6
View File
@@ -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):
@@ -1,6 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- Views -->
<record id="all_soong_user_role_user" model="ir.actions.server">
<field name="name">刷新部门</field>
<field name="model_id" ref="soong_workflow.model_soong_user_role"/>
<field name="binding_model_id" ref="soong_workflow.model_soong_user_role"/>
<field name="state">code</field>
<field name="code">action = model.f5_new()</field>
</record>
<record id="view_soong_user_role_tree" model="ir.ui.view">
<field name="name">soong.user.role.tree</field>
<field name="model">soong.user.role</field>
@@ -49,7 +49,7 @@
</record>
<record id="soong_workflow_record_action" model="ir.actions.act_window">
<field name="name">WorkFollow Record</field>
<field name="name">工作流记录</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">soong.workflow.record</field>
<field name="view_mode">tree,form</field>
@@ -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:
+3
View File
@@ -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,
@@ -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?',
]
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8" ?>
<templates xml:space="preserve">
<t t-inherit="web_gantt.GanttPopover" t-inherit-mode="extension">
<xpath expr="//t[@t-if='props.button']" position="replace">
<div t-if="props.slotTemplate">
<div class="d-flex align-items-center p-2">
<strong class="me-2">班次</strong>
<select id="selectTemplate" class="form-select" t-on-change="onTemplateChange">
<t t-foreach="props.slotTemplate.templateList" t-as="template" t-key="template.id">
<option t-att-value="template.id">
<t t-esc="template.name"/>
</option>
</t>
</select>
</div>
</div>
<!-- <t t-debugger=""/>-->
<t t-if="props.button or props.delButton">
<div class="popover-footer border-top p-3">
<t t-if="props.button">
<button class="btn btn-primary btn-sm me-2" t-on-click="onClick" t-esc="props.button.text"/>
</t>
<t t-if="props.delButton">
<button type="button"
class="btn btn-primary btn-sm me-2"
t-esc="props.delButton.text"
data-bs-toggle="modal"
data-bs-target="#deleteModal"/>
<!-- Modal -->
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="deleteModalLabel">Confirmation</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"/>
</div>
<div class="modal-body">
Are you sure you want to delete this shift?
</div>
<div class="modal-footer">
<button class="btn btn-primary" t-esc="props.delButton.text" t-on-click="onDelete"/>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
</t>
</div>
</t>
</xpath>
</t>
</templates>
@@ -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));
},
})
@@ -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"
@@ -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:
@@ -1,5 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="all_hr_job_user" model="ir.actions.server">
<field name="name">刷新部门</field>
<field name="model_id" ref="hr.model_hr_job"/>
<field name="binding_model_id" ref="hr.model_hr_job"/>
<field name="state">code</field>
<field name="code">action = model.f5_new()</field>
</record>
<record id="hr_job_inherit" model="ir.ui.view">
<field name="name">hr.job.inherit</field>
<field name="model">hr.job</field>
@@ -115,8 +115,8 @@
</xpath>
<xpath expr="//group[@name='active_group']" position="after">
<group string="工作信息">
<field name="new_start_contract_data"/>
<field name="new_end_contract_data"/>
<!-- <field name="new_start_contract_data"/>-->
<!-- <field name="new_end_contract_data"/>-->
<field name="open_start_time"/>
<field name="open_start_time_today"/>
<field name="social_insurance_date"/>
@@ -237,7 +237,7 @@
<field name="retire_years" optional="hide"/>
<field name="political_aspects" optional="hide"/>
<field name="dang_data" optional="hide"/>
<field name="new_start_contract_data" optional="hide"/>
<!-- <field name="new_start_contract_data" optional="hide"/>-->
<field name="open_start_time" optional="hide"/>
<field name="open_start_time_today" optional="hide"/>
<field name="interrupt_work_month" optional="hide"/>
@@ -1,6 +1,6 @@
.list_width{
width: 240px;
max-width: 240px;
width: 400px !important;
max-width: 400px !important;
}
.list_ids_width{
width: 500px !important;