@@ -552,15 +552,16 @@ class HolidaysRequestBatch(models.Model):
|
||||
'is_void': False,
|
||||
'text': f"请假审批"
|
||||
})
|
||||
if self.users_id.employee_ids.company_id.name == '集团本部':
|
||||
overtime_records = self.env['vacation.over.line'].search([
|
||||
('start_time', '>=', datetime(2025, 12, 1)),
|
||||
domain = [
|
||||
('employee_id', '=', self.users_id.employee_ids.id),
|
||||
('start_time', '>=', datetime(2025, 12, 1)),
|
||||
('is_visible', '=', False),
|
||||
('is_void', '=', False),
|
||||
('text', '!=', '上月继承额度'),
|
||||
], order='start_time ASC')
|
||||
|
||||
]
|
||||
if self.users_id.employee_ids.company_id.name == '集团本部':
|
||||
domain.append(('start_time', '>=', datetime(2025, 12, 1)),)
|
||||
overtime_records = self.env['vacation.over.line'].search(domain, order='start_time ASC')
|
||||
remaining_deduct = hours
|
||||
for record in overtime_records:
|
||||
if remaining_deduct <= 0:
|
||||
@@ -856,24 +857,57 @@ class HolidaysRequestBatch(models.Model):
|
||||
('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"),
|
||||
("年假", "previous_year", "year_distribution"),
|
||||
("补休", "previous_year1", "this_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 name == "年假" and prev_field and curr_field:
|
||||
used_this_year = getattr(reports_id, 'used_this_year', 0.0) # 本年已用
|
||||
prev_value = getattr(reports_id, prev_field, 0.0) # 上年结余(previous_year)
|
||||
curr_value = getattr(reports_id, curr_field, 0.0) # 本年额度(year_distribution)
|
||||
valid_date = getattr(reports_id, 'valid_date', None) # previous_year的有效期
|
||||
|
||||
is_prev_valid = True
|
||||
if valid_date:
|
||||
is_prev_valid = date.today() <= valid_date
|
||||
|
||||
remain_used = used_this_year
|
||||
final_prev = prev_value
|
||||
final_curr = curr_value
|
||||
|
||||
if is_prev_valid and final_prev > 0 and remain_used > 0:
|
||||
# 扣减previous_year:取剩余已用和previous_year的较小值
|
||||
deduct_prev = min(remain_used, final_prev)
|
||||
final_prev -= deduct_prev
|
||||
remain_used -= deduct_prev
|
||||
|
||||
# 4. 剩余已用扣减year_distribution
|
||||
if remain_used > 0 and final_curr > 0:
|
||||
deduct_curr = min(remain_used, final_curr)
|
||||
final_curr -= deduct_curr
|
||||
remain_used -= deduct_curr
|
||||
|
||||
# 5. 根据扣减后的值判断是否显示
|
||||
if final_prev > 0:
|
||||
parts.append(f"上年结余{final_prev:.3f}天")
|
||||
if final_curr > 0:
|
||||
parts.append(f"本年剩余{final_curr:.3f}天")
|
||||
else:
|
||||
if prev_field:
|
||||
prev_value = getattr(reports_id, prev_field, 0.0)
|
||||
if prev_value > 0:
|
||||
parts.append(f"上年结余{prev_value:.3f}天")
|
||||
curr_value = getattr(reports_id, curr_field, 0.0)
|
||||
if curr_value > 0:
|
||||
parts.append(f"本年剩余{curr_value:.3f}天")
|
||||
|
||||
if parts:
|
||||
result_parts.append(f"{name}:{','.join(parts)}")
|
||||
|
||||
|
||||
@@ -23,7 +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="已补卡次数")
|
||||
number_cards_replaced = fields.Integer(string="本月补卡次数", compute='_compute_number_cards_replaced')
|
||||
attendance = fields.Char(string="补卡日期")
|
||||
is_attendance = fields.Boolean(string="字段隐藏")
|
||||
replacement_time = fields.Selection([('work', '上班卡'), ('quitting', '下班卡'), ('all', '全天卡')], string="补卡", store=True)
|
||||
@@ -38,6 +38,27 @@ class CardApprovals(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.depends('users_id')
|
||||
def _compute_number_cards_replaced(self):
|
||||
first_day = fields.Date.today().replace(day=1)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', self.users_id.employee_ids.id),
|
||||
('vacation_date', '=', first_day),
|
||||
], limit=1)
|
||||
if vacation_report:
|
||||
self.number_cards_replaced = vacation_report.number_card
|
||||
|
||||
@api.constrains("users_id")
|
||||
def _check_user(self):
|
||||
first_day = fields.Date.today().replace(day=1)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', self.users_id.employee_ids.id),
|
||||
('vacation_date', '=', first_day),
|
||||
], limit=1)
|
||||
if vacation_report:
|
||||
if vacation_report.number_card >= 3:
|
||||
raise UserError("该员工当月已补卡超过3次,请勿重复补卡!")
|
||||
|
||||
@api.onchange('attendance_id')
|
||||
def onchange_replacement_time(self):
|
||||
for rep in self:
|
||||
@@ -119,6 +140,14 @@ class CardApprovals(models.Model):
|
||||
'workflow_id': workflow_id,
|
||||
})
|
||||
|
||||
first_day = fields.Date.today().replace(day=1)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', self.users_id.employee_ids.id),
|
||||
('vacation_date', '=', first_day),
|
||||
], limit=1)
|
||||
if vacation_report:
|
||||
vacation_report.number_card += 1
|
||||
|
||||
@api.onchange('is_issues')
|
||||
def _onchange_is_issues(self):
|
||||
if self.is_issues:
|
||||
|
||||
@@ -33,7 +33,7 @@ class OvertimeApprovals(models.Model):
|
||||
documents_ids = fields.Many2many('ir.attachment', string="附件")
|
||||
overtime_methods = fields.Selection([('leave', '补休'), ('fee', '加班费结算')], string='加班补偿方式', default='leave')
|
||||
duration = fields.Float(string="结算时长", compute='_compute_duration', store=True)
|
||||
overtime_hours = fields.Float(string="本月加班时长", compute='_compute_duration')
|
||||
overtime_hours = fields.Float(string="本月加班时长", compute='_compute_overtime_hours')
|
||||
start_time = fields.Datetime(string="开始时间")
|
||||
attendance_id = fields.Many2one('hr.attendance', string="当天考勤")
|
||||
start_week = fields.Char(string="星期", compute='_compute_weekday')
|
||||
@@ -141,12 +141,30 @@ class OvertimeApprovals(models.Model):
|
||||
corrected_end_time = max_allowed_end_time - timedelta(hours=8)
|
||||
rec.end_time = corrected_end_time
|
||||
|
||||
@api.depends('users_id', 'duration')
|
||||
def _compute_overtime_hours(self):
|
||||
for rec in self:
|
||||
employee = rec.users_id.employee_ids
|
||||
# 一个月加班时长不能超过36小时
|
||||
first_day = fields.Date.today().replace(day=1)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', employee.id),
|
||||
('vacation_date', '=', first_day),
|
||||
], limit=1)
|
||||
|
||||
cop_leave = vacation_report.done_working_overtime * 8 if vacation_report else 0.0
|
||||
if cop_leave + rec.duration > 36 and not rec.is_thwg:
|
||||
rec.overtime_hours = 0.0
|
||||
message = f'本月已加班时长已超过 36 小时'
|
||||
raise ValidationError(message)
|
||||
else:
|
||||
rec.overtime_hours = cop_leave
|
||||
|
||||
@api.depends('start_time', 'end_time', 'attendance_id', 'rest_start_time', 'rest_end_time')
|
||||
def _compute_duration(self):
|
||||
for rec in self:
|
||||
max_hours = 99
|
||||
rec.duration = 0.0
|
||||
rec.overtime_hours = 0.0
|
||||
if not (rec.start_time and rec.end_time):
|
||||
continue
|
||||
|
||||
@@ -195,27 +213,6 @@ class OvertimeApprovals(models.Model):
|
||||
calculated_hours -= (rec.rest_end_time - rec.rest_start_time).total_seconds() / 3600
|
||||
rec.duration = min(calculated_hours, max_hours)
|
||||
|
||||
employee = rec.users_id.employee_id
|
||||
if not employee:
|
||||
rec.duration = calculated_hours
|
||||
continue
|
||||
|
||||
# 一个月加班时长不能超过36小时
|
||||
first_day = rec.start_time.date().replace(day=1)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', employee.id),
|
||||
('vacation_date', '=', first_day),
|
||||
], limit=1)
|
||||
|
||||
cop_leave = vacation_report.done_working_overtime * 8 if vacation_report else 0.0
|
||||
leave_hours = calculated_hours
|
||||
if cop_leave + leave_hours > 36 and not rec.is_thwg:
|
||||
rec.overtime_hours = 0.0
|
||||
message = f'本月已加班时长已超过 36 小时'
|
||||
raise ValidationError(message)
|
||||
else:
|
||||
rec.overtime_hours = cop_leave
|
||||
|
||||
|
||||
@api.depends('start_time', 'end_time')
|
||||
def _compute_weekday(self):
|
||||
|
||||
@@ -16,15 +16,16 @@ class YuthonVacationReports(models.Model):
|
||||
_order = "vacation_date desc"
|
||||
|
||||
employee_id = fields.Many2one('hr.employee', string='员工')
|
||||
number_card = fields.Integer(string='补卡次数')
|
||||
salary_group_id = fields.Many2one(related='employee_id.salary_group_id', string="工资单分组", store=True)
|
||||
department_id = fields.Many2one(related='employee_id.department_id', string="部门", store=True)
|
||||
open_start_time = fields.Date(related='employee_id.open_start_time',string="参加工作时间")
|
||||
company_old = fields.Char(related='employee_id.company_old', string="工作年限")
|
||||
previous_year = fields.Float(string="上年剩余", digits=(16, 3))
|
||||
previous_year = fields.Float(string="上年剩余", digits=(16, 3)) # 固定值
|
||||
valid_date = fields.Date(string="有效期至")
|
||||
year_distribution = fields.Float(string="本年发放", digits=(16, 3))
|
||||
used_this_year = fields.Float(string="本年已用", digits=(16, 3))
|
||||
remainder_year = fields.Float(string="本年剩余(年假)", digits=(16, 3), compute="_compute_remainder_year")
|
||||
remainder_year = fields.Float(string="剩余(年假)", digits=(16, 3), compute="_compute_remainder_year")
|
||||
last_holiday = fields.Float(string="上年公休日", digits=(16, 3))
|
||||
last_workday = fields.Float(string="上年工作日", digits=(16, 3))
|
||||
valid_date1 = fields.Date(string="有效期至")
|
||||
@@ -32,6 +33,7 @@ class YuthonVacationReports(models.Model):
|
||||
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))
|
||||
this_year1 = fields.Float(string="本年剩余(补休)", digits=(16, 3), compute="_compute_year_sum")
|
||||
used_this_year1 = fields.Float(string="本年已休", digits=(16, 3))
|
||||
remainder_year1 = fields.Float(string="剩余(补休)", digits=(16, 3), compute="_compute_year_sum")
|
||||
|
||||
@@ -255,14 +257,15 @@ class YuthonVacationReports(models.Model):
|
||||
@api.depends('year_distribution', 'used_this_year')
|
||||
def _compute_remainder_year(self):
|
||||
for record in self:
|
||||
record.remainder_year = record.year_distribution - record.used_this_year
|
||||
record.remainder_year = record.year_distribution + record.previous_year - 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.remainder_year1 = record.last_holiday + record.last_workday + record.year_holiday + record.year_workday - record.used_this_year1
|
||||
record.previous_year1 = record.last_holiday + record.last_workday
|
||||
record.this_year1 = record.year_holiday + record.year_workday
|
||||
|
||||
@api.constrains('employee_id', 'vacation_date')
|
||||
def _check_duplicate_monthly_record(self):
|
||||
@@ -359,8 +362,8 @@ class YuthonVacationReports(models.Model):
|
||||
total_leave_days = 0 # 请假工作流总天数(含小时折算)
|
||||
is_retired = rec.employee_id.user_state in ('leave', 'withdraw')
|
||||
if rec.employee_id and rec.vacation_date and not is_retired:
|
||||
year = rec.vacation_date.year
|
||||
month = rec.vacation_date.month
|
||||
year = (fields.Date.today() - relativedelta(months=1)).year
|
||||
month = (fields.Date.today() - relativedelta(months=1)).month
|
||||
month_start = date(year, month, 1)
|
||||
entry_date = rec.employee_id.entry_date
|
||||
days_in_month = calendar.monthrange(year, month)[1]
|
||||
@@ -1288,6 +1291,16 @@ class VacationLeaveLine(models.Model):
|
||||
if vals.get('update_type') == 'reduce' and vals.get('vacation_id'):
|
||||
vacation_main = self.env['yuthon.vacation.reports'].browse(vals['vacation_id'])
|
||||
deduct_amount = vals.get('update_lines', 0.0) / 8
|
||||
remain_deduct = deduct_amount
|
||||
|
||||
is_previous_valid = True
|
||||
if vacation_main.valid_date:
|
||||
is_previous_valid = date.today() <= vacation_main.valid_date
|
||||
|
||||
if is_previous_valid and vacation_main.previous_year > 0:
|
||||
deduct_previous = min(remain_deduct, vacation_main.previous_year)
|
||||
vacation_main.write({'previous_year': vacation_main.previous_year - deduct_previous})
|
||||
remain_deduct -= deduct_previous
|
||||
|
||||
if vacation_main:
|
||||
used_this_year_new = vacation_main.used_this_year + deduct_amount
|
||||
@@ -1350,7 +1363,6 @@ 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='是否作废')
|
||||
@@ -1458,13 +1470,12 @@ class VacationOverline(models.Model):
|
||||
rec._compute_employee_id()
|
||||
rec._compute_last_balance()
|
||||
|
||||
@api.depends('vacation_id')
|
||||
@api.depends('vacation_id', 'carry_forward_quantity')
|
||||
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
|
||||
rec.remaining_quantity = rec.public_holidays + rec.workday - rec.carry_forward_quantity
|
||||
else:
|
||||
rec.last_balance = 0
|
||||
|
||||
@@ -1528,18 +1539,47 @@ class VacationOverline(models.Model):
|
||||
|
||||
if vals.get('update_type') == 'reduce' and vals.get('vacation_id'):
|
||||
vacation_main = self.env['yuthon.vacation.reports'].browse(vals['vacation_id'])
|
||||
deduct_amount = vals.get('workday', 0.0) / 8 # 扣减额度
|
||||
current_vacation_date = vacation_main.vacation_date
|
||||
next_month_first_day = current_vacation_date + relativedelta(months=+1, day=1)
|
||||
deduct_workday = vals.get('workday', 0.0)
|
||||
deduct_public = vals.get('public_holidays', 0.0)
|
||||
deduct_workday_convert = deduct_workday / 8
|
||||
deduct_public_convert = deduct_public / 8
|
||||
deduct_total = deduct_workday_convert + deduct_public_convert
|
||||
if vacation_main:
|
||||
vacation_used_vals = {
|
||||
'used_this_year1': (vacation_main.used_this_year1 or 0.0) + deduct_total
|
||||
}
|
||||
vacation_main.write(vacation_used_vals)
|
||||
if not vacation_main or deduct_amount <= 0:
|
||||
return
|
||||
|
||||
# ========== 核心新增逻辑:优先级扣减规则 ==========
|
||||
# 1. 先判断上年数据是否有效(valid_date1 有效期内,无则视为无限期)
|
||||
is_last_valid = True
|
||||
if vacation_main.valid_date1:
|
||||
is_last_valid = date.today() <= vacation_main.valid_date1 # 仅有效期内的上年数据可扣减
|
||||
|
||||
# 2. 初始化待扣减剩余量
|
||||
remain_deduct = deduct_amount
|
||||
|
||||
# 3. 优先扣减上年工作日(last_holiday)
|
||||
if is_last_valid and vacation_main.last_workday > 0:
|
||||
deduct_workday = min(remain_deduct, vacation_main.last_workday)
|
||||
vacation_main.write({'last_workday': vacation_main.last_workday - deduct_workday})
|
||||
remain_deduct -= deduct_workday
|
||||
|
||||
# 4. 剩余扣减金额扣减公休日(last_holiday)
|
||||
if remain_deduct > 0 and is_last_valid and vacation_main.last_holiday > 0:
|
||||
deduct_holiday = min(remain_deduct, vacation_main.last_holiday)
|
||||
vacation_main.write({'last_holiday': vacation_main.last_holiday - deduct_holiday})
|
||||
remain_deduct -= deduct_holiday
|
||||
|
||||
# 5. 上年数据扣减完仍有剩余 → 扣减本年工作日(year_workday)
|
||||
if remain_deduct > 0 and vacation_main.year_workday > 0:
|
||||
deduct_year_workday = min(remain_deduct, vacation_main.year_workday)
|
||||
vacation_main.write({'year_workday': vacation_main.year_workday - deduct_year_workday})
|
||||
remain_deduct -= deduct_year_workday
|
||||
|
||||
# 6. 最后扣减本年公休日(year_holiday)
|
||||
if remain_deduct > 0 and vacation_main.year_holiday > 0:
|
||||
deduct_year_holiday = min(remain_deduct, vacation_main.year_holiday)
|
||||
vacation_main.write({'year_holiday': vacation_main.year_holiday - deduct_year_holiday})
|
||||
remain_deduct -= deduct_year_holiday
|
||||
|
||||
used_this_year_new = vacation_main.used_this_year1 + deduct_amount
|
||||
vacation_main.write({'used_this_year1': used_this_year_new})
|
||||
|
||||
is_cross_year = False
|
||||
# 计算下月1号并判断是否跨年
|
||||
@@ -1556,8 +1596,8 @@ class VacationOverline(models.Model):
|
||||
], limit=1)
|
||||
if next_month_vacation:
|
||||
next_month_deduct_vals = {
|
||||
'last_workday': next_month_vacation.last_workday - deduct_workday_convert,
|
||||
'last_holiday': next_month_vacation.last_holiday - deduct_public_convert,
|
||||
'last_workday': next_month_vacation.last_workday - deduct_amount,
|
||||
'last_holiday': next_month_vacation.last_holiday - deduct_amount,
|
||||
}
|
||||
next_month_vacation.write(next_month_deduct_vals)
|
||||
|
||||
|
||||
@@ -198,6 +198,9 @@
|
||||
<field name="remaining_parental_leave"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="number_card"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="年假">
|
||||
<field name="leave_ids" context="{'default_employee_id': employee_id}">
|
||||
@@ -616,24 +619,6 @@
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_yuthon_vacation_overtime_briefly_tree" model="ir.ui.view">
|
||||
<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" 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"/>
|
||||
<button name="open_record" type="object" string="详情" class="btn-primary"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_yuthon_vacation_overtime_tree" model="ir.ui.view">
|
||||
<field name="name">vacation.over.line.overtime.tree</field>
|
||||
<field name="model">vacation.over.line</field>
|
||||
@@ -645,7 +630,6 @@
|
||||
<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"/>
|
||||
|
||||
Reference in New Issue
Block a user