odex30_standard/hr_holidays_public/models/hr_holidays.py

2096 lines
140 KiB
Python

# -*- coding: utf-8 -*-
import math
from datetime import datetime
import datetime as dt
from odoo import SUPERUSER_ID, fields
from odoo import models, fields, api, _
from dateutil.relativedelta import relativedelta
from dateutil import relativedelta
from datetime import timedelta
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
from odoo.exceptions import AccessError, ValidationError, MissingError, UserError
import calendar
from collections import defaultdict
def daterange(start_date, end_date):
for n in range(int((end_date - start_date).days)):
yield start_date + timedelta(n)
class HRHolidays(models.Model):
_inherit = 'hr.holidays'
_order = "create_date desc"
replace_by = fields.Many2one(comodel_name='hr.employee', string="Replace By")
emp_id = fields.Integer(string="id")
employee_id = fields.Many2one('hr.employee', 'Employee', default=lambda item: item.get_user_id(), )
last_employee_contract = fields.Many2one(related='employee_id.contract_id', readonly=True)
employee_type = fields.Selection(related='employee_id.contract_id.emp_type', store=True, readonly=True)
issuing_clearance_form = fields.Selection(selection=[('yes', 'Yes'), ('no', 'No')], default='no')
issuing_deliver_custdy = fields.Selection(selection=[('yes', 'Yes'), ('no', 'No')], default='no')
start_date = fields.Date(string="Start Date", default=fields.Datetime.now())
end_date = fields.Date(string="End Date")
notes = fields.Text()
issuing_exit_return = fields.Selection(selection=[('yes', 'Yes'), ('no', 'No')], default='no')
check_allocation_view = fields.Selection(selection=[('allocation', 'Allocation'), ('balance', 'Balance')])
exit_return_duration = fields.Float(related='number_of_days_temp')
permission_request_for = fields.Selection(selection=[
('employee', 'For Employee Only'),
('family', 'For Family Only'),
('all', 'For Employee And Family Only')
])
issuing_ticket = fields.Selection(selection=[('yes', 'Yes'), ('no', 'No')], default='no')
# ticket_cash_request_type = fields.Selection(
# selection=[('request_ticket', _('Request Ticket')), ('cash_in_lieu', _('Cash In Lieu'))])
ticket_cash_request_type = fields.Many2one('hr.ticket.request.type')
ticket_cash_request_for = fields.Selection(selection=[
('employee', 'For Employee Only'),
('family', 'For Family Only'),
('all', 'For Employee And Family Only')
])
check_state = fields.Boolean('check', default=True)
check_related = fields.Boolean('Check Related', default=False)
leaves_taken = fields.Float(tracking=True)
remaining_leaves = fields.Float(tracking=False)
cron_run_date = fields.Date()
holiday_ids = fields.One2many(comodel_name='hr.inverse.holidays', inverse_name='holiday_id')
hiring_date = fields.Date(related='employee_id.first_hiring_date', store=True, readonly=True)
# check_boolean = fields.Boolean(default=True)
check_unlimit = fields.Boolean()
holiday_limit_check = fields.Boolean(store=True)
canceled_duration = fields.Float(readonly=True)
state = fields.Selection(selection_add=[
('approved', 'Wait Approval')
])
holiday_status_id = fields.Many2one('hr.holidays.status', domain=[('id', 'in', [])])
number_of_days_temp = fields.Float(
'Allocation', copy=False, readonly=False,
help='Number of days of the leave request according to your working schedule.')
# TODO: Add readonly logic in XML view: readonly="state not in ('draft', 'confirm')"
return_from_leave = fields.Boolean(readonly=True)
current_date_plus_years = fields.Datetime()
official_holiday_days = fields.Float('Included Official Holidays', copy=False, readonly=False, default=0,
help='Number of days of official holiday during this period.')
reconcile_leave = fields.Boolean()
date_on = fields.Boolean()
leave_balance = fields.Float('Current Balance', copy=False, compute='_compute_leave_balance', store=True,
readonly=True)
delegate_acc = fields.Boolean('Delegate Permissions', default=False)
delegated_group_ids = fields.Many2many('res.groups', string="Delegated Access Groups", )
delegated_company_ids = fields.Many2many('res.company', string="Delegated Companies", )
delegated_department_ids = fields.Many2many('hr.department', string="Delegated Departments")
leave_balance_date = fields.Float(store=True, readonly=True, compute='_leave_balance_date',
help='The Balance Remains until the end date of the current Holiday Request')
attach_ids = fields.One2many('ir.attachment', 'att_holiday_ids')
company_id = fields.Many2one('res.company', default=lambda self: self.env.company)
emp_company_id = fields.Many2one(related='employee_id.company_id')
emp_number = fields.Char(related='employee_id.emp_no',store=True)
request_done = fields.Boolean(default=False,readonly=True)
is_branch = fields.Many2one(related='department_id.branch_name', store=True, readonly=True)
to_date = fields.Boolean(string='Today',compute='_leave_today_run', store=True)
def _compute_number_of_days(self):
res = super(HRHolidays, self)._compute_number_of_days()
self._leave_today_run()
@api.depends('date_from','date_to', 'create_date','state')
def _leave_today_run(self):
today = datetime.now().date()
for item in self:
if item.date_to and item.date_from:
if item.date_from.date() <= today <= item.date_to.date():
item.to_date = True
else:
item.to_date = False
## to remove followers ##
def _remove_followers_holiday(self):
for rec in self:
followers = self.env['mail.followers'].search(
[('res_id', '=', rec.id),('res_model','=','hr.holidays')])
followers.sudo().unlink()
def _check_state_access_right(self, vals):
if vals.get('state') and vals['state'] not in ['draft', 'confirm', 'cancel'] and not \
(self.env.user and self.env.user.has_group(
'hr_holidays_community.group_hr_holidays_user,hr.group_hr_manager,hr_base.group_general_manager')):
return False
return True
def check_annual_balance(self):
for rec in self:
if rec.type == "remove":
annual = rec.env['hr.holidays.status'].search([('leave_type', '=', 'annual')])
if rec.employee_id and annual:
balance = self.env['hr.holidays'].search([('employee_id', '=', rec.employee_id.id), ('type', '=', 'add'),
# ('holiday_status_id', '=', annual.id),
('holiday_status_id.leave_type', '=', 'annual'),
('check_allocation_view', '=', 'balance')
], order='id desc', limit=1).remaining_leaves or 0.0
if balance >= 1:
raise ValidationError(_("You Can not order this leave and you have annual Leave Balance"))
def check_balance_per_period(self, rec):
old_holiday_id = self.env['hr.holidays'].search([('employee_id', '=', rec.employee_id.id), ('type', '=', 'remove'),
('holiday_status_id', '=', rec.holiday_status_id.id),
('state', 'not in', ['cancel', 'refuse']),
], limit=1, order="date_from desc")
if old_holiday_id:
old_leave_date_from = datetime.strptime(str(old_holiday_id.date_from),
DEFAULT_SERVER_DATETIME_FORMAT)
date_from = datetime.strptime(str(rec.date_from),
DEFAULT_SERVER_DATETIME_FORMAT)
if old_leave_date_from > date_from:
date_from = datetime.strptime(str(rec.date_from),
DEFAULT_SERVER_DATETIME_FORMAT)
date_of_period = date_from + relativedelta.relativedelta(months=rec.holiday_status_id.period_unpaid_leave)
holiday_ids = self.env['hr.holidays'].search([('employee_id', '=', rec.employee_id.id), ('type', '=', 'remove'),
('holiday_status_id', '=', rec.holiday_status_id.id),
('state', 'not in', ['cancel', 'refuse']),
('date_from', '>=', str(date_from)),
('date_from', '<=', str(date_of_period))])
number_days_of_leaves = sum(holiday_ids.mapped('number_of_days_temp')) + rec.number_of_days_temp
max_allowed = rec.holiday_status_id.unpaid_leave_days_per_period
if rec.holiday_status_id.type_unpaid == 'termination':
if number_days_of_leaves > max_allowed:
raise ValidationError(_('The number of days of leave exceed the maximum allowed %s') % (max_allowed))
@api.depends('date_from','date_to', 'holiday_status_id')
def _leave_balance_date(self):
for rec in self:
rec._remove_followers_holiday()
to_work_days = 0
to_work_days2 = 0
leave = rec.holiday_status_id
current_date = (datetime.utcnow() + timedelta(hours=3)).date()
if rec.type == 'remove' and rec.employee_id.first_hiring_date and rec.date_from:
first_hiring_date = datetime.strptime(str(rec.employee_id.first_hiring_date), "%Y-%m-%d").date()
contract_start_date1 = datetime.strftime(first_hiring_date, DEFAULT_SERVER_DATE_FORMAT)
contract_start_date = datetime.strptime(str(contract_start_date1), "%Y-%m-%d").date()
working_days = (current_date - contract_start_date).days + 1
working_years = working_days / 365
holiday_duration = 0
for item in leave.duration_ids:
if item.date_from <= working_years < item.date_to:
holiday_duration = item.duration
###### get last cron date to compute leave_balance_date #
if leave:
balance_holiday = self.env['hr.holidays'].search([('employee_id', '=', rec.employee_id.id), ('type', '=', 'add'),
('holiday_status_id', '=', leave.id),('check_allocation_view', '=', 'balance')
], order='id desc', limit=1).holiday_ids
if balance_holiday:
last_cron_date = datetime.strptime(str(balance_holiday[-1].cron_run_date), DEFAULT_SERVER_DATE_FORMAT).date()
holi_date = (datetime.strptime(str(rec.date_from), "%Y-%m-%d %H:%M:%S")).date()
if last_cron_date < holi_date:
to_work_days2 = (holi_date - last_cron_date).days
#else:
#to_work_days2 = -(last_cron_date - holi_date).days
##### end ########
'''to_work_days = fields.Datetime.from_string(rec.date_from) > \
fields.Datetime.from_string(fields.Datetime.now()) and \
(datetime.strptime(str(rec.date_from), "%Y-%m-%d %H:%M:%S") -
(datetime.utcnow() + timedelta(hours=3))).days + 1 or 0'''
upcoming_leave = self.remaining_leaves_of_day_by_date(rec.employee_id, str(current_date), leave , is_month=False, is_years=False) * to_work_days2
if upcoming_leave > 0 and leave.leave_type == 'annual':
rec.leave_balance_date = round(rec.leave_balance + upcoming_leave, 2)
exceed_days = leave.number_of_save_days + holiday_duration
if rec.leave_balance_date > exceed_days and not (
rec.holiday_limit_check or leave.limit or self._context.get('stop_const')):
raise ValidationError(
_("Sorry the days you are trying to taken exceed tha maximum allowed days to be given"))
else:
rec.leave_balance_date = round(rec.leave_balance, 2)
@api.constrains('date_from', 'date_to', 'holiday_status_id', 'holiday_limit_check')
def _check_number_of_days(self):
for rec in self:
leave = rec.holiday_status_id
if rec.type == 'add' and rec.check_allocation_view == 'allocation':
holidays = self.env['hr.holidays'].search([('type', '=', 'add'),
('check_allocation_view', '=', 'allocation'),
('holiday_status_id', '=', rec.holiday_status_id.id),
('employee_id', '=', rec.employee_id.id),
('state', 'not in', ('cancel', 'refuse')),
('id', '!=', rec.id)])
taken = holidays and sum(holidays.mapped('number_of_days_temp')) or 0
if leave.payslip_type == 'unpaid' and leave.check_annual_holiday:
rec.check_annual_balance()
if leave.leave_annual_type == 'open_balance' \
and rec.number_of_days_temp \
and (leave.visible_fields
and
(
leave.number_of_save_days
and leave.number_of_save_days >= 1
and rec.number_of_days_temp > (leave.duration + leave.number_of_save_days - taken)
)
or (
not leave.number_of_save_days
and leave.number_of_years
and (
(
leave.number_of_years > 0
and rec.number_of_days_temp > (leave.duration + (
leave.duration * leave.number_of_years) - taken)
)
or
(
leave.number_of_years < 1
and rec.number_of_days_temp > (leave.duration - taken)
)
)
)
) \
or (not leave.visible_fields and leave.duration and (
rec.number_of_days_temp > (leave.duration - taken))):
raise ValidationError(_(
"Sorry the days you are trying to allocate exceed tha maximum allowed days to be given"))
elif rec.type == 'remove':
if leave.payslip_type == 'unpaid' and leave.check_annual_holiday:
rec.check_annual_balance()
rec.check_balance_per_period(rec)
if not (rec.employee_id.contract_id and rec.employee_id.first_hiring_date and rec.date_from):
raise ValidationError(_('Please make sure employee contract, first hiring date and leave start date'
' are set.'))
balance = self.env['hr.holidays'].search([('employee_id', '=', rec.employee_id.id),
('type', '=', 'add'),
('holiday_status_id', '=', rec.holiday_status_id.id),
('check_allocation_view', '=', 'balance')
], order='id desc', limit=1)
if not balance:
raise ValidationError(_('Sorry you have no balance'))
worked_days = ((datetime.utcnow() + timedelta(hours=3)).date() -
datetime.strptime(str(rec.employee_id.first_hiring_date), "%Y-%m-%d").date()).days + 1
#if worked_days < rec.holiday_status_id.number_of_days:
# raise UserError(_('Sorry you can not create leave request you have not holidays'))
#### Delete upcoming_leave and add up##
if rec.number_of_days_temp > rec.leave_balance_date and rec.state != 'validate1' and not (
rec.holiday_limit_check or leave.limit or self._context.get('stop_const')):
raise UserError(
_('Sorry your request refused your holidays not cover this duration For Employee %s') % (
rec.employee_id.name))
if leave.leave_type == 'hajj':
if self.env['ir.module.module'].sudo().search([('state', '=', 'installed'),
('name', '=', 'web_hijri_datepicker')]):
if rec.date_to and rec.date_from:
hijri_df = rec.employee_id.contract_id.change_current_date_hijri(fields.Date.to_string(
fields.Date.from_string(rec.date_from)))
hijri_dt = rec.employee_id.contract_id.change_current_date_hijri(fields.Date.to_string(
fields.Date.from_string(rec.date_to)))
if hijri_df.datetuple()[1] != 12 and hijri_dt.datetuple()[1] != 12:
raise UserError(
_('Sorry Hajj Leave can only be requested in the month of Zu Alhejja'))
@api.constrains('date_from', 'date_to', 'holiday_status_id')
#@api.constrains('holiday_status_id')
def _chick_leave_balance(self):
for rec in self:
taken_days = 0.0
if rec.employee_id and rec.holiday_status_id:
holi_id = self.env['hr.holidays'].search([('employee_id', '=', rec.employee_id.id), ('type', '=', 'add'),
('holiday_status_id', '=', rec.holiday_status_id.id),
('check_allocation_view', '=', 'balance')
], order='id desc', limit=1).id
taken_days = self.env['hr.holidays'].search([('employee_id', '=', rec.employee_id.id),
('type', '=', 'add'),
('holiday_status_id', '=', rec.holiday_status_id.id),
('check_allocation_view', '=', 'balance')
], order='id desc', limit=1).leaves_taken
if taken_days < 0 and rec.type == 'remove':
raise UserError(_('Sorry the leaves taken is less than zero'))
if not holi_id and rec.type == 'remove':
raise UserError(_('There Is No Holiday Balance Record'))
if rec.holiday_status_id.leave_type == 'sick' and rec.type == 'remove':
sickness_leaves = self.env['hr.holidays'].search([('employee_id', '=', rec.employee_id.id),
('type', '=', 'add'),
('holiday_status_id.leave_type', '=', 'sick'),
('holiday_status_id', '!=', rec.holiday_status_id.id),
('holiday_status_id.sickness_severity', '<',
rec.holiday_status_id.sickness_severity),
('check_allocation_view', '=', 'balance')
])
active_leaves = self.env['hr.holidays'].search([('employee_id', '=', rec.employee_id.id),
('type', '=', 'remove'),
('holiday_status_id.leave_type', '=', 'sick'),
('holiday_status_id', '!=', rec.holiday_status_id.id),
('holiday_status_id.sickness_severity', '<',
rec.holiday_status_id.sickness_severity),
('state', 'not in', ('refuse', 'validate1', 'cancel'))
])
if sickness_leaves:
msg = ''
for sk in sickness_leaves:
if sk.remaining_leaves > 0:
days = sum(active_leaves.filtered(
lambda t: t.holiday_status_id.id == sk.holiday_status_id.id).mapped(
'number_of_days_temp')) or 0
if days < sk.remaining_leaves:
msg += sk.holiday_status_id.name + '\n'
if msg:
raise UserError(_('Sorry you can not request %s leave while you '
'still have available balance in the following leaves \n %s')
% (rec.holiday_status_id.name, msg))
###############chick other request same holiday type####
active_leaves_request = self.env['hr.holidays'].search([('employee_id', '=', rec.employee_id.id),
('type', '=', 'remove'),
('id', '!=', rec.id),
('holiday_status_id', '=', rec.holiday_status_id.id),
('state', 'not in', ('refuse', 'validate1', 'cancel'))
])
if active_leaves_request and rec.type == 'remove':
list_holiday = ''
sum_duration = 0.0
for lis in active_leaves_request:
list_holiday += lis.holiday_status_id.name + '\n'
sum_duration += lis.number_of_days_temp
#curnet_balance = rec.leave_balance - sum_duration
curnet_balance = rec.leave_balance_date - sum_duration
if list_holiday and rec.number_of_days_temp > curnet_balance:
raise UserError(
_('Sorry you can not Create Holiday Request while you still have available Holiday request '
'in state Not Approve or Refuse Same Type : \n %s') % list_holiday)
# check end of service
Module = self.env['ir.module.module'].sudo()
modules = Module.search([('state', '=', 'installed'), ('name', '=', 'hr_termination')])
if modules:
end_of_service_rec = self.env['hr.termination'].search(
[('employee_id', '=', rec.employee_id.id), ('state', 'not in', ('refused', 'draft'))])
if end_of_service_rec and rec.type == 'remove':
raise UserError(
_('Sorry ! you can not Create Holiday Request and there is an Employee Termination Request %s') % (
rec.employee_id.name))
@api.depends('holiday_status_id', 'date_from', 'date_to')
def _compute_leave_balance(self):
for rec in self:
balance = 0.0
if rec.employee_id and rec.holiday_status_id:
balance = self.env['hr.holidays'].search([('employee_id', '=', rec.employee_id.id), ('type', '=', 'add'),
('holiday_status_id', '=', rec.holiday_status_id.id),
('check_allocation_view', '=', 'balance')
], order='id desc', limit=1).remaining_leaves or 0.0
rec.leave_balance = balance
# chick missions for employee or holiday period employee replace
@api.constrains('replace_by', 'holiday_status_id', 'date_from', 'date_to','state')
def replace_by_not_holiday(self):
for rec in self:
if rec.type == 'remove':
Module = self.env['ir.module.module'].sudo()
modules = Module.search([('state', '=', 'installed'), ('name', '=', 'exp_official_mission')])
modules_permission = Module.search([('state', '=', 'installed'), ('name', '=', 'employee_requests')])
if modules and rec.holiday_status_id.mission_chick == False:
mission_dfrm = self.env['hr.official.mission'].search(
[('employee_ids.employee_id', '=', rec.employee_id.id),
('mission_type.special_hours', '!=', 'True'), ('state', '!=', 'refused'),
('employee_ids.date_from', '<=', rec.date_from),
('employee_ids.date_to', '>=', rec.date_from)], order='id desc',
limit=1)
if mission_dfrm:
raise UserError(
_('Sorry The Employee %s Actually On %s For this Period') % (
rec.employee_id.name, mission_dfrm.mission_type.name))
mission_dto = self.env['hr.official.mission'].search(
[('employee_ids.employee_id', '=', rec.employee_id.id),
('mission_type.special_hours', '!=', 'True'),
('state', '!=', 'refused'), ('employee_ids.date_from', '<=', rec.date_to),
('employee_ids.date_to', '>=', rec.date_to)], order='id desc', limit=1)
if mission_dto:
raise UserError(
_('Sorry The Employee %s Actually On %s For this Period') % (
rec.employee_id.name, mission_dto.mission_type.name))
mission_btw = self.env['hr.official.mission'].search(
[('employee_ids.employee_id', '=', rec.employee_id.id),
('mission_type.special_hours', '!=', 'True'),
('state', '!=', 'refused'), ('employee_ids.date_from', '>=', rec.date_from),
('employee_ids.date_from', '<=', rec.date_to)], order='id desc',
limit=1)
if mission_btw:
raise UserError(
_('Sorry The Employee %s Actually On %s For this Period') % (
rec.employee_id.name, mission_btw.mission_type.name))
mission_hours = self.env['hr.official.mission'].search(
[('employee_ids.employee_id', '=', rec.employee_id.id),
('mission_type.special_hours', '!=', 'True'),
('mission_type.duration_type', '=', 'hours'), ('state', '!=', 'refused'),
('date', '>=', rec.date_from), ('date', '<=', rec.date_to)], order='id desc', limit=1)
if mission_hours:
raise UserError(_('Sorry The Employee %s Actually On %s For this Period') %
(rec.employee_id.name, mission_hours.mission_type.name))
if modules_permission:
date_to = datetime.strptime(str(rec.date_to), DEFAULT_SERVER_DATETIME_FORMAT)
hour = datetime.strptime(str("23:59:00"), "%H:%M:%S").time()
date_to = str(datetime.combine(date_to, hour))
date_from = datetime.strftime(datetime.strptime(str(rec.date_from), DEFAULT_SERVER_DATETIME_FORMAT),
DEFAULT_SERVER_DATETIME_FORMAT)
clause_1 = ['&', ('date_to', '<=', date_to), ('date_to', '>=', date_from)]
clause_2 = ['&', ('date_from', '<=', date_to), ('date_from', '>=', date_from)]
clause_3 = ['&', ('date_from', '<=', date_from), ('date_to', '>=', date_to)]
final_case = [('employee_id', '=', rec.employee_id.id), ('state', '!=', 'refused'), '|',
'|'] + clause_1 + clause_2 + clause_3
permissions_day = self.env['hr.personal.permission'].search(final_case)
if permissions_day:
raise UserError(
_('Sorry The Employee %s Actually On Permission For this Period') % rec.employee_id.name)
if rec.replace_by:
if rec.state != 'validate1':
holiday_dfrm = self.env['hr.holidays'].search(
[('employee_id', '=', rec.replace_by.id), ('type', '=', 'remove'), ('state', '!=', 'refuse'),
('date_from', '<=', rec.date_from), ('date_to', '>=', rec.date_from)], order='id desc',
limit=1)
holiday_dto = self.env['hr.holidays'].search(
[('employee_id', '=', rec.replace_by.id), ('type', '=', 'remove'), ('state', '!=', 'refuse'),
('date_from', '<=', rec.date_to), ('date_to', '>=', rec.date_to)], order='id desc', limit=1)
holiday_btw = self.env['hr.holidays'].search(
[('employee_id', '=', rec.replace_by.id), ('type', '=', 'remove'), ('state', '!=', 'refuse'),
('date_from', '>=', rec.date_from), ('date_from', '<=', rec.date_to)], order='id desc',
limit=1)
if holiday_dfrm or holiday_dto or holiday_btw:
raise UserError(
_('Sorry The Replacement Employee %s Actually On Holiday For this Period') % rec.replace_by.name)
rec.delegate_acc = True
else:
rec.delegate_acc = False
def send_email_holiday(self, holiday, emp):
if holiday.visible_fields and holiday.remained_before > 0 and holiday.leave_type=='annual':
today = datetime.now().date()
today = datetime.strptime(str(today), "%Y-%m-%d").date()
years = today.year
last_date = datetime.strftime(today, "{0}-12-31".format(years))
last_date = datetime.strptime(str(last_date), "%Y-%m-%d").date()
start_days = last_date - timedelta(days=int(holiday.remained_before))
if today < last_date:
balance = self.env['hr.holidays'].search([('employee_id', '=', emp.id),
('holiday_status_id', '=', holiday.id),
('type', '=', 'add'),
('check_allocation_view', '=', 'balance')
], limit=1, order="id desc")
holi_balance = balance.remaining_leaves or 0.0
if today >= start_days < last_date:
if holi_balance > holiday.number_of_save_days:
if emp.user_id:
template = self.env.ref('hr_holidays_public.email_template_holiday_balance', False)
template.write({'email_to': emp.user_id.partner_id.email, 'lang': emp.user_id.lang,
'email_cc': '%s' % (self.env.company.hr_email)})
template.send_mail(balance.id)
if holiday.payslip_type == 'unpaid':
tomorrow = (fields.Datetime.from_string(fields.Datetime.now()) + timedelta(days=1)).strftime(
'%Y-%m-%d 00:00:00')
upcoming_leaves = self.env['hr.holidays'].search([('employee_id', '=', emp.id),
('type', '=', 'remove'),
('holiday_status_id', '=', holiday.id),
('state', '=', 'validate1'),
('date_from', '=', tomorrow)])
for up in upcoming_leaves:
template = self.env.ref('hr_holidays_public.unpaid_leave_email', False)
template.write({'lang': up.employee_id.parent_id.user_id.lang,
'subject': _('%s unpaid leave beginning') % (up.employee_id.name),
'email_to': up.employee_id.parent_id.work_email,
'email_cc': '%s, %s' % (self.env.company.hr_email, up.employee_id.work_email)
})
template.send_mail(up.id, force_send=True, raise_exception=False)
def remaining_leaves_of_day_by_date(self, employee_id, specific_date, item , is_years=False, is_month=False):
first_hiring_date = datetime.strptime(str(employee_id.first_hiring_date), DEFAULT_SERVER_DATE_FORMAT).date()
specific_date = datetime.strptime(str(specific_date), DEFAULT_SERVER_DATE_FORMAT).date()
working_years = relativedelta.relativedelta(specific_date, first_hiring_date).years
holiday_duration = 0
num_days = calendar.monthrange(specific_date.year, specific_date.month)[1]
for rec in item.duration_ids:
if rec.date_from <= working_years < rec.date_to:
holiday_duration = rec.duration
if is_years:
return holiday_duration
if is_month:
return holiday_duration / 12
return (holiday_duration / 12) / num_days
def calc_not_balance_annual_leave(self, emp, cron_date, is_month=False, is_year=False):
holiday_status = self.env['hr.holidays.status'].search([('company_id', '=', self.env.company.id)])
holiday_current_date_ids = self.env['hr.holidays'] \
.search(
[('employee_id', '=', emp.id), ('type', '=', 'remove'),
('date_from', '<=', str(cron_date)),
('holiday_status_id', 'in', holiday_status.filtered(lambda h: h.not_balance_annual_leave).ids),
('date_to', '>=', str(cron_date)), ('state', 'not in', ['refuse', 'cancel', 'draft'])])
return holiday_current_date_ids and 1 or 0
def reset_remaining_leaves(self , current_date, item, emp, already_exist , is_years):
if self.is_last_day_of_year(current_date):
dutartion = 0
this_year_balance = 0
if item.number_of_save_days > 0:
dutartion = item.number_of_save_days
if is_years:
open_year = datetime(current_date.year - 1, 12, 31).date()
days_diff = (current_date - open_year).days + 1
for index in range(1, days_diff):
open_year_date = open_year + timedelta(days=index)
this_year_balance += self.remaining_leaves_of_day_by_date(emp, str(open_year_date), item , is_month=False, is_years=False)
else:
years_save = item.number_of_years
if is_years:
years_save = item.number_of_years + 1
open_year = datetime(current_date.year - years_save, 12, 31).date()
days_diff = (current_date - open_year).days + 1
for index in range(1, days_diff):
open_year_date = open_year + timedelta(days=index)
dutartion += self.remaining_leaves_of_day_by_date(emp, str(open_year_date), item , is_month=False, is_years=False)
# fix fix
if already_exist.remaining_leaves - this_year_balance > dutartion:
dutartion = dutartion + this_year_balance
already_exist.write({'remaining_leaves': dutartion})
@api.model
def process_holidays_scheduler_queue(self):
current_date_run = (datetime.utcnow() + timedelta(hours=3)).date()
employees = self.env['hr.employee'].search(
[('state', '=', 'open'), ('company_id', '=', self.env.company.id)]
).filtered(
lambda emp: emp.first_hiring_date
and emp.first_hiring_date <= current_date_run
and emp.contract_id
and emp.contract_id.emp_type in ('other', 'saudi', 'displaced', 'external', 'external2')
and (not emp.contract_id.date_end or emp.contract_id.date_end and emp.contract_id.date_end >= current_date_run))
holiday_status = self.env['hr.holidays.status'].search([('company_id', '=', self.env.company.id)])
for emp in employees:
already_exist = None
current_date = (datetime.utcnow() + timedelta(hours=3)).date()
# current_date = datetime(2025, 12, 31).date()
first_hiring_date = datetime.strptime(str(emp.first_hiring_date), "%Y-%m-%d").date()
days = (current_date - first_hiring_date).days + 1
for item in holiday_status:
# current_date = datetime(2025, 12, 31).date()
if days < item.number_of_days:
continue
is_years , is_month = False , False
if item.balance_type == 'monthly':
is_month = True
if item.balance_type == 'yearly':
is_years = True # True
self.send_email_holiday(item, emp)
if item.leave_type == 'annual' and (item.emp_type == 'all' or item.emp_type == emp.contract_id.emp_type):
if item.leave_annual_type == 'open_balance': # or item.leave_annual_type == 'save_annual_year' and item.number_of_holidays_save_years <= 0:
already_exist = self.env['hr.holidays'].search([('employee_id', '=', emp.id),
('holiday_status_id', '=', item.id),
('type', '=', 'add'),
('check_allocation_view', '=', 'balance')
], limit=1, order="id desc")
create_open_balance = self.env['hr.holidays'].search([('holiday_status_id', '=', item.id),
('type', '=', 'add'),
('check_allocation_view', '=', 'balance')
], order="id desc")
if is_years:
current_date = current_date.replace(year=current_date.year , month=12, day=31)
current_date = datetime.strptime(str(current_date), DEFAULT_SERVER_DATE_FORMAT).date()
if is_month:
if self.is_last_day_of_month(current_date):
current_date = current_date
else:
current_date = datetime.strptime(str(current_date), DEFAULT_SERVER_DATE_FORMAT).date()
current_date = current_date.replace(day=1) - timedelta(days=1)
if not already_exist and len(create_open_balance) > 1 and item.leave_annual_type == 'open_balance':
# if not already_exist and item.leave_annual_type == 'open_balance':
balance_leaves = self.remaining_leaves_of_day_by_date(emp, str(first_hiring_date), item , is_month=False, is_years=False)
already_exist = self.env['hr.holidays'].create({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'employee_id': emp.id,
'holiday_status_id': item.id,
'check_allocation_view': 'balance',
'type': 'add',
'remaining_leaves': balance_leaves,
})
self.env['hr.inverse.holidays'].create(
{'holiday_id': already_exist.id, 'cron_run_date': first_hiring_date, 'balance_leaves':balance_leaves })
if already_exist:
if not already_exist.holiday_ids:
not_balance = 0
not_no_balance = 0
if not is_years and not is_month:
not_balance = self.remaining_leaves_of_day_by_date(emp, str(current_date), item , is_month=False, is_years=False)
not_no_balance = self.calc_not_balance_annual_leave(emp, current_date) * not_balance
already_exist.write({
'remaining_leaves': already_exist.remaining_leaves + not_balance - not_no_balance,
})
self.env['hr.inverse.holidays'].create({'holiday_id': already_exist.id, 'cron_run_date': current_date, 'balance_leaves':not_balance, 'no_balance_leaves':not_no_balance })
holiday = already_exist.holiday_ids[-1]
if not holiday.cron_run_date:
not_balance = 0
not_no_balance = 0
if not is_years and not is_month:
not_balance = self.remaining_leaves_of_day_by_date(emp, str(current_date), item , is_month=False, is_years=False)
not_no_balance = self.calc_not_balance_annual_leave(emp, current_date) * not_balance
already_exist.write({
'remaining_leaves': already_exist.remaining_leaves + not_balance - not_no_balance,
})
holiday.write({'cron_run_date': current_date})
holiday_cron_run_date = datetime.strptime(str(holiday.cron_run_date ), "%Y-%m-%d").date()
if current_date > holiday_cron_run_date or is_years:
holiday_cron_run_date = datetime.strptime(str(holiday.cron_run_date), DEFAULT_SERVER_DATE_FORMAT).date()
current_date = datetime.strptime(str(current_date), DEFAULT_SERVER_DATE_FORMAT).date()
if holiday_cron_run_date >= current_date:
continue
delta = current_date - holiday_cron_run_date # timedelta
months_date = holiday_cron_run_date
months = (current_date.year - months_date.year) * 12 + (current_date.month - months_date.month) + 1
item_values = []
year = current_date.year - holiday_cron_run_date.year
range_val = []
range_val = range(1, delta.days + 1)
if is_years:
range_val = range(1, year + 1)
end_day = (holiday_cron_run_date.replace(day=1) + relativedelta.relativedelta(months=1)) - timedelta(days=1)
end_date_cron = (end_day - holiday_cron_run_date).days
if end_date_cron > 0:
no_year_balance , year_balance = 0, 0
for i in range(1, end_date_cron + 1):
cala_date = holiday_cron_run_date + timedelta(days=i)
balance = self.remaining_leaves_of_day_by_date(emp, str(cala_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, cala_date) * balance)
year_balance = year_balance + balance
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves': already_exist.remaining_leaves + year_balance - no_year_balance,
})
already_exist.write({'holiday_ids': [fields.Command.create({'cron_run_date': end_day, 'balance_leaves':year_balance, 'no_balance_leaves':no_year_balance})]})
complete_month = datetime.strptime(str(already_exist.holiday_ids[-1].cron_run_date), DEFAULT_SERVER_DATE_FORMAT).date()
cron_run_date_y = 12 - complete_month.month
for x in range(1 , cron_run_date_y + 1):
no_year_balance , year_balance = 0, 0
end_day = (complete_month.replace(day=1) + relativedelta.relativedelta(months=x + 1)) - timedelta(days=1)
y = end_day.replace(day=1)
for i in range(0, (end_day - y).days + 1):
cala_date = y + timedelta(days=i)
balance = self.remaining_leaves_of_day_by_date(emp, str(cala_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, cala_date) * balance)
year_balance = year_balance + balance
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves': (already_exist.remaining_leaves + year_balance) - no_year_balance,
})
already_exist.write({'holiday_ids': [fields.Command.create({'cron_run_date': end_day, 'balance_leaves':year_balance, 'no_balance_leaves':no_year_balance})]})
if is_month:
end_day = (holiday_cron_run_date.replace(day=1) + relativedelta.relativedelta(months=1)) - timedelta(days=1)
end_date_cron = (end_day - holiday_cron_run_date).days
if end_date_cron > 0:
no_year_balance , year_balance = 0, 0
for i in range(1, end_date_cron + 1):
cala_date = holiday_cron_run_date + timedelta(days=i)
balance = self.remaining_leaves_of_day_by_date(emp, str(cala_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, cala_date) * balance)
year_balance = year_balance + balance
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves': already_exist.remaining_leaves + (year_balance - no_year_balance),
})
already_exist.write({'holiday_ids': [fields.Command.create({'cron_run_date': end_day, 'balance_leaves':year_balance, 'no_balance_leaves':no_year_balance})]})
range_val = range(1, months)
for i in range_val:
no_year_balance , year_balance = 0, 0
cron_date = holiday_cron_run_date + timedelta(days=i)
balance = self.remaining_leaves_of_day_by_date(emp, str(cron_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, cron_date) * balance)
year_balance = year_balance + balance
if is_years:
no_year_balance , year_balance = 0, 0
cron_date = holiday_cron_run_date.replace(year=holiday_cron_run_date.year + i , month=12, day=31)
y = cron_date.replace(year=cron_date.year - 1 , month=12, day=31)
for i in range(1, (cron_date - y).days + 1):
cala_date = y + timedelta(days=i)
balance = self.remaining_leaves_of_day_by_date(emp, str(cala_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, cala_date) * balance)
year_balance = year_balance + balance
if is_month:
cron_date = (holiday_cron_run_date.replace(day=1) + relativedelta.relativedelta(months=i + 1)) - timedelta(days=1)
y = cron_date.replace(day=1)
no_year_balance , year_balance = 0, 0
for i in range(0, (cron_date - y).days + 1):
cala_date = y + timedelta(days=i)
balance = self.remaining_leaves_of_day_by_date(emp, str(cala_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, cala_date) * balance)
year_balance = year_balance + balance
item_values.append({'cron_run_date': cron_date, 'balance_leaves':year_balance, 'no_balance_leaves':no_year_balance})
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves':(already_exist.remaining_leaves + year_balance) - no_year_balance,
})
already_exist.write({'holiday_ids': [(0, 0, item) for item in item_values]})
# TO DO cala dutartion if val days_save == 0 or set days_save BY ABUZAR
# DONE call end method ---
# self.reset_remaining_leaves(current_date, item, emp, already_exist,is_years)
elif item.leave_annual_type == 'save_annual_year':
# and item.number_of_holidays_save_years > 0:
current_date = (datetime.utcnow() + timedelta(hours=3)).date() # replace with: current_date_time++
# current_date = datetime(2025, 12, 31).date()
current_date_val = current_date.year
old_year_date_val = current_date.year - 1 # previous year
end_of_save_year = datetime.strftime(current_date, "{0}-12-31 23:59:59".format(old_year_date_val)) # previous_year_end
end_of_save_year_value = datetime.strptime(str(end_of_save_year), "%Y-%m-%d 23:59:59").date() # previous_year_end Date
start_of_new_year = datetime.strftime(first_hiring_date, "{0}-01-01".format(current_date_val))
start_of_save_year_value = datetime.strptime(str(start_of_new_year), "%Y-%m-%d").date() # start of new year
working_days_old = (end_of_save_year_value - first_hiring_date).days + 1 # working days till end prv year عدد ايام عمل الموظف الي السنة الحالية
employee_working_years = item.number_of_holidays_save_years * 365 # balance of prev years to give?
if working_days_old >= employee_working_years:
remaining_leaves_of_day = self.remaining_leaves_of_day_by_date(emp, str(current_date), item , is_month=False, is_years=False)
already_exist = self.env['hr.holidays'].search([('employee_id', '=', emp.id),
('holiday_status_id', '=', item.id),
('type', '=', 'add'),
('check_allocation_view', '=', 'balance')
], limit=1, order="id desc")
if already_exist:
"""
Important note:
we are no longer saving years but carrying balance from year to the next only;
according to Bakri Request done by Yousra.
"""
if is_years:
current_date = current_date.replace(year=current_date.year , month=12, day=31)
current_date = datetime.strptime(str(current_date), DEFAULT_SERVER_DATE_FORMAT).date()
if is_month:
if self.is_last_day_of_month(current_date):
current_date = current_date
else:
current_date = datetime.strptime(str(current_date), DEFAULT_SERVER_DATE_FORMAT).date()
current_date = current_date.replace(day=1) - timedelta(days=1)
if not already_exist.holiday_ids:
self.env['hr.inverse.holidays'].create({'holiday_id': already_exist.id, 'cron_run_date': current_date, })
holiday = already_exist.holiday_ids[-1]
if holiday.cron_run_date:
cron_run_date1 = datetime.strptime(str(holiday.cron_run_date), DEFAULT_SERVER_DATE_FORMAT).date()
current_date = datetime.strptime(str(current_date), DEFAULT_SERVER_DATE_FORMAT).date()
if cron_run_date1 > current_date:
continue
delta = current_date - cron_run_date1 # timedelta
months_date = cron_run_date1
year = current_date.year - cron_run_date1.year
months = (current_date.year - months_date.year) * 12 + (current_date.month - months_date.month) + 1
item_values = []
range_val = []
range_val = range(1, delta.days + 1)
if is_years:
if year <= item.number_of_holidays_save_years:
range_val = range(1, year + 1)
end_day = (cron_run_date1.replace(day=1) + relativedelta.relativedelta(months=1)) - timedelta(days=1)
end_date_cron = (end_day - cron_run_date1).days
if end_date_cron > 0:
no_year_balance , year_balance = 0, 0
for i in range(1, end_date_cron + 1):
cala_date = cron_run_date1 + timedelta(days=i)
balance = self.remaining_leaves_of_day_by_date(emp, str(cala_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, cala_date) * balance)
year_balance = year_balance + balance
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves': already_exist.remaining_leaves + year_balance - no_year_balance,
})
already_exist.write({'holiday_ids': [fields.Command.create({'cron_run_date': end_day, 'balance_leaves':year_balance, 'no_balance_leaves':no_year_balance})]})
complete_month = datetime.strptime(str(already_exist.holiday_ids[-1].cron_run_date), DEFAULT_SERVER_DATE_FORMAT).date()
cron_run_date_y = 12 - complete_month.month
for x in range(1, cron_run_date_y + 1):
no_year_balance , year_balance = 0, 0
end_day = (complete_month.replace(day=1) + relativedelta.relativedelta(months=x + 1)) - timedelta(days=1)
y = end_day.replace(day=1)
for i in range(0, (end_day - y).days + 1):
cala_date = y + timedelta(days=i)
balance = self.remaining_leaves_of_day_by_date(emp, str(cala_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, cala_date) * balance)
year_balance = year_balance + balance
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves': (already_exist.remaining_leaves + year_balance) - no_year_balance,
})
already_exist.write({'holiday_ids': [fields.Command.create({'cron_run_date': end_day, 'balance_leaves':year_balance, 'no_balance_leaves':no_year_balance})]})
else:
cron_run_date1 = current_date.replace(year=current_date.year - item.number_of_holidays_save_years, month=12, day=31)
range_val = range(0, item.number_of_holidays_save_years + 1)
if is_month:
if year <= item.number_of_holidays_save_years:
end_day = (cron_run_date1.replace(day=1) + relativedelta.relativedelta(months=1)) - timedelta(days=1)
end_date_cron = (end_day - cron_run_date1).days
if end_date_cron > 0:
no_year_balance , year_balance = 0, 0
for i in range(1, end_date_cron + 1):
cala_date = cron_run_date1 + timedelta(days=i)
balance = self.remaining_leaves_of_day_by_date(emp, str(cala_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, cala_date) * balance)
year_balance = year_balance + balance
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves': already_exist.remaining_leaves + (year_balance - no_year_balance),
})
already_exist.write({'holiday_ids': [fields.Command.create({'cron_run_date': end_day, 'balance_leaves':year_balance, 'no_balance_leaves':no_year_balance})]})
range_val = range(1, months)
else:
cron_run_date1 = current_date.replace(year=current_date.year - item.number_of_holidays_save_years , month=1, day=31)
range_val = range(0, (item.number_of_holidays_save_years) * 12 + (current_date.month - cron_run_date1.month) + 1)
for i in range_val:
no_year_balance , year_balance = 0, 0
cron_date = cron_run_date1 + timedelta(days=i)
balance = self.remaining_leaves_of_day_by_date(emp, str(cron_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, cron_date) * balance)
year_balance = year_balance + balance
if is_years:
no_year_balance , year_balance = 0, 0
cron_date = cron_run_date1.replace(year=cron_run_date1.year + i , month=12, day=31)
y = cron_date.replace(year=cron_date.year - 1 , month=12, day=31)
for i in range(1, (cron_date - y).days + 1):
cala_date = y + timedelta(days=i)
balance = self.remaining_leaves_of_day_by_date(emp, str(cala_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, cala_date) * balance)
year_balance = year_balance + balance
if is_month:
cron_date = (cron_run_date1.replace(day=1) + relativedelta.relativedelta(months=i + 1)) - timedelta(days=1)
y = cron_date.replace(day=1)
no_year_balance , year_balance = 0, 0
for i in range(0, (cron_date - y).days + 1):
cala_date = y + timedelta(days=i)
balance = self.remaining_leaves_of_day_by_date(emp, str(cala_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, cala_date) * balance)
year_balance = year_balance + balance
item_values.append({'cron_run_date': cron_date, 'balance_leaves':year_balance, 'no_balance_leaves':no_year_balance})
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves':(already_exist.remaining_leaves + year_balance) - no_year_balance,
})
already_exist.write({'holiday_ids': [(0, 0, item) for item in item_values]})
else:
holiday.write({'cron_run_date': current_date, 'balance_leaves':remaining_leaves_of_day })
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves': already_exist.remaining_leaves + float(remaining_leaves_of_day),
})
else:
year_balance = 0
no_year_balance = 0
start_of_save_year_value = start_of_save_year_value.replace(year=(current_date.year - item.number_of_holidays_save_years))
working_days_new = ((current_date - start_of_save_year_value).days + 1)
if not is_years and not is_month:
for index in range(0, working_days_new):
current_date = start_of_save_year_value + timedelta(days=index)
balance = self.remaining_leaves_of_day_by_date(emp, str(current_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, current_date) * balance)
year_balance = year_balance + balance
if is_years:
year_balance = 0
remaining_leaves_of_day = 0
current_date = current_date.replace(year=current_date.year , month=12, day=31)
year_new = (current_date.year - first_hiring_date.year)
year_new = min(year_new, item.number_of_holidays_save_years) + 1
y = current_date.replace(year=current_date.year - year_new , month=12, day=31)
for i in range(1, (current_date - y).days + 1):
cala_date = y + timedelta(days=i)
balance = self.remaining_leaves_of_day_by_date(emp, str(cala_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, cala_date) * balance)
year_balance = year_balance + balance
if is_month:
year_balance = 0
remaining_leaves_of_day = 0
current_date = (current_date.replace(day=1) + relativedelta.relativedelta(months=0)) - timedelta(days=1)
first_hiring_date = datetime.strptime(str(emp.first_hiring_date), "%Y-%m-%d").date()
remaining_leaves_of_day = self.remaining_leaves_of_day_by_date(emp, str(current_date), item , is_month=is_month, is_years=is_years)
months_date = first_hiring_date
months_new = (current_date.year - months_date.year) * 12 + current_date.month - months_date.month
save_month = item.number_of_holidays_save_years * 12
min_months = min(months_new, save_month)
if months_new > save_month:
last_date = current_date.replace(year=current_date.year - 1, month=12, day=31)
open_years_month = (current_date.year - last_date.year) * 12 + current_date.month - last_date.month
min_months = min_months + open_years_month
y = (current_date - relativedelta.relativedelta(months=min_months - 1)).replace(day=1)
for i in range(0, (current_date - y).days + 1):
cala_date = y + timedelta(days=i)
balance = self.remaining_leaves_of_day_by_date(emp, str(cala_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, cala_date) * balance)
year_balance = year_balance + balance
already_exist = self.env['hr.holidays'].create({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'employee_id': emp.id,
'holiday_status_id': item.id,
'check_allocation_view': 'balance',
'type': 'add',
'remaining_leaves': year_balance - no_year_balance,
})
self.env['hr.inverse.holidays'].create({'holiday_id': already_exist.id, 'cron_run_date': current_date, 'balance_leaves':year_balance , 'no_balance_leaves':no_year_balance })
else:
if is_years:
current_date = current_date.replace(year=current_date.year , month=12, day=31)
current_date = datetime.strptime(str(current_date), DEFAULT_SERVER_DATE_FORMAT).date()
if is_month:
current_date = (current_date.replace(day=1) + relativedelta.relativedelta(months=0)) - timedelta(days=1)
days_of_new_employee = (current_date - first_hiring_date).days + 1
if days_of_new_employee >= item.number_of_days:
already_exist = self.env['hr.holidays'].search([('employee_id', '=', emp.id),
('holiday_status_id', '=', item.id),
('type', '=', 'add'),
('check_allocation_view', '=', 'balance')
], limit=1, order="id desc")
if not already_exist:
balance_leaves = self.remaining_leaves_of_day_by_date(emp, str(first_hiring_date), item , is_month=False, is_years=False)
already_exist = self.env['hr.holidays'].create({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'employee_id': emp.id,
'holiday_status_id': item.id,
'check_allocation_view': 'balance',
'type': 'add',
'remaining_leaves': balance_leaves,
})
self.env['hr.inverse.holidays'].create(
{'holiday_id': already_exist.id, 'cron_run_date': first_hiring_date, 'balance_leaves':balance_leaves })
if not is_years and not is_month:
working_days_new = ((current_date - first_hiring_date).days) + 1
year_balance = already_exist.remaining_leaves or 0
no_balance = 0
for index in range(1, working_days_new):
current_date = first_hiring_date + timedelta(days=index)
balance = self.remaining_leaves_of_day_by_date(emp, str(current_date), item , is_month=False, is_years=False)
no_balance = no_balance + self.calc_not_balance_annual_leave(emp, current_date) * balance
year_balance = year_balance + balance
already_exist.holiday_ids[-1].cron_run_date = current_date
already_exist.holiday_ids[-1].balance_leaves = year_balance
already_exist.holiday_ids[-1].no_balance_leaves = no_balance
already_exist.remaining_leaves = year_balance - no_balance
if already_exist:
if not already_exist.holiday_ids:
current_date_new = (datetime.utcnow() + timedelta(hours=3)).date()
balance_leaves = self.remaining_leaves_of_day_by_date(emp, str(current_date_new), item , is_month=False, is_years=False)
self.env['hr.inverse.holidays'].create({'holiday_id': already_exist.id, 'cron_run_date': current_date_new, 'balance_leaves':balance_leaves })
holiday.write({'cron_run_date': current_date, })
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves': already_exist.remaining_leaves + balance_leaves,
})
else:
holiday = already_exist.holiday_ids[-1]
if holiday.cron_run_date:
cron_run_date1 = datetime.strptime(str(holiday.cron_run_date), DEFAULT_SERVER_DATE_FORMAT).date()
if cron_run_date1 >= current_date:
continue
current_date1 = datetime.strptime(str(current_date), DEFAULT_SERVER_DATE_FORMAT).date()
delta = current_date1 - cron_run_date1 # timedelta
months_date = cron_run_date1
months = (current_date1.year - months_date.year) * 12 + current_date1.month - months_date.month
year = current_date1.year - cron_run_date1.year
item_values = []
range_val = []
range_val = range(1, delta.days + 1)
if is_years:
range_val = range(1, year + 1)
end_day = (cron_run_date1.replace(day=1) + relativedelta.relativedelta(months=1)) - timedelta(days=1)
end_date_cron = (end_day - cron_run_date1).days
if end_date_cron > 0:
balance_leaves = 0
no_year_balance = 0
start_date = (end_day - cron_run_date1).days + 1
for index in range(1, start_date):
calc_date = cron_run_date1 + timedelta(days=index)
balance = self.remaining_leaves_of_day_by_date(emp, str(calc_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, calc_date) * balance)
balance_leaves = balance_leaves + balance
# balance_leaves = balance_leaves - no_year_balance
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves': already_exist.remaining_leaves + balance_leaves - no_year_balance,
})
already_exist.write({'holiday_ids': [fields.Command.create({'cron_run_date': end_day, 'balance_leaves':balance_leaves, 'no_balance_leaves':no_year_balance})]})
complete_month = datetime.strptime(str(already_exist.holiday_ids[-1].cron_run_date), DEFAULT_SERVER_DATE_FORMAT).date()
cron_run_date_y = 12 - complete_month.month
for x in range(1, cron_run_date_y + 1):
end_day = (complete_month.replace(day=1) + relativedelta.relativedelta(months=x + 1)) - timedelta(days=1)
balance_leaves = 0
no_year_balance = 0
start_date = (end_day - end_day.replace(day=1)).days + 1
for index in range(0, start_date):
calc_date = end_day.replace(day=1) + timedelta(days=index)
balance = self.remaining_leaves_of_day_by_date(emp, str(calc_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, calc_date) * balance)
balance_leaves = balance_leaves + balance
# balance_leaves = balance_leaves - no_year_balance
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves': already_exist.remaining_leaves + balance_leaves - no_year_balance
})
already_exist.write({'holiday_ids': [fields.Command.create({\
'cron_run_date': end_day, \
'balance_leaves':balance_leaves, \
'no_balance_leaves':no_year_balance})]})
if is_month:
balance_leaves = 0
no_year_balance = 0
end_day = (cron_run_date1.replace(day=1) + relativedelta.relativedelta(months=1)) - timedelta(days=1)
end_date_cron = (end_day - cron_run_date1).days
if end_date_cron > 0:
for index in range(1, end_date_cron + 1):
calc_date = cron_run_date1 + timedelta(days=index)
balance = self.remaining_leaves_of_day_by_date(emp, str(calc_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, calc_date) * balance)
balance_leaves = balance_leaves + balance
# balance_leaves = balance_leaves - no_year_balance
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves': already_exist.remaining_leaves + balance_leaves - no_year_balance,
})
already_exist.write({'holiday_ids': [fields.Command.create({'cron_run_date': end_day, 'balance_leaves':balance_leaves, 'no_balance_leaves':no_year_balance})]})
range_val = range(1, months + 1)
for i in range_val:
cron_date = cron_run_date1 + timedelta(days=i)
balance_leaves = self.remaining_leaves_of_day_by_date(emp, str(cron_date), item , is_month=False, is_years=False)
no_year_balance = self.calc_not_balance_annual_leave(emp, cron_date) * balance_leaves
if is_years:
cron_date = cron_run_date1.replace(year=cron_run_date1.year + i , month=12, day=31)
if is_month:
cron_date = (cron_run_date1.replace(day=1) + relativedelta.relativedelta(months=i + 1)) - timedelta(days=1)
if current_date >= cron_date:
if is_month:
balance_leaves = 0
no_year_balance = 0
start_date = cron_date.replace(day=1)
start_days = (cron_date - cron_date.replace(day=1)).days + 1
for index in range(0, start_days):
calc_date = start_date + timedelta(days=index)
balance = self.remaining_leaves_of_day_by_date(emp, str(calc_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, calc_date) * balance)
balance_leaves = balance_leaves + balance
if is_years:
balance_leaves = 0
no_year_balance = 0
start_date = cron_date.replace(year=cron_date.year - 1)
start_date_number = (cron_date - start_date).days + 1
for index in range(1, start_date_number):
calc_date = start_date + timedelta(days=index)
balance = self.remaining_leaves_of_day_by_date(emp, str(calc_date), item , is_month=False, is_years=False)
no_year_balance = no_year_balance + (self.calc_not_balance_annual_leave(emp, calc_date) * balance)
balance_leaves = balance_leaves + balance
remaining_leaves_of_day = balance_leaves - no_year_balance
item_values.append({ 'cron_run_date': cron_date, 'balance_leaves':balance_leaves, 'no_balance_leaves':no_year_balance})
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves': already_exist.remaining_leaves + float(balance_leaves - no_year_balance),
})
already_exist.write({'holiday_ids': [(0, 0, item) for item in item_values]})
else:
current_date_new = (datetime.utcnow() + timedelta(hours=3)).date()
holiday.write({'cron_run_date': current_date_new})
self.reset_remaining_leaves(current_date, item, emp, already_exist, is_years)
elif item.leave_type != 'annual' and (item.gender == 'both' or item.gender == emp.gender):
if days >= item.number_of_days:
current_date = (datetime.utcnow() + timedelta(hours=3)).date()
already_exist = self.env['hr.holidays'].search([('employee_id', '=', emp.id),
('holiday_status_id', '=', item.id),
('type', '=', 'add'),
('check_allocation_view', '=', 'balance')
], limit=1, order="id desc")
remaining_leaves = item.duration
if already_exist:
# Renewal Balance of Sick Leave
self.renewal_balance_sick_leave(emp, item, already_exist, current_date)
# Renewal Balance of Unpaid Leave
self.renewal_balance_unpaid_leave(emp, item, already_exist, current_date)
# Renewal Balance of Last Day OF Year
# leave_type = ['exam','death'] # Just set type leave in list add new Leave
self.renewal_balance_leaves_last_day_of_year(current_date, item, already_exist , emp)
# Renewal Balance of daily
#renewal_daily_leave_type = ['death', 'new_baby'] # Just set type leave in list add new Leave
self.renewal_balance_leaves_daily(current_date, item, already_exist )
else:
hr_holidays = self.env['hr.holidays'].create({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'employee_id': emp.id,
'holiday_status_id': item.id,
'remaining_leaves': remaining_leaves,
'check_allocation_view': 'balance',
'type': 'add'
})
self.env['hr.inverse.holidays'].create({'holiday_id': hr_holidays.id,
'cron_run_date': current_date,
'balance_leaves':remaining_leaves})
def is_last_day_of_month(self, date):
# Get the last day of the month for the given date
last_day_of_month = (date.replace(day=1) \
.replace(month=date.month % 12 + 1, day=1) \
-timedelta(days=1)).day
# Return True if the given date is the last day of the month, False otherwise
return date.day == last_day_of_month
def is_last_day_of_year(self, date):
# Get the last day of the year for the given date
last_day_of_year = datetime(date.year, 12, 31).date()
# Check if the given date is the same as the last day of the year
return date == last_day_of_year
def renewal_balance_leaves_daily(self , current_date, item, already_exist ):
renewal_daily_leave_type = ['death', 'new_baby'] # Just set type leave in list add new Leave
if (item.leave_type in renewal_daily_leave_type) and (already_exist.remaining_leaves != item.duration):
duration = item.duration
already_exist.write({'remaining_leaves': duration })
self.env['hr.inverse.holidays'].create({'holiday_id': already_exist.id,
'cron_run_date': current_date,
'balance_leaves':duration})
def renewal_balance_leaves_last_day_of_year(self , current_date, item, already_exist , emp):
leave_type = ['exam', 'marriage','parental','emergency']#'death'] # Just set type leave in list add new Leave
if (item.leave_type in leave_type) and (already_exist.remaining_leaves < item.duration):
duration = item.duration # >= already_exist.remaining_leaves and item.duration or already_exist.remaining_leaves
# current_date = datetime(2024, 12, 31).date()
cron_run_date = current_date
if already_exist.holiday_ids:
holiday = already_exist.holiday_ids[-1]
cron_run_date = datetime.strptime(str(holiday.cron_run_date or current_date), DEFAULT_SERVER_DATE_FORMAT).date()
current_date = current_date + timedelta(days=1)
current_date = current_date.replace(year=current_date.year , month=12, day=31) # last day curent year
start_date = current_date.replace(day=1).replace(month=1)
domain = [
('employee_id', '=', emp.id),
('type', '=', 'remove'),
('date_from', '<=', str(current_date)),
('date_to', '>=', str(start_date)),
('state', 'in', ['validate1']), # Added comma here
('holiday_status_id', '=', item.id), # Fixed typo in the variable name
]
diff_years = current_date.year - cron_run_date.year
holiday_current_date_ids = self.env['hr.holidays'].read_group(domain, ['date_from', 'number_of_days'], ['date_from:year'])
if (diff_years >= 0) and (current_date > cron_run_date):
days = (current_date - start_date).days + 1
total_day = 0
if holiday_current_date_ids:
for day in range(0, days):
calc_date = start_date + timedelta(days=day)
holiday_current_date_ids = self.env['hr.holidays'].search([
('employee_id', '=', emp.id),
('type', '=', 'remove'),
('date_from', '<=', str(calc_date)),
('date_to', '>=', str(calc_date)),
('state', 'in', ['validate1']), # Added comma here
('holiday_status_id', '=', item.id), # Fixed typo in the variable name
])
if holiday_current_date_ids:
total_day = total_day + 1
remaining_leaves = duration - total_day
already_exist.write({'remaining_leaves': remaining_leaves > 0 and remaining_leaves or 0 })
self.env['hr.inverse.holidays'].create({'holiday_id': already_exist.id,
'cron_run_date': current_date,
'balance_leaves':duration})
def renewal_balance_sick_leave(self, emp, item, already_exist, current_date):
if item.leave_type != 'sick':
return True
# current_date = datetime(2024, 11, 23).date()
while True:
# old_sick_leave = self._get_latest_approved_leave(emp, item)
# if not old_sick_leave:
# break
cron_run_date = emp.first_hiring_date
if already_exist.holiday_ids:
cron_run_date = already_exist.holiday_ids[-1].cron_run_date
old_sick_leave = self._get_latest_approved_leave_after_date(emp, item, cron_run_date)
if not old_sick_leave:
break
holiday_id = old_sick_leave[-1]
date_from = fields.Date.from_string(holiday_id.date_from)
next_years = date_from.replace(year=date_from.year + 1)
number_of_years = relativedelta.relativedelta(current_date, date_from).years
if number_of_years >= 1:
remaining_leaves = self._calculate_remaining_leaves(emp , item, next_years)
self._create_inverse_holiday(already_exist, next_years,remaining_leaves)
already_exist.write({
'name': f'Yearly Allocation of {item.name} Leaves',
'remaining_leaves': remaining_leaves,
})
else:
break
return True
def _get_latest_approved_leave(self, emp, item):
domain = [
('employee_id', '=', emp.id),
('holiday_status_id', '=', item.id),
('type', '=', 'remove'),
('state', 'in', ['validate1'])
]
return self.env['hr.holidays'].search(domain, limit=1, order="date_from desc")
def _get_latest_approved_leave_after_date(self, emp, item, date):
domain = [
('employee_id', '=', emp.id),
('holiday_status_id', '=', item.id),
('type', '=', 'remove'),
('state', 'in', ['validate1']),
('date_from', '>', str(date))
]
return self.env['hr.holidays'].search(domain, order="date_from desc")
def _create_inverse_holiday(self, already_exist, next_years,balance):
self.env['hr.inverse.holidays'].create({
'holiday_id': already_exist.id,
'cron_run_date': next_years,
'balance_leaves': balance,
})
def _calculate_remaining_leaves(self, emp,item, next_years):
domain = [
('employee_id', '=', emp.id),
('holiday_status_id', '=', item.id),
('type', '=', 'remove'),
('state', 'in', ['validate1']),
('date_from', '<=', str(next_years.replace(year=next_years.year + 1))),
('date_from', '>', str(next_years))
]
old_sick_leave = self.env['hr.holidays'].search(domain, order="date_from desc")
return float(item.duration) - sum(old_sick_leave.mapped('number_of_days_temp'))
def renewal_balance_unpaid_leave(self, emp, item, already_exist, current_date):
if item.type_unpaid == 'termination':
if already_exist.holiday_ids:
last_update_date = datetime.strptime(str(already_exist.holiday_ids[-1].cron_run_date),
DEFAULT_SERVER_DATE_FORMAT)
next_run_date = current_date.replace(year=last_update_date.year + item.period_giving_balance)
if current_date >= next_run_date:
already_exist.write({
'name': 'Yearly Allocation of ' + item.name + ' Leaves',
'remaining_leaves': float(item.duration),
})
self.env['hr.inverse.holidays'].create({'holiday_id': already_exist.id,
'cron_run_date': current_date, })
return True
@api.onchange('employee_id')
def _get_leaves_ids(self):
for item in self:
item.holiday_status_id = False
genders, emp_types, durations = ['both', ], ['all', ], ['all', ]
genders.append(item.employee_id.gender)
emp_types.append(item.employee_type)
domain = [('active', '=', True), ('gender', 'in', genders), ('emp_type', 'in', emp_types)]
if item.employee_id.contract_id.contract_description == 'permanent':
durations.append(item.employee_id.contract_id.contract_duration)
domain += [('contract_duration', 'in', durations)]
return {'domain': {'holiday_status_id': [('id', 'in', self.env['hr.holidays.status'].search(domain).ids)]}}
def draft_state(self):
for item in self:
item._remove_followers_holiday()
have_cancel_request = self.env['leave.cancellation'].search([('leave_request_id', '=', item.id),
('state', 'not in', ('draft', 'refuse'))])
have_return_from_leave = self.env['return.from.leave'].search(
[('leave_request_id', '=', item.id), ('state', 'not in', ('draft', 'refuse'))])
if have_cancel_request:
raise UserError(_("You can't set this request to draft as it's already have a cancel request"))
if have_return_from_leave:
raise UserError(_("You can't set this request to draft as it's already have a return from "
"leave request"))
Module = self.env['ir.module.module'].sudo()
modules_reconcile = Module.search([('state', '=', 'installed'), ('name', '=', 'exp_payroll_loans')])
if modules_reconcile:
have_reconcile_leaves = self.env['reconcile.leaves'].search(
[('yearly_vacation', '=', item.id), ('state', 'not in', ('draft', 'refuse'))])
if have_reconcile_leaves:
raise ValidationError(
_("You can't set this request to draft as it's already have Reconcile Holiday"))
if item.state == 'validate1':
item.reconcile_holiday_balance()
item.remove_delegated_access()
item.write({'state': 'draft','request_done':False})
item.call_cron_function()
self.check_allocation_balance_annual('addition')
# if item.state == 'validate1':
# self.reconcile_holiday_balance()
self.write({'state': 'draft'})
def confirm(self):
for item in self:
self._compute_leave_balance()
item._remove_followers_holiday()
## ticket allowance per year ###
if item.issuing_ticket == 'yes':
current_date = (datetime.utcnow() + timedelta(hours=3)).date()
if item.employee_id.contract_id.hiring_date:
employee_date = datetime.strptime(str(item.employee_id.contract_id.hiring_date), "%Y-%m-%d").date()
else:
employee_date = datetime.strptime(str(item.employee_id.contract_id.date_start), "%Y-%m-%d").date()
last_ticket = self.env['hr.ticket.request'].search(
[('employee_id', '=', item.employee_id.id), ('state', 'not in', ['draft', 'refuse'])],
order='id desc', limit=1)
if last_ticket:
last_ticket_date = datetime.strptime(str(last_ticket.request_date), "%Y-%m-%d").date()
dif2 = relativedelta.relativedelta(current_date, last_ticket_date)
dif_ticket_date = dif2.years * 12 + dif2.months
if dif_ticket_date < item.employee_id.contract_id.period_ticket:
raise UserError(_(
'Sorry The employee can not be given a ticket allowance until contractual year after the previous ticket'))
dif1 = relativedelta.relativedelta(current_date, employee_date)
dif_employee_date = dif1.years * 12 + dif1.months
if dif_employee_date < item.employee_id.contract_id.period_ticket and item.type == 'remove':
raise UserError(_(
'Sorry The employee can not be given a ticket allowance unless a contractual year has been established'))
if item.issuing_deliver_custdy == 'yes' and item.type == 'remove':
Module = self.env['ir.module.module'].sudo()
emp_modules = Module.search([('state', '=', 'installed'), ('name', '=', 'exp_employee_custody')])
petty_cash_modules = Module.search(
[('state', '=', 'installed'), ('name', '=', 'hr_expense_petty_cash')])
if emp_modules:
custody_ids = self.env['custom.employee.custody'].search(
[('employee_id', '=', item.employee_id.id),
('state', 'not in', ['done', 'refuse', 'draft'])]).ids
if custody_ids:
raise UserError(_(
'Sorry employee have custody he must deliver his custody to take this request'))
if petty_cash_modules:
payment_ids = self.env['petty.cash'].search(
[('partner_id', '=', self.employee_id.user_id.partner_id.id),
('state', 'in', ['submit', 'direct', 'fm', 'ceo', 'accepted', 'validate'])]).ids
if payment_ids:
raise UserError(_(
'Sorry employee have custody he must deliver his custody to take this request'))
if item.holiday_status_id.attach_chick == True and item.type == 'remove':
if item.attach_ids:
for rec in item.attach_ids:
if not rec.datas:
raise UserError(_('Attach the attachment to the Document %s') % (rec.name))
else:
raise UserError(_('Sorry This %s requires a Documents To Be Attached To Approve') % (
item.holiday_status_id.name))
self.set_date()
self._chick_leave_balance()
self._check_number_of_days()
self.write({'state': 'confirm'})
def hr_manager(self):
self._compute_leave_balance()
self._remove_followers_holiday()
if not self.replace_by and self.type == 'remove':
if self.holiday_status_id.alternative_chick == True and self.number_of_days_temp >= self.holiday_status_id.alternative_days:
raise UserError(_('Select employee Replacement before The approve holiday Request'))
if self.delegate_acc == True:
raise UserError(_('The replacement Employee Must be entered To Giving him Access'))
if self.holiday_status_id.attach_chick == True and self.type == 'remove':
if self.attach_ids:
for rec in self.attach_ids:
if not rec.datas:
raise UserError(_('Attach the attachment to the Document %s') % (rec.name))
else:
raise UserError(
_('Sorry This %s requires a Documents To Be Attached To Approve') % (self.holiday_status_id.name))
#The Approval For The Direct Manager only
for rec in self:
manager = rec.sudo().employee_id.parent_id
hr_manager = rec.sudo().employee_id.company_id.hr_manager_id
if manager:
if manager.user_id.id == rec.env.uid or hr_manager.user_id.id == rec.env.uid:
rec._chick_leave_balance()
rec.write({'state': 'validate'})
else:
raise UserError(_("Sorry, The Approval For The Direct Manager '%s' Only OR HR Manager!")%(rec.employee_id.parent_id.name))
else:
rec._chick_leave_balance()
rec.write({'state': 'validate'})
#self._chick_leave_balance()
#self.write({'state': 'validate'})
def approved(self):
self.check_sickness_leave_approval()
self._chick_leave_balance()
self.write({'state': 'approved'})
def financial_manager(self):
for item in self:
item._remove_followers_holiday()
if not item.replace_by and item.type == 'remove':
if item.holiday_status_id.alternative_chick == True and item.number_of_days_temp >= item.holiday_status_id.alternative_days:
raise UserError(_('Select employee Replacement before The approve holiday Request'))
if item.delegate_acc == True:
raise UserError(_('The replacement Employee Must be entered To Giving him Access'))
current_date = (datetime.utcnow() + timedelta(hours=3)).date()
employee_balance = self.env['hr.holidays'].search([('employee_id', '=', item.employee_id.id),
('holiday_status_id', '=', item.holiday_status_id.id),
('type', '=', 'add'),
('check_allocation_view', '=', 'balance')],
order='id desc', limit=1)
employee_allocation = self.env['hr.holidays'].search([('employee_id', '=', item.employee_id.id),
('holiday_status_id', '=', item.holiday_status_id.id),
('type', '=', 'add'),
('check_allocation_view', '=', 'allocation')],
order='id desc', limit=1)
if employee_balance:
if item.type == 'remove' and item.request_done==False:
holiday_days = item._chick_year_leavs_balance()
employee_balance.write({
'remaining_leaves': employee_balance.remaining_leaves - holiday_days,
'leaves_taken': employee_balance.leaves_taken + item.number_of_days_temp,
})
if item.issuing_ticket == 'yes':
self.env['hr.ticket.request'].create({
'employee_id': item.employee_id.id,
'leave_request_id': item.id,
'request_for': item.ticket_cash_request_for,
'request_type': item.ticket_cash_request_type.id,
# 'state':item.submit,
})
if item.issuing_exit_return == 'yes':
self.env['hr.exit.return'].create({
'employee_id': item.employee_id.id,
'leave_request_id': item.id,
'request_for': item.ticket_cash_request_for,
# 'state':item.request,
})
if item.issuing_clearance_form == 'yes':
self.env['hr.clearance.form'].create({
'employee_id': item.employee_id.id,
'leave_request_id': item.id,
'request_for': item.ticket_cash_request_for,
'clearance_type': 'vacation',
'date_deliver_work': item.date_from,
'date': current_date,
})
# self.env['hr.sick.leave'].create({
# 'leave_request': item.name,
# 'date_from': item.date_from,
# 'date_to':item.date_to,
# 'duration':item.number_of_days_temp,
# 'status':item.state,
# 'allocation_start_date':item.date_from,
# 'allocation_end_date':item.date_to,
# 'sick_relation':item.employee_id.id
#
# })
else:
employee_balance.write({
'name': 'Yearly Allocation of ' + item.holiday_status_id.name + ' Leaves',
'employee_id': item.employee_id.id,
'holiday_status_id': item.holiday_status_id.id,
'remaining_leaves': employee_balance.remaining_leaves + employee_allocation.number_of_days_temp,
'type': 'add',
})
else:
hr_holidays = self.env['hr.holidays'].create({
'name': 'Yearly Allocation of ' + item.holiday_status_id.name + ' Leaves',
'number_of_days_temp': employee_allocation.number_of_days_temp,
'employee_id': item.employee_id.id,
'holiday_status_id': item.holiday_status_id.id,
'remaining_leaves': employee_allocation.number_of_days_temp,
'check_allocation_view': 'balance',
'type': 'add',
})
self.env['hr.inverse.holidays'].create(
{'holiday_id': hr_holidays.id,
'cron_run_date': current_date, })
# if item.delegate_acc:
# item.delegate_access()
self._chick_leave_balance()
self.check_sickness_leave_approval()
self.write({'state': 'validate1','request_done': True})
self.send_email()
self.call_cron_function()
self.check_allocation_balance_annual('deduction')
def check_allocation_balance_annual(self, action):
if self.type == 'remove':
start_date = datetime.strptime(str(self.date_from), DEFAULT_SERVER_DATETIME_FORMAT)
end_date = datetime.strptime(str(self.date_to), DEFAULT_SERVER_DATETIME_FORMAT)
delta = timedelta(days=1)
if self.holiday_status_id.not_balance_annual_leave:
balance_holiday_id = self.env['hr.holidays'].search(
[('employee_id', '=', self.employee_id.id), ('type', '=', 'add'),
('holiday_status_id.leave_type', '=', 'annual'),
('check_allocation_view', '=', 'balance')
], order='id desc', limit=1)
while start_date <= end_date:
current_date = start_date.strftime("%Y-%m-%d")
remaining_leave_to_deduct = self.remaining_leaves_of_day_by_date(self.employee_id, current_date,
balance_holiday_id.holiday_status_id)
if action == 'deduction' and \
current_date in balance_holiday_id.holiday_ids.mapped('cron_run_date'):
balance_holiday_id.write({
'remaining_leaves': balance_holiday_id.remaining_leaves - float(remaining_leave_to_deduct)
})
balance_holiday_id.holiday_ids.filtered(lambda t: t.cron_run_date == current_date).unlink()
if action == 'addition' and \
current_date not in balance_holiday_id.holiday_ids.mapped('cron_run_date'):
balance_holiday_id.write({
'remaining_leaves': balance_holiday_id.remaining_leaves + float(remaining_leave_to_deduct)
})
self.env['hr.inverse.holidays'].create({'holiday_id': balance_holiday_id.id,
'cron_run_date': current_date, })
start_date += delta
return True
def send_email(self):
if self.replace_by:
template = self.sudo().env.ref('hr_holidays_public.email_template_employee_replace', False)
template.sudo().send_mail(self.id)
def check_sickness_leave_approval(self):
for leave in self:
if leave.type == 'remove' and leave.holiday_status_id.leave_type == 'sick':
emp_sickness = self.env['hr.holidays'].search([('employee_id', '=', self.employee_id.id),
('type', '=', 'remove'),
('state', 'not in', ('refuse', 'cancel', 'validate1')),
('holiday_status_id.leave_type', '=', 'sick'),
('holiday_status_id', '!=', self.holiday_status_id.id),
('holiday_status_id.sickness_severity', '<',
self.holiday_status_id.sickness_severity)]
)
if emp_sickness:
msg = ''
for sk in emp_sickness:
msg += sk.display_name + ' - ' + sk.date_from + '\n'
raise UserError(_('Sorry you can not approve this leave while following '
'leaves are not approved yet \n %s') % (msg))
def call_cron_function(self):
if self.date_from and self.date_to and self.type == 'remove':
transaction = self.env['hr.attendance.transaction'].sudo()
start_date = datetime.strptime(str(self.date_from), "%Y-%m-%d %H:%M:%S")
end_date = datetime.strptime(str(self.date_to), "%Y-%m-%d %H:%M:%S")
delta = end_date - start_date
today = datetime.now().date()
today = datetime.strptime(str(today), "%Y-%m-%d").date()
for i in range(delta.days + 1):
day = start_date + timedelta(days=i)
if today >= day.date():
transaction.process_attendance_scheduler_queue(day, self.employee_id)
def cancel(self):
for item in self:
have_cancel_request = self.env['leave.cancellation'].search(
[('leave_request_id', '=', item.id), ('state', 'not in', ('draft', 'refuse'))])
have_return_from_leave = self.env['return.from.leave'].search(
[('leave_request_id', '=', item.id), ('state', 'not in', ('draft', 'refuse'))])
if have_cancel_request:
raise UserError(
_("You can't set this request to draft as it's already have a cancel request\n" "Please contact with your administrator"))
if have_return_from_leave:
raise UserError(_(
"You can't set this request to draft as it's already have a return from leave request\n" "Please contact with your administrator"))
self._chick_leave_balance()
self.reconcile_holiday_balance()
self.remove_delegated_access()
self.write({'state': 'cancel'})
def _chick_year_leavs_balance(self):
"""chick a holiday take balance with years balance"""
for item in self:
holiday_days = item.number_of_days_temp
employee_balance = self.env['hr.holidays'].search([('employee_id', '=', item.employee_id.id),
('holiday_status_id', '=', item.holiday_status_id.id),
('type', '=', 'add'),
('check_allocation_view', '=', 'balance')],
order='id desc', limit=1)
leave_type = ['exam', 'marriage','parental','emergency','sick']
if item.holiday_status_id.leave_type in leave_type:
cron_run_date = item.employee_id.first_hiring_date
holi_date_from = fields.Date.from_string(item.date_from)
holi_date_to = fields.Date.from_string(item.date_to)
if employee_balance.holiday_ids:
cron_run_date = employee_balance.holiday_ids[-1].cron_run_date
if cron_run_date > holi_date_to:
holiday_days = 0
if holi_date_to >= cron_run_date > holi_date_from:
holiday_days = (holi_date_to - cron_run_date).days+1
return holiday_days
def reconcile_holiday_balance(self):
for holiday in self:
domain = [('check_allocation_view', '=', 'balance'),
('employee_id', '=', holiday.employee_id.id),
('holiday_status_id', '=', holiday.holiday_status_id.id),
('type', '=', 'add')]
balance = self.env['hr.holidays'].search(domain, order='id desc', limit=1)
domain[0] = ('check_allocation_view', '=', 'allocation')
allocation = self.env['hr.holidays'].search(domain, order='id desc', limit=1)
if balance:
if holiday.type == 'remove':
holiday_days = holiday._chick_year_leavs_balance()
balance.write({
'remaining_leaves': balance.remaining_leaves + holiday_days,
'leaves_taken': balance.leaves_taken - holiday.number_of_days_temp,
})
[self.env[model].search([('employee_id', '=', holiday.employee_id.id),
('leave_request_id', '=', holiday.id)]).unlink() \
for model in ['hr.ticket.request', 'hr.exit.return', 'hr.clearance.form']]
else:
balance.write({'remaining_leaves': balance.remaining_leaves - allocation.number_of_days_temp, })
def refuse(self):
for item in self:
item._remove_followers_holiday()
have_cancel_request = self.env['leave.cancellation'].search(
[('leave_request_id', '=', item.id), ('cancellation_type', '!=', 'cancel'), ('state', 'not in', ('draft', 'refuse'))])
have_return_from_leave = self.env['return.from.leave'].search(
[('leave_request_id', '=', item.id), ('state', 'not in', ('draft', 'refuse'))])
if have_cancel_request:
raise UserError(
_("You can't set this request to draft as it's already have a cancel request\n"
"Please contact with your administrator"))
if have_return_from_leave:
raise UserError(_(
"You can't set this request to draft as it's already have a return from leave request\n"
"Please contact with your administrator"))
Module = self.env['ir.module.module'].sudo()
modules_reconcile = Module.search([('state', '=', 'installed'), ('name', '=', 'exp_payroll_loans')])
if modules_reconcile:
have_reconcile_leaves = self.env['reconcile.leaves'].search(
[('yearly_vacation', '=', item.id), ('state', 'not in', ('draft', 'refuse'))])
if have_reconcile_leaves:
raise ValidationError(_("You can't set this request to draft"
" as it's already have Reconcile Holiday"))
if item.state == 'validate1':
item.reconcile_holiday_balance()
item.remove_delegated_access()
item.call_cron_function()
self.check_allocation_balance_annual('addition')
#Need Review
self.write({'request_done': False})
item.write({'state': 'refuse'})
def direct_manager_refused(self):
for rec in self:
manager = rec.sudo().employee_id.parent_id
hr_manager = rec.sudo().employee_id.company_id.hr_manager_id
if manager:
if manager.user_id.id == rec.env.uid or hr_manager.user_id.id == rec.env.uid:
rec.refuse()
else:
raise UserError(_("Sorry, The Refuse For The Direct Manager '%s' Only OR HR Manager!") % (manager.name))
else:
rec.refuse()
@api.onchange('holiday_status_id')
def _get_holiday_related_date(self):
for item in self:
if item.employee_id.first_hiring_date:
leaves_ids = self.env['hr.holidays'].search([('employee_id', '=', item.employee_id.id),
('state', '=', 'validate1'),
('type', '=', 'remove'),
('holiday_status_id.used_once', '=', True)])
for leave_id in leaves_ids:
if item.holiday_status_id == leave_id.holiday_status_id:
raise UserError(_('Sorry you used this type of leave before and it used for once'))
if item.holiday_status_id.exit_return_permission and item.employee_id.check_nationality == False:
item.issuing_exit_return = 'yes'
item.check_related = True
else:
item.issuing_exit_return = 'no'
item.check_related = False
if item.holiday_status_id.issuing_ticket and item.employee_id.check_nationality == False:
item.issuing_ticket = 'yes'
item.check_related = True
else:
item.issuing_ticket = 'no'
item.check_related = False
hiring_valu = datetime.strptime(str(self.employee_id.first_hiring_date), "%Y-%m-%d")
current_date = (datetime.utcnow() + timedelta(hours=3)).date()
different_years = relativedelta.relativedelta(current_date, hiring_valu).years
if not self.holiday_status_id:
self.check_unlimit = False
elif self.holiday_status_id.advance_request_years <= different_years:
self.check_unlimit = True
else:
self.check_unlimit = False
if item.holiday_status_id.issuing_clearance_form:
item.issuing_clearance_form = 'yes'
else:
item.issuing_clearance_form = 'no'
if item.holiday_status_id.issuing_deliver_custody:
item.issuing_deliver_custdy = 'yes'
else:
item.issuing_deliver_custdy = 'no'
if item.holiday_status_id.include_weekend and item.date_to: self.include_weekend()
def _check_state_access_right(self, vals):
"""
override the function to allow division manager to confirm employee's holiday.
"""
if vals.get('state') and vals['state'] not in ['draft', 'confirm', 'cancel'] \
and not ((self.env.user and self.env.user.has_group('hr_holidays_community.group_hr_holidays_user')) or
(self.env.user and self.env.user.has_group('hr_base.group_division_manager'))):
return False
return True
def get_user_id(self):
employee_id = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
if employee_id:
return employee_id.id
else:
return False
@api.model
def _get_employee_domain(self):
if self.env.user.id != SUPERUSER_ID:
employee_id = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1).ids
if employee_id:
return [('id', 'in', employee_id)]
else:
return [('id', 'in', [])]
else:
employee_id = self.env['hr.employee']
if employee_id:
return employee_id.id
else:
return False
@api.onchange('employee_id')
def _onchange_employee(self):
self.department_id = self.employee_id.department_id
self.emp_id = self.employee_id.id
def unlink(self):
for i in self:
if i.state != 'draft':
raise UserError(_('You can not delete record in state not in draft'))
if i.check_allocation_view == 'balance' and i.leaves_taken > 0:
raise UserError(_('You can not delete Balance records and there is leave taken'))
return super(HRHolidays, self).unlink()
def _get_number_of_days(self, date_from, date_to, employee_id, official_event=True, working_days=False):
""" Returns a float equals to the timedelta between two dates given as string."""
from_dt = fields.Datetime.from_string(date_from)
to_dt = fields.Datetime.from_string(date_to)
if not employee_id: return 0.0
employee = self.env['hr.employee'].browse(employee_id)
# if not employee.is_calender:
# return employee.get_work_days_count(from_dt, fields.Datetime.from_string(date_to) + timedelta(hours=23))
time_delta = to_dt - from_dt
time_delta = math.ceil(time_delta.days + 1 + float(time_delta.seconds) / 86400)
if not official_event or working_days:
hlist = []
for i in range((to_dt - from_dt).days + 1): hlist.append(from_dt.date() + timedelta(days=i))
if official_event is False:
# dont count official holidays in the holiday
dlist = []
for event in self.env['hr.holiday.officials'].search([('active', '=', True), ('state', '=', 'confirm'),
('date_from', '<=', date_to),
('date_to', '>=', date_from)]):
if event.religion and employee_id and employee.religion != event.religion: continue
edate_from = datetime.strptime(str(event.date_from), '%Y-%m-%d').date()
dlt = datetime.strptime(str(event.date_to), '%Y-%m-%d').date() - edate_from
for i in range(dlt.days + 1): dlist.append(edate_from + timedelta(days=i))
time_delta = len(list(set(hlist) - set(dlist)))
self.official_holiday_days = len([rec for rec in dlist if rec >= from_dt.date() and rec <= to_dt.date()])
if working_days:
wkends = employee.resource_calendar_id.full_day_off or employee.resource_calendar_id.shift_day_off
wknd_days = [d.name.lower() for d in wkends]
rlist = official_event is False and dlist and list(set(hlist) - set(dlist)) or hlist
for dt in rlist:
if dt.strftime('%A').lower() in wknd_days: time_delta -= 1
return time_delta
def set_date(self):
for item in self:
if item.date_from and item.date_to:
current_date = (datetime.utcnow() + timedelta(hours=3))
date_from_value = datetime.strptime(str(item.date_from), "%Y-%m-%d %H:%M:%S")
date_to_value = datetime.strptime(str(item.date_to), "%Y-%m-%d %H:%M:%S")
user = self.env.user
# Check if user is **NOT** in the HR group
# self.env.user.has_group(
if date_to_value < date_from_value:
raise UserError(_('Sorry Date TO must be bigger than Date From'))
if not self.env.user.has_group("hr.group_hr_user"):
if (date_from_value - current_date).days + 1 < item.holiday_status_id.request_before:
raise UserError(_('Sorry your request must be before %s Days of your leave') \
% item.holiday_status_id.request_before)
# if date_to_value < date_from_value:
# raise UserError(_('Sorry Date TO must be bigger than Date From'))
# if (date_from_value - current_date).days + 1 < item.holiday_status_id.request_before:
# raise UserError(_('Sorry your request must be before %s Days of your leave') \
# % item.holiday_status_id.request_before)
self.number_of_days_temp = self._get_number_of_days(item.date_from, item.date_to, self.employee_id.id,
self.holiday_status_id.official_holidays,
self.holiday_status_id.working_days)
if item.number_of_days_temp < item.holiday_status_id.minimum_duration:
raise UserError(_('Sorry duration must be bigger than or equal to %s Days') \
% item.holiday_status_id.minimum_duration)
@api.onchange('date_from')
def _onchange_date_from(self):
if self.date_from:
self.date_from = fields.Datetime.from_string(self.date_from).replace(hour=0, minute=0, second=0,
microsecond=0)
if self.holiday_status_id.include_weekend:
self.include_weekend()
self.date_on = True
self.set_date()
@api.onchange('date_from')
def _onchange_date_from_2(self):
if self.date_to:
self.date_to = False
self.number_of_days_temp = False
@api.onchange('date_to')
def _onchange_date_to(self):
""" Update the number_of_days. """
if self.date_to:
self.date_to = fields.Datetime.from_string(self.date_to).replace(hour=0, minute=0, second=0, microsecond=0)
self.date_on = True
self.set_date()
@api.onchange('number_of_days_temp')
def _get_end_date(self, context=None):
if self.date_on:
self.date_on = False
return
for item in self:
if item.number_of_days_temp:
if item.date_from:
self.date_to = (datetime.strptime(str(item.date_from), "%Y-%m-%d %H:%M:%S") +
dt.timedelta(days=item.number_of_days_temp - 1))
self.set_date()
if item.number_of_days_temp < item.holiday_status_id.minimum_duration:
raise UserError(_(
'Sorry duration must be bigger than or equal to %s Days') % item.holiday_status_id.minimum_duration)
@api.constrains('date_from')
def _check_include_weekend(self):
if self.holiday_status_id.include_weekend:
prev_holiday = self.env['hr.holidays'].search([('employee_id', '=', self.employee_id.id),
('holiday_status_id', '=', self.holiday_status_id.id),
('date_to', '<', self.date_from),
('type', '=', 'remove'),
('state', '!=', 'refuse')], limit=1, order="date_to desc")
if not prev_holiday: return
if not self.date_from : return
date_from, last_dt_to = fields.Date.from_string(self.date_from), fields.Date.from_string(prev_holiday.date_to)
days_btwn = (date_from - last_dt_to).days - 1
if days_btwn < 1: return
count, dates_btwn, wknd_days = 0, [], [d.name.lower() for d in
self.employee_id.resource_calendar_id.full_day_off]
for r in range(days_btwn): dates_btwn.append(date_from + relativedelta.relativedelta(days=-(r + 1)))
if days_btwn > len(wknd_days) or dates_btwn[0].strftime('%A').lower() not in wknd_days: return
for dt in dates_btwn:
if dt.strftime('%A').lower() in wknd_days: count += 1
if count == days_btwn:
raise UserError(_('Sorry, it is not possible to request a leave at the beginning of the week, as there is a leave before it that ends at the end of the week, and the leave includes the holiday.'))
def include_weekend(self):
prev_holiday = self.env['hr.holidays'].search([('employee_id', '=', self.employee_id.id),
('holiday_status_id', '=', self.holiday_status_id.id),
('type', '=', 'remove'),
('state', '!=', 'refuse')], limit=1, order="date_to desc")
if not prev_holiday: return
if not self.date_from : return
date_from, last_dt_to = fields.Date.from_string(self.date_from), fields.Date.from_string(prev_holiday.date_to)
days_btwn = (date_from - last_dt_to).days - 1
if days_btwn < 1: return
count, dates_btwn, wknd_days = 0, [], [d.name.lower() for d in
self.employee_id.resource_calendar_id.full_day_off]
for r in range(days_btwn): dates_btwn.append(date_from + relativedelta.relativedelta(days=-(r + 1)))
if days_btwn > len(wknd_days) or dates_btwn[0].strftime('%A').lower() not in wknd_days: return
for dt in dates_btwn:
if dt.strftime('%A').lower() in wknd_days: count += 1
if count == days_btwn: self.date_from = date_from + relativedelta.relativedelta(days=-count)
def delegate_access(self):
for rec in self:
if not rec.employee_id.user_id: raise UserError(
_('Kindly set a user for employee %s') % (rec.employee_id.name))
if not rec.replace_by.user_id: raise UserError(
_('Kindly set a user or employee for replace by %s') % (rec.replace_by.name))
group_ids = list(
set(rec.employee_id.user_id.groups_id.ids) - set(rec.sudo().replace_by.user_id.groups_id.ids))
rec.replace_by.user_id.sudo().write({'groups_id': [(4, g) for g in group_ids]})
rec.sudo().write({'delegated_group_ids': [fields.Command.set(group_ids)], })
allowed_comp = set(rec.employee_id.user_id.company_ids.ids) - set(
rec.sudo().replace_by.user_id.company_ids.ids)
# if allowed_comp:
rec.replace_by.user_id.sudo().write({'company_ids': [(4, c) for c in allowed_comp]})
rec.delegated_company_ids = [fields.Command.set(list(allowed_comp))]
dept_ids = rec.employee_id.department_id.search(
[('manager_id', '=', rec.employee_id.id), ('active', '=', True)])
for d in dept_ids: d.sudo().write({'manager_id': rec.replace_by.id, }, )
rec.delegated_department_ids = [fields.Command.set(dept_ids.ids)]
def remove_delegated_access(self):
for rec in self:
groups, companies = rec.delegated_group_ids.ids, rec.delegated_company_ids.ids
departments, manager, holiday = rec.delegated_department_ids.ids, rec.employee_id.id, rec
while (holiday):
rec.remove_access(holiday, groups, companies, departments, manager)
holiday = holiday.search([('employee_id', '=', holiday.replace_by.id), ('type', '=', 'remove'),
('date_from', '<=', fields.Date.today()),
('date_to', '>=', fields.Date.today()),
('state', '=', 'validate1')])
def remove_access(self, holiday, groups, companies, departments, manager):
if set(holiday.delegated_group_ids.ids) & set(groups):
holiday.replace_by.user_id.sudo().write({'groups_id': [(3, g) for g in groups]})
holiday.delegated_group_ids = [(3, g) for g in groups]
if set(holiday.delegated_department_ids.ids) & set(departments):
for d in holiday.department_id.search([('id', 'in', departments)]): d.sudo().write(
{'manager_id': manager, }, )
holiday.delegated_department_ids = [(3, d) for d in departments]
if set(holiday.delegated_company_ids.ids) & set(companies):
holiday.replace_by.user_id.sudo().write({'company_ids': [(3, c) for c in companies]})
holiday.delegated_company_ids = [(3, c) for c in companies]
def _process_delegation_access(self):
"""cron for Handling Delegation Access Process"""
holiday = self.env['hr.holidays']
start_day_holiday = holiday.search([('delegate_acc', '=', True),
('date_from', '=', fields.Date.today()),
('state', '=', 'validate1')])
end_day_holiday = holiday.search([('delegate_acc', '=', True),
('date_to', '=', fields.Date.today()),
('state', '=', 'validate1')])
if start_day_holiday:
start_day_holiday.delegate_access()
if end_day_holiday:
end_day_holiday.remove_delegated_access()
class HRINVERSHolidays(models.Model):
_name = 'hr.inverse.holidays'
_description = 'Inverse Holidays'
holiday_id = fields.Many2one(comodel_name='hr.holidays')
cron_run_date = fields.Date()
balance_leaves = fields.Float(string='Balance')
no_balance_leaves = fields.Float(string='No Balance')
class holidaysAttach(models.Model):
_inherit = 'ir.attachment'
att_holiday_ids = fields.Many2one(comodel_name='hr.holidays')
@api.onchange('att_holiday_ids')
def _onchange_att_holiday_ids(self):
if self.att_holiday_ids:
self.res_model = self.att_holiday_ids._name
self.res_id = self.att_holiday_ids.id
@api.model
def check(self, mode, values=None):
"""Restricts the access to an ir.attachment, according to referred model
In the 'document' module, it is overriden to relax this hard rule, since
more complex ones apply there.
"""
# collect the records to check (by model)
model_ids = defaultdict(set) # {model_name: set(ids)}
require_employee = False
if self:
self._cr.execute('SELECT res_model, res_id, create_uid, public FROM ir_attachment WHERE id IN %s', [tuple(self.ids)])
for res_model, res_id, create_uid, public in self._cr.fetchall():
if public and mode == 'read':
continue
if not (res_model and res_id):
if create_uid != self._uid:
require_employee = True
continue
model_ids[res_model].add(res_id)
if values and values.get('res_model') and values.get('res_id'):
model_ids[values['res_model']].add(values['res_id'])
# check access rights on the records
for res_model, res_ids in model_ids.items():
# ignore attachments that are not attached to a resource anymore
# when checking access rights (resource was deleted but attachment
# was not)
if res_model not in self.env:
require_employee = True
continue
elif res_model == 'res.users' and len(res_ids) == 1 and self._uid == list(res_ids)[0]:
# by default a user cannot write on itself, despite the list of writeable fields
# e.g. in the case of a user inserting an image into his image signature
# we need to bypass this check which would needlessly throw us away
continue
records = self.env[res_model].browse(res_ids).exists()
if len(records) < len(res_ids):
require_employee = True
# For related models, check if we can write to the model, as unlinking
# and creating attachments can be seen as an update to the model
records.check_access('write' if mode in ('create', 'unlink') else mode)
records.check_access(mode)
if require_employee:
if not (self.env.user._is_admin() or self.env.user.has_group('base.group_user') or self._context.get('bypass_check_public_holidays', False)):
raise AccessError(_("Sorry, you are not allowed to access this document."))
# @api.model
# def create(self, values):
# print("**********************************************create")
# result = super(holidaysAttach, self).create(values)
# print("**********************************************result",result)
# if result.att_holiday_ids:
# result.update({
# 'res_model': result.att_holiday_ids._name,
# 'res_id': result.att_holiday_ids.id
# })
# return result