|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors |
| 3 | +# For license information, please see license.txt |
| 4 | + |
| 5 | +from __future__ import unicode_literals |
| 6 | +import frappe |
| 7 | +from frappe import _ |
| 8 | +from frappe.utils import date_diff, add_days, getdate, cint, format_date |
| 9 | +from frappe.model.document import Document |
| 10 | +from erpnext.hr.utils import validate_dates, validate_overlap, get_leave_period, validate_active_employee, \ |
| 11 | + create_additional_leave_ledger_entry, get_holiday_dates_for_employee |
| 12 | + |
| 13 | +class CompensatoryLeaveRequest(Document): |
| 14 | + |
| 15 | + def validate(self): |
| 16 | + validate_active_employee(self.employee) |
| 17 | + validate_dates(self, self.work_from_date, self.work_end_date) |
| 18 | + if self.half_day: |
| 19 | + if not self.half_day_date: |
| 20 | + frappe.throw(_("Half Day Date is mandatory")) |
| 21 | + if not getdate(self.work_from_date)<=getdate(self.half_day_date)<=getdate(self.work_end_date): |
| 22 | + frappe.throw(_("Half Day Date should be in between Work From Date and Work End Date")) |
| 23 | + validate_overlap(self, self.work_from_date, self.work_end_date) |
| 24 | + self.validate_holidays() |
| 25 | + self.validate_attendance() |
| 26 | + if not self.leave_type: |
| 27 | + frappe.throw(_("Leave Type is madatory")) |
| 28 | + |
| 29 | + def validate_attendance(self): |
| 30 | + attendance = frappe.get_all('Attendance', |
| 31 | + filters={ |
| 32 | + 'attendance_date': ['between', (self.work_from_date, self.work_end_date)], |
| 33 | + 'status': 'Present', |
| 34 | + 'docstatus': 1, |
| 35 | + 'employee': self.employee |
| 36 | + }, fields=['attendance_date', 'status']) |
| 37 | + |
| 38 | + if len(attendance) < date_diff(self.work_end_date, self.work_from_date) + 1: |
| 39 | + frappe.throw(_("You are not present all day(s) between compensatory leave request days")) |
| 40 | + |
| 41 | + def validate_holidays(self): |
| 42 | + holidays = get_holiday_dates_for_employee(self.employee, self.work_from_date, self.work_end_date) |
| 43 | + if len(holidays) < date_diff(self.work_end_date, self.work_from_date) + 1: |
| 44 | + if date_diff(self.work_end_date, self.work_from_date): |
| 45 | + msg = _("The days between {0} to {1} are not valid holidays.").format(frappe.bold(format_date(self.work_from_date)), frappe.bold(format_date(self.work_end_date))) |
| 46 | + else: |
| 47 | + msg = _("{0} is not a holiday.").format(frappe.bold(format_date(self.work_from_date))) |
| 48 | + |
| 49 | + frappe.throw(msg) |
| 50 | + |
| 51 | + def on_submit(self): |
| 52 | + company = frappe.db.get_value("Employee", self.employee, "company") |
| 53 | + date_difference = date_diff(self.work_end_date, self.work_from_date) + 1 |
| 54 | + if self.half_day: |
| 55 | + date_difference -= 0.5 |
| 56 | + leave_period = get_leave_period(self.work_from_date, self.work_end_date, company) |
| 57 | + if leave_period: |
| 58 | + leave_allocation = self.get_existing_allocation_for_period(leave_period) |
| 59 | + if leave_allocation: |
| 60 | + leave_allocation.new_leaves_allocated += date_difference |
| 61 | + leave_allocation.validate() |
| 62 | + leave_allocation.db_set("new_leaves_allocated", leave_allocation.total_leaves_allocated) |
| 63 | + leave_allocation.db_set("total_leaves_allocated", leave_allocation.total_leaves_allocated) |
| 64 | + |
| 65 | + # generate additional ledger entry for the new compensatory leaves off |
| 66 | + create_additional_leave_ledger_entry(leave_allocation, date_difference, add_days(self.work_end_date, 1)) |
| 67 | + |
| 68 | + else: |
| 69 | + leave_allocation = self.create_leave_allocation(leave_period, date_difference) |
| 70 | + self.db_set("leave_allocation", leave_allocation.name) |
| 71 | + else: |
| 72 | + frappe.throw(_("There is no leave period in between {0} and {1}").format(format_date(self.work_from_date), format_date(self.work_end_date))) |
| 73 | + |
| 74 | + def on_cancel(self): |
| 75 | + if self.leave_allocation: |
| 76 | + date_difference = date_diff(self.work_end_date, self.work_from_date) + 1 |
| 77 | + if self.half_day: |
| 78 | + date_difference -= 0.5 |
| 79 | + leave_allocation = frappe.get_doc("Leave Allocation", self.leave_allocation) |
| 80 | + if leave_allocation: |
| 81 | + leave_allocation.new_leaves_allocated -= date_difference |
| 82 | + if leave_allocation.new_leaves_allocated - date_difference <= 0: |
| 83 | + leave_allocation.new_leaves_allocated = 0 |
| 84 | + leave_allocation.validate() |
| 85 | + leave_allocation.db_set("new_leaves_allocated", leave_allocation.total_leaves_allocated) |
| 86 | + leave_allocation.db_set("total_leaves_allocated", leave_allocation.total_leaves_allocated) |
| 87 | + |
| 88 | + # create reverse entry on cancelation |
| 89 | + create_additional_leave_ledger_entry(leave_allocation, date_difference * -1, add_days(self.work_end_date, 1)) |
| 90 | + |
| 91 | + def get_existing_allocation_for_period(self, leave_period): |
| 92 | + leave_allocation = frappe.db.sql(""" |
| 93 | + select name |
| 94 | + from `tabLeave Allocation` |
| 95 | + where employee=%(employee)s and leave_type=%(leave_type)s |
| 96 | + and docstatus=1 |
| 97 | + and (from_date between %(from_date)s and %(to_date)s |
| 98 | + or to_date between %(from_date)s and %(to_date)s |
| 99 | + or (from_date < %(from_date)s and to_date > %(to_date)s)) |
| 100 | + """, { |
| 101 | + "from_date": leave_period[0].from_date, |
| 102 | + "to_date": leave_period[0].to_date, |
| 103 | + "employee": self.employee, |
| 104 | + "leave_type": self.leave_type |
| 105 | + }, as_dict=1) |
| 106 | + |
| 107 | + if leave_allocation: |
| 108 | + return frappe.get_doc("Leave Allocation", leave_allocation[0].name) |
| 109 | + else: |
| 110 | + return False |
| 111 | + |
| 112 | + def create_leave_allocation(self, leave_period, date_difference): |
| 113 | + is_carry_forward = frappe.db.get_value("Leave Type", self.leave_type, "is_carry_forward") |
| 114 | + allocation = frappe.get_doc(dict( |
| 115 | + doctype="Leave Allocation", |
| 116 | + employee=self.employee, |
| 117 | + employee_name=self.employee_name, |
| 118 | + leave_type=self.leave_type, |
| 119 | + from_date=add_days(self.work_end_date, 1), |
| 120 | + to_date=leave_period[0].to_date, |
| 121 | + carry_forward=cint(is_carry_forward), |
| 122 | + new_leaves_allocated=date_difference, |
| 123 | + total_leaves_allocated=date_difference, |
| 124 | + description=self.reason |
| 125 | + )) |
| 126 | + allocation.insert(ignore_permissions=True) |
| 127 | + allocation.submit() |
| 128 | + return allocation |
0 commit comments