# Conflicts:
#	soong_workflow/views/soong_workflow_record.xml
This commit is contained in:
李鹏宇
2026-01-26 18:17:03 +08:00
58 changed files with 1072 additions and 431 deletions
+10 -8
View File
@@ -38,20 +38,22 @@
</t>
<t t-else="">
<div t-attf-class="o_attachment o_attachment_many2many #{ editable ? 'o_attachment_editable' : '' } #{upload ? 'o_attachment_uploading' : ''}" t-att-title="file.name">
<div class="o_attachment_wrap">
<div class="o_attachment_wrap d-flex">
<t t-set="ext" t-value="getExtension(file)"/>
<t t-set="url" t-value="getUrl(file.id)"/>
<div class="o_image_box float-start" t-att-data-tooltip="'Preview ' + file.name">
<span class="o_image o_hover" t-on-click.stop="() => this.preview_Obj(file.id,file.name)" t-att-data-mimetype="file.mimetype" t-att-data-ext="ext" role="img"/>
</div>
<div class="caption">
<a class="ml4" t-att-data-tooltip="'Download ' + file.name" t-att-href="getUrl(file.id)"><t t-esc='file.name'/></a>
</div>
<div class="caption small">
<a class="ml4 small text-uppercase" t-att-href="getUrl(file.id)"><b><t t-esc='ext'/></b></a>
<div t-if="editable" class="progress o_attachment_progress_bar">
<div class="progress-bar progress-bar-striped active" style="width: 100%">Uploading</div>
<div class="d-flex flex-column">
<div class="caption" style="white-space: unset;">
<a class="ml4" t-att-data-tooltip="'Download ' + file.name" t-att-href="getUrl(file.id)"><t t-esc='file.name'/></a>
</div>
<div class="caption small">
<a class="ml4 small text-uppercase" t-att-href="getUrl(file.id)"><b><t t-esc='ext'/></b></a>
<div t-if="editable" class="progress o_attachment_progress_bar">
<div class="progress-bar progress-bar-striped active" style="width: 100%">Uploading</div>
</div>
</div>
</div>
@@ -2931,7 +2931,7 @@ nav.o_main_navbar {
}
}
.modal.o_modal_full {
z-index: 1111;
z-index: 1070;
}
html {
body {
@@ -19,4 +19,16 @@
}
.o_comment_combined_input {
flex: 2;
}
.o_kanban_soong_wkf_record {
.o_kanban_record_headings {
flex: 1;
}
.o_kanban_record_bottom {
flex: 0 0 94px;
@include media-breakpoint-down(sm) {
flex: 0 0 56px;
}
}
}
@@ -175,21 +175,21 @@
<field name="node_btn_name"/>
<templates>
<t t-name="kanban-box">
<div class="o_kanban_record d-md-none card h-100">
<div class="o_kanban_record d-md-none card h-100 border-0">
<div class="card-body">
<div class="mb-2">
<small>
节点:<field name="name" />
</small>
<div class="d-flex justify-content-between align-items-center">
<small>
节点:<field name="name" />
</small>
<small>
状态:<field name="approval_state"/>
</small>
</div>
</div>
<div class="mb-2">
<small>
状态:<field name="approval_state"/>
</small>
</div>
<div class="mb-2">
<small>
经办人:<field name="done_by"/>
经办人:<field name="done_by"/> <field name="lase_click_date"/>
</small>
</div>
<div class="mb-2">
@@ -197,7 +197,7 @@
意见:<field name="comment"/>
</small>
</div>
<div class="mb-2">
<div class="mb-2" t-if="record.document_ids.raw_value.length">
<small>
附件:<field name="document_ids" widget="preview_many2many"/>
</small>
@@ -637,10 +637,11 @@ class SoongWorkflowCommentWizard(models.TransientModel):
has_archive_btn = any(btn_name.name == '归档' for btn_name in self.node_btn_id.node_id.button_ids)
if has_archive_btn:
log_id = record_id.log_ids.filtered(lambda l: l.name == '归档')
employee_id = self.env['hr.employee'].sudo().search([('user_id', '=', record_id.log_ids[0].done_by.id)], limit=1)
if workflow_record:
workflow_record.write({
'approve_state': 'end',
'employee_ids': [(6, 0, [record_id.log_ids[0].done_by.employee_id.id])],
'employee_ids': [(6, 0, [employee_id.id])],
'soong_state': 'to_active',
'node_id': False,
})
+3 -4
View File
@@ -85,12 +85,11 @@ class YuThonPhone(http.Controller):
user_id = request.env['res.users'].sudo().browse(kw.get('employee'))
employee_id = user_id.with_company(user_id.company_id.id).employee_id
applet_security_setting_ids = request.env['applet.security'].sudo().search([('employee_id', '=', employee_id.id)]).applet_security_setting_ids
task_ids = request.env['yuthon.will.task'].sudo().search([('users_ids', 'in', [user_id])])
data = [{
'日程': 5,
'抄表': 10,
'OA': 0,
'工作流': 10,
'日程': len(task_ids),
}]
_logger.info(f'{data}-------------------/phone/base/self------------收到请求')
return json.dumps({'data': data, 'code': 200, 'message': ''})
@http.route('/phone/base/test', type='http', auth="none", csrf=False, cors='*')
+1 -1
View File
@@ -3,7 +3,7 @@
import { patch } from "@web/core/utils/patch";
import { DateTimePicker } from "@web/core/datetime/datetime_picker";
import { isMobileOS } from "@web/core/browser/feature_detection";
import { useEffect, useRef, reactive } from "@odoo/owl";
import { useEffect, useRef } from "@odoo/owl";
patch(DateTimePicker.prototype, {
setup() {
+30 -10
View File
@@ -353,7 +353,7 @@ class HolidaysRequestBatch(models.Model):
column1='leave_id',
column2='attachment_id'
)
holiday_allowance = fields.Char(string="可用额度", compute='_compute_holiday_allowance', store=True)
holiday_allowance = fields.Text(string="可用额度", compute='_compute_holiday_allowance', store=True)
active = fields.Boolean('Active', default=True, tracking=True)
def _get_default_name_title(self):
@@ -365,7 +365,7 @@ class HolidaysRequestBatch(models.Model):
@api.onchange('is_day')
def _onchange_is_day(self):
if not self.is_day:
self.leave_ids = [(5, 0, 0)] # 清空One2many字段
self.leave_ids = [(5, 0, 0)]
@api.onchange('is_hour')
def _onchange_is_hour(self):
@@ -411,7 +411,7 @@ class HolidaysRequestBatch(models.Model):
other_leave_types = [
'产假', '事假', '法定假', '调休', '补休', '值班调休',
'婚假', '陪产假', '计生假', '丧假', '探亲假',
'家长会假', '病假(普通)', '病假(住院期)',
'家长会假', '病假(普通)', '病假(住院期)', '育儿假',
'病假(出院恢复期)', '考试假'
]
for leave_type in other_leave_types:
@@ -851,13 +851,33 @@ class HolidaysRequestBatch(models.Model):
current_date = fields.Date.today()
vacation_date = current_date
for record in self:
reports_id = self.env['yuthon.vacation.reports'].search([('employee_id', '=', record.users_id.employee_ids.id),
('vacation_date', '=', vacation_date.replace(day=1))
], limit=1)
if reports_id:
leave_days = reports_id.leave
overtime_days = reports_id.working_overtime
record.holiday_allowance = f"年假{leave_days:.3f}天, 补休{overtime_days:.3f}天"
result_parts = []
reports_id = self.env['yuthon.vacation.reports'].search([
('employee_id', '=', record.users_id.employee_ids.id),
('vacation_date', '=', vacation_date.replace(day=1))
], limit=1)
if not reports_id:
record.holiday_allowance = ""
continue
holiday_configs = [
("年假", "previous_year", "remainder_year"),
("补休", "previous_year1", "remainder_year1"),
("育儿假", None, "remaining_parental_leave")
]
for name, prev_field, curr_field in holiday_configs:
parts = []
if prev_field:
prev_value = getattr(reports_id, prev_field, 0.0)
if prev_value > 0: # 大于0才显示
parts.append(f"上年结余{prev_value:.0f}天")
curr_value = getattr(reports_id, curr_field, 0.0)
if curr_value > 0:
parts.append(f"本年剩余{curr_value:.0f}天")
if parts:
result_parts.append(f"{name}:{','.join(parts)}")
record.holiday_allowance = "\n".join(result_parts)
def action_print_leave_batch(self):
"""按钮触发打印请假单"""
+3
View File
@@ -58,6 +58,8 @@
'views/card_remind_form.xml',
'views/yuthon_customer_planning_views.xml',
'views/planning_slot_template_views.xml',
'views/yuthon_overtime_line_views.xml',
'views/vacation_overtime_active_views.xml',
'views/hr_attendance_month_views.xml',
'views/wifi_message_view.xml',
'views/back_approval.xml',
@@ -65,6 +67,7 @@
'views/meal_approval.xml',
'views/applet_address_views.xml',
'views/yuthon_holiday_statement.xml',
'views/yuthon_parenting_allocate_views.xml',
'views/all_attendance_menu.xml',
'views/overtime_approval_inherit_header.xml',
+40 -6
View File
@@ -4,6 +4,7 @@ from odoo import fields, http, SUPERUSER_ID, _
from odoo.exceptions import AccessError, MissingError, ValidationError
from odoo.http import request
from ....addons.portal.controllers import portal
from datetime import datetime, date, time, timedelta
class CustomerPortal(portal.CustomerPortal):
@@ -69,13 +70,46 @@ class CustomerPortal(portal.CustomerPortal):
@http.route('/phone/vacation/self/detail', type='http', auth="none", csrf=False, cors='*')
def phone_vacation_self_detail(self, **kw):
records = request.env['yuthon.vacation.reports'].sudo().search([('id', '=', kw.get('id'))])
record = request.env['yuthon.vacation.reports'].sudo().search([('id', '=', kw.get('id'))])
current_date = record.vacation_date
if current_date.month == 1:
last_month_year = current_date.year - 1
last_month = 12
else:
last_month_year = current_date.year
last_month = current_date.month - 1
records = request.env['yuthon.vacation.reports'].sudo().search([
('employee_id', '=', record.employee_id.id),
('vacation_date', '>=', f'{last_month_year}-{last_month:02d}-01'),
('vacation_date', '<', f'{last_month_year}-{last_month + 1:02d}-01' if last_month < 12 else f'{last_month_year + 1}-01-01')
], limit=1)
data = {
'日期': records.display_date,
'剩余年假': records.leave,
'剩余补休': records.working_overtime,
'剩余误餐费': records.meal_fee,
'剩余体检费': records.medical_fee,
'日期': record.display_date,
'应到': records.should_attendance,
'实到': records.actual_attendance,
'迟到': records.is_late_card,
'早退': records.is_early_card,
'缺卡': records.is_no_card,
'旷工': records.is_work,
'异常': records.is_abnormal,
'年假': records.done_leave,
'加班时': records.done_working_overtime,
'调休': records.compensatory_leave,
'事假': records.leave_of_absence,
'加班时(法定假)': records.statutory_leave,
'育儿假': records.parental_leave,
'值班调休': records.duty_off_leave,
'婚假': records.marriage_leave,
'产假': records.maternity_leave,
'陪产假': records.paternity_leave,
'计生假': records.family_planning_leave,
'丧假': records.bereavement_leave,
'探亲假': records.home_visit_leave,
'家长会假': records.parents_meeting_leave,
'病假(普通)': records.general_sick_leave,
'病假(住院期)': records.hospital_sick_leave,
'病假(出院恢复期)': records.recovery_sick_leave,
'考试假': records.exam_leave,
}
return json.dumps({'data': data, 'code': 200, 'message': ''})
@@ -14,19 +14,6 @@
<field name="numbercall">-1</field>
<field eval="False" name="doall"/>
</record>
<record forcecreate="True" id="yuthon_vacation_start_end_time" model="ir.cron">
<field name="name">定时任务:更新我的考勤确认单实到数据</field>
<field name="model_id" ref="model_yuthon_vacation_reports"/>
<field name="state">code</field>
<field name="code">model.monthly_day_report()</field>
<field eval="False" name="active"/>
<field name="user_id" ref="base.user_root"/>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="nextcall" eval="(DateTime.now()).strftime('%Y-%m-%d 00:00:00')"/>
<field name="numbercall">-1</field>
<field eval="False" name="doall"/>
</record>
<record forcecreate="True" id="yuthon_vacation_attendance_confirmation" model="ir.cron">
<field name="name">定时任务:批量发送考勤确认</field>
<field name="model_id" ref="model_yuthon_vacation_reports"/>
+3 -1
View File
@@ -34,7 +34,9 @@ from . import staff_dining_report
from . import message_reminder_tasks
from . import yuthon_holiday_statement
from . import yuthon_meal_case
from . import yuthon_parenting_allocate
from . import vacation_overtime_active
from . import yuthon_overtime_line
# from odoo.tools import SQL
# import odoo
# odoo.models.READ_GROUP_AGGREGATE.update({
@@ -23,6 +23,7 @@ class CardApprovals(models.Model):
reason_application = fields.Text(string="申请事由")
documents_ids = fields.Many2many('ir.attachment', string="附件")
attendance_id = fields.Many2one('hr.attendance', string="补卡日期")
number_cards_replaced = fields.Integer(string="已补卡次数")
attendance = fields.Char(string="补卡日期")
is_attendance = fields.Boolean(string="字段隐藏")
replacement_time = fields.Selection([('work', '上班卡'), ('quitting', '下班卡'), ('all', '全天卡')], string="补卡", store=True)
@@ -14,6 +14,7 @@ class OvertimeApprovals(models.Model):
_rec_name = 'name'
name = fields.Char(string="标题", compute='_compute_name')
number_card = fields.Char(string="补卡次数")
code = fields.Char(string="编号", default=lambda self: self.env['ir.sequence'].next_by_code('overtime_approval'))
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
company_id = fields.Many2one(related='users_id.employee_ids.company_id', string="公司")
@@ -58,6 +59,23 @@ class OvertimeApprovals(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])])
@api.constrains('start_time')
def _check_start_time(self):
for rec in self:
workflow_records = self.env['soong.workflow.record'].search([
('workflow_id.name', '=', '加班'),
('create_uid', '=', self.env.user.id),
])
if not workflow_records:
continue
for wf_rec in workflow_records:
target_model = self.env[wf_rec.res_model]
target_record = target_model.browse(wf_rec.res_id)
if not target_record.exists() or not target_record.start_time:
continue
if target_record.start_time.date() == rec.start_time.date():
raise UserError('当天已有加班审批,请重新选择开始时间')
def open_record(self):
if self.start_time and self.end_time and self.employee_ids:
start_date = fields.Date.to_date(self.start_time)
@@ -0,0 +1,24 @@
from datetime import datetime, timedelta, time
from email.policy import default
from operator import index
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
import calendar
from datetime import date
from dateutil.relativedelta import relativedelta
from odoo.exceptions import UserError, ValidationError
class VacationOvertimeActive(models.Model):
_name = 'vacation.overtime.active'
_description = '加班情况归档'
employee_id = fields.Many2one('hr.employee', string='员工')
department_id = fields.Many2one('hr.department', related='employee_id.department_id', string="部门")
company_id = fields.Many2one('res.company', related='employee_id.company_id', string="公司")
workflow_record_id = fields.Many2one('soong.workflow.record', string='流程')
overtime_name = fields.Char(string="标题")
carry_forward_date = fields.Date(string="结转日期")
carry_forward_quantity = fields.Float(string="结转时长")
carry_result = fields.Selection([('success', '成功'), ('failed', '失败')], string="结转结果")
remaining_quantity = fields.Float(string="剩余数")
@@ -5,6 +5,7 @@ from datetime import date, timedelta
class YuthonOvertimeReport(models.Model):
_name = 'yuthon.holiday.statement'
class InheritHrLeave(models.Model):
_inherit = 'hr.leave'
_description = '请假情况'
@@ -0,0 +1,23 @@
from odoo import api, fields, models, tools, _
from datetime import datetime, time, timedelta
from odoo.exceptions import UserError
from datetime import date, timedelta
class YuthonOvertimeLine(models.Model):
_name = 'yuthon.overtime.line'
_description = '加班明细'
employee_id = fields.Many2one('hr.employee', string="员工")
last_balance = fields.Float(string="上年结余")
valid_date = fields.Date(string="有效至")
workday = fields.Float(string='工作日')
public_holidays = fields.Float(string='公休日')
vacation_sum = fields.Float(string='合计数')
carry_forward_quantity = fields.Float(string="结转时长")
carry_forward_date = fields.Date(string="结转日期")
remaining_quantity = fields.Float(string="剩余数")
def open_record(self):
pass
@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models, tools, _
from datetime import datetime, time, timedelta
from odoo.exceptions import UserError
class YuthonParentingAllocate(models.Model):
_name = 'yuthon.parenting.allocate'
_description = '育儿额度分配规则'
company_id = fields.Many2one("res.company", string="公司", default=lambda self: self.env.company)
cycle_years = fields.Integer(string='周期年数', default=1, help='按出生日计算的周期年数,如1表示1年')
cycle_unit = fields.Integer(string='周期单位', default=1, help='周期的描述单位,如“1”周期')
valid_limit = fields.Integer(string='有效期限(岁)', default=1, help='规则生效的截止条件')
distribute = fields.Integer(string='年/发放额度')
start_date = fields.Date(string="生效日期", copy=False, default=fields.Date.today())
end_date = fields.Date(string="失效日期", copy=False, default=fields.Date.from_string('2099-01-01'))
is_enable = fields.Boolean(string="是否启用", compute="compute_is_enable", store=True)
birth_certificate = fields.Text(string='备注', default='需要在花名册配置紧急联系人才能生效')
@api.depends('start_date', 'end_date')
def compute_is_enable(self):
for rec in self:
if not rec.end_date:
rec.is_enable = True
else:
if rec.start_date and rec.end_date:
if rec.start_date <= fields.Date.today() < rec.end_date:
rec.is_enable = True
else:
rec.is_enable = False
@@ -31,6 +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")
previous_year1 = fields.Float(string="上年剩余(补休)", digits=(16, 3))
used_this_year1 = fields.Float(string="本年已休", digits=(16, 3))
remainder_year1 = fields.Float(string="剩余(补休)", digits=(16, 3), compute="_compute_year_sum")
@@ -40,6 +41,7 @@ class YuthonVacationReports(models.Model):
overtime_ids = fields.One2many('vacation.over.line', 'vacation_id', string='加班明细')
meal_fee_ids = fields.One2many('vacation.meal.line', 'vacation_id', string='误餐明细')
medical_fee_ids = fields.One2many('vacation.medical.line', 'vacation_id', string='体检费明细')
parenting_line_ids = fields.One2many('vacation.parenting.line', 'vacation_id', string='育儿假明细')
other_fee_ids = fields.One2many('vacation.other.line', 'vacation_id', string='其他明细')
vacation_date = fields.Date(string='日期', default=lambda self: fields.Date.today().replace(day=1))
display_date = fields.Char(string='日期', compute='_compute_display_date')
@@ -68,6 +70,8 @@ class YuthonVacationReports(models.Model):
general_sick_leave = fields.Float(string='病假(普通)', digits=(16, 3), compute='_compute_other_leave', store=True, group_operator=None)
hospital_sick_leave = fields.Float(string='病假(住院期)', digits=(16, 3), compute='_compute_other_leave', store=True, group_operator=None)
recovery_sick_leave = fields.Float(string='病假(出院恢复期)', digits=(16, 3), compute='_compute_other_leave', store=True, group_operator=None)
parental_leave = fields.Float(string='育儿假', digits=(16, 3), compute='_compute_parental_leave', store=True, group_operator=None)
remaining_parental_leave = fields.Float(string='剩余育儿假', digits=(16, 3), compute='_compute_parental_leave', store=True, group_operator=None)
exam_leave = fields.Integer(string='考试假', compute='_compute_other_leave', store=True, group_operator=None)
right_days = fields.Float(string='转正天数', group_operator=None, compute='compute_attendance_fields')
internship_days = fields.Float(string='实习天数', group_operator=None)
@@ -97,6 +101,122 @@ class YuthonVacationReports(models.Model):
tracking=3,
default='not_sent')
def update_overtime(self):
today = date.today()
over_line_domain = [
('vacation_id', '!=', False),
('update_type', '=', 'add'),
('is_void', '=', False)
]
over_lines = self.env['vacation.over.line'].search(over_line_domain)
void_lines = self.env['vacation.over.line']
for line in over_lines:
# 确定判断超期的基准日期:有adjust_date则用adjust_date,否则用valid_date
check_date = line.adjust_date if line.adjust_date else line.valid_date
if check_date and today > check_date:
void_lines |= line
# 批量标记作废
if void_lines:
void_lines.write({'is_void': True})
for void_line in void_lines:
# 跳过vacation_id为空的情况
if not void_line.vacation_id:
continue
main_vacation = void_line.vacation_id
vacation_date = main_vacation.vacation_date
# 查找vacation_date之后的加班记录中,text='上月继承额度'的行
inherit_domain = [
('vacation_id', '=', main_vacation.id),
('create_date', '>=', fields.Datetime.to_datetime(vacation_date)),
('text', '=', '上月额度继承'),
]
inherit_lines = self.env['vacation.over.line'].search(inherit_domain)
if not inherit_lines:
continue
deduct_value = void_line.update_lines or 0.0
for inherit_line in inherit_lines:
new_lines = inherit_line.update_lines - deduct_value
inherit_line.write({'update_lines': new_lines})
def update_leave(self):
today = date.today()
leave_line_domain = [
('vacation_id', '!=', False),
('update_type', '=', 'add'),
('is_void', '=', False)
]
leave_lines = self.env['vacation.leave.line'].search(leave_line_domain)
void_lines = self.env['vacation.leave.line']
for line in leave_lines:
check_date = line.adjust_date if line.adjust_date else line.valid_date
if check_date and today > check_date:
void_lines |= line
if void_lines:
void_lines.write({'is_void': True})
# 3. 扣减update_lines中「上月继承额度」的workday
for void_line in void_lines:
if not void_line.vacation_id:
continue
main_vacation = void_line.vacation_id
vacation_date = main_vacation.vacation_date
if not vacation_date:
continue
# 查找vacation_date之后的年假继承记录(关联update_lines)
inherit_domain = [
('vacation_id', '=', main_vacation.id),
('create_date', '>=', fields.Datetime.to_datetime(vacation_date)),
('text', '=', '上月额度继承'),
('is_void', '=', False)
]
inherit_lines = self.env['vacation.leave.line'].search(inherit_domain)
if not inherit_lines:
continue
# 扣减年假workday
deduct_value = void_line.workday or 0.0
for inherit_line in inherit_lines:
new_workday = inherit_line.workday - deduct_value
inherit_line.write({'workday': new_workday})
@api.depends('other_fee_ids', 'other_fee_ids.holiday_type', 'other_fee_ids.lines',
'other_fee_ids.is_void', 'other_fee_ids.update_type', 'parenting_line_ids',
'parenting_line_ids.update_date', 'parenting_line_ids.end_date', 'parenting_line_ids.lines')
def _compute_parental_leave(self):
today = date.today()
for rec in self:
used_amount = 0.0
deduct_fee_lines = rec.other_fee_ids.filtered(
lambda l:
l.holiday_type.name == '育儿假'
and l.update_type == 'reduce'
and not l.is_void
and l.lines > 0
)
if deduct_fee_lines:
used_amount = sum(line.lines for line in deduct_fee_lines)
rec.parental_leave = used_amount
total_amount = 0.0
valid_parenting_lines = rec.parenting_line_ids.filtered(
lambda l:
l.update_date <= today
and (l.end_date >= today if l.end_date else True)
)
if valid_parenting_lines:
total_amount = sum(line.lines for line in valid_parenting_lines)
rec.remaining_parental_leave = max(total_amount - used_amount, 0.0)
def update_vacation_state(self):
records = self.env["yuthon.vacation.reports"].browse(
self._context.get('active_ids', self._context.get('active_id', self.ids))
@@ -132,16 +252,17 @@ class YuthonVacationReports(models.Model):
record.other_fee_ids.write({'is_confirm': True})
return result
@api.depends('previous_year', 'year_distribution', 'used_this_year')
@api.depends('year_distribution', 'used_this_year')
def _compute_remainder_year(self):
for record in self:
record.remainder_year = record.previous_year + record.year_distribution - record.used_this_year
record.remainder_year = record.year_distribution - record.used_this_year
@api.depends('last_holiday', 'last_workday', 'year_holiday', 'year_workday', 'used_this_year1')
def _compute_year_sum(self):
for record in self:
record.year_sum = record.last_holiday + record.last_workday + record.year_holiday + record.year_workday
record.remainder_year1 = record.year_sum - record.used_this_year1
record.previous_year1 = record.last_holiday + record.last_workday
@api.constrains('employee_id', 'vacation_date')
def _check_duplicate_monthly_record(self):
@@ -217,8 +338,6 @@ class YuthonVacationReports(models.Model):
if invalid_overtimes:
raise UserError('有加班单未结束,请先结束加班批次')
rec.manage_reject()
@api.depends('vacation_date')
def _compute_display_date(self):
for rec in self:
@@ -493,11 +612,19 @@ class YuthonVacationReports(models.Model):
return f'{month}月{day}日'
def button_put(self):
url = f'https://oa.thtzjt.com/webh5/#/vacation?id={self.id}'
we_id = self.env['hr.employee'].search([('id', '=', self.employee_id.id)]).wecom_userid
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='default', user_id=we_id, title="考勤确认",
description=self.employee_id.name + '请确认你的考勤:',
url=url, btntxt="详细信息")
we_id = self.employee_id.wecom_userid
if we_id:
url = f'https://phone.thtzjt.com/phone/Notarize/{self.id}/{self.employee_id.id}'
year = self.vacation_date.year
month = self.vacation_date.month
data = f"你{year}年{month}月的考勤确认单已经生成,请确认"
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='att_ok', user_id=we_id,
title="考勤确认单", description=data, url=url,
btntxt="详细信息")
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='att_ok', user_id="18562027762",
title="考勤确认单", description=data, url=url,
btntxt="详细信息")
self.write({'vacation_state': 'pending'})
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
@@ -509,27 +636,32 @@ class YuthonVacationReports(models.Model):
}
def all_put(self):
vacation_ids = self.env["yuthon.vacation.reports"].browse(
self._context.get('active_ids', self._context.get('active_id')))
vacation_list = []
vacation_ids = self.env["yuthon.vacation.reports"].browse(self._context.get('active_ids', self._context.get('active_id')))
for rec in vacation_ids:
vacation_list.append(rec.id)
we_id = rec.employee_id.wecom_userid
year = rec.vacation_date.year
month = rec.vacation_date.month
if we_id:
url = f'https://phone.thtzjt.com/phone/Notarize/{rec.id}/{rec.employee_id.id}'
data = f"你{year}年{month}月的考勤确认单已经生成,请确认"
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='att_ok', user_id=we_id, title="考勤确认单", description=data, url=url, btntxt="详细信息")
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='att_ok', user_id="18562027762", title="考勤确认单", description=data, url=url, btntxt="详细信息")
rec.write({'vacation_state': 'pending'})
return {
'type': 'ir.actions.act_window',
'name': '批量发送确认弹窗',
'res_model': 'vacation.put.wizard',
'view_mode': 'form',
'target': 'new',
'context': {'default_vacation_ids': [(6, 0, [vacation_list])]
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'type': 'success',
'message': '已发送提醒消息',
'sticky': False,
}
}
def manage_confirmation(self):
vacation_ids = self.env["yuthon.vacation.reports"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for rec in vacation_ids:
rec.manage_reject()
rec.vacation_state = 'confirmed'
def manage_reject(self):
'''
@@ -543,10 +675,7 @@ class YuthonVacationReports(models.Model):
('employee_id', '=', rec.employee_id.id),
('vacation_date', '>=', fields.Date.to_string(last_month_first)),
('vacation_date', '<=', fields.Date.to_string(last_month_last)),
('vacation_state', '=', 'confirmed')
], limit=1)
rec.vacation_state = 'confirmed'
current_year = rec.vacation_date.year
last_month_year = last_month_last.year
is_cross_year = current_year != last_month_year
@@ -565,6 +694,18 @@ class YuthonVacationReports(models.Model):
'leave': last_month_record.leave,
'working_overtime': last_month_record.working_overtime,
'medical_fee': last_month_record.medical_fee,
'previous_year': last_month_record.previous_year,
'valid_date': last_month_record.valid_date,
'year_distribution': last_month_record.year_distribution,
'used_this_year': last_month_record.used_this_year,
'last_holiday': last_month_record.last_holiday,
'last_workday': last_month_record.last_workday,
'valid_date1': last_month_record.valid_date1,
'year_holiday': last_month_record.year_holiday,
'year_workday': last_month_record.year_workday,
'previous_year1': last_month_record.previous_year1,
'used_this_year1': last_month_record.used_this_year1,
'remainder_year1': last_month_record.remainder_year1,
}
rec.write(inherit_vals)
if rec.leave:
@@ -585,7 +726,6 @@ class YuthonVacationReports(models.Model):
total += line.lines
elif line.update_type == 'reduce':
total -= line.lines
record.medical_fee = max(total, 0.0)
def disposable_report(self):
@@ -701,9 +841,9 @@ class YuthonVacationReports(models.Model):
)
def _compute_working_overtime(self):
for record in self:
total_add1 = 0.0
total_add2 = 0.0
total_add = 0.0
total_add1 = 0.0 # 加班时
total_add2 = 0.0 # (已用补休)
total_add = 0.0 # (剩余补休)
legal_total = 0.0
for line in record.overtime_ids:
if line.is_void:
@@ -718,8 +858,10 @@ class YuthonVacationReports(models.Model):
if line.workflow_record_id and line.update_type == 'add' and line.overtime_methods == 'leave':
total_add1 += line_total
if line.workflow_record_id and line.update_type == 'reduce':
total_add2 += line_total
adjust_holiday_days = 0.0
for other_line in record.other_fee_ids:
if other_line.holiday_type and other_line.holiday_type.name == '调休':
@@ -790,7 +932,7 @@ class YuthonVacationReports(models.Model):
], limit=1)
# 如果考勤异常,则不自动确认
if not attendance_exception:
rec.manage_reject()
rec.vacation_state = 'confirmed'
def monthly_report(self):
today = fields.Date.today()
@@ -952,6 +1094,7 @@ class VacationLeaveLine(models.Model):
self._sync_to_employee(reverse=True)
return super(VacationLeaveLine, self).unlink()
class VacationOverline(models.Model):
_name = 'vacation.over.line'
_description = '加班明细'
@@ -967,6 +1110,7 @@ class VacationOverline(models.Model):
last_balance = fields.Float(string='上年结余', compute='_compute_last_balance', store=True)
legal_day = fields.Float(string='法定节假日')
public_holidays = fields.Float(string='公休日')
vacation_sum = fields.Float(string='合计数', compute='_compute_last_balance')
meal_number = fields.Integer(string='误餐次数')
update_date = fields.Date(string='更新时间')
is_void = fields.Boolean(string='是否作废')
@@ -991,10 +1135,24 @@ class VacationOverline(models.Model):
],string='结转状态',
default='pending',
)
remaining_quantity = fields.Float(string='剩余数', compute="_compute_remaining_quantity", store=True)
remaining_quantity = fields.Float(string='剩余数', compute="_compute_last_balance", store=True)
def open_record1(self):
tree_id = self.env.ref("yuthon_hr_attendance.view_yuthon_vacation_overtime_tree").id
return {
'type': 'ir.actions.act_window',
'name': 'Overtime Record',
'res_model': 'vacation.meal.line',
'view_mode': 'tree',
'views': [[tree_id, 'tree']],
'domain': [('employee_id', '=', self.employee_id.id),
('carry_forward_state', '=', 'pending')
],
}
@api.model
def confirm(self):
# 1. 构建筛选域
domain = [
'|',
['is_initial_number', '=', True],
@@ -1012,11 +1170,39 @@ class VacationOverline(models.Model):
filtered_records = self.search(domain)
if not filtered_records:
return
records_to_update = filtered_records.filtered(
lambda r: fields.float_compare(r.duration, r.carry_forward_quantity) == 0
valid_records = filtered_records.filtered(
lambda r: r.carry_forward_quantity and r.carry_forward_quantity != 0.0
)
if records_to_update:
records_to_update.write({'is_filing': True})
if not valid_records:
return
active_model = self.env['vacation.overtime.active']
for rec in valid_records:
if rec.remaining_quantity == 0:
rec.is_filing = True
match_domain = [
('employee_id', '=', rec.employee_id.id if rec.employee_id else False),
('workflow_record_id', '=', rec.workflow_record_id.id if rec.workflow_record_id else False),
('carry_forward_date', '=', rec.carry_forward_date or fields.Date.today()),
('overtime_name', '=', rec.overtime_name or '')
]
existing_active = active_model.search(match_domain, limit=1)
active_vals = {
'employee_id': rec.employee_id.id if rec.employee_id else False,
'workflow_record_id': rec.workflow_record_id.id if rec.workflow_record_id else False,
'overtime_name': rec.overtime_name or '',
'remaining_quantity': rec.remaining_quantity,
'carry_forward_date': rec.carry_forward_date or fields.Date.today(),
'carry_forward_quantity': rec.carry_forward_quantity,
'carry_result': 'success'
}
if existing_active:
existing_active.write(active_vals)
else:
active_model.create(active_vals)
def update_is_visible(self):
over_ids = self.env["vacation.over.line"].browse(
@@ -1028,21 +1214,17 @@ class VacationOverline(models.Model):
over_ids = self.env["vacation.over.line"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for rec in over_ids:
rec._compute_remaining_quantity()
rec._compute_overtime()
rec._compute_employee_id()
rec._compute_last_balance()
@api.depends('duration', 'carry_forward_quantity')
def _compute_remaining_quantity(self):
for rec in self:
rec.remaining_quantity = rec.duration - rec.carry_forward_quantity
@api.depends('vacation_id')
def _compute_last_balance(self):
for rec in self:
if rec.vacation_id:
rec.last_balance = rec.vacation_id.last_holiday + rec.vacation_id.last_workday
rec.vacation_sum = rec.last_balance + rec.public_holidays + rec.workday
rec.remaining_quantity = rec.vacation_sum - rec.carry_forward_quantity
else:
rec.last_balance = 0
@@ -1320,6 +1502,19 @@ class VacationMealLine(models.Model):
return super(VacationMealLine, self).unlink()
class VacationParentingLine(models.Model):
_name = 'vacation.parenting.line'
_description = '育儿明细'
vacation_id = fields.Many2one('yuthon.vacation.reports', string='关联假期额度记录')
employee_id = fields.Many2one('hr.employee', string='员工')
update_date = fields.Date(string='发放日期')
end_date = fields.Date(string='失效日期')
lines = fields.Float(string='额度')
text = fields.Text(string='备注')
is_confirm = fields.Boolean(string="是否确认")
class VacationMedicalLine(models.Model):
_name = 'vacation.medical.line'
_description = '体检费明细'
@@ -85,4 +85,9 @@ access_applet_security_quick_perm_wizard,access_applet_security_quick_perm_wizar
access_vacation_reports_wizard,vacation.reports.wizard,model_vacation_reports_wizard,base.group_user,1,1,1,1
access_yuthon_holiday_statement,access_yuthon_holiday_statement,model_yuthon_holiday_statement,base.group_user,1,1,1,1
access_yuthon_meal_case,access_yuthon_meal_case,model_yuthon_meal_case,base.group_user,1,1,1,1
access_pay_carryover_wizard,pay.carryover.wizard,model_pay_carryover_wizard,base.group_user,1,1,1,1
access_pay_carryover_wizard,pay.carryover.wizard,model_pay_carryover_wizard,base.group_user,1,1,1,1
access_vacation_parenting_line,vacation.parenting.line,model_vacation_parenting_line,base.group_user,1,1,1,1
access_yuthon_parenting_allocate,yuthon.parenting.allocate,model_yuthon_parenting_allocate,base.group_user,1,1,1,1
access_vacation_overtime_active,vacation.overtime.active,model_vacation_overtime_active,base.group_user,1,1,1,1
access_yuthon_overtime_line,yuthon.overtime.line,model_yuthon_overtime_line,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
85
86
87
88
89
90
91
92
93
@@ -7,17 +7,10 @@ export class CustomAttendanceMealConfirmController extends ListController {
setup() {
super.setup();
}
async getAction(lock_type) {
const action = await this.orm.call('vacation.meal.line', 'confirm', [lock_type], {context: this.props.context});
action["context"] = {
...action.context,
...this.model.root.context,
}
return action
await this.orm.call('vacation.meal.line', 'confirm', []);
}
}
registry.category("views").add("custom_vacation_meal_button", {
...listView,
Controller: CustomAttendanceMealConfirmController,
@@ -8,13 +8,9 @@ export class CustomAttendanceStatementConfirmController extends ListController {
super.setup();
}
async getAction(lock_type) {
const action = await this.orm.call('hr.leave', 'confirm', [lock_type], {context: this.props.context});
action["context"] = {
...action.context,
...this.model.root.context,
}
return action
await this.orm.call('hr.leave', 'confirm', []);
}
}
@@ -9,12 +9,13 @@ export class CustomAttendanceVacationConfirmController extends ListController {
}
async getAction(lock_type) {
const action = await this.orm.call('vacation.over.line', 'confirm', [lock_type], {context: this.props.context});
action["context"] = {
...action.context,
...this.model.root.context,
}
return action
await this.orm.call('vacation.over.line', 'confirm', []);
}
async getNextAction(lock_type) {
await this.orm.call('vacation.meal.line', 'confirm', []);
}
async getLastAction(lock_type) {
await this.orm.call('vacation.meal.line', 'confirm', []);
}
}
@@ -42,27 +42,13 @@ export class CustomAttendanceVacationPutController extends ListController {
openVacationOverWizard() {
this.actionService.doAction({
type: 'ir.actions.act_window',
res_model: 'vacation.over.line',
name: '加班情况',
res_model: 'yuthon.overtime.line',
name: '加班合计数报表',
view_mode: 'tree',
view_type: 'form',
views: [[false, 'tree']],
target: 'current',
context: {'tree_view_ref': "yuthon_hr_attendance.view_yuthon_vacation_overtime_briefly_tree"},
domain: [
'|',
['is_initial_number', '=', true],
'&',
['is_initial_number', '=', false],
'&',
['update_type', '=', 'add'],
'&',
['workflow_record_id', '!=', false],
'!',
'&',
['start_time', '>=', '2025-12-01 00:00:00'],
['start_time', '<', '2026-01-01 00:00:00']
],
context: {'tree_view_ref': "yuthon_hr_attendance.view_yuthon_overtime_line_tree"},
});
}
@@ -5,6 +5,12 @@
<button type="button" class="btn btn-primary" style="margin-left: 10px;" t-on-click="getAction">
确认
</button>
<button type="button" class="btn btn-primary" style="margin-left: 10px;" t-on-click="getLastAction">
上月
</button>
<button type="button" class="btn btn-primary" style="margin-left: 10px;" t-on-click="getNextAction">
下月
</button>
</xpath>
</t>
</templates>
@@ -8,7 +8,7 @@
</xpath>
<xpath expr="//div[hasclass('o_list_buttons')]" position="after">
<button type="button" class="btn btn-primary" style="margin-left: 10px;" t-on-click="openVacationOverWizard">
加班情况
加班合计数报表
</button>
</xpath>
<xpath expr="//div[hasclass('o_list_buttons')]" position="after">
@@ -49,6 +49,7 @@
<field name="shift_id" invisible="shift_name" readonly="1"/>
<field name="shift_name" invisible="shift_id" readonly="1"/>
<field name="replacement_time"/>
<field name="number_cards_replaced"/>
</group>
<group>
<field name="attendance_id" domain="[('employee_id', '=', employee_id), '|', '|', '|', '|', ('is_abnormal', '=', True), ('is_early_card', '=', True), ('is_late_card', '=', True), ('absenteeism_card', '=', True), ('is_no_card', '=', True)]" invisible="is_attendance"/>
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_vacation_overtime_active_tree" model="ir.ui.view">
<field name="name">vacation.overtime.active.tree</field>
<field name="model">vacation.overtime.active</field>
<field name="arch" type="xml">
<tree string="加班情况(归档)" editable="bottom">
<field name="overtime_name"/>
<field name="employee_id"/>
<field name="department_id"/>
<field name="carry_forward_quantity"/>
<field name="remaining_quantity"/>
<field name="carry_forward_date"/>
<field name="carry_result"/>
</tree>
</field>
</record>
<record id="view_vacation_overtime_active_action" model="ir.actions.act_window">
<field name="name">加班情况(归档)</field>
<field name="res_model">vacation.overtime.active</field>
<field name="view_mode">tree</field>
<field name="view_id" ref="view_vacation_overtime_active_tree"/>
</record>
</odoo>
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_yuthon_overtime_line_tree" model="ir.ui.view">
<field name="name">yuthon.overtime.line.tree</field>
<field name="model">yuthon.overtime.line</field>
<field name="arch" type="xml">
<tree string="加班合计数报表" editable="bottom" js_class="custom_vacation_confirm_button" create="0">
<field name="employee_id"/>
<field name="last_balance"/>
<field name="valid_date"/>
<field name="workday"/>
<field name="public_holidays"/>
<field name="vacation_sum"/>
<field name="carry_forward_quantity"/>
<field name="carry_forward_date"/>
<field name="remaining_quantity"/>
<button name="open_record" type="object" string="结束" dclass="oe_highlight"/>
</tree>
</field>
</record>
<record id="view_yuthon_overtime_line_action" model="ir.actions.act_window">
<field name="name">加班合计数报表</field>
<field name="res_model">yuthon.overtime.line</field>
<field name="view_mode">tree</field>
</record>
</odoo>
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id ="yuthon_parenting_allocate_tree" model="ir.ui.view">
<field name="name">yuthon.parenting.allocate.tree</field>
<field name="model">yuthon.parenting.allocate</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="cycle_years"/>
<field name="cycle_unit"/>
<field name="valid_limit"/>
<field name="distribute"/>
<field name="birth_certificate"/>
<field name="company_id"/>
</tree>
</field>
</record>
<record id ="yuthon_parenting_allocate_action" model="ir.actions.act_window">
<field name="name">育儿假规则</field>
<field name="res_model">yuthon.parenting.allocate</field>
<field name="view_mode">tree</field>
</record>
</odoo>
@@ -4,13 +4,13 @@
<field name="name">vacation.meal.line.tree</field>
<field name="model">vacation.meal.line</field>
<field name="arch" type="xml">
<tree string="误餐情况" create="false" delete="false" js_class="custom_vacation_meal_button">
<field name="employee_id"/>
<field name="meal_name"/>
<field name="start_date" column_invisible="1"/>
<field name="update_lines"/>
<field name="is_filing" column_invisible="1"/>
</tree>
<tree string="误餐情况" create="false" delete="false" js_class="custom_vacation_meal_button">
<field name="employee_id"/>
<field name="meal_name"/>
<field name="start_date" column_invisible="1"/>
<field name="update_lines"/>
<field name="is_filing" column_invisible="1"/>
</tree>
</field>
</record>
<record id="view_yuthon_vacation_meal_search" model="ir.ui.view">
@@ -21,13 +21,13 @@
<field name="employee_id"/>
<field name="department_id"/>
<filter string="员工" name="group_by_employee_id" domain="[]" context="{'group_by': 'employee_id'}"/>
<filter name="now_month" string="当月" domain="[('vacation_date', '&gt;=', (context_today() + relativedelta(day=1)).strftime('%Y-%m-%d')),
<filter name="now_month" string="当月" domain="[('vacation_date', '&gt;=', (context_today() + relativedelta(day=1)).strftime('%Y-%m-%d')),
('vacation_date', '&lt;', (context_today() + relativedelta(months=+1, day=1)).strftime('%Y-%m-%d'))]"/>
<header_search class="header-search-inline">
<field name="vacation_date"/>
<field name="employee_id"/>
<field name="department_id"/>
</header_search>
<field name="vacation_date"/>
<field name="employee_id"/>
<field name="department_id"/>
</header_search>
</search>
</field>
</record>
@@ -35,29 +35,33 @@
<field name="name">yuthon.vacation.reports.tree</field>
<field name="model">yuthon.vacation.reports</field>
<field name="arch" type="xml">
<tree string="假期额度记录" editable="bottom" edit="0" default_order="vacation_date desc" js_class="custom_vacation_put_button" limit="10">
<field name="vacation_state" widget="badge" decoration-info="vacation_state == 'not_sent'"
<tree string="考勤确认单台账" editable="bottom" edit="0" default_order="vacation_date desc"
js_class="custom_vacation_put_button" limit="10">
<header>
<button name="manage_confirmation" type="object" string="批量确认" dclass="oe_highlight"/>
</header>
<field name="vacation_state" widget="badge" decoration-info="vacation_state == 'not_sent'"
decoration-success="vacation_state == 'confirmed'"/>
<field name="employee_id" options="{'no_open': True}"/>
<field name="department_id" column_invisible="1"/>
<field name="company_id" column_invisible="1"/>
<field name="vacation_date" column_invisible="1"/>
<field name="open_start_time"/>
<field name="company_old"/>
<field name="previous_year"/>
<field name="valid_date"/>
<field name="year_distribution"/>
<field name="used_this_year"/>
<field name="remainder_year"/>
<field name="last_holiday"/>
<field name="last_workday"/>
<field name="valid_date1"/>
<field name="year_holiday"/>
<field name="year_workday"/>
<field name="year_sum"/>
<field name="used_this_year1"/>
<field name="remainder_year1"/>
<field name="should_attendance" options='{ "fg_color": "white: should_attendance == False"}'/>
<field name="open_start_time"/>
<field name="company_old"/>
<field name="previous_year"/>
<field name="valid_date"/>
<field name="year_distribution"/>
<field name="used_this_year"/>
<field name="remainder_year"/>
<field name="last_holiday"/>
<field name="last_workday"/>
<field name="valid_date1"/>
<field name="year_holiday"/>
<field name="year_workday"/>
<field name="year_sum"/>
<field name="used_this_year1"/>
<field name="remainder_year1"/>
<field name="should_attendance" options='{ "fg_color": "white: should_attendance == False"}'/>
<field name="actual_attendance" options='{ "fg_color": "white: actual_attendance == False"}'/>
<field name="right_days" options='{ "fg_color": "white: right_days == False"}'/>
<field name="test_days" options='{ "fg_color": "white: test_days == False"}'/>
@@ -66,15 +70,17 @@
<field name="is_no_card" options='{ "fg_color": "white: is_no_card == False"}'/>
<field name="is_work" options='{ "fg_color": "white: is_work == False"}'/>
<field name="is_abnormal" options='{ "fg_color": "white: not is_abnormal"}'/>
<field name="late_allowed" options='{ "fg_color": "white: late_allowed == False"}'/>
<field name="late_allowed" options='{ "fg_color": "white: late_allowed == False"}'/>
<field name="done_leave" options='{ "fg_color": "white: done_leave == False"}'/>
<field name="done_working_overtime" options='{ "fg_color": "white: done_working_overtime == False"}'/>
<field name="meal_fee" options='{ "fg_color": "white: meal_fee == False"}'/>
<field name="medical_fee" options='{ "fg_color": "white: medical_fee == False"}'/>
<field name="compensatory_leave" options='{ "fg_color": "white: compensatory_leave == False"}'/>
<field name="leave_of_absence" options='{ "fg_color": "white: leave_of_absence == False"}'/>
<field name="statutory_leave" string="加班时(法定假)" options='{ "fg_color": "white: statutory_leave == False"}'/>
<field name="statutory_leave" string="加班时(法定假)"
options='{ "fg_color": "white: statutory_leave == False"}'/>
<field name="cop_leave" options='{ "fg_color": "white: cop_leave == False"}'/>
<field name="parental_leave" options='{ "fg_color": "white: parental_leave == False"}'/>
<field name="duty_off_leave" options='{ "fg_color": "white: duty_off_leave == False"}'/>
<field name="marriage_leave" options='{ "fg_color": "white: marriage_leave == False"}'/>
<field name="maternity_leave" options='{ "fg_color": "white: maternity_leave == False"}'/>
@@ -87,8 +93,9 @@
<field name="hospital_sick_leave" options='{ "fg_color": "white: hospital_sick_leave == False"}'/>
<field name="recovery_sick_leave" options='{ "fg_color": "white: recovery_sick_leave == False"}'/>
<field name="exam_leave" options='{ "fg_color": "white: exam_leave == False"}'/>
<button name="log" type="object" string="详情" class="oe_highlight"/>
<button name="button_put" string="发送" type="object" class="oe_highlight"/>
<button name="log" type="object" string="详情" class="oe_highlight"/>
<button name="button_put" string="发送" invisible="vacation_state == 'confirmed'" type="object"
class="oe_highlight"/>
</tree>
</field>
</record>
@@ -96,7 +103,8 @@
<field name="name">yuthon.vacation.my.reports.tree</field>
<field name="model">yuthon.vacation.reports</field>
<field name="arch" type="xml">
<tree string="我的假期额度记录" editable="bottom" edit="0" delete="0" default_order="vacation_date desc" create="0">
<tree string="我的假期额度记录" editable="bottom" edit="0" delete="0" default_order="vacation_date desc"
create="0">
<field name="vacation_state" widget="badge" decoration-info="vacation_state == 'unconfirmed'"
decoration-success="vacation_state == 'confirmed'"/>
<field name="employee_id" options="{'no_open': True}"/>
@@ -122,8 +130,10 @@
<field name="medical_fee" options='{ "fg_color": "white: medical_fee == False"}'/>
<field name="compensatory_leave" options='{ "fg_color": "white: compensatory_leave == False"}'/>
<field name="leave_of_absence" options='{ "fg_color": "white: leave_of_absence == False"}'/>
<field name="statutory_leave" string="加班时(法定假)" options='{ "fg_color": "white: statutory_leave == False"}'/>
<field name="statutory_leave" string="加班时(法定假)"
options='{ "fg_color": "white: statutory_leave == False"}'/>
<field name="cop_leave" options='{ "fg_color": "white: cop_leave == False"}'/>
<field name="parental_leave" options='{ "fg_color": "white: parental_leave == False"}'/>
<field name="duty_off_leave" options='{ "fg_color": "white: duty_off_leave == False"}'/>
<field name="marriage_leave" options='{ "fg_color": "white: marriage_leave == False"}'/>
<field name="maternity_leave" options='{ "fg_color": "white: maternity_leave == False"}'/>
@@ -137,7 +147,8 @@
<field name="recovery_sick_leave" options='{ "fg_color": "white: recovery_sick_leave == False"}'/>
<field name="exam_leave" options='{ "fg_color": "white: exam_leave == False"}'/>
<button name="log" type="object" string="详情" class="oe_highlight"/>
<button name="confirm_state" type="object" string="确认" class="oe_highlight" invisible="vacation_state == 'confirmed'"/>
<button name="confirm_state" type="object" string="确认" class="oe_highlight"
invisible="vacation_state == 'confirmed'"/>
</tree>
</field>
</record>
@@ -183,16 +194,20 @@
<group>
<field name="test_days"/>
</group>
<group/>
<group>
<field name="remaining_parental_leave"/>
</group>
</group>
<notebook>
<page string="年假">
<field name="leave_ids" context="{'default_employee_id': employee_id}">
<tree editable="bottom" delete="false" decoration-muted="is_void">
<button name="open_record" type="object" string="详情" class="btn-primary" invisible="not workflow_record_id"/>
<button name="open_record" type="object" string="详情" class="btn-primary"
invisible="not workflow_record_id"/>
<field name="employee_id" column_invisible="1"/>
<field name="vacation_id" column_invisible="1"/>
<field name="workflow_record_id" domain="[('workflow_id.name', '=', '请假'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="vacation_id" column_invisible="1"/>
<field name="workflow_record_id"
domain="[('workflow_id.name', '=', '请假'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="update_type" readonly="0"/>
<field name="update_date" readonly="0"/>
<field name="update_lines"/>
@@ -202,9 +217,12 @@
<field name="is_void"/>
<field name="text"/>
<field name="is_confirm" column_invisible="1"/>
<button name="unlink" string="删除" type="object" class="btn-primary" groups="yuthon_holiday.group_yuthon_holiday_admin"/>
<button name="unlink" string="撤销" invisible="is_confirm == True" type="object" class="btn-primary"/>
<button name="action_void" string="作废" class="btn-primary" invisible="is_confirm != True" type="object"/>
<button name="unlink" string="删除" type="object" class="btn-primary"
groups="yuthon_holiday.group_yuthon_holiday_admin"/>
<button name="unlink" string="撤销" invisible="is_confirm == True" type="object"
class="btn-primary"/>
<button name="action_void" string="作废" class="btn-primary"
invisible="is_confirm != True" type="object"/>
</tree>
</field>
</page>
@@ -212,10 +230,12 @@
<button name="overtime_allocation" string="分配" type="object" class="btn btn-primary"/>
<field name="overtime_ids" context="{'default_employee_id': employee_id}">
<tree editable="bottom" delete="false" decoration-muted="is_void">
<button name="open_record" type="object" string="详情" class="btn-primary" invisible="not workflow_record_id"/>
<field name="vacation_id" column_invisible="1"/>
<button name="open_record" type="object" string="详情" class="btn-primary"
invisible="not workflow_record_id"/>
<field name="vacation_id" column_invisible="1"/>
<field name="employee_id" column_invisible="1"/>
<field name="workflow_record_id" domain="[('workflow_id.name', '=', '加班'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="workflow_record_id"
domain="[('workflow_id.name', '=', '加班'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="update_type" readonly="0"/>
<field name="update_date" readonly="0"/>
<field name="workday"/>
@@ -227,9 +247,12 @@
<field name="overtime_methods"/>
<field name="is_void"/>
<field name="text"/>
<button name="unlink" string="删除" type="object" class="btn-primary" groups="yuthon_holiday.group_yuthon_holiday_admin"/>
<button name="unlink" string="撤销" invisible="is_confirm == True" type="object" class="btn-primary"/>
<button name="action_void" string="作废" class="btn-primary" invisible="is_confirm != True" type="object"/>
<button name="unlink" string="删除" type="object" class="btn-primary"
groups="yuthon_holiday.group_yuthon_holiday_admin"/>
<button name="unlink" string="撤销" invisible="is_confirm == True" type="object"
class="btn-primary"/>
<button name="action_void" string="作废" class="btn-primary"
invisible="is_confirm != True" type="object"/>
<field name="is_confirm" column_invisible="1"/>
</tree>
</field>
@@ -237,10 +260,12 @@
<page string="误餐">
<field name="meal_fee_ids" context="{'default_employee_id': employee_id}">
<tree editable="bottom" delete="false" decoration-muted="is_void">
<button name="open_record" type="object" string="详情" class="btn-primary" invisible="not workflow_record_id"/>
<button name="open_record" type="object" string="详情" class="btn-primary"
invisible="not workflow_record_id"/>
<field name="employee_id" column_invisible="1"/>
<field name="vacation_id" column_invisible="1"/>
<field name="workflow_record_id" domain="[('workflow_id.name', '=', '外出'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="workflow_record_id"
domain="[('workflow_id.name', '=', '外出'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="update_type" readonly="0"/>
<field name="update_date" readonly="0"/>
<field name="update_lines"/>
@@ -248,9 +273,12 @@
<field name="adjust_date"/>
<field name="is_void"/>
<field name="text"/>
<button name="unlink" string="删除" type="object" class="btn-primary" groups="yuthon_holiday.group_yuthon_holiday_admin"/>
<button name="unlink" string="撤销" invisible="is_confirm == True" type="object" class="btn-primary"/>
<button name="action_void" string="作废" class="btn-primary" invisible="is_confirm != True" type="object"/>
<button name="unlink" string="删除" type="object" class="btn-primary"
groups="yuthon_holiday.group_yuthon_holiday_admin"/>
<button name="unlink" string="撤销" invisible="is_confirm == True" type="object"
class="btn-primary"/>
<button name="action_void" string="作废" class="btn-primary"
invisible="is_confirm != True" type="object"/>
<field name="is_confirm" column_invisible="1"/>
</tree>
</field>
@@ -258,19 +286,24 @@
<page string="其他请假">
<field name="other_fee_ids" context="{'default_employee_id': employee_id}">
<tree editable="bottom" delete="false" decoration-muted="is_void">
<button name="open_record" type="object" string="详情" class="btn-primary" invisible="not workflow_record_id"/>
<button name="open_record" type="object" string="详情" class="btn-primary"
invisible="not workflow_record_id"/>
<field name="employee_id" column_invisible="1"/>
<field name="vacation_id" column_invisible="1"/>
<field name="workflow_record_id" domain="[('workflow_id.name', '=', '请假'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="workflow_record_id"
domain="[('workflow_id.name', '=', '请假'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="holiday_type"/>
<field name="update_type" readonly="0"/>
<field name="update_date" readonly="0"/>
<field name="lines"/>
<field name="is_void"/>
<field name="text"/>
<button name="unlink" string="删除" type="object" class="btn-primary" groups="yuthon_holiday.group_yuthon_holiday_admin"/>
<button name="unlink" string="撤销" invisible="is_confirm == True" type="object" class="btn-primary"/>
<button name="action_void" string="作废" class="btn-primary" invisible="is_confirm != True" type="object"/>
<button name="unlink" string="删除" type="object" class="btn-primary"
groups="yuthon_holiday.group_yuthon_holiday_admin"/>
<button name="unlink" string="撤销" invisible="is_confirm == True" type="object"
class="btn-primary"/>
<button name="action_void" string="作废" class="btn-primary"
invisible="is_confirm != True" type="object"/>
<field name="is_confirm" column_invisible="1"/>
</tree>
</field>
@@ -280,7 +313,8 @@
<tree editable="bottom" delete="false" decoration-muted="is_void">
<field name="employee_id" column_invisible="1"/>
<field name="vacation_id" column_invisible="1"/>
<field name="workflow_record_id" domain="[('workflow_id.name', '=', '外出'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="workflow_record_id"
domain="[('workflow_id.name', '=', '外出'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="update_type" readonly="0"/>
<field name="update_date" readonly="0"/>
<field name="lines"/>
@@ -288,29 +322,32 @@
<field name="adjust_date"/>
<field name="is_void"/>
<field name="text"/>
<button name="unlink" string="删除" type="object" class="btn-primary" groups="yuthon_holiday.group_yuthon_holiday_admin"/>
<button name="unlink" string="撤销" invisible="is_confirm == True" type="object" class="btn-primary"/>
<button name="action_void" string="作废" class="btn-primary" invisible="is_confirm != True" type="object"/>
<button name="unlink" string="删除" type="object" class="btn-primary"
groups="yuthon_holiday.group_yuthon_holiday_admin"/>
<button name="unlink" string="撤销" invisible="is_confirm == True" type="object"
class="btn-primary"/>
<button name="action_void" string="作废" class="btn-primary"
invisible="is_confirm != True" type="object"/>
<field name="is_confirm" column_invisible="1"/>
</tree>
</field>
</page>
<!-- <page string="出勤消息日志" invisible="1">-->
<!-- <field name="attendance_message_log_ids">-->
<!-- <tree editable="bottom" create="false" edit="false" delete="false">-->
<!-- <field name="vacation_id" column_invisible="1"/>-->
<!-- <field name="employee_id"/>-->
<!-- <field name="update_date"/>-->
<!-- <field name="message_type"/>-->
<!-- <field name="message_url"/>-->
<!-- <button name="unlink" string="删除" type="object" class="btn-primary" groups="yuthon_holiday.group_yuthon_holiday_admin"/>-->
<!-- </tree>-->
<!-- </field>-->
<!-- </page>-->
<!-- <page string="出勤消息日志" invisible="1">-->
<!-- <field name="attendance_message_log_ids">-->
<!-- <tree editable="bottom" create="false" edit="false" delete="false">-->
<!-- <field name="vacation_id" column_invisible="1"/>-->
<!-- <field name="employee_id"/>-->
<!-- <field name="update_date"/>-->
<!-- <field name="message_type"/>-->
<!-- <field name="message_url"/>-->
<!-- <button name="unlink" string="删除" type="object" class="btn-primary" groups="yuthon_holiday.group_yuthon_holiday_admin"/>-->
<!-- </tree>-->
<!-- </field>-->
<!-- </page>-->
<page string="管理员修改字段" groups="base.group_system">
<group col="2">
<group>
<field name="previous_year"/>
<field name="previous_year"/>
<field name="year_distribution"/>
<field name="used_this_year"/>
<field name="last_holiday"/>
@@ -323,7 +360,20 @@
</group>
</group>
</page>
<page string="汇总" >
<page string="育儿假">
<field name="parenting_line_ids" context="{'default_employee_id': employee_id}">
<tree editable="bottom" delete="false" edit="false" create="false">
<field name="employee_id" column_invisible="1"/>
<field name="vacation_id" column_invisible="1"/>
<field name="update_date"/>
<field name="end_date"/>
<field name="lines"/>
<field name="text"/>
<field name="is_confirm" column_invisible="1"/>
</tree>
</field>
</page>
<page string="汇总">
<group>
<field name="is_late_card"/>
<field name="is_early_card"/>
@@ -358,28 +408,33 @@
</field>
</record>
<record id="view_yuthon_vacation_reports_search" model="ir.ui.view">
<field name="name">yuthon.vacation.reports.search</field>
<field name="model">yuthon.vacation.reports</field>
<field name="arch" type="xml">
<search>
<filter name="now_month" string="当月" domain="[('vacation_date', '&gt;=', (context_today() + relativedelta(day=1)).strftime('%Y-%m-%d')),
<field name="name">yuthon.vacation.reports.search</field>
<field name="model">yuthon.vacation.reports</field>
<field name="arch" type="xml">
<search>
<filter name="now_month" string="当月" domain="[('vacation_date', '&gt;=', (context_today() + relativedelta(day=1)).strftime('%Y-%m-%d')),
('vacation_date', '&lt;', (context_today() + relativedelta(months=+1, day=1)).strftime('%Y-%m-%d'))]"/>
<field name="employee_id"/>
<group expand="0" string="Group By">
<filter string="公司" name="group_by_company_id" domain="[]" context="{'group_by': 'company_id'}"/>
<filter string="部门" name="group_by_department_id" domain="[]"
context="{'group_by': 'department_id'}"/>
<filter string="工资组" name="group_by_salary_group_id" domain="[]"
context="{'group_by': 'salary_group_id'}"/>
<filter string="员工" name="group_by_employee_id" domain="[]"
context="{'group_by': 'employee_id'}"/>
<filter string="按年" name="group_by_vacation_year" domain="[]"
context="{'group_by': 'vacation_date:year'}"/>
<filter string="按月" name="group_by_vacation_month" domain="[]"
context="{'group_by': 'vacation_date:month'}"/>
</group>
<header_search class="header-search-inline">
<field name="vacation_date"/>
<field name="employee_id"/>
<group expand="0" string="Group By">
<filter string="公司" name="group_by_company_id" domain="[]" context="{'group_by': 'company_id'}"/>
<filter string="部门" name="group_by_department_id" domain="[]" context="{'group_by': 'department_id'}"/>
<filter string="工资组" name="group_by_salary_group_id" domain="[]" context="{'group_by': 'salary_group_id'}"/>
<filter string="员工" name="group_by_employee_id" domain="[]" context="{'group_by': 'employee_id'}"/>
<filter string="按年" name="group_by_vacation_year" domain="[]" context="{'group_by': 'vacation_date:year'}"/>
<filter string="按月" name="group_by_vacation_month" domain="[]" context="{'group_by': 'vacation_date:month'}"/>
</group>
<header_search class="header-search-inline">
<field name="vacation_date"/>
<field name="employee_id"/>
<field name="department_id"/>
</header_search>
</search>
</field>
<field name="department_id"/>
</header_search>
</search>
</field>
</record>
<record id="view_yuthon_vacation_reports_form1" model="ir.ui.view">
<field name="name">yuthon.vacation.reports.form</field>
@@ -407,26 +462,31 @@
<notebook>
<page string="年假">
<field name="leave_ids" context="{'default_employee_id': employee_id}">
<tree editable="bottom" delete="false" decoration-muted="is_void" edit="false" create="false">
<tree editable="bottom" delete="false" decoration-muted="is_void" edit="false"
create="false">
<field name="employee_id" column_invisible="1"/>
<field name="vacation_id" column_invisible="1"/>
<field name="workflow_record_id" domain="[('workflow_id.name', '=', '请假'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="vacation_id" column_invisible="1"/>
<field name="workflow_record_id"
domain="[('workflow_id.name', '=', '请假'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="update_type" readonly="1"/>
<field name="update_date" readonly="1"/>
<field name="update_lines"/>
<field name="allocation_type" optional="hide"/>
<field name="is_void"/>
<field name="text"/>
<button name="unlink" string="删除" invisible="workflow_record_id" type="object" class="btn-primary" groups="yuthon_holiday.group_yuthon_holiday_admin"/>
<button name="unlink" string="删除" invisible="workflow_record_id" type="object"
class="btn-primary" groups="yuthon_holiday.group_yuthon_holiday_admin"/>
</tree>
</field>
</page>
<page string="加班">
<field name="overtime_ids" context="{'default_employee_id': employee_id}">
<tree editable="bottom" delete="false" decoration-muted="is_void" edit="false" create="false">
<field name="vacation_id" column_invisible="1"/>
<tree editable="bottom" delete="false" decoration-muted="is_void" edit="false"
create="false">
<field name="vacation_id" column_invisible="1"/>
<field name="employee_id" column_invisible="1"/>
<field name="workflow_record_id" domain="[('workflow_id.name', '=', '加班'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="workflow_record_id"
domain="[('workflow_id.name', '=', '加班'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="update_type" readonly="1"/>
<field name="update_date" readonly="1"/>
<field name="workday"/>
@@ -436,31 +496,37 @@
<field name="overtime_methods"/>
<field name="is_void"/>
<field name="text"/>
<button name="unlink" string="删除" invisible="workflow_record_id" type="object" class="btn-primary" groups="yuthon_holiday.group_yuthon_holiday_admin"/>
<button name="unlink" string="删除" invisible="workflow_record_id" type="object"
class="btn-primary" groups="yuthon_holiday.group_yuthon_holiday_admin"/>
</tree>
</field>
</page>
<page string="误餐">
<field name="meal_fee_ids" context="{'default_employee_id': employee_id}">
<tree editable="bottom" delete="false" decoration-muted="is_void" edit="false" create="false">
<tree editable="bottom" delete="false" decoration-muted="is_void" edit="false"
create="false">
<field name="employee_id" column_invisible="1"/>
<field name="vacation_id" column_invisible="1"/>
<field name="workflow_record_id" domain="[('workflow_id.name', '=', '外出'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="workflow_record_id"
domain="[('workflow_id.name', '=', '外出'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="update_type" readonly="1"/>
<field name="update_date" readonly="1"/>
<field name="update_lines"/>
<field name="is_void"/>
<field name="text"/>
<button name="unlink" string="删除" invisible="workflow_record_id" type="object" class="btn-primary" groups="yuthon_holiday.group_yuthon_holiday_admin"/>
<button name="unlink" string="删除" invisible="workflow_record_id" type="object"
class="btn-primary" groups="yuthon_holiday.group_yuthon_holiday_admin"/>
</tree>
</field>
</page>
<page string="其他请假">
<field name="other_fee_ids" context="{'default_employee_id': employee_id}">
<tree editable="bottom" delete="false" decoration-muted="is_void" edit="false" create="false">
<tree editable="bottom" delete="false" decoration-muted="is_void" edit="false"
create="false">
<field name="employee_id" column_invisible="1"/>
<field name="vacation_id" column_invisible="1"/>
<field name="workflow_record_id" domain="[('workflow_id.name', '=', '请假'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="workflow_record_id"
domain="[('workflow_id.name', '=', '请假'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="holiday_type"/>
<field name="update_type" readonly="1"/>
<field name="update_date" readonly="1"/>
@@ -472,10 +538,12 @@
</page>
<page string="体检费">
<field name="medical_fee_ids" context="{'default_employee_id': employee_id}">
<tree editable="bottom" delete="false" decoration-muted="is_void" edit="false" create="false">
<tree editable="bottom" delete="false" decoration-muted="is_void" edit="false"
create="false">
<field name="employee_id" column_invisible="1"/>
<field name="vacation_id" column_invisible="1"/>
<field name="workflow_record_id" domain="[('workflow_id.name', '=', '外出'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="workflow_record_id"
domain="[('workflow_id.name', '=', '外出'), ('create_uid.employee_id', '=', employee_id)]"/>
<field name="update_type" readonly="1"/>
<field name="update_date" readonly="1"/>
<field name="lines"/>
@@ -486,17 +554,30 @@
</tree>
</field>
</page>
<!-- <page string="出勤消息日志" invisible="1">-->
<!-- <field name="attendance_message_log_ids">-->
<!-- <tree>-->
<!-- <field name="vacation_id" column_invisible="1"/>-->
<!-- <field name="employee_id"/>-->
<!-- <field name="update_date"/>-->
<!-- <field name="message_type"/>-->
<!-- <field name="message_url"/>-->
<!-- </tree>-->
<!-- </field>-->
<!-- </page>-->
<page string="育儿假">
<field name="parenting_line_ids" context="{'default_employee_id': employee_id}">
<tree editable="bottom" delete="false" edit="false" create="false">
<field name="employee_id" column_invisible="1"/>
<field name="vacation_id" column_invisible="1"/>
<field name="update_date"/>
<field name="end_date"/>
<field name="lines"/>
<field name="text"/>
<field name="is_confirm" column_invisible="1"/>
</tree>
</field>
</page>
<!-- <page string="出勤消息日志" invisible="1">-->
<!-- <field name="attendance_message_log_ids">-->
<!-- <tree>-->
<!-- <field name="vacation_id" column_invisible="1"/>-->
<!-- <field name="employee_id"/>-->
<!-- <field name="update_date"/>-->
<!-- <field name="message_type"/>-->
<!-- <field name="message_url"/>-->
<!-- </tree>-->
<!-- </field>-->
<!-- </page>-->
<page string="汇总" invisible="1">
<group>
<field name="is_late_card"/>
@@ -539,31 +620,17 @@
<field name="name">vacation.over.line.overtime.briefly.tree</field>
<field name="model">vacation.over.line</field>
<field name="arch" type="xml">
<tree string="加班情况弹窗" editable="bottom" js_class="custom_vacation_confirm_button" create="0">
<tree string="加班合计数报表" editable="bottom" create="0">
<field name="employee_id"/>
<field name="last_balance" groups="yuthon_salary.group_lc_user,yuthon_salary.group_wg_user"/>
<field name="valid_date" groups="yuthon_salary.group_lc_user,yuthon_salary.group_wg_user"/>
<field name="workday"/>
<field name="public_holidays"/>
<field name="vacation_sum"/>
<field name="carry_forward_quantity"/>
<field name="carry_forward_date"/>
<field name="remaining_quantity"/>
</tree>
</field>
</record>
<record id="view_yuthon_vacation_overtime_active_tree" model="ir.ui.view">
<field name="name">vacation.over.line.overtime.tree</field>
<field name="model">vacation.over.line</field>
<field name="arch" type="xml">
<tree string="加班情况(归档)" editable="bottom">
<field name="overtime_name"/>
<field name="employee_id" invisible="1"/>
<field name="department_id"/>
<field name="carry_forward_quantity"/>
<field name="carry_forward_date"/>
<field name="is_filing" column_invisible="1"/>
<field name="is_visible" column_invisible="1"/>
<field name="carry_result"/>
<button name="open_record" type="object" string="详情" class="btn-primary"/>
</tree>
</field>
</record>
@@ -578,6 +645,7 @@
<field name="start_time"/>
<field name="end_time"/>
<field name="duration"/>
<field name="vacation_sum"/>
<field name="carry_forward_quantity"/>
<field name="carry_forward_date"/>
<field name="carry_forward_state"/>
@@ -597,13 +665,13 @@
<field name="department_id"/>
<field name="start_time"/>
<filter string="员工" name="group_by_employee_id" domain="[]" context="{'group_by': 'employee_id'}"/>
<filter name="now_month" string="当月" domain="[('start_time', '&gt;=', (context_today() + relativedelta(day=1)).strftime('%Y-%m-%d')),
<filter name="now_month" string="当月" domain="[('start_time', '&gt;=', (context_today() + relativedelta(day=1)).strftime('%Y-%m-%d')),
('start_time', '&lt;', (context_today() + relativedelta(months=+1, day=1)).strftime('%Y-%m-%d'))]"/>
<header_search class="header-search-inline">
<field name="start_time"/>
<field name="employee_id"/>
<field name="department_id"/>
</header_search>
<field name="start_time"/>
<field name="employee_id"/>
<field name="department_id"/>
</header_search>
</search>
</field>
</record>
@@ -611,21 +679,14 @@
<field name="name">加班情况</field>
<field name="res_model">vacation.over.line</field>
<field name="view_mode">tree</field>
<field name="domain">['|', ('workflow_record_id','!=', False), ('is_initial_number', '=', True), ('update_type', '=', 'add'), ('is_filing','=', False), ('is_visible', '=', False)]</field>
<field name="domain">['|', ('workflow_record_id','!=', False), ('is_initial_number', '=', True), ('update_type',
'=', 'add'), ('is_filing','=', False), ('is_visible', '=', False)]
</field>
<field name="context">{'search_default_now_month': 1, 'search_default_group_by_employee_id':1}</field>
<field name="view_id" ref="view_yuthon_vacation_overtime_tree"/>
<field name="search_view_id" ref="view_yuthon_vacation_overtime_search"/>
</record>
<record id="action_overtime_approval_active_report" model="ir.actions.act_window">
<field name="name">加班情况(归档)</field>
<field name="res_model">vacation.over.line</field>
<field name="view_mode">tree</field>
<field name="domain">['|', ('workflow_record_id','!=', False), ('is_initial_number', '=', True), ('update_type', '=', 'add'), ('is_filing','=', True), ('is_visible', '=', False)]</field>
<field name="context">{'search_default_group_by_employee_id':1}</field>
<field name="view_id" ref="view_yuthon_vacation_overtime_active_tree"/>
<field name="search_view_id" ref="view_yuthon_vacation_overtime_search"/>
</record>
<record id="update_vacation_over_line" model="ir.actions.server">
<record id="update_vacation_over_line" model="ir.actions.server">
<field name="name">触发计算逻辑</field>
<field name="model_id" ref="yuthon_hr_attendance.model_vacation_over_line"/>
<field name="binding_model_id" ref="yuthon_hr_attendance.model_vacation_over_line"/>
@@ -644,9 +705,9 @@
<field name="res_model">vacation.meal.line</field>
<field name="view_mode">tree</field>
<field name="domain">[('is_filing','=', False)]</field>
<field name="context">{'search_default_now_month': 1, 'search_default_group_by_employee_id':1}</field>
<field name="context">{'search_default_now_month': 1,}</field>
<field name="search_view_id" ref="view_yuthon_vacation_meal_search"/>
<field name="view_ids" eval="[(5, 0, 0),
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_hr_attendance.view_vacation_meal_line_tree')}),]"/>
</record>
<record id="update_vacation_meal_line" model="ir.actions.server">
@@ -663,7 +724,7 @@
<field name="domain">[('is_filing','=', True)]</field>
<field name="context">{'search_default_now_month': 1, 'search_default_group_by_employee_id':1}</field>
<field name="search_view_id" ref="view_yuthon_vacation_meal_search"/>
<field name="view_ids" eval="[(5, 0, 0),
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_hr_attendance.view_vacation_meal_line_tree')}),]"/>
</record>
<record id="view_yuthon_vacation_reports_action" model="ir.actions.act_window">
@@ -672,7 +733,7 @@
<field name="view_mode">tree,form</field>
<field name="domain">[('is_filing','=', False)]</field>
<field name="context">{'search_default_now_month': 1, 'search_default_group_by_employee_id':1}</field>
<field name="view_ids" eval="[(5, 0, 0),
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_hr_attendance.view_yuthon_vacation_reports_tree')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('yuthon_hr_attendance.view_yuthon_vacation_reports_form')})]"/>
</record>
@@ -682,17 +743,19 @@
<field name="view_mode">tree,form</field>
<field name="domain">[('is_filing','=', True)]</field>
<field name="context">{'search_default_now_month': 1, 'search_default_group_by_employee_id':1}</field>
<field name="view_ids" eval="[(5, 0, 0),
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_hr_attendance.view_yuthon_vacation_reports_tree')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('yuthon_hr_attendance.view_yuthon_vacation_reports_form')})]"/>
</record>
<record id="action_server_open_my_vacation_form1" model="ir.actions.act_window">
<field name="name">我的考勤确认</field>
<field name="res_model">yuthon.vacation.reports</field>
<field name="res_model">yuthon.vacation.reports</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('employee_id.user_id', '=', uid)]</field>
<field name="context">{'search_default_group_by_vacation_year': True, 'search_default_group_by_vacation_month': True}</field>
<field name="view_ids" eval="[(5, 0, 0),
<field name="context">{'search_default_group_by_vacation_year': True, 'search_default_group_by_vacation_month':
True}
</field>
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_hr_attendance.view_yuthon_vacation_my_reports_tree')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('yuthon_hr_attendance.view_yuthon_vacation_reports_form1')})]"/>
</record>
@@ -10,4 +10,4 @@ class AppletSecurityQuickPermWizard(models.TransientModel):
def confirm(self):
for applet in self.applet_security_ids:
applet.write({'applet_security_setting_ids': [(6, 0, self.applet_security_setting_ids.ids)]})
applet.write({'applet_security_setting_ids': [(4, setting_id) for setting_id in self.applet_security_setting_ids.ids]})
@@ -22,7 +22,7 @@ class PayCarryoverWizard(models.TransientModel):
is_2025_december = rec.vacation_date.year == 2026 and rec.vacation_date.month == 1
if rec.overtime_ids:
for overtime in rec.overtime_ids:
if overtime.text == '上月额度继承' and overtime.total > 40:
if overtime.text == '上月额度继承' and overtime.duration > 40:
reduce_workday = overtime.workday - 40
new_overtime = self.env['vacation.over.line'].create([{
'vacation_id': rec.id,
@@ -26,15 +26,10 @@ class VacationPutWizard(models.TransientModel):
elif report.vacation_date > employee_reports_map[emp].vacation_date:
employee_reports_map[emp] = report
for employee, report in employee_reports_map.items():
url = f'https://oa.thtzjt.com/webh5/#/vacation?id={report.id}'
we_id = employee.wecom_userid
if we_id:
self.sudo().env["wecom.apps"].sync_send_message_textcard(
category='default',
user_id=we_id,
title="考勤确认",
description=f'{employee.name} 请确认你的考勤:',
url=url,
btntxt="详细信息"
)
# for employee, report in employee_reports_map.items():
# we_id = employee.wecom_userid
# message = f"你{self.select_year}年{self.select_time}月的考勤确认单已经生成,请到手机端确认",
# if we_id:
# self.sudo().env["wecom.apps"].sync_send_message(category='att', user_id=we_id, message=message,)
# self.sudo().env["wecom.apps"].sync_send_message(category='att', user_id="18562027762", message=message,)
# self.write({'confirm_status': 'un_confirm'})
+40 -25
View File
@@ -876,10 +876,15 @@ class YuthonHrEmployee(models.Model):
def update_parental_leave(self):
today = datetime.now().date()
active_contracts = self.env['hr.contract'].search([
('employee_id.name','=', '和博延'),
('state', '=', 'open'),
('contract_type_id.name', 'ilike', '正式合同'),
('employee_id', '!=', False)
])
allocate_config = self.env['yuthon.parenting.allocate'].search([], limit=1)
valid_limit = allocate_config.valid_limit # 截至年龄(如3)
cycle_years = allocate_config.cycle_years # 周期年数(如1)
distribute = allocate_config.distribute #
if not active_contracts:
return
employees = active_contracts.mapped('employee_id')
@@ -905,50 +910,60 @@ class YuthonHrEmployee(models.Model):
except (ValueError, IndexError):
continue
age_delta = today - birth_date
if age_delta > timedelta(days=3 * 365):
valid_end_date = birth_date + relativedelta(years=valid_limit)
if today > valid_end_date:
continue
cycle1_end = birth_date + relativedelta(years=1) # 第1年到期日
cycle2_end = birth_date + relativedelta(years=2) # 第2年到期日
cycle3_end = birth_date + relativedelta(years=3) # 第3年到期日(3岁生日)
cycle_list = []
current_cycle_start = birth_date
total_cycles = int(valid_limit / cycle_years)
if today <= cycle1_end:
date_from = birth_date
date_to = cycle1_end - timedelta(days=1)
elif today <= cycle2_end:
date_from = cycle1_end
date_to = cycle2_end - timedelta(days=1)
else:
date_from = cycle2_end
date_to = cycle3_end - timedelta(days=1)
for i in range(1, total_cycles + 1):
current_cycle_end = current_cycle_start + relativedelta(years=cycle_years)
cycle_list.append({
'cycle_num': i,
'start': current_cycle_start,
'end': current_cycle_end
})
current_cycle_start = current_cycle_end
date_from = birth_date
date_to = valid_end_date - timedelta(days=1)
for cycle in cycle_list:
if today <= cycle['end']:
date_from = cycle['start']
date_to = cycle['end'] - timedelta(days=1)
break
total_days = distribute
if total_days <= 0:
continue
total_days = (date_to - date_from).days + 1
holiday_status_id = self.env['hr.leave.type'].search([('name', '=', '育儿假')], limit=1)
# 更新报表
other_list = []
parenting_line_ids = []
reports_id = self.env['yuthon.vacation.reports'].search([
('employee_id', '=', employee.id),
('vacation_date', '=', fields.Date.today().replace(day=1))
], limit=1) #
if reports_id:
existing_line = reports_id.other_fee_ids.search([
('holiday_type', '=', holiday_status_id.id),
existing_line = reports_id.parenting_line_ids.search([
('vacation_id', '=', reports_id.id),
('employee_id', '=', employee.id),
('update_date', '=', date_from),
('update_type', '=', 'add')
('end_date', '=', date_to),
('text','=', '育儿假分配')
], limit=1)
if not existing_line:
other_list.append([0, 0, {
parenting_line_ids.append([0, 0, {
'vacation_id': reports_id.id,
'holiday_type': holiday_status_id.id,
'employee_id': employee.id,
'update_date': date_from,
'update_type': 'add',
'end_date': date_to,
'lines': total_days,
'text': '育儿假'
'text': '育儿假分配'
}])
if other_list:
reports_id.write({'other_fee_ids': other_list})
if parenting_line_ids :
reports_id.write({'parenting_line_ids': parenting_line_ids})
# 6. 检查是否已存在相同分配记录,避免重复
existing_allocation = self.env['hr.leave.allocation'].search([
@@ -71,8 +71,8 @@ class YuthonOnboardApproval(models.Model):
representatives = fields.Char(related='party_id.representatives', string='法定代表人或委托代理人')
economy_type = fields.Char(related='party_id.economy_type', string='经济类型')
address = fields.Text(related='party_id.address', string='通讯地址')
phone = fields.Char(related='information_form_id.phone', string='联系电话')
card = fields.Char(related='information_form_id.id_card', string='身份证号码')
phone = fields.Char(string='联系电话', required=True)
card = fields.Char(string='身份证号码', required=True)
salary_group_id = fields.Many2one(
"yuthon.salary.group", string="工资单分组", store=True, index=True
)
@@ -1,3 +1,5 @@
from email.policy import default
from odoo import models, fields, api
from odoo.exceptions import UserError
from datetime import datetime, time, timedelta, date
@@ -10,7 +12,7 @@ class YuthonReassignmentApproval(models.Model):
name = fields.Char(string="标题")
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
employee_id = fields.Many2one('hr.employee', string="员工姓名")
employee_id = fields.Many2one('hr.employee', string="员工姓名", default=lambda self: self.env.user.employee_id.id)
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
company_id = fields.Many2one(related='users_id.employee_id.company_id', string="公司")
code = fields.Char(string="编号",
@@ -55,6 +57,18 @@ class YuthonReassignmentApproval(models.Model):
change_place_of_work = fields.Char(string="工作地点")
handing_information_ids = fields.One2many('yuthon.over.infor.detail.lines','infor_id')
@api.onchange('employee_id')
def _onchange_employee_id(self):
if self.employee_id:
self.phone = self.employee_id.mobile_phone
self.job_id = self.employee_id.job_id.id
self.structure_id = self.employee_id.contract_id.structure_type_id.id
self.onboarding_date = self.employee_id.entry_date
self.end_of_contract = self.employee_id.entry_date
self.parent_id = self.employee_id.parent_id.id
self.version = self.employee_id.contract_id.version
@api.onchange('is_issues')
def _onchange_is_issues(self):
if self.is_issues:
@@ -80,7 +80,7 @@
<field name="is_office"/>
</group>
<group>
<field name="department_id1" domain = "[('company_id', '=', company_id)] if is_this_company else []" options="{'no_create': True}"/>
<field name="department_id1" domain = "[('company_id', '=', company_id)] if is_company else []" options="{'no_create': True}"/>
<field name="contract_type" invisible="employment_form == 'formal' or not employment_form"/>
<field name="contract_type1" invisible="1"/>
<field name="salary_group_id"/>
@@ -35,7 +35,6 @@ class YuthonFileProcessing(models.Model):
string="抄送单位"
)
department_ids = fields.Many2many('hr.department', string='部门范围')
employee_ids = fields.Many2many('hr.employee', string='人员范围')
users_role_ids = fields.Many2many('soong.user.role', string='角色范围')
servings_number = fields.Integer(string="份数")
@@ -65,7 +64,7 @@ class YuthonFileProcessing(models.Model):
red_suit = fields.Char(string="套红")
official_documents_ids = fields.Many2many('ir.attachment', string="附件")
completion_time = fields.Datetime(string="办结时间")
is_supervising = fields.Boolean(string="是否督办")
deadline = fields.Datetime(string="办理期限")
done_date = fields.Date(string="完成时间")
@@ -74,6 +73,18 @@ class YuthonFileProcessing(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="状态")
employee_ids1 = fields.Many2many(
'hr.employee',
'yuthon_file_processing_employee1_rel',
'file_id', 'employee_id',
string="经办人"
)
employee_ids = fields.Many2many(
'hr.employee',
'yuthon_file_processing_employee_rel',
'file_id', 'employee_id',
string='人员范围'
)
def _get_default_name_title(self):
return self._description if self._description else self._name
@@ -88,7 +99,7 @@ class YuthonFileProcessing(models.Model):
default=lambda self: [(6, 0, [self.env.user.id])]
)
users_ids = fields.Many2many('res.users',
string="当前经办人",
string="用户",
relation='yuthon_file_processing_users_rel',
column1='processing_id',
column2='compute_user_id',
@@ -138,21 +149,34 @@ class YuthonFileProcessing(models.Model):
else:
return [("users_ids", "in", [current_user_id])]
def get_no_read_count(self):
domain = [
('employee_ids1', 'in', self.env.user.employee_id.id),
]
return self.search_count(domain)
@api.depends('code')
def _compute_workflow(self):
for record in self:
record.users_ids = False
record.approve_state = False
record.soong_state = False
record.employee_ids1 = False
workflow = self.env['soong.workflow.record'].sudo().search(
[('code', '=', record.code)],
limit=1
)
if workflow:
record.users_ids = workflow.employee_ids.mapped('user_id')
record.employee_ids1 = workflow.employee_ids.ids
record.users_ids = workflow.users_ids.ids
record.approve_state = workflow.approve_state
record.soong_state = workflow.soong_state
if record.log_ids:
record.completion_time = record.log_ids[-1].lase_click_date
else:
record.completion_time = False
@api.onchange('is_cold')
def onchange_is_cold(self):
if self.is_cold:
@@ -28,6 +28,9 @@ class YuthonSubEnterprises(models.Model):
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
work_end = fields.Boolean(string="结束")
employee_ids = fields.Many2many('hr.employee', string="经办人")
completion_time = fields.Datetime(string="办结时间")
def _get_default_name_title(self):
return self._description if self._description else self._name
@@ -41,7 +44,7 @@ class YuthonSubEnterprises(models.Model):
default=lambda self: [(6, 0, [self.env.user.id])]
)
users_ids = fields.Many2many('res.users',
string="当前经办人",
string="用户",
relation='yuthon_sub_enterprises_users_rel',
column1='enterprise_id',
column2='compute_user_id',
@@ -84,21 +87,35 @@ class YuthonSubEnterprises(models.Model):
else:
return [("users_ids", "in", [current_user_id])]
def get_no_read_count(self):
domain = [
('employee_ids', 'in', self.env.user.employee_id.id),
]
return self.search_count(domain)
@api.depends('code')
def _compute_workflow(self):
for record in self:
record.users_ids = False
record.approve_state = False
record.soong_state = False
record.employee_ids = False
workflow = self.env['soong.workflow.record'].sudo().search(
[('code', '=', record.code)],
limit=1
)
if workflow:
record.users_ids = workflow.employee_ids.mapped('user_id')
record.employee_ids = workflow.employee_ids.ids
record.users_ids = workflow.users_ids.ids
record.approve_state = workflow.approve_state
record.soong_state = workflow.soong_state
if record.log_ids:
record.completion_time = record.log_ids[-1].lase_click_date
else:
record.completion_time = False
def compute_workflow(self):
enterprises_ids = self.env["yuthon.sub.enterprises"].browse(
self._context.get('active_ids', self._context.get('active_id')))
@@ -8,7 +8,9 @@
<field name="code"/>
<field name="name"/>
<field name="approve_state" widget="badge" decoration-danger="approve_state == 'end'" decoration-success="approve_state == 'pending'"/>
<field name="users_ids" widget="many2many_tags"/>
<field name="employee_ids1" widget="many2many_tags"/>
<field name="users_ids" widget="many2many_tags" column_invisible="1"/>
<field name="completion_time"/>
<field name="soong_state"/>
</tree>
</field>
@@ -7,9 +7,12 @@
<tree string="文件处理(子企业)">
<field name="code"/>
<field name="name"/>
<field name="approve_state" widget="badge" decoration-danger="approve_state == 'end'" decoration-success="approve_state == 'pending'"/>
<field name="users_ids" widget="many2many_tags"/>
<field name="soong_state"/>
<field name="approve_state" widget="badge" decoration-danger="approve_state == 'end'"
decoration-success="approve_state == 'pending'"/>
<field name="employee_ids" widget="many2many_tags"/>
<field name="users_ids" widget="many2many_tags" column_invisible="1"/>
<field name="completion_time"/>
<field name="soong_state"/>
</tree>
</field>
</record>
+1
View File
@@ -43,6 +43,7 @@
'wizard/temporary_payslip_wizard_views.xml',
'wizard/salary_import_wizard_views.xml',
'wizard/yuthon_payroll_wizard_views.xml',
'wizard/salary_active_wizard_views.xml',
'wizard/basic_pension_wizard_views.xml',
'wizard/payroll_labor_wizard_views.xml',
'wizard/payroll_retired_wizard_views.xml',
+23 -43
View File
@@ -71,59 +71,39 @@ class YuthonWillTask(http.Controller):
for record in records:
year = int(record.select_year)
month = int(record.select_time)
status = 'yes' if record.confirm_status == 'confirm' else 'no'
if year not in data.keys():
data[year] = {'total': 0}
if month not in data[year].keys():
data[year][month] = {'total': record.actual_paid_salary}
data[year][month] = {'total': record.actual_paid_salary, 'id': record.id, 'state': status}
data[year]['total'] += record.actual_paid_salary
return json.dumps({'data': data, 'code': 200, 'message': ''})
@http.route('/phone/salary/self/detail', type='http', auth="none", csrf=False, cors='*')
def phone_salary_self_detail(self, **kw):
users_id = int(kw.get('users_id'))
user = request.env['res.users'].sudo().browse(int(users_id))
employee_id = user.with_company(user.company_id.id).employee_id.id
year = int(kw.get('year'))
month = int(kw.get('month'))
records = request.env['hr.payslip'].sudo().search(
[('employee_id', '=', employee_id)])
detail = {}
total = 0
id = 0
for record in records:
tar_year = record.date_from.year
tar_month = record.date_from.month
status = record.state
id = record.id
if tar_year == year and tar_month == month:
for line in record.line_ids:
name = line.name
contract = line.category_id.name
amount = line.amount
if contract not in detail.keys():
detail[contract] = {'total': 0}
detail[contract][name] = amount
detail[contract]['total'] += amount
total += amount
data = {
'status': status,
'year': year,
'month': month,
'tatal': total,
'detail': detail,
'id': id
}
record = request.env['yuthon.salary.active'].sudo().search([('id', '=', int(kw.get('id')))])
data = {}
other_fields_list = ['ID', '员工', '公司', '部门', '司龄', '入职日期', '状态', 'Display Name', 'Created by', 'Created on', 'Last Updated by', 'Last Updated on']
if record:
# 找出所有字段的string和value
fields_info = record.fields_get()
record_data = record.read()[0]
for field_name, field_value in record_data.items():
if field_value in [0, 0.0, False] or field_value is None:
continue
if field_name in fields_info:
field_string = fields_info[field_name].get('string', field_name)
if field_string in other_fields_list:
continue
if isinstance(field_value, float):
# 使用格式化字符串保留两位小数
field_value = f"{field_value:.2f}"
data[field_string] = field_value
return json.dumps({'data': data, 'code': 200, 'message': ''})
@http.route('/phone/salary/self/status', type='http', auth="none", csrf=False, cors='*')
def phone_salary_self_status(self, **kw):
record_id = int(kw.get('record_id'))
state = kw.get('state')
record = request.env['hr.payslip'].sudo().browse(record_id)
if state == 'done':
record.state = 'done'
data = 'success'
else:
data = ''
return json.dumps({'data': data, 'code': 200, 'message': ''})
record = request.env['yuthon.salary.active'].sudo().search([('id', '=', int(kw.get('id')))])
record.write({'confirm_status': 'confirm'})
return json.dumps({'code': 200, 'message': 'OK'})
+36 -11
View File
@@ -44,6 +44,7 @@ class YuthonSalaryActive(models.Model):
balance_salary = fields.Float(string='2025年结余工资')
liquidation_salary_staff = fields.Float(string='2024年清算工资(职工)')
business_special_bonus = fields.Float(string='2025经营特别奖')
business_base = fields.Float(string='2025年基础年终奖')
# 扣发类字段
deduct_performance_bonus = fields.Float(string='扣发绩效奖金')
@@ -88,25 +89,49 @@ class YuthonSalaryActive(models.Model):
self.write({'confirm_status': 'confirm'})
def payslip_transmit(self):
self.sudo().env["wecom.apps"].sync_send_message(
category='att', user_id=self.employee_id.wecom_userid,
message=f"你{self.select_year}年{self.select_time}月的薪资条已经发放,请到手机端查看",
url="https://phone.thtzjt.com/phone/Salary/153/23"
self.sudo().env["wecom.apps"].sync_send_message_textcard(
category='salary', user_id=self.employee_id.wecom_userid,
url=url,title='工资条', description=f"{self.select_year}年{self.select_time}月的薪资条已经发放", btntxt = "查看详情"
)
self.sudo().env["wecom.apps"].sync_send_message(
category='att', user_id="18562027762",
message=f"你{self.select_year}年{self.select_time}月的薪资条已经发放,请到手机端查看",
self.sudo().env["wecom.apps"].sync_send_message_textcard(
category='salary', user_id='18562027762',
url=url, title='工资条', description=f"{self.select_year}年{self.select_time}月的薪资条已经发放",
btntxt="查看详情"
)
self.write({'confirm_status': 'un_confirm'})
def all_payslip_transmit(self):
salary_ids = self.env["yuthon.salary.active"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for rec in salary_ids:
rec.payslip_transmit()
def open_archive_record(self):
tree_id = self.env.ref("yuthon_salary.view_yuthon_salary_active_tree").id
self.ensure_one()
float_fields_with_value = []
for field_name, field in self._fields.items():
if field.type == 'float' and self[field_name] != 0 and self[field_name] is not False:
float_fields_with_value.append({
'field_name': field_name,
'field_string': field.string,
'field_value': self[field_name]
})
return {
'name': '工资条',
'type': 'ir.actions.act_window',
'res_model': 'yuthon.salary.active',
'views': [[tree_id, 'tree']],
'view_mode': 'tree',
'domain': [('employee_id', '=', self.employee_id.id)],
'res_model': 'salary.active.wizard',
'view_mode': 'form',
'target': 'new',
'context': {
'default_actual_wages': self.actual_paid_salary,
'default_select_year': self.select_year,
'default_select_time': self.select_time,
'default_active_line': [(0, 0, {
'name': item['field_string'],
'amount': item['field_value']
}) for item in float_fields_with_value]
}
}
def _get_default_month(self):
+4 -1
View File
@@ -45,4 +45,7 @@ access_party_send_wizard,access_party_send_wizard,model_party_send_wizard,base.g
access_yuthon_meal_expenses,access_yuthon_meal_expenses,model_yuthon_meal_expenses,base.group_user,1,1,1,1
access_party_meal_wizard,access_party_meal_wizard,model_party_meal_wizard,base.group_user,1,1,1,1
access_salary_meal_wizard,access_salary_meal_wizard,model_salary_meal_wizard,base.group_user,1,1,1,1
access_yuthon_salary_active,access_yuthon_salary_active,model_yuthon_salary_active,base.group_user,1,1,1,1
access_yuthon_salary_active,access_yuthon_salary_active,model_yuthon_salary_active,base.group_user,1,1,1,1
access_salary_active_wizard,access__salary_active_wizard,model_salary_active_wizard,base.group_user,1,1,1,1
access_salary_active_line,access_salary_active_line,model_salary_active_line,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
45 access_salary_active_line access_salary_active_line model_salary_active_line base.group_user 1 1 1 1
46
47
48
49
50
51
@@ -4,9 +4,13 @@
<field name="name">yuthon.salary.active.tree</field>
<field name="model">yuthon.salary.active</field>
<field name="arch" type="xml">
<tree string="工资单归档" create="0" edit="0" delete="0">
<tree string="工资单归档" create="1" edit="0" delete="1">
<header>
<button name="all_payslip_transmit" type="object" string="批量发送" dclass="oe_highlight"/>
</header>
<!-- 核心关联字段:员工 -->
<button type="object" name="payslip_transmit" string="发送" class="oe_highlight"/>
<field name="confirm_status"/>
<field name="employee_id" string="员工"/>
<field name="department_id" column_invisible="1"/>
<field name="company_id" column_invisible="1"/>
@@ -18,7 +22,7 @@
<!-- 基础薪资字段 -->
<field name="basic_salary" string="基本工资"/>
<field name="rank_salary" string="职级工资"/>
<field name="pre_performance_bonus" string="预发绩效奖金"/>
<field name="pre_performance_bonus" string="月绩效"/>
<field name="post_salary" string="岗位工资"/>
<field name="communication_subsidy" string="通讯补贴"/>
<field name="seniority_wage" string="工龄工资"/>
@@ -31,6 +35,7 @@
<field name="balance_salary" string="2025年结余工资"/>
<field name="liquidation_salary_staff" string="2024年清算工资(职工)"/>
<field name="business_special_bonus" string="2025经营特别奖"/>
<field name="business_base" string="2025年基础年终奖"/>
<!-- 扣发类字段 -->
<field name="deduct_performance_bonus" string="扣发绩效奖金"/>
@@ -65,7 +70,7 @@
<field name="meal_allowance" string="误餐费"/>
<field name="reimbursed_medical_exam_fee" string="已报销体检费"/>
<field name="remaining_medical_exam_fee" string="剩余体检费"/>
<field name="confirm_status"/>
</tree>
</field>
</record>
@@ -87,7 +92,7 @@
<field name="model">yuthon.salary.active</field>
<field name="arch" type="xml">
<tree string="我的薪资" create="false" delete="false" edit="false">
<button name="salary_confirm" string="确认" type="object" class="oe_highlight"/>
<button name="salary_confirm" string="确认" type="object" class="oe_highlight" invisible="confirm_status == 'confirm'"/>
<button name="open_archive_record" string="详情" type="object" class="oe_highlight"/>
<field name="select_year"/>
<field name="select_time"/>
@@ -98,6 +103,7 @@
<field name="enterprise_annuity" string="年金"/>
<field name="trade_union_dues" string="工会费"/>
<field name="meal_allowance"/>
<field name="confirm_status" column_invisible="1"/>
</tree>
</field>
</record>
+2 -1
View File
@@ -17,4 +17,5 @@ from . import salary_party_wizard
from . import salary_import_wizard
from . import party_send_wizard
from . import party_meal_wizard
from . import salary_meal_wizard
from . import salary_meal_wizard
from . import salary_active_wizard
@@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
from dateutil.relativedelta import relativedelta
from odoo import models, fields, api, _, SUPERUSER_ID
from odoo.exceptions import ValidationError, UserError
from odoo.exceptions import ValidationError
import calendar
from pypinyin import pinyin, Style
import math
import xlrd
import base64
import datetime
from datetime import datetime, timedelta
class SalaryActiveWizard(models.TransientModel):
_name = 'salary.active.wizard'
_description = '工资条查询'
active_line = fields.One2many('salary.active.line', 'active_id', string='明细')
select_time = fields.Selection([('1', '一月'), ('2', '二月'), ('3', '三月'), ('4', '四月'),
('5', '五月'), ('6', '六月'), ('7', '七月'), ('8', '八月'),
('9', '九月'), ('10', '十月'), ('11', '十一月'),
('12', '十二月')], string='月份',
default=lambda self: self._get_default_month())
select_year = fields.Selection(selection=[(str(i), str(i)) for i in range(2024, 2040)], string='年份')
select_name = fields.Char(compute='_get_default_name')
actual_wages = fields.Float(string='实发工资')
@api.depends('select_year', 'select_time')
def _get_default_name(self):
for rec in self:
rec.select_name = rec.select_year + '年' + rec.select_time + '月'
class SalaryActiveLine(models.TransientModel):
_name = 'salary.active.line'
_description = '明细'
sequence = fields.Char(string='序号', store=True)
active_id = fields.Many2one('salary.active.wizard', string='工资条')
name = fields.Char(string='工资条')
amount = fields.Float(string='金额')
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="salary_active_wizard_form" model="ir.ui.view">
<field name="name">工资条查询</field>
<field name="model">salary.active.wizard</field>
<field name="arch" type="xml">
<form>
<sheet>
<field name="select_year" invisible="1"/>
<field name="select_time" invisible="1"/>
<field name="select_name" invisible="1"/>
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
<field name="select_name" readonly="1" style="font-weight: bold; font-size: 18px;"/>
<div style="text-align: right;">
<span style="font-size: 14px; color: #666; margin-right: 8px;"/>
<h1 style="display: inline; font-weight: bold; font-size: 20px; margin: 0;">
<field name="actual_wages" readonly="1"/>
</h1>
</div>
</div>
<field name="active_line" string=" ">
<tree editable="bottom" create="0" edit="0" delete="0">
<field name="sequence" widget="handle"/>
<field name="active_id" column_invisible="1"/>
<field name="name"/>
<field name="amount" readonly="1"/>
</tree>
</field>
</sheet>
</form>
</field>
</record>
</odoo>
+1 -2
View File
@@ -26,8 +26,7 @@
'views/auth_oauth_template.xml',
'views/left_login_template.xml',
'views/right_login_template.xml',
'views/right_login_template.xml',
# 'views/inherit_board_views.xml',
'views/inherit_board_views.xml',
]
}
+3 -3
View File
@@ -67,9 +67,9 @@
<a t-if="signup_enabled" t-attf-href="/web/signup?{{ keep_query() }}">还没有账户?</a>
<a t-if="reset_password_enabled" t-attf-href="/web/reset_password?{{ keep_query() }}">重置密码</a>
</div>
<!-- <div class="o_login_auth">-->
<!-- <t t-call="yuthon_tianhe.yuthon_providers"/>-->
<!-- </div>-->
<div class="o_login_auth">
<t t-call="yuthon_tianhe.yuthon_providers"/>
</div>
</div>
<input type="hidden" name="redirect" t-att-value="redirect"/>
+3 -3
View File
@@ -68,9 +68,9 @@
<a t-if="signup_enabled" t-attf-href="/web/signup?{{ keep_query() }}">还没有账户?</a>
<a t-if="reset_password_enabled" t-attf-href="/web/reset_password?{{ keep_query() }}">重置密码</a>
</div>
<!-- <div class="o_login_auth">-->
<!-- <t t-call="yuthon_tianhe.yuthon_providers"/>-->
<!-- </div>-->
<div class="o_login_auth">
<t t-call="yuthon_tianhe.yuthon_providers"/>
</div>
</div>
<input type="hidden" name="redirect" t-att-value="redirect"/>
+2 -2
View File
@@ -5,7 +5,7 @@
<field name="name">Wechat Corp</field>
<field name="body">企业微信扫码登录</field>
<field name="client_id">corpid agentid corpsecret</field>
<field name="css_class">fa fa-fw fa-sign-in text-primary wecom_qr_login</field>
<field name="css_class">fa fa-fw fa-sign-in text-primary</field>
<field name="auth_endpoint">https://open.work.weixin.qq.com/wwopen/sso/qrConnect</field>
<field name="validation_endpoint">https://qyapi.weixin.qq.com/cgi-bin/gettoken</field>
<field name="data_endpoint">https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo</field>
@@ -15,7 +15,7 @@
<field name="name">Wechat Corp2</field>
<field name="body">企业微信直接登录</field>
<field name="client_id">corpid agentid corpsecret</field>
<field name="css_class">fa fa-fw fa-sign-in text-primary wecom_quick_login</field>
<field name="css_class">fa fa-fw fa-sign-in text-primary</field>
<field name="auth_endpoint">https://open.weixin.qq.com/connect/oauth2/authorize</field>
<field name="validation_endpoint">https://qyapi.weixin.qq.com/cgi-bin/gettoken</field>
<field name="data_endpoint">https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo</field>
+1 -1
View File
@@ -160,7 +160,7 @@ class WeComApps(models.Model):
"btntxt": btntxt
},
}
elif category == 'task':
elif category in ['task', 'att_ok', 'salary']:
data = {
'touser': user_id,
'msgtype': 'textcard',
@@ -29,6 +29,7 @@ class WecomAppsConfig(models.Model):
('att', '出勤类型'),
('task', '日程类型'),
('att_ok', '考勤确认类型'),
('salary', '薪资消息通知'),
], default="default")
wecom_apps_id = fields.Many2one("wecom.apps", string="企业微信的应用")
+1 -3
View File
@@ -73,12 +73,10 @@ class YuthonWillTask(http.Controller):
@http.route('/will/task/list', methods=['POST'], type='http', auth='public', csrf=False)
def will_task_list(self, **kwargs):
employee_id = request.env['hr.employee'].search([('user_id', '=', int(kwargs.get('users_id')))])
start = kwargs.get('start')
request_hour_selection = request.env['yuthon.will.task'].sudo().fields_get(allfields=['request_hour_from'])['request_hour_from']['selection']
result_list = []
# task_ids = request.env['yuthon.will.task'].sudo().search([], offset=start, limit=20)
task_ids = request.env['yuthon.will.task'].sudo().search(['|', ('employee_ids', 'in', employee_id.id), ('employee_id.id', '=', employee_id.id)], offset=start, limit=20)
task_ids = request.env['yuthon.will.task'].sudo().search([('users_ids', 'in', [int(kwargs.get('users_id'))])], offset=start, limit=20)
for task in task_ids:
weekday_str = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"][task.start_date.weekday()]
result = {
+9 -4
View File
@@ -166,17 +166,17 @@
sequence="14"/>
<menuitem id="menu_yuthon_overtime_report_board_work_brand"
name="加班情况"
name="加班明细"
parent="hr_attendance_root_board_menu"
action="yuthon_hr_attendance.action_overtime_approval_report"
sequence="15"/>
<menuitem id="menu_yuthon_holiday_statement_board"
name="请假情况"
name="请假明细"
parent="hr_attendance_root_board_menu"
action="yuthon_hr_attendance.view_yuthon_holiday_statement_action"
sequence="16"/>
<menuitem id="menu_yuthon_meal_case_board"
name="误餐情况"
name="误餐明细"
parent="hr_attendance_root_board_menu"
action="yuthon_hr_attendance.view_yuthon_vacation_meal_action"
sequence="17"/>
@@ -311,6 +311,11 @@
parent="attendance_resources_setting_root_board"
action="hr_holidays.hr_leave_allocation_action_approve_department"
sequence="20"/>
<menuitem id="yuthon_parenting_allocate_board"
name="育儿假规则"
parent="attendance_resources_setting_root_board"
action="yuthon_hr_attendance.yuthon_parenting_allocate_action"
sequence="21"/>
<menuitem id="holiday_set_vacation_board"
name="公共假期"
parent="attendance_resources_setting_root_board"
@@ -735,7 +740,7 @@
<menuitem id="yuthon_overtime_active_menu"
parent="yuthon_vacation_active_menu"
name="加班归档"
action="yuthon_hr_attendance.action_overtime_approval_active_report"
action="yuthon_hr_attendance.view_vacation_overtime_active_action"
sequence="20"
/>
<menuitem id="yuthon_menu_active_menu"