from logging import exception from odoo import api, models, _, fields from odoo.exceptions import ValidationError from odoo.tools.misc import format_date from datetime import datetime class HRLeave(models.Model): _inherit = "hr.leave" def flutter_check_overlap_constrain(self,employee_id, to_date, from_date, fetched_leave_id=None): if self.env.context.get('leave_skip_date_check', False): return date_from = datetime.fromisoformat(from_date).replace(hour=0, minute=0, second=0) date_to = datetime.fromisoformat(to_date).replace(hour=23, minute=59, second=59) employee_id = int(employee_id) all_leaves = self.search([ ('date_from', '<', date_to), ('date_to', '>', date_from), ('employee_id', 'in', [employee_id]), ('state', 'not in', ['cancel', 'refuse']), ]) domain = [ ('employee_id', '=', employee_id), ('date_from', '<', date_to), ('date_to', '>', date_from), ('state', 'not in', ['cancel', 'refuse']), ] if fetched_leave_id and fetched_leave_id > 0: all_leaves = self.search([ ('date_from', '<', date_to), ('date_to', '>', date_from), ('employee_id', 'in', [employee_id]), ('id','!=', fetched_leave_id), ('state', 'not in', ['cancel', 'refuse']), ]) domain = [ ('employee_id', '=', employee_id), ('date_from', '<', date_to), ('date_to', '>', date_from), ('id', '!=', fetched_leave_id), ('state', 'not in', ['cancel', 'refuse']), ] conflicting_holidays = all_leaves.filtered_domain(domain) if conflicting_holidays: conflicting_holidays_list = [] # Do not display the name of the employee if the conflicting holidays have an employee_id.user_id equivalent to the user id holidays_only_have_uid = bool(employee_id) holiday_states = dict(conflicting_holidays.fields_get(allfields=['state'])['state']['selection']) for conflicting_holiday in conflicting_holidays: conflicting_holiday_data = {} conflicting_holiday_data['employee_name'] = conflicting_holiday.employee_id.name conflicting_holiday_data['date_from'] = format_date(self.env, min(conflicting_holiday.mapped('date_from'))) conflicting_holiday_data['date_to'] = format_date(self.env, min(conflicting_holiday.mapped('date_to'))) conflicting_holiday_data['state'] = holiday_states[conflicting_holiday.state] if conflicting_holiday.employee_id.user_id.id != self.env.uid: holidays_only_have_uid = False if conflicting_holiday_data not in conflicting_holidays_list: conflicting_holidays_list.append(conflicting_holiday_data) if not conflicting_holidays_list: return conflicting_holidays_strings = [] if holidays_only_have_uid: for conflicting_holiday_data in conflicting_holidays_list: conflicting_holidays_string = _('from %(date_from)s to %(date_to)s - %(state)s', date_from=conflicting_holiday_data['date_from'], date_to=conflicting_holiday_data['date_to'], state=conflicting_holiday_data['state']) conflicting_holidays_strings.append(conflicting_holidays_string) error = """\ You've already booked time off which overlaps with this period: %s Attempting to double-book your time off won't magically make your vacation 2x better! """.join(conflicting_holidays_strings) return error for conflicting_holiday_data in conflicting_holidays_list: conflicting_holidays_string = "\n" + _( '%(employee_name)s - from %(date_from)s to %(date_to)s - %(state)s', employee_name=conflicting_holiday_data['employee_name'], date_from=conflicting_holiday_data['date_from'], date_to=conflicting_holiday_data['date_to'], state=conflicting_holiday_data['state']) conflicting_holidays_strings.append(conflicting_holidays_string) error = "An employee already booked time off which overlaps with this period:%s","".join(conflicting_holidays_strings) return error @api.model def calculate_leave_duration(self, date_from, date_to, employee_id): """ Calculate the number of days and hours for the given date range and employee. """ employee = self.env['hr.employee'].browse(employee_id) if not employee: return {'error': 'Employee not found'} from_date = datetime.fromisoformat(date_from).replace(hour=0, minute=0, second=0) to_date = datetime.fromisoformat(date_to).replace(hour=23, minute=59, second=59) # Define a fake leave record to use _get_durations leave_values = { 'employee_id': employee.id, 'date_from': fields.Datetime.from_string(from_date), 'date_to': fields.Datetime.from_string(to_date), 'holiday_status_id': self.env['hr.leave.type'].search([], limit=1).id, # Replace with appropriate leave type ID 'resource_calendar_id': employee.resource_calendar_id.id, } leave = self.new(leave_values) durations = leave._get_durations() leave_id = list(durations.keys())[0] days, hours = durations[leave_id] return { 'days': float(days), 'hours': float(hours), } @api.model def submit_leave_flutter_odoo(self,leave_request_data, existing_leave_id = None): try: date_from = datetime.fromisoformat(leave_request_data['date_from']).replace(hour=0, minute=0, second=0) date_to = datetime.fromisoformat(leave_request_data['date_to']).replace(hour=23, minute=59, second=59) if existing_leave_id and existing_leave_id > 0: leave_id = self.env['hr.leave'].sudo().browse(existing_leave_id) else: leave_id = False if leave_id: leave_id.sudo().write({ 'employee_id': leave_request_data['employee_id'], 'holiday_status_id': leave_request_data['holiday_status_id'], 'request_date_from': date_from.date(), 'request_date_to':date_to.date(), 'name': leave_request_data['description'], 'request_unit_half': leave_request_data['is_half_day'], 'request_date_from_period': 'pm' if leave_request_data['half_day_option'] == 'afternoon' else 'am', }) leave = leave_id else: leave = self.env['hr.leave'].sudo().create({ 'employee_id': leave_request_data['employee_id'], 'holiday_status_id': leave_request_data['holiday_status_id'], 'request_date_from': date_from.date(), 'request_date_to':date_to.date(), 'name':leave_request_data['description'], 'request_unit_half': leave_request_data['is_half_day'], 'request_date_from_period': 'pm' if leave_request_data['half_day_option'] == 'afternoon' else 'am', }) attachment_ids = [] for attachment in leave_request_data['attachments']: attachment_record = self.env['ir.attachment'].create({ 'name': attachment['name'], # Attachment name 'datas': attachment['datas'], # Base64 encoded data 'res_model': 'hr.leave', # Model to link 'res_id': leave.id, # ID of the leave record }) attachment_ids.append(attachment_record.id) # Link the attachments to the leave record if attachment_ids: leave.supported_attachment_ids = [(6, 0, attachment_ids)] leave._check_validity() leave.state = 'confirm' return {'status': 'success', 'leave_id': leave.id, 'message': ''} except Exception as e: return {'status': 'error','leave_id': '', 'message': str(e)}