diff --git a/.env.dist b/.env.dist
index 8684675c0..4a81c9751 100644
--- a/.env.dist
+++ b/.env.dist
@@ -39,4 +39,4 @@ DB_PORT=5432
# Microsoft SQL Server: ``mssql://``
# PyODBC: ``pyodbc://``
# Amazon Redshift: ``redshift://``
-# LDAP: ``ldap://``
+# LDAP: ``ldap://``
\ No newline at end of file
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 61ef1fd91..8483e624d 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -36,4 +36,4 @@ services:
retries: 5
volumes:
- horilla-data:
+ horilla-data:
\ No newline at end of file
diff --git a/employee/forms.py b/employee/forms.py
index 9f851c9a5..23d20d8d1 100644
--- a/employee/forms.py
+++ b/employee/forms.py
@@ -285,6 +285,7 @@ class Meta:
"email",
"mobile",
"date_joining",
+ "anniversary_date",
"contract_end_date",
"tags",
"basic_salary",
@@ -295,6 +296,7 @@ class Meta:
widgets = {
"date_joining": DateInput(attrs={"type": "date"}),
"contract_end_date": DateInput(attrs={"type": "date"}),
+ "anniversary_date": DateInput(attrs={"type": "date", "class": "oh-input w-100", "placeholder": _("Select Anniversary Date"),}),
}
def __init__(self, *args, disable=False, **kwargs):
diff --git a/employee/models.py b/employee/models.py
index 0ce216d71..d66d10d85 100644
--- a/employee/models.py
+++ b/employee/models.py
@@ -638,6 +638,12 @@ class EmployeeWorkInformation(models.Model):
)
additional_info = models.JSONField(null=True, blank=True)
experience = models.FloatField(null=True, blank=True, default=0)
+ anniversary_date = models.DateField(
+ null=True,
+ blank=True,
+ verbose_name=_("Anniversary Date"),
+ help_text=_("Date used for anniversary-based leave resets")
+ )
history = HorillaAuditLog(
related_name="history_set",
bases=[
@@ -684,6 +690,25 @@ def experience_calculator(self):
self.save()
return self
+ def clean(self):
+ super().clean()
+ if self.anniversary_date:
+ # Ensure anniversary date isn't in the future
+ if self.anniversary_date > timezone.now().date():
+ raise ValidationError({
+ 'anniversary_date': _('Anniversary date cannot be in the future')
+ })
+
+ # Check if employee has anniversary-based leave types
+ has_anniversary_leaves = self.employee_id.available_leave.filter(
+ leave_type_id__reset_based='anniversary'
+ ).exists()
+
+ if has_anniversary_leaves and not self.anniversary_date:
+ raise ValidationError({
+ 'anniversary_date': _('Anniversary date is required for employees with anniversary-based leave types')
+ })
+
class EmployeeBankDetails(HorillaModel):
"""
diff --git a/employee/templates/employee/profile/work_info.html b/employee/templates/employee/profile/work_info.html
index 236f0abac..27ef13c28 100644
--- a/employee/templates/employee/profile/work_info.html
+++ b/employee/templates/employee/profile/work_info.html
@@ -99,7 +99,13 @@
-
+
+
+
+
+ {{work_form.anniversary_date}}
+
+
diff --git a/employee/templates/tabs/personal_tab.html b/employee/templates/tabs/personal_tab.html
index 9d46ddca8..28d4e74aa 100644
--- a/employee/templates/tabs/personal_tab.html
+++ b/employee/templates/tabs/personal_tab.html
@@ -264,6 +264,20 @@
class="oh-profile__info-value dateformat_changer">{{employee.employee_work_info.date_joining|default:_("None")}}
+
+
+
+ {% trans "Anniversary Date" %}
+
+ {% if employee.employee_work_info.anniversary_date %}
+ {{ employee.employee_work_info.anniversary_date }}
+ {% else %}
+ {% trans "None" %}
+ {% endif %}
+
+
+
@@ -273,9 +287,13 @@
{% if employee.employee_work_info.tags.all %}
{% for i in employee.employee_work_info.tags.all %}
{% with tag_width=i.title|length %}
- {{ i.title }}
+
+ {{ i.title }}
+
{% endwith %}
{% endfor %}
{% else %}
diff --git a/entrypoint.sh b/entrypoint.sh
old mode 100644
new mode 100755
index d063e8bbf..c744ee402
--- a/entrypoint.sh
+++ b/entrypoint.sh
@@ -5,4 +5,4 @@ python3 manage.py makemigrations
python3 manage.py migrate
python3 manage.py collectstatic --noinput
python3 manage.py createhorillauser --first_name admin --last_name admin --username admin --password admin --email admin@example.com --phone 1234567890
-gunicorn --bind 0.0.0.0:8000 horilla.wsgi:application
+gunicorn --bind 0.0.0.0:8000 horilla.wsgi:application
\ No newline at end of file
diff --git a/horilla/settings.py b/horilla/settings.py
index 93958c92a..05fde70d5 100755
--- a/horilla/settings.py
+++ b/horilla/settings.py
@@ -222,14 +222,14 @@
LANGUAGE_CODE = "en-us"
+# Timezone settings
TIME_ZONE = env("TIME_ZONE", default="Asia/Kolkata")
+USE_TZ = True
USE_I18N = True
USE_L10N = True
-USE_TZ = True
-
# Production settings
if not DEBUG:
SECURE_BROWSER_XSS_FILTER = True
diff --git a/leave/forms.py b/leave/forms.py
index ef6abfc60..6c8b698f9 100644
--- a/leave/forms.py
+++ b/leave/forms.py
@@ -201,6 +201,17 @@ def clean(self):
cleaned_data["reset_month"] = "1"
cleaned_data["reset_day"] = "1"
+ reset = cleaned_data.get('reset')
+ reset_based = cleaned_data.get('reset_based')
+ reset_month = cleaned_data.get('reset_month')
+ reset_day = cleaned_data.get('reset_day')
+
+ if reset and reset_based != 'anniversary':
+ if not reset_month:
+ raise ValidationError(_('Reset month is required when reset is enabled'))
+ if not reset_day:
+ raise ValidationError(_('Reset day is required when reset is enabled'))
+
return cleaned_data
def save(self, *args, **kwargs):
@@ -388,7 +399,7 @@ def clean(self):
if f"{today.month}-{today.year}" in unique_dates:
unique_dates.remove(f"{today.strftime('%m')}-{today.year}")
- forcated_days = available_leave.forcasted_leaves(start_date)
+ forcasted_days = available_leave.forcasted_leaves(start_date)
total_leave_days = (
available_leave.leave_type_id.carryforward_max
if available_leave.leave_type_id.carryforward_type
@@ -401,7 +412,7 @@ def clean(self):
and available_leave.carryforward_days
):
total_leave_days = total_leave_days - available_leave.carryforward_days
- total_leave_days += forcated_days
+ total_leave_days += forcasted_days
if not effective_requested_days <= total_leave_days:
raise forms.ValidationError(_("Employee doesn't have enough leave days.."))
@@ -516,7 +527,7 @@ def clean(self):
if f"{today.month}-{today.year}" in unique_dates:
unique_dates.remove(f"{today.strftime('%m')}-{today.year}")
- forcated_days = available_leave.forcasted_leaves(start_date)
+ forcasted_days = available_leave.forcasted_leaves(start_date)
total_leave_days = (
available_leave.leave_type_id.carryforward_max
if available_leave.leave_type_id.carryforward_type
@@ -529,7 +540,7 @@ def clean(self):
and available_leave.carryforward_days
):
total_leave_days = total_leave_days - available_leave.carryforward_days
- total_leave_days += forcated_days
+ total_leave_days += forcasted_days
if not effective_requested_days <= total_leave_days:
raise forms.ValidationError(_("Employee doesn't have enough leave days.."))
diff --git a/leave/models.py b/leave/models.py
index 67fa0e593..63826be4d 100644
--- a/leave/models.py
+++ b/leave/models.py
@@ -61,6 +61,7 @@
("yearly", _("Yearly")),
("monthly", _("Monthly")),
("weekly", _("Weekly")),
+ ("anniversary", _("Anniversary")),
]
MONTHS = [
("1", _("Jan")),
@@ -209,6 +210,22 @@ class LeaveType(HorillaModel):
company_id = models.ForeignKey(
Company, null=True, editable=False, on_delete=models.PROTECT
)
+ carryforward = models.BooleanField(
+ default=False,
+ verbose_name=_("Allow Carryforward"),
+ help_text=_("Enable to allow carrying forward unused leaves")
+ )
+ carryforward_period = models.PositiveIntegerField(
+ null=True,
+ blank=True,
+ verbose_name=_("Carryforward Period (Years)"),
+ help_text=_("Number of years before carried forward leaves expire")
+ )
+ carryforward_expire_date = models.DateField(
+ null=True,
+ blank=True,
+ verbose_name=_("Carryforward Expiry Date")
+ )
objects = HorillaCompanyManager(related_company_field="company_id")
class Meta:
@@ -226,7 +243,10 @@ def get_avatar(self):
url = self.icon.url
return url
- def leave_type_next_reset_date(self):
+ def leave_type_next_reset_date(self, employee=None):
+ """
+ Method to get the next reset date for leave type
+ """
today = datetime.now().date()
if not self.reset:
@@ -239,15 +259,33 @@ def get_reset_day(month, day):
else int(day)
)
- if self.reset_based == "yearly":
- month, day = int(self.reset_month), get_reset_day(
- int(self.reset_month), self.reset_day
- )
- reset_date = datetime(
- today.year + (datetime(today.year, month, day).date() < today),
- month,
- day,
- ).date()
+ if self.reset_based == "anniversary":
+ if not employee:
+ return None # Can't calculate anniversary without employee
+
+ work_info = employee.employee_work_info
+ if not work_info or not work_info.anniversary_date:
+ return None
+
+ # Calculate next anniversary date
+ anniversary_date = work_info.anniversary_date
+ next_anniversary = anniversary_date.replace(year=today.year)
+ if next_anniversary < today:
+ next_anniversary = next_anniversary.replace(year=today.year + 1)
+ return next_anniversary
+
+ elif self.reset_based == "yearly":
+ try:
+ month = int(self.reset_month)
+ day = get_reset_day(month, self.reset_day)
+ reset_date = datetime(
+ today.year + (datetime(today.year, month, day).date() < today),
+ month,
+ day,
+ ).date()
+ return reset_date
+ except (ValueError, TypeError):
+ return None
elif self.reset_based == "monthly":
month = today.month
@@ -272,15 +310,18 @@ def get_reset_day(month, day):
return reset_date
def set_expired_date(self, assigned_date):
- period = self.carryforward_expire_in
- if self.carryforward_expire_period == "day":
- expired_date = assigned_date + relativedelta(days=period)
- elif self.carryforward_expire_period == "month":
- expired_date = assigned_date + relativedelta(months=period)
- else:
+ """
+ Method to set the expiry date for carried forward leaves
+ """
+ if not assigned_date or not self.carryforward_period:
+ return None
+
+ try:
+ period = int(self.carryforward_period)
expired_date = assigned_date + relativedelta(years=period)
-
- return expired_date
+ return expired_date
+ except (ValueError, TypeError):
+ return None
def clean(self, *args, **kwargs):
if self.is_compensatory_leave:
@@ -410,60 +451,64 @@ def update_carryforward(self):
# Setting the reset date for carryforward leaves
- def set_reset_date(self, assigned_date, available_leave):
- if available_leave.leave_type_id.reset_based == "monthly":
- reset_day = available_leave.leave_type_id.reset_day
- if reset_day == "last day":
- temp_date = assigned_date + relativedelta(months=0, day=31)
- if assigned_date < temp_date:
- reset_date = temp_date
- else:
- reset_date = assigned_date + relativedelta(months=1, day=31)
+ def set_reset_date(self, available_leave):
+ """
+ Method to set the reset date for leave allocation
+ """
+ today = datetime.now().date()
- else:
- temp_date = assigned_date + relativedelta(months=0, day=int(reset_day))
- if assigned_date < temp_date:
- reset_date = temp_date
- else:
- reset_date = assigned_date + relativedelta(
- months=1, day=int(reset_day)
- )
+ # Check if the leave type has reset enabled
+ if not self.leave_type_id.reset:
+ return None
- elif available_leave.leave_type_id.reset_based == "weekly":
- temp = 7 - (
- assigned_date.isoweekday()
- - int(available_leave.leave_type_id.reset_weekend)
- - 1
+ def get_reset_day(month, day):
+ return (
+ calendar.monthrange(today.year, month)[1]
+ if day == "last day"
+ else int(day)
)
- if temp != 7:
- reset_date = assigned_date + relativedelta(days=(temp % 7))
- else:
- reset_date = assigned_date + relativedelta(days=7)
- else:
- reset_month = int(available_leave.leave_type_id.reset_month)
- reset_day = available_leave.leave_type_id.reset_day
- if reset_day == "last day":
- temp_date = assigned_date + relativedelta(
- years=0, month=reset_month, day=31
- )
- if assigned_date < temp_date:
- reset_date = temp_date
- else:
- reset_date = assigned_date + relativedelta(
- years=1, month=reset_month, day=31
- )
- else:
- temp_date = assigned_date + relativedelta(
- years=0, month=reset_month, day=int(reset_day)
- )
- if assigned_date < temp_date:
- reset_date = temp_date
- else:
- # nth_day = int(reset_day)
- reset_date = assigned_date + relativedelta(
- years=1, month=reset_month, day=int(reset_day)
- )
+ if self.leave_type_id.reset_based == "anniversary":
+ work_info = self.employee_id.employee_work_info
+ if not work_info or not work_info.anniversary_date:
+ return None
+
+ anniversary_date = work_info.anniversary_date
+ next_anniversary = anniversary_date.replace(year=today.year)
+ if next_anniversary < today:
+ next_anniversary = next_anniversary.replace(year=today.year + 1)
+ return next_anniversary
+
+ elif self.leave_type_id.reset_based == "yearly":
+ month, day = int(self.leave_type_id.reset_month), get_reset_day(
+ int(self.leave_type_id.reset_month), self.leave_type_id.reset_day
+ )
+ reset_date = datetime(
+ today.year + (datetime(today.year, month, day).date() < today),
+ month,
+ day,
+ ).date()
+ return reset_date
+
+ elif self.leave_type_id.reset_based == "monthly":
+ month = today.month
+ reset_date = datetime(
+ today.year, month, get_reset_day(month, self.reset_day)
+ ).date()
+ if reset_date < today:
+ month = (month % 12) + 1
+ year = today.year + (month == 1)
+ reset_date = datetime(
+ year, month, get_reset_day(month, self.reset_day)
+ ).date()
+
+ elif self.leave_type_id.reset_based == "weekly":
+ target_weekday = WEEK_DAYS[self.reset_day]
+ days_until_reset = (target_weekday - today.weekday()) % 7 or 7
+ reset_date = today + timedelta(days=days_until_reset)
+
+ else:
+ reset_date = None
return reset_date
@@ -491,23 +536,31 @@ def set_expired_date(self, available_leave, assigned_date):
return expired_date
def save(self, *args, **kwargs):
- # if self.assigned_date == datetime.now().date() or self.assigned_date.date() == datetime.now().date():
- if self.reset_date is None:
- # Check whether the reset is enabled
- if self.leave_type_id.reset:
- reset_date = self.set_reset_date(
- assigned_date=self.assigned_date, available_leave=self
- )
+ if not self.id:
+ # Set the reset date to the employee's anniversary date if the leave type is anniversary-based
+ if self.leave_type_id.reset_based == "anniversary":
+ work_info = self.employee_id.employee_work_info
+ if work_info and work_info.anniversary_date:
+ self.reset_date = work_info.anniversary_date
+
+ if self.leave_type_id.reset:
+ today = datetime.now().date()
+ reset_date = self.set_reset_date(self)
+
+ if reset_date and reset_date <= today:
+ # Reset the available days
+ self.available_days = self.leave_type_id.total_days
self.reset_date = reset_date
- # assigning expire date
- if self.leave_type_id.carryforward_type == "carryforward expire":
- expiry_date = self.assigned_date
- if self.leave_type_id.carryforward_expire_date:
- expiry_date = self.leave_type_id.carryforward_expire_date
- self.expired_date = expiry_date
-
- self.total_leave_days = max(self.available_days + self.carryforward_days, 0)
- self.carryforward_days = max(self.carryforward_days, 0)
+
+ # Calculate next reset date
+ if self.leave_type_id.reset_based == "anniversary":
+ work_info = self.employee_id.employee_work_info
+ if work_info and work_info.anniversary_date:
+ next_year = reset_date.year + 1
+ self.reset_date = work_info.anniversary_date.replace(year=next_year)
+ else:
+ self.reset_date = self.set_reset_date(self)
+
super().save(*args, **kwargs)
diff --git a/leave/scheduler.py b/leave/scheduler.py
index dbc1933ae..b87026fbe 100644
--- a/leave/scheduler.py
+++ b/leave/scheduler.py
@@ -9,27 +9,91 @@
today = datetime.now()
+def update_anniversary_reset_dates():
+ """
+ Updates reset dates for anniversary-based leave types when anniversary dates change
+ """
+ from leave.models import AvailableLeave
+ from employee.models import EmployeeWorkInformation
+
+ today_date = today.date()
+
+ # Get all employees with anniversary-based leaves
+ available_leaves = AvailableLeave.objects.filter(
+ leave_type_id__reset_based='anniversary',
+ employee_id__employee_work_info__isnull=False
+ ).select_related('employee_id__employee_work_info')
+
+ for available_leave in available_leaves:
+ work_info = available_leave.employee_id.employee_work_info
+ if work_info and work_info.anniversary_date:
+ # Calculate next anniversary date
+ next_anniversary = work_info.anniversary_date.replace(year=today_date.year)
+ if next_anniversary < today_date:
+ next_anniversary = next_anniversary.replace(year=today_date.year + 1)
+
+ # Update reset date if it's different
+ if available_leave.reset_date != next_anniversary:
+ available_leave.reset_date = next_anniversary
+ available_leave.save()
+
+
def leave_reset():
- from leave.models import LeaveType
+ from leave.models import LeaveType, AvailableLeave
+ from employee.models import EmployeeWorkInformation
today_date = today.date()
+
+ # Handle anniversary-based resets
+ anniversary_leaves = AvailableLeave.objects.filter(
+ leave_type_id__reset_based='anniversary',
+ reset_date__lte=today_date
+ )
+
+ for available_leave in anniversary_leaves:
+ # Reset available days
+ available_leave.available_days = available_leave.leave_type_id.total_days
+
+ # Calculate next reset date
+ work_info = available_leave.employee_id.employee_work_info
+ if work_info and work_info.anniversary_date:
+ next_year = today_date.year + 1
+ available_leave.reset_date = work_info.anniversary_date.replace(year=next_year)
+ available_leave.save()
+
leave_types = LeaveType.objects.filter(reset=True)
# Looping through filtered leave types with reset is true
for leave_type in leave_types:
+ # Skip if carryforward is not enabled
+ if not leave_type.carryforward:
+ continue
+
+ expire_date = leave_type.set_expired_date(today_date)
+ if expire_date:
+ leave_type.carryforward_expire_date = expire_date
+ leave_type.save()
+
# Looping through all available leaves
available_leaves = leave_type.employee_available_leave.all()
for available_leave in available_leaves:
- reset_date = available_leave.reset_date
+ reset_date = None
expired_date = available_leave.expired_date
+
+ if leave_type.reset_based == "anniversary":
+ work_info = available_leave.employee_id.employee_work_info
+ if work_info and work_info.anniversary_date:
+ anniversary_date = work_info.anniversary_date
+ next_anniversary = anniversary_date.replace(year=today_date.year)
+ # Check if the next anniversary is today
+ if next_anniversary == today_date:
+ reset_date = next_anniversary
+
if reset_date == today_date:
available_leave.update_carryforward()
- # new_reset_date = available_leave.set_reset_date(assigned_date=today_date,available_leave = available_leave)
- new_reset_date = available_leave.set_reset_date(
- assigned_date=today_date, available_leave=available_leave
- )
- available_leave.reset_date = new_reset_date
+ available_leave.reset_date = reset_date
available_leave.save()
+
if expired_date and expired_date <= today_date:
new_expired_date = available_leave.set_expired_date(
available_leave=available_leave, assigned_date=today_date
@@ -37,15 +101,6 @@ def leave_reset():
available_leave.expired_date = new_expired_date
available_leave.save()
- if (
- leave_type.carryforward_expire_date
- and leave_type.carryforward_expire_date <= today_date
- ):
- leave_type.carryforward_expire_date = leave_type.set_expired_date(
- today_date
- )
- leave_type.save()
-
if not any(
cmd in sys.argv
@@ -56,5 +111,7 @@ def leave_reset():
"""
scheduler = BackgroundScheduler()
scheduler.add_job(leave_reset, "interval", seconds=20)
+ # Add the new job to run every hour
+ scheduler.add_job(update_anniversary_reset_dates, "interval", hours=1)
scheduler.start()
diff --git a/leave/templates/leave/leave_request/employee_available_leave_count.html b/leave/templates/leave/leave_request/employee_available_leave_count.html
index a673868f8..85e40922f 100644
--- a/leave/templates/leave/leave_request/employee_available_leave_count.html
+++ b/leave/templates/leave/leave_request/employee_available_leave_count.html
@@ -42,7 +42,7 @@
display: flex;
">
{% trans "Available Leaves" %} : {{ total_leave_days }}
- {% if forcated_days and forcated_days > 0 %}
+ {% if forcasted_days and forcasted_days > 0 %}
{% endif %}
diff --git a/leave/views.py b/leave/views.py
index be18fd421..66f90a86e 100644
--- a/leave/views.py
+++ b/leave/views.py
@@ -1241,10 +1241,7 @@ def leave_assign_one(request, obj_id):
available_days=leave_type.total_days,
)
if leave.reset_date is None:
- if leave_type.reset:
- leave.reset_date = leave.set_reset_date(
- assigned_date=leave.assigned_date, available_leave=leave
- )
+ leave.reset_date = leave.set_reset_date(leave)
if leave_type.carryforward_type == "carryforward expire":
if not expiry_date:
@@ -3788,16 +3785,8 @@ def user_request_select_filter(request):
def employee_available_leave_count(request):
leave_type_id = request.GET.get("leave_type_id")
start_date = request.GET.get("start_date")
- try:
- start_date_format = datetime.strptime(start_date, "%Y-%m-%d").date()
- except:
- leave_type_id = None
- hx_target = request.META.get("HTTP_HX_TARGET", None)
- employee_id = (
- request.GET.getlist("employee_id")[0]
- if request.GET.getlist("employee_id")
- else None
- )
+ employee_id = request.GET.getlist("employee_id")[0] if request.GET.getlist("employee_id") else None
+
available_leave = (
AvailableLeave.objects.filter(
leave_type_id=leave_type_id, employee_id=employee_id
@@ -3805,38 +3794,19 @@ def employee_available_leave_count(request):
if leave_type_id and employee_id
else None
)
- total_leave_days = available_leave.total_leave_days if available_leave else 0
- forcated_days = 0
- if (
- available_leave
- and available_leave.leave_type_id.leave_type_next_reset_date()
- and available_leave
- and start_date_format
- >= available_leave.leave_type_id.leave_type_next_reset_date()
- ):
- forcated_days = available_leave.forcasted_leaves(start_date)
- total_leave_days = (
- available_leave.leave_type_id.carryforward_max
- if available_leave.leave_type_id.carryforward_type
- in ["carryforward", "carryforward expire"]
- and available_leave.leave_type_id.carryforward_max < total_leave_days
- else total_leave_days
- )
- if available_leave.leave_type_id.carryforward_type == "no carryforward":
- total_leave_days = 0
- total_leave_days += forcated_days
+ total_leave_days = 0
+ if available_leave:
+ total_leave_days = available_leave.available_days + available_leave.carryforward_days
- context = {
- "hx_target": hx_target,
- "leave_type_id": leave_type_id,
+ # Additional logic for calculating forcated_days and updating total_leave_days
+ # ...
+
+ return render(request, "leave/leave_request/employee_available_leave_count.html", {
"available_leave": available_leave,
"total_leave_days": total_leave_days,
- "forcated_days": forcated_days,
- }
- return render(
- request, "leave/leave_request/employee_available_leave_count.html", context
- )
+ # other context variables...
+ })
@login_required
@@ -4110,7 +4080,7 @@ def create_allocationrequest_comment(request, leave_id):
verb_ar="تلقى طلب تخصيص الإجازة الخاص بك تعليقًا.",
verb_de="Ihr Antrag auf Urlaubszuweisung hat einen Kommentar erhalten.",
verb_es="Tu solicitud de asignación de permisos ha recibido un comentario.",
- verb_fr="Votre demande d'allocation de congé a reçu un commentaire.",
+ verb_fr=f"La demande d'allocation de congé de {leave.employee_id} a reçu un commentaire.",
redirect=reverse("leave-allocation-request-view")
+ f"?id={leave.id}",
icon="chatbox-ellipses",
@@ -4910,9 +4880,9 @@ def create_compensatory_leave_comment(request, comp_leave_id):
recipient=rec,
verb="Your compensatory leave request has received a comment.",
verb_ar="تلقى طلب إجازة العوض الخاص بك تعليقًا.",
- verb_de="Ihr Antrag auf Freizeitausgleich hat einen Kommentar erhalten.",
+ verb_de=f"Ihr Antrag auf Freizeitausgleich hat einen Kommentar erhalten.",
verb_es="Su solicitud de permiso compensatorio ha recibido un comentario.",
- verb_fr="Votre demande de congé compensatoire a reçu un commentaire.",
+ verb_fr=f"Votre demande de congé compensatoire a reçu un commentaire.",
redirect=reverse("view-compensatory-leave")
+ f"?id={comp_leave.id}",
icon="chatbox-ellipses",
@@ -5198,3 +5168,4 @@ def leave_allocation_approve(request):
# "current_date":date.today(),
},
)
+