Merge branch 'master' of https://gitee.com/jinan-pengyusen-data/gzth
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
'license': 'LGPL-3',
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'data/res_users_data.xml',
|
||||
'views/system_version_views.xml',
|
||||
'views/system_logs_views.xml',
|
||||
'views/ir_cron_act_views.xml',
|
||||
@@ -25,7 +26,7 @@
|
||||
]
|
||||
},
|
||||
'demo': [],
|
||||
'depends': ['hr', 'mail', 'base', 'survey'],
|
||||
'depends': ['hr', 'mail', 'base', 'survey', 'account'],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo noupdate="0">
|
||||
<!-- 从默认用户模板中移除财务管理员权限组,新建用户不再默认带这些权限 -->
|
||||
<record id="base.default_user" model="res.users">
|
||||
<field name="groups_id" eval="[
|
||||
(3, ref('account.group_account_manager')),
|
||||
(3, ref('account.group_account_invoice')),
|
||||
]"/>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -7,4 +7,6 @@ from . import yuthon_timed_tasks
|
||||
from . import yuthon_phone_lottery
|
||||
from . import res_partner
|
||||
from . import base_month_year
|
||||
from . import system_logs
|
||||
from . import system_logs
|
||||
from . import res_users
|
||||
from . import mail_thread
|
||||
@@ -0,0 +1,43 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
# from odoo import models
|
||||
# import json
|
||||
#
|
||||
#
|
||||
# class MailThread(models.AbstractModel):
|
||||
# _inherit = "mail.thread"
|
||||
#
|
||||
# def _notify_by_web_push(self, message, recipients_data, msg_vals=False):
|
||||
# """
|
||||
# 重写 Web Push 通知方法,强制使用异步发送方式,
|
||||
# 避免同步发送导致的请求阻塞问题(如加班审批转交按钮反应慢)。
|
||||
# """
|
||||
# msg_vals = dict(msg_vals or {})
|
||||
# partner_ids = self._extract_partner_ids_for_notifications(message, msg_vals, recipients_data)
|
||||
# if not partner_ids:
|
||||
# return
|
||||
#
|
||||
# partner_devices_sudo = self.env['mail.partner.device'].sudo()
|
||||
# devices = partner_devices_sudo.search([
|
||||
# ('partner_id', 'in', partner_ids)
|
||||
# ])
|
||||
# if not devices:
|
||||
# return
|
||||
#
|
||||
# ir_parameter_sudo = self.env['ir.config_parameter'].sudo()
|
||||
# vapid_private_key = ir_parameter_sudo.get_param('mail.web_push_vapid_private_key')
|
||||
# vapid_public_key = ir_parameter_sudo.get_param('mail.web_push_vapid_public_key')
|
||||
# if not vapid_private_key or not vapid_public_key:
|
||||
# return
|
||||
#
|
||||
# payload = self._notify_by_web_push_prepare_payload(message, msg_vals=msg_vals)
|
||||
# payload = self._truncate_payload(payload)
|
||||
#
|
||||
# # 强制使用异步发送方式
|
||||
# # 不再同步调用 push_to_end_point,避免阻塞请求
|
||||
# self.env['mail.notification.web.push'].sudo().create([{
|
||||
# 'user_device': device.id,
|
||||
# 'payload': json.dumps(payload),
|
||||
# } for device in devices])
|
||||
# self.env.ref('mail.ir_cron_web_push_notification')._trigger()
|
||||
@@ -0,0 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
from odoo import api, models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ResUsers(models.Model):
|
||||
_inherit = 'res.users'
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
_logger.info("====== [yuthon_base] res.users.create 被调用,准备创建 %d 个用户 ======", len(vals_list))
|
||||
users = super().create(vals_list)
|
||||
# 新建用户后确保移除财务和薪资管理员权限组
|
||||
groups_to_remove = []
|
||||
group_refs = [
|
||||
'account.group_account_manager',
|
||||
'account.group_account_invoice',
|
||||
'hr_payroll.group_hr_payroll_manager',
|
||||
]
|
||||
for ref in group_refs:
|
||||
group = self.env.ref(ref, raise_if_not_found=False)
|
||||
if group:
|
||||
groups_to_remove.append((3, group.id))
|
||||
_logger.info("====== [yuthon_base] 找到组 %s (id=%d),将移除 ======", ref, group.id)
|
||||
else:
|
||||
_logger.warning("====== [yuthon_base] 未找到组 %s ======", ref)
|
||||
if groups_to_remove:
|
||||
_logger.info("====== [yuthon_base] 对用户 %s 移除 %d 个组 ======", users.mapped('login'), len(groups_to_remove))
|
||||
users.sudo().write({'groups_id': groups_to_remove})
|
||||
_logger.info("====== [yuthon_base] res.users.create 完成 ======")
|
||||
return users
|
||||
@@ -12,6 +12,7 @@ class YuthonCateringConf(models.Model):
|
||||
effective_date = fields.Date(string='生效日期')
|
||||
expiry_date = fields.Date(string='失效日期')
|
||||
is_active = fields.Integer(string='是否生效', compute='_compute_is_active', store=True)
|
||||
note = fields.Text(string='备注')
|
||||
|
||||
@api.depends('employee_ids')
|
||||
def _compute_employee_count(self):
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<field name="employee_count"/>
|
||||
<field name="effective_date"/>
|
||||
<field name="expiry_date"/>
|
||||
<field name="note"/>
|
||||
<field name="is_active" column_invisible="1"/>
|
||||
<button name="action_change_employees" string="变更员工" type="object" class="btn btn-primary" invisible="expiry_date != False"/>
|
||||
<button name="action_fix_null_effective_date" string="修复日期" type="object" class="btn btn-secondary"/>
|
||||
|
||||
@@ -22,10 +22,25 @@ class CateringConfChangeWizard(models.TransientModel):
|
||||
res['employee_ids'] = [(6, 0, conf.employee_ids.ids)]
|
||||
return res
|
||||
|
||||
def _compute_change_note(self):
|
||||
"""计算增减员备注"""
|
||||
old_ids = set(self.conf_id.employee_ids.ids)
|
||||
new_ids = set(self.employee_ids.ids)
|
||||
added_ids = new_ids - old_ids
|
||||
removed_ids = old_ids - new_ids
|
||||
parts = []
|
||||
if added_ids:
|
||||
added_names = self.env['hr.employee'].browse(list(added_ids)).mapped('name')
|
||||
parts.append('增员:' + '、'.join(added_names))
|
||||
if removed_ids:
|
||||
removed_names = self.env['hr.employee'].browse(list(removed_ids)).mapped('name')
|
||||
parts.append('减员:' + '、'.join(removed_names))
|
||||
return '\n'.join(parts) if parts else ''
|
||||
|
||||
def action_confirm(self):
|
||||
"""确认:旧记录加失效日期,生成新记录"""
|
||||
today = fields.Date.today()
|
||||
# 旧记录加失效日期(跳过write覆写,直接用super)
|
||||
note = self._compute_change_note()
|
||||
from odoo.models import Model
|
||||
Model.write(self.conf_id, {'expiry_date': today})
|
||||
# 生成新记录
|
||||
@@ -33,6 +48,7 @@ class CateringConfChangeWizard(models.TransientModel):
|
||||
'company_id': self.conf_id.company_id.id,
|
||||
'employee_ids': [(6, 0, self.employee_ids.ids)],
|
||||
'effective_date': today,
|
||||
'note': note,
|
||||
})
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
@@ -42,6 +58,10 @@ class CateringConfChangeWizard(models.TransientModel):
|
||||
|
||||
def action_modify(self):
|
||||
"""仅修改当前记录员工,不生成新记录,不更新日期"""
|
||||
note = self._compute_change_note()
|
||||
from odoo.models import Model
|
||||
Model.write(self.conf_id, {'employee_ids': [(6, 0, self.employee_ids.ids)]})
|
||||
Model.write(self.conf_id, {
|
||||
'employee_ids': [(6, 0, self.employee_ids.ids)],
|
||||
'note': note,
|
||||
})
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
@@ -1217,19 +1217,19 @@ class HolidaysRequestBatch(models.Model):
|
||||
if leave_type_name not in leave_type_mapping or leave_days <= 0:
|
||||
continue
|
||||
type_config = leave_type_mapping[leave_type_name]
|
||||
remaining_hours = leave_days * 8
|
||||
|
||||
remaining_hours = leave_days * 8
|
||||
if type_config['prev']:
|
||||
prev_balance = leave_balance[type_config['prev']]
|
||||
prev_balance = leave_balance[type_config['prev']] * 8
|
||||
if prev_balance > 0:
|
||||
deduct = round(min(remaining_hours, prev_balance), 1)
|
||||
leave_balance[type_config['prev']] = round(leave_balance[type_config['prev']] - deduct, 1)
|
||||
leave_balance[type_config['prev']] = round((prev_balance - deduct) / 8, 1)
|
||||
remaining_hours = round(remaining_hours - deduct, 1)
|
||||
|
||||
if remaining_hours > 0 and type_config['curr']:
|
||||
curr_balance = leave_balance[type_config['curr']]
|
||||
curr_balance = leave_balance[type_config['curr']] * 8
|
||||
deduct = round(min(remaining_hours, curr_balance), 1)
|
||||
leave_balance[type_config['curr']] = round(leave_balance[type_config['curr']] - deduct, 1)
|
||||
leave_balance[type_config['curr']] = round((curr_balance - deduct) / 8, 1)
|
||||
remaining_hours = round(remaining_hours - deduct, 1)
|
||||
|
||||
if type_config['prev']:
|
||||
|
||||
@@ -1181,8 +1181,8 @@ class HrAttendance(models.Model):
|
||||
# 检查是否为节假日
|
||||
for leave in leave_records:
|
||||
if leave.date_from and leave.date_to:
|
||||
from_date = fields.Date.to_date(leave.date_from)
|
||||
to_date = fields.Date.to_date(leave.date_to)
|
||||
from_date = fields.Date.to_date(leave.date_from + timedelta(hours=8))
|
||||
to_date = fields.Date.to_date(leave.date_to + timedelta(hours=8))
|
||||
if from_date <= record.current_data <= to_date:
|
||||
is_holiday = True # 标记为节假日
|
||||
|
||||
|
||||
@@ -130,11 +130,11 @@ class HrAttendanceDetail(models.Model):
|
||||
category='att', user_id=employee_id.wecom_userid,
|
||||
message=message,
|
||||
)
|
||||
if record.employee_id.name == '蒋彬':
|
||||
self.sudo().env["wecom.apps"].sync_send_message(
|
||||
category='att', user_id='18562027762',
|
||||
message=message + f'管理员测试管理员测试{vals}',
|
||||
)
|
||||
# if record.employee_id.name == '蒋彬':
|
||||
# self.sudo().env["wecom.apps"].sync_send_message(
|
||||
# category='att', user_id='18562027762',
|
||||
# message=message + f'管理员测试管理员测试{vals}',
|
||||
# )
|
||||
self.write({'remark': message})
|
||||
_logger.info(message)
|
||||
else:
|
||||
@@ -208,16 +208,16 @@ class HrAttendanceDetail(models.Model):
|
||||
|
||||
if checkin_datetime > sch_check_out_time:
|
||||
message = f"打卡成功!今日下班时间:{record.checkin_time + timedelta(hours=8)}: {employee_id.name},祝您归途平安!"
|
||||
if record.employee_id.name not in ['蒋彬', '麦丽娜']:
|
||||
self.sudo().env["wecom.apps"].sync_send_message(
|
||||
category='att', user_id=employee_id.wecom_userid,
|
||||
message=message,
|
||||
)
|
||||
if record.employee_id.name in ['蒋彬', '麦丽娜']:
|
||||
self.sudo().env["wecom.apps"].sync_send_message(
|
||||
category='att', user_id='18562027762',
|
||||
message=message + f'管理员测试管理员测试{vals}',
|
||||
)
|
||||
# if record.employee_id.name not in ['蒋彬', '麦丽娜']:
|
||||
self.sudo().env["wecom.apps"].sync_send_message(
|
||||
category='att', user_id=employee_id.wecom_userid,
|
||||
message=message,
|
||||
)
|
||||
# if record.employee_id.name in ['蒋彬', '麦丽娜']:
|
||||
# self.sudo().env["wecom.apps"].sync_send_message(
|
||||
# category='att', user_id='18562027762',
|
||||
# message=message + f'管理员测试管理员测试{vals}',
|
||||
# )
|
||||
self.write({'remark': message})
|
||||
_logger.info(message)
|
||||
|
||||
|
||||
@@ -29,27 +29,27 @@
|
||||
groups="yuthon_hr_attendance.group_he_attendance_sign_manager"
|
||||
confirm="确定要删除选中的记录吗?" />
|
||||
</header>
|
||||
<field name="employee_id" class="list_current_data" options="{'no_create': True}" />
|
||||
<field name="employee_id" options="{'no_create': True}"/>
|
||||
<field name="is_expatriation" column_invisible="1"/>
|
||||
<field name="current_data" optional="show" class="list_current_data" />
|
||||
<field name="week" optional="show" class="list_ids_width" />
|
||||
<field name="current_data" optional="show"/>
|
||||
<field name="week" optional="show"/>
|
||||
<field name="check_in" optional="show" widget="time"
|
||||
decoration-danger="is_check_in_red == 1" />
|
||||
<field name="check_out" optional="show" widget="time" class="list_current_data"
|
||||
<field name="check_out" optional="show" widget="time"
|
||||
decoration-danger="is_check_out_red == 1" />
|
||||
<field name="shift_id" column_invisible="1"/>
|
||||
<field name="shift_name" optional="show" class="list_current_data" />
|
||||
<field name="shift_name" optional="show"/>
|
||||
<field name="is_week" column_invisible="1" />
|
||||
<field name="is_holiday" column_invisible="1" />
|
||||
<field name="create_date" />
|
||||
<field name="user_id" column_invisible="1" />
|
||||
<field name="is_clock_card" column_invisible="1" />
|
||||
<field name="department_id" column_invisible="1" />
|
||||
<field name="is_no_card" optional="show" class="list_ids_width" />
|
||||
<field name="is_early_card" optional="show" class="list_ids_width" />
|
||||
<field name="is_late_card" optional="show" class="list_ids_width" />
|
||||
<field name="absenteeism_card" optional="show" class="list_ids_width" string="旷工" />
|
||||
<field name="is_abnormal" optional="show" class="list_ids_width" string="异常" />
|
||||
<field name="is_no_card" optional="show"/>
|
||||
<field name="is_early_card" optional="show"/>
|
||||
<field name="is_late_card" optional="show"/>
|
||||
<field name="absenteeism_card" optional="show" string="旷工" />
|
||||
<field name="is_abnormal" optional="show" string="异常" />
|
||||
<field name="abnormal" column_invisible="1" />
|
||||
<field name="work_time_type" column_invisible="1" />
|
||||
<field name="is_approval" column_invisible="1" />
|
||||
@@ -69,7 +69,7 @@
|
||||
<button name="revoke" type="object" string="撤销" class="btn btn-blue"
|
||||
invisible="not (is_check_out_red or is_check_in_red)"
|
||||
groups="yuthon_hr_attendance.group_he_attendance_sign_manager" />
|
||||
<button name="button_workflow" type="object" string="流程" class="oe_highlight"
|
||||
<button name="button_workflow" type="object" string="流程" class="btn btn-blue"
|
||||
invisible="not is_workflow" />
|
||||
<button name="button_source" type="object" string="详情" class="btn btn-blue"
|
||||
groups="yuthon_hr_attendance.group_he_attendance_sign_manager" />
|
||||
@@ -87,21 +87,21 @@
|
||||
<!-- <button name="compute_company_id" string="公司更新" type="object" class="btn
|
||||
btn-primary"/>-->
|
||||
<!-- </header>-->
|
||||
<field name="current_data" optional="show" class="list_current_data" />
|
||||
<field name="week" optional="show" class="list_ids_width" />
|
||||
<field name="current_data" optional="show"/>
|
||||
<field name="week" optional="show"/>
|
||||
<field name="check_in" optional="show" widget="time" />
|
||||
<field name="check_out" optional="show" widget="time" class="list_current_data" />
|
||||
<field name="check_out" optional="show" widget="time"/>
|
||||
<field name="shift_id" column_invisible="1"/>
|
||||
<field name="shift_name" optional="show" class="list_current_data" />
|
||||
<field name="shift_name" optional="show" />
|
||||
<field name="create_date" column_invisible="1" />
|
||||
<field name="user_id" column_invisible="1" />
|
||||
<field name="is_clock_card" column_invisible="1" />
|
||||
<field name="department_id" column_invisible="1" />
|
||||
<field name="is_no_card" optional="show" class="list_ids_width" />
|
||||
<field name="is_early_card" optional="show" class="list_ids_width" />
|
||||
<field name="is_late_card" optional="show" class="list_ids_width" />
|
||||
<field name="absenteeism_card" optional="show" class="list_ids_width" string="旷工" />
|
||||
<field name="is_abnormal" optional="show" class="list_ids_width" string="异常" />
|
||||
<field name="is_no_card" optional="show" />
|
||||
<field name="is_early_card" optional="show" />
|
||||
<field name="is_late_card" optional="show" />
|
||||
<field name="absenteeism_card" optional="show" string="旷工" />
|
||||
<field name="is_abnormal" optional="show" string="异常" />
|
||||
<field name="is_late_allowed" column_invisible="1"/>
|
||||
<field name="abnormal" optional="show" column_invisible="1" />
|
||||
<field name="work_time_type" column_invisible="1" />
|
||||
@@ -111,6 +111,9 @@
|
||||
<field name="is_warning" column_invisible="1"/>
|
||||
<field name="is_check_in_red" column_invisible="1" />
|
||||
<field name="is_check_out_red" column_invisible="1" />
|
||||
<field name="is_warning" column_invisible="1"/>
|
||||
<field name="is_workflow" column_invisible="1"/>
|
||||
<field name="workflow_id" column_invisible="1"/>
|
||||
<button name="button_controls_wizard" type="object" string="操作" class="btn btn-blue"
|
||||
invisible="not (is_abnormal or is_early_card or is_late_card or absenteeism_card or is_no_card)" />
|
||||
<button name="button_correct_wizard" type="object" string="修正"
|
||||
@@ -120,6 +123,8 @@
|
||||
<button name="revoke" type="object" string="撤销" class="btn btn-blue"
|
||||
invisible="not (is_check_out_red or is_check_in_red)"
|
||||
groups="yuthon_hr_attendance.group_he_attendance_sign_manager" />
|
||||
<button name="button_workflow" type="object" string="流程" class="btn-link text-danger"
|
||||
invisible="not is_workflow" />
|
||||
<button name="button_source" type="object" string="详情" class="btn btn-blue"
|
||||
groups="yuthon_hr_attendance.group_he_attendance_sign_manager" />
|
||||
</tree>
|
||||
|
||||
@@ -13,4 +13,5 @@ from . import inherit_res_groups
|
||||
from . import soong_user_role
|
||||
from . import yuthon_medical_manage
|
||||
from . import yuthon_medical_rule
|
||||
from . import res_users
|
||||
|
||||
|
||||
@@ -46,7 +46,9 @@ class ResGroups(models.Model):
|
||||
if not department:
|
||||
return valid_user_ids
|
||||
|
||||
dept_id = department.id if isinstance(department, models.Model) else int(department)
|
||||
# 处理虚拟记录(onchange时可能出现)
|
||||
dept_id = department.id.origin if hasattr(department.id, 'origin') else department.id
|
||||
dept_id = int(dept_id) if isinstance(dept_id, str) else dept_id
|
||||
|
||||
# 当前部门员工
|
||||
employees = self.env['hr.employee'].search([('department_id', '=', dept_id)])
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import werkzeug.urls
|
||||
from urllib.parse import urlparse
|
||||
import urllib.request
|
||||
import requests
|
||||
import json
|
||||
from odoo import api, fields, models
|
||||
class ResUsers(models.Model):
|
||||
_inherit = 'res.users'
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
user = super().create(vals)
|
||||
# 2. 定义要强制移除的 Payroll 权限组 ID
|
||||
remove_group_ids = [
|
||||
184, # 工资 / 管理员(人事专员)
|
||||
728, # 管理员(本部财务) (会计)
|
||||
609, # 管理员(财务)
|
||||
]
|
||||
user.write({
|
||||
'groups_id': [(3, gid) for gid in remove_group_ids]
|
||||
})
|
||||
user.write({
|
||||
'sel_groups_732_760': False, # 库存 选择框
|
||||
'sel_groups_678_679': False, # 采购 选择框
|
||||
})
|
||||
return user
|
||||
|
||||
@@ -51,13 +51,19 @@
|
||||
<group col="2" string="审批详情">
|
||||
<group colspan="2">
|
||||
<field name="name" string="标题"/>
|
||||
<field name="is_back" invisible="1"/>
|
||||
<field name="users_id" options="{'no_create': True}"/>
|
||||
<field name="department_id" invisible="1"/>
|
||||
<field name="end_date"/>
|
||||
<field name="work_end" invisible="1"/>
|
||||
<field name="documents_id" widget="preview_many2one"/>
|
||||
</group>
|
||||
<field name="is_back" invisible="1"/>
|
||||
<field name="users_id" options="{'no_create': True}"/>
|
||||
<field name="department_id" invisible="1"/>
|
||||
<field name="end_date"/>
|
||||
<field name="work_end" invisible="1"/>
|
||||
<field name="documents_id" widget="preview_many2one"/>
|
||||
<!-- <field name="is_back" invisible="1"/>-->
|
||||
<!-- <field name="users_id" options="{'no_create': True}"/>-->
|
||||
<!-- <field name="department_id" invisible="1"/>-->
|
||||
<!-- <field name="end_date"/>-->
|
||||
<!-- <field name="work_end" invisible="1"/>-->
|
||||
<!-- <field name="documents_id" widget="preview_many2one"/>-->
|
||||
</group>
|
||||
<group string="考核详情">
|
||||
<group>
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
<field name="secret_level"/>
|
||||
<field name="official_type_id" options="{'no_create': True}"/>
|
||||
<field name="is_chapter"/>
|
||||
<field name="type_stamp_ids" widget="many2many_tags" options="{'no_create': True, 'no_open': True}}"/>
|
||||
<field name="type_stamp_ids" widget="many2many_tags" options="{'no_create': True, 'no_open': True}}" required="is_chapter"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="is_cold"/>
|
||||
|
||||
@@ -2603,12 +2603,24 @@ class PropertyManagementBreakdownLine(models.Model):
|
||||
management_monthly_amount = fields.Float(string="金额", digits=(16, 2))
|
||||
start_data = fields.Date(string="开始日期")
|
||||
end_data = fields.Date(string="结束日期")
|
||||
management_month_number = fields.Integer(string="期间月数")
|
||||
management_month_number = fields.Float(string="期间月数", digits=(16, 2))
|
||||
management_period_rent = fields.Float(string="期间费用", digits=(16, 2))
|
||||
|
||||
@api.onchange('management_monthly_amount', 'month_number')
|
||||
@api.onchange('start_data', 'end_data')
|
||||
def _onchange_management_month_number(self):
|
||||
if self.start_data and self.end_data:
|
||||
if self.end_data >= self.start_data:
|
||||
total_days = (self.end_data - self.start_data).days + 1
|
||||
start_month_days = calendar.monthrange(self.start_data.year, self.start_data.month)[1]
|
||||
self.management_month_number = round(total_days / start_month_days, 2)
|
||||
else:
|
||||
self.management_month_number = 0
|
||||
else:
|
||||
self.management_month_number = 0
|
||||
|
||||
@api.onchange('management_monthly_amount', 'management_month_number')
|
||||
def _onchange_management_amount(self):
|
||||
self.management_period_rent = self.management_monthly_amount * self.management_month_number
|
||||
self.management_period_rent = round(self.management_monthly_amount * self.management_month_number, 2)
|
||||
|
||||
|
||||
class PropertyWaterFeeLine(models.Model):
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="handling_opinions" invisible="contract_sort != 'property'"/>
|
||||
<field name="handling_opinions"/>
|
||||
</group>
|
||||
<!-- 隐藏字段单独放一个不占布局的分组 -->
|
||||
<group>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'security/salary_security_rule.xml',
|
||||
'data/res_users_data.xml',
|
||||
'data/rank_log_time.xml',
|
||||
'data/meal_cron.xml',
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo noupdate="0">
|
||||
<!-- 从默认用户模板中移除薪资管理员权限组,新建用户不再默认带此权限 -->
|
||||
<record id="base.default_user" model="res.users">
|
||||
<field name="groups_id" eval="[(3, ref('hr_payroll.group_hr_payroll_manager'))]"/>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,5 +1,5 @@
|
||||
from odoo import api, fields, models
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
import calendar
|
||||
|
||||
|
||||
@@ -90,6 +90,54 @@ class YuthonMealExpenses(models.Model):
|
||||
current_month = datetime.now().month
|
||||
return str(current_month)
|
||||
|
||||
def _remove_leading_zero(self, date_str):
|
||||
"""去掉日期字符串的前导零,如 '01月01日' -> '1月1日'"""
|
||||
month, day = date_str.split('月')
|
||||
day = day.replace('日', '')
|
||||
return f"{int(month)}月{int(day)}日"
|
||||
|
||||
def _is_chinese_workday(self, check_date=None):
|
||||
"""判断给定日期是否为中国工作日(考虑法定节假日和调休)"""
|
||||
if check_date is None:
|
||||
check_date = datetime.now()
|
||||
|
||||
# 获取当年行政考勤工作日的节假日数据
|
||||
current_year = check_date.year
|
||||
query_start = datetime(current_year, 1, 1, 0, 0, 0) - timedelta(hours=8)
|
||||
query_end = datetime(current_year, 12, 31, 23, 59, 59) - timedelta(hours=8)
|
||||
|
||||
calendar_leaves = self.env['resource.calendar.leaves'].sudo().search([
|
||||
("calendar_id.name", "=", "行政考勤工作日"),
|
||||
("date_from", ">=", query_start),
|
||||
("date_from", "<=", query_end)
|
||||
])
|
||||
|
||||
holidays_list = []
|
||||
shift_days_list = []
|
||||
|
||||
for leave in calendar_leaves:
|
||||
if leave.holidays:
|
||||
holidays_list.extend(leave.holidays.split(','))
|
||||
if leave.alternate_rest_day:
|
||||
holidays_list.extend(leave.alternate_rest_day.split(','))
|
||||
if leave.shift_replacement_day:
|
||||
shift_days_list.extend(leave.shift_replacement_day.split(','))
|
||||
|
||||
holidays_list = [self._remove_leading_zero(d) for d in holidays_list]
|
||||
shift_days_list = [self._remove_leading_zero(d) for d in shift_days_list]
|
||||
|
||||
date_str = self._remove_leading_zero(check_date.strftime('%m月%d日'))
|
||||
|
||||
if date_str in shift_days_list:
|
||||
# 调休补班日,强制算工作日
|
||||
return True
|
||||
if date_str in holidays_list:
|
||||
# 法定节假日或调休休息日,算非工作日
|
||||
return False
|
||||
|
||||
# 没有特殊安排的,按周末判断
|
||||
return check_date.weekday() < 5
|
||||
|
||||
def send_meal(self):
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
@@ -112,6 +160,18 @@ class YuthonMealExpenses(models.Model):
|
||||
|
||||
def cron_send_meal_reminder(self):
|
||||
"""定时任务:给状态为已发送且缴费状态为待缴的记录发送缴费提醒"""
|
||||
# 节假日不发送
|
||||
if not self._is_chinese_workday():
|
||||
self.env['ir.logging'].sudo().create({
|
||||
'name': '餐费缴费提醒',
|
||||
'type': 'server',
|
||||
'message': f'今天{datetime.now().strftime("%Y-%m-%d")}是节假日或周末,跳过发送餐费缴费提醒',
|
||||
'path': __name__,
|
||||
'func': 'cron_send_meal_reminder',
|
||||
'line': 0,
|
||||
})
|
||||
return True
|
||||
|
||||
# 找出所有 已发送 且 仍然 待缴 的餐费记录
|
||||
meals = self.sudo().search([
|
||||
('meal_state', '=', 'done'),
|
||||
@@ -253,15 +313,15 @@ class YuthonMealExpenses(models.Model):
|
||||
"""定时任务:每月第一个工作日发送餐费缴费提醒"""
|
||||
from datetime import datetime, timedelta
|
||||
import calendar
|
||||
|
||||
# 检查是否是工作日
|
||||
|
||||
# 检查是否是中国工作日(含法定节假日和调休判断)
|
||||
today = datetime.now()
|
||||
if today.weekday() >= 5: # 0-4是工作日,5-6是周末
|
||||
if not self._is_chinese_workday(today):
|
||||
# 记录日志
|
||||
self.env['ir.logging'].sudo().create({
|
||||
'name': '餐费缴费提醒',
|
||||
'type': 'server',
|
||||
'message': f'今天{today.strftime("%Y-%m-%d")}是周末,跳过发送餐费缴费提醒',
|
||||
'message': f'今天{today.strftime("%Y-%m-%d")}是节假日或周末,跳过发送餐费缴费提醒',
|
||||
'path': __name__,
|
||||
'func': 'cron_send_monthly_meal_reminder',
|
||||
'line': 0,
|
||||
|
||||
@@ -179,6 +179,16 @@ class ResUsers(models.Model):
|
||||
try:
|
||||
with self.env.cr.savepoint():
|
||||
user_id = template_user.sudo().with_context(no_reset_password=True).copy(values)
|
||||
# 移除财务管理员权限组
|
||||
groups_to_remove = []
|
||||
group_manager = self.env.ref('account.group_account_manager', raise_if_not_found=False)
|
||||
group_invoice = self.env.ref('account.group_account_invoice', raise_if_not_found=False)
|
||||
if group_manager:
|
||||
groups_to_remove.append((3, group_manager.id))
|
||||
if group_invoice:
|
||||
groups_to_remove.append((3, group_invoice.id))
|
||||
if groups_to_remove:
|
||||
user_id.sudo().write({'groups_id': groups_to_remove})
|
||||
return user_id
|
||||
except Exception as e:
|
||||
_logger.exception("OAuth Wechat: 微信访问用户【UserId:%s】自动创建失败【Odoo错误:%s】!" % (userid, ustr(e)))
|
||||
|
||||
@@ -777,25 +777,25 @@
|
||||
|
||||
<!--我的-->
|
||||
<menuitem id="holiday_manage_menu_root_board" name="我的" web_icon="yuthon_work_brand,static/description/holiday.png" sequence="3">
|
||||
<menuitem id="menu_workflow_approval_request_new" name="新建流程" action="soong_workflow.action_kklw_workflow_approval_request" sequence="5"/>
|
||||
<menuitem id="menu_soong_workflow_todo_record" name="待办流程" action="soong_workflow.soong_workflow_record_todo_action" sequence="10"/>
|
||||
<menuitem id="menu_soong_workflow_done_record" name="已办流程" action="soong_workflow.soong_workflow_record_done_action" sequence="15"/>
|
||||
<menuitem id="menu_soong_workflow_department_record" name="流程查询" action="soong_workflow.soong_workflow_department_record_action" sequence="20"/>
|
||||
<menuitem id="menu_workflow_approval_request_new" name="新建流程" action="soong_workflow.action_kklw_workflow_approval_request" sequence="5" groups="base.group_user"/>
|
||||
<menuitem id="menu_soong_workflow_todo_record" name="待办流程" action="soong_workflow.soong_workflow_record_todo_action" sequence="10" groups="base.group_user"/>
|
||||
<menuitem id="menu_soong_workflow_done_record" name="已办流程" action="soong_workflow.soong_workflow_record_done_action" sequence="15" groups="base.group_user"/>
|
||||
<menuitem id="menu_soong_workflow_department_record" name="流程查询" action="soong_workflow.soong_workflow_department_record_action" sequence="20" groups="base.group_user"/>
|
||||
<menuitem id="menu_workflow_approval_request_admin" name="流程监控" action="soong_workflow.soong_workflow_record_action_admin" sequence="25"/>
|
||||
<menuitem id="menu_soong_workflow_hr_employee" name="人力资源流程" action="soong_workflow.soong_workflow_hr_employee_action" sequence="30" groups="soong_workflow.group_soong_workflow_hr"/>
|
||||
<menuitem id="yuthon_official_incoming_normal" name="行政收文" action="yuthon_official.yuthon_official_incoming_normal_action" sequence="32"/>
|
||||
<menuitem id="yuthon_file_processing_menu" name="文件处理" action="yuthon_official.yuthon_file_processing_action" sequence="35"/>
|
||||
<menuitem id="yuthon_sub_enterprises" name="文件处理(子企业)" action="yuthon_official.view_yuthon_sub_enterprises_action" sequence="40"/>
|
||||
<menuitem id="yuthon_notice_menu1_board" name="通知公告" action="yuthon_notice.approval_notice_action" sequence="45"/>
|
||||
<menuitem id="menu_soong_workflow_task" name="我的任务" action="project_todo.project_task_action_todo" sequence="50"/>
|
||||
<menuitem id='menu_yuthon_will_task_root' name='我的日程' action='yuthon_will_task.view_yuthon_will_task_action' sequence='55'/>
|
||||
<menuitem id="yuthon_notice_menu1_board" name="通知公告" action="yuthon_notice.approval_notice_action" sequence="45" groups="base.group_user"/>
|
||||
<menuitem id="menu_soong_workflow_task" name="我的任务" action="project_todo.project_task_action_todo" sequence="50" groups="base.group_user"/>
|
||||
<menuitem id='menu_yuthon_will_task_root' name='我的日程' action='yuthon_will_task.view_yuthon_will_task_action' sequence='55' groups="base.group_user"/>
|
||||
<menuitem id="yuthon_salary_party_my_board" name="党费" action="yuthon_salary.view_my_yuthon_salary_party_action" sequence="60"/>
|
||||
<menuitem id="menu_hr_attendance_my_record_board" name="我的考勤" action="yuthon_hr_attendance.hr_attendance_action1" sequence="65"/>
|
||||
<menuitem id="menu_hr_attendance_my_abnormal_board" name="我的异常" action="yuthon_hr_attendance.hr_attendance_my_abnormal" sequence="70"/>
|
||||
<menuitem id="yuthon_vacation_reports_my" name="考勤确认单" action="yuthon_hr_attendance.action_server_open_my_vacation_form1" sequence="75"/>
|
||||
<menuitem id="yuthon_salary_active_my2" name="工资条" action="yuthon_salary.yuthon_salary_active_my_action" sequence="80"/>
|
||||
<menuitem id="yuthon_meal_expenses_my_board" name="餐费" action="yuthon_salary.view_my_yuthon_meal_expenses_action" sequence="85"/>
|
||||
<menuitem id="property_device_repair_action_brand" name="报事报修" action="yuthon_maintain.property_device_repair_action" sequence="90"/>
|
||||
<menuitem id="menu_hr_attendance_my_record_board" name="我的考勤" action="yuthon_hr_attendance.hr_attendance_action1" sequence="65" groups="base.group_user"/>
|
||||
<menuitem id="menu_hr_attendance_my_abnormal_board" name="我的异常" action="yuthon_hr_attendance.hr_attendance_my_abnormal" sequence="70" groups="base.group_user"/>
|
||||
<menuitem id="yuthon_vacation_reports_my" name="考勤确认单" action="yuthon_hr_attendance.action_server_open_my_vacation_form1" sequence="75" groups="base.group_user"/>
|
||||
<menuitem id="yuthon_salary_active_my2" name="工资条" action="yuthon_salary.yuthon_salary_active_my_action" sequence="80" groups="base.group_user"/>
|
||||
<menuitem id="yuthon_meal_expenses_my_board" name="餐费" action="yuthon_salary.view_my_yuthon_meal_expenses_action" sequence="85" groups="base.group_user"/>
|
||||
<menuitem id="property_device_repair_action_brand" name="报事报修" action="yuthon_maintain.property_device_repair_action" sequence="90" groups="base.group_user"/>
|
||||
<menuitem id="property_device_repair_action_brand_all" name="报事报修(管理员)" action="yuthon_maintain.property_device_repair_all_action" groups="base.group_system" sequence="95"/>
|
||||
<menuitem id="salary_view_Individual" name="个税计算" action="yuthon_salary.action_view_hr_payslip_month_form2" sequence="100"/>
|
||||
</menuitem>
|
||||
|
||||
Reference in New Issue
Block a user