Upload files to "base"

Signed-off-by: nestict <developer@nestict.com>
This commit is contained in:
2026-01-16 15:38:54 +01:00
parent cac187ab10
commit 7ef7852d0e
23 changed files with 18398 additions and 0 deletions

BIN
base/.DS_Store vendored Normal file

Binary file not shown.

1
base/__init__.py Normal file
View File

@@ -0,0 +1 @@
from . import scheduler

72
base/admin.py Normal file
View File

@@ -0,0 +1,72 @@
"""
admin.py
This page is used to register base models with admins site.
"""
from django.contrib import admin
from simple_history.admin import SimpleHistoryAdmin
from base.models import (
Announcement,
Attachment,
Company,
CompanyLeaves,
DashboardEmployeeCharts,
Department,
DynamicEmailConfiguration,
DynamicPagination,
EmailLog,
EmployeeShift,
EmployeeShiftDay,
EmployeeShiftSchedule,
EmployeeType,
Holidays,
JobPosition,
JobRole,
MultipleApprovalCondition,
MultipleApprovalManagers,
PenaltyAccounts,
RotatingShift,
RotatingShiftAssign,
RotatingWorkType,
RotatingWorkTypeAssign,
ShiftRequest,
ShiftRequestComment,
Tags,
WorkType,
WorkTypeRequest,
WorkTypeRequestComment,
)
# Register your models here.
admin.site.register(Company)
admin.site.register(Department, SimpleHistoryAdmin)
admin.site.register(JobPosition)
admin.site.register(JobRole)
admin.site.register(EmployeeShift)
admin.site.register(EmployeeShiftSchedule)
admin.site.register(EmployeeShiftDay)
admin.site.register(EmployeeType)
admin.site.register(WorkType)
admin.site.register(RotatingWorkType)
admin.site.register(RotatingWorkTypeAssign)
admin.site.register(RotatingShift)
admin.site.register(RotatingShiftAssign)
admin.site.register(ShiftRequest)
admin.site.register(WorkTypeRequest)
admin.site.register(Tags)
admin.site.register(DynamicEmailConfiguration)
admin.site.register(MultipleApprovalManagers)
admin.site.register(ShiftRequestComment)
admin.site.register(WorkTypeRequestComment)
admin.site.register(DynamicPagination)
admin.site.register(Announcement)
admin.site.register(Attachment)
admin.site.register(EmailLog)
admin.site.register(DashboardEmployeeCharts)
admin.site.register(Holidays)
admin.site.register(CompanyLeaves)
admin.site.register(PenaltyAccounts)
admin.site.register(MultipleApprovalCondition)

416
base/announcement.py Normal file
View File

@@ -0,0 +1,416 @@
"""
Module for managing announcements, including creation, updates, comments, and views.
"""
import json
from datetime import datetime, timedelta
from django.contrib import messages
from django.contrib.auth.models import User
from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from base.forms import AnnouncementCommentForm, AnnouncementForm
from base.methods import closest_numbers, filter_own_records
from base.models import (
Announcement,
AnnouncementComment,
AnnouncementExpire,
AnnouncementView,
Attachment,
)
from employee.models import Employee
from horilla.decorators import hx_request_required, login_required, permission_required
from notifications.signals import notify
@login_required
@hx_request_required
def announcement_list(request):
"""
Renders a list of announcements for the authenticated user.
This view fetches all announcements and updates their expiration dates if not already set.
It filters announcements based on the user's permissions and whether the announcements
are still valid (not expired). Additionally, it checks if the user has viewed each announcement.
"""
general_expire_date = (
AnnouncementExpire.objects.values_list("days", flat=True).first() or 30
)
announcements = Announcement.objects.all()
announcements_to_update = []
for announcement in announcements.filter(expire_date__isnull=True):
announcement.expire_date = announcement.created_at + timedelta(
days=general_expire_date
)
announcements_to_update.append(announcement)
if announcements_to_update:
Announcement.objects.bulk_update(announcements_to_update, ["expire_date"])
has_view_permission = request.user.has_perm("base.view_announcement")
announcements = announcements.filter(expire_date__gte=datetime.today().date())
announcement_items = (
announcements
if has_view_permission
else announcements.filter(
Q(employees=request.user.employee_get) | Q(employees__isnull=True)
)
)
filtered_announcements = announcement_items.prefetch_related(
"announcementview_set"
).order_by("-created_at")
for announcement in filtered_announcements:
announcement.has_viewed = announcement.announcementview_set.filter(
user=request.user, viewed=True
).exists()
instance_ids = json.dumps([instance.id for instance in filtered_announcements])
context = {
"announcements": filtered_announcements,
"general_expire_date": general_expire_date,
"instance_ids": instance_ids,
}
return render(request, "announcement/announcements_list.html", context)
@login_required
@hx_request_required
def create_announcement(request):
"""
Create a new announcement and notify relevant users.
"""
form = AnnouncementForm()
if request.method == "POST":
form = AnnouncementForm(request.POST, request.FILES)
if form.is_valid():
announcement, attachment_ids = form.save(commit=False)
announcement.save()
announcement.attachments.set(attachment_ids)
employees = form.cleaned_data["employees"]
departments = form.cleaned_data["department"]
job_positions = form.cleaned_data["job_position"]
company = form.cleaned_data["company_id"]
announcement.department.set(departments)
announcement.job_position.set(job_positions)
announcement.company_id.set(company)
dept_ids = departments.values_list("id", flat=True)
job_ids = job_positions.values_list("id", flat=True)
employees_from_dept = Employee.objects.filter(
employee_work_info__department_id__in=dept_ids
)
employees_from_job = Employee.objects.filter(
employee_work_info__job_position_id__in=job_ids
)
all_employees = (
employees | employees_from_dept | employees_from_job
).distinct()
announcement.employees.add(*all_employees)
all_emps = employees_from_dept | employees_from_job | employees
user_map = User.objects.filter(employee_get__in=all_emps).distinct()
dept_emp_ids = set(employees_from_dept.values_list("id", flat=True))
job_emp_ids = set(employees_from_job.values_list("id", flat=True))
direct_emp_ids = set(employees.values_list("id", flat=True))
notified_ids = dept_emp_ids.union(job_emp_ids)
direct_only_ids = direct_emp_ids - notified_ids
sender = request.user.employee_get
def send_notification(users, verb):
if users.exists():
notify.send(
sender,
recipient=users,
verb=verb,
verb_ar="لقد تم ذكرك في إعلان.",
verb_de="Sie wurden in einer Ankündigung erwähnt.",
verb_es="Has sido mencionado en un anuncio.",
verb_fr="Vous avez été mentionné dans une annonce.",
redirect="/",
icon="chatbox-ellipses",
)
send_notification(
user_map.filter(employee_get__id__in=dept_emp_ids),
_("Your department was mentioned in an announcement."),
)
send_notification(
user_map.filter(employee_get__id__in=job_emp_ids),
_("Your job position was mentioned in an announcement."),
)
send_notification(
user_map.filter(employee_get__id__in=direct_only_ids),
_("You have been mentioned in an announcement."),
)
messages.success(request, _("Announcement created successfully."))
form = AnnouncementForm() # Reset the form
return render(request, "announcement/announcement_form.html", {"form": form})
@login_required
@hx_request_required
def delete_announcement(request, anoun_id):
"""
This method is used to delete announcements.
"""
announcement = Announcement.find(anoun_id)
if announcement:
announcement.delete()
messages.success(request, _("Announcement deleted successfully."))
instance_ids = request.GET.get("instance_ids")
instance_ids_list = json.loads(instance_ids)
__, next_instance_id = (
closest_numbers(instance_ids_list, anoun_id)
if instance_ids_list
else (None, None)
)
if anoun_id in instance_ids_list:
instance_ids_list.remove(anoun_id)
if next_instance_id and next_instance_id != anoun_id:
url = reverse("announcement-single-view", kwargs={"anoun_id": next_instance_id})
return redirect(f"{url}?instance_ids={json.dumps(instance_ids_list)}")
return redirect(announcement_single_view)
@login_required
@hx_request_required
def update_announcement(request, anoun_id):
"""
This method renders form and template to update Announcement
"""
announcement = Announcement.objects.get(id=anoun_id)
form = AnnouncementForm(instance=announcement)
existing_attachments = list(announcement.attachments.all())
instance_ids = request.GET.get("instance_ids")
if request.method == "POST":
form = AnnouncementForm(request.POST, request.FILES, instance=announcement)
if form.is_valid():
anou, attachment_ids = form.save(commit=False)
anou.save()
if attachment_ids:
all_attachments = set(existing_attachments) | set(
Attachment.objects.filter(id__in=attachment_ids)
)
anou.attachments.set(all_attachments)
else:
anou.attachments.set(existing_attachments)
employees = form.cleaned_data["employees"]
departments = form.cleaned_data["department"]
job_positions = form.cleaned_data["job_position"]
company = form.cleaned_data["company_id"]
anou.department.set(departments)
anou.job_position.set(job_positions)
anou.company_id.set(company)
messages.success(request, _("Announcement updated successfully."))
emp_dep = User.objects.filter(
employee_get__employee_work_info__department_id__in=departments
)
emp_jobs = User.objects.filter(
employee_get__employee_work_info__job_position_id__in=job_positions
)
employees = employees | Employee.objects.filter(
employee_work_info__department_id__in=departments
)
employees = employees | Employee.objects.filter(
employee_work_info__job_position_id__in=job_positions
)
anou.employees.add(*employees)
notify.send(
request.user.employee_get,
recipient=emp_dep,
verb="Your department was mentioned in a post.",
verb_ar="تم ذكر قسمك في منشور.",
verb_de="Ihr Abteilung wurde in einem Beitrag erwähnt.",
verb_es="Tu departamento fue mencionado en una publicación.",
verb_fr="Votre département a été mentionné dans un post.",
redirect="/",
icon="chatbox-ellipses",
)
notify.send(
request.user.employee_get,
recipient=emp_jobs,
verb="Your job position was mentioned in a post.",
verb_ar="تم ذكر وظيفتك في منشور.",
verb_de="Ihre Arbeitsposition wurde in einem Beitrag erwähnt.",
verb_es="Tu puesto de trabajo fue mencionado en una publicación.",
verb_fr="Votre poste de travail a été mentionné dans un post.",
redirect="/",
icon="chatbox-ellipses",
)
return render(
request,
"announcement/announcement_update_form.html",
{
"form": form,
"instance_ids": instance_ids,
"hx_target": request.META.get("HTTP_HX_TARGET", ""),
},
)
@login_required
@hx_request_required
def remove_announcement_file(request, obj_id, attachment_id):
announcement = get_object_or_404(Announcement, id=obj_id)
attachment = get_object_or_404(Attachment, id=attachment_id)
announcement.attachments.remove(attachment)
messages.success(request, _("The file has been successfully deleted."))
return HttpResponse("<script>reloadMessage();</script>")
@login_required
@hx_request_required
def create_announcement_comment(request, anoun_id):
"""
This method renders form and template to create Announcement comments
"""
anoun = Announcement.objects.filter(id=anoun_id).first()
emp = request.user.employee_get
form = AnnouncementCommentForm(
initial={"employee_id": emp.id, "request_id": anoun_id}
)
comments = AnnouncementComment.objects.filter(announcement_id=anoun_id)
commentators = []
if comments:
for i in comments:
commentators.append(i.employee_id.employee_user_id)
unique_users = list(set(commentators))
if request.method == "POST":
form = AnnouncementCommentForm(request.POST)
if form.is_valid():
form.instance.employee_id = emp
form.instance.announcement_id = anoun
form.save()
form = AnnouncementCommentForm(
initial={"employee_id": emp.id, "request_id": anoun_id}
)
messages.success(request, _("You commented a post."))
notify.send(
request.user.employee_get,
recipient=unique_users,
verb=f"Comment under the announcement {anoun.title}.",
verb_ar=f"تعليق تحت الإعلان {anoun.title}.",
verb_de=f"Kommentar unter der Ankündigung {anoun.title}.",
verb_es=f"Comentario bajo el anuncio {anoun.title}.",
verb_fr=f"Commentaire sous l'annonce {anoun.title}.",
redirect="/",
icon="chatbox-ellipses",
)
return redirect("announcement-view-comment", anoun_id=anoun_id)
return render(
request,
"announcement/comment_view.html",
{"form": form, "request_id": anoun_id},
)
@login_required
@hx_request_required
def comment_view(request, anoun_id):
"""
This method is used to view all comments in the announcements
"""
announcement = Announcement.objects.get(id=anoun_id)
comments = AnnouncementComment.objects.filter(announcement_id=anoun_id).order_by(
"-created_at"
)
if not announcement.public_comments:
comments = filter_own_records(
request, comments, "base.view_announcementcomment"
)
no_comments = not comments.exists()
return render(
request,
"announcement/comment_view.html",
{
"comments": comments,
"no_comments": no_comments,
"request_id": anoun_id,
"announcement": announcement,
},
)
@login_required
@hx_request_required
def delete_announcement_comment(request, comment_id):
"""
This method is used to delete announcement comments
"""
comment = AnnouncementComment.objects.get(id=comment_id)
comment.delete()
messages.success(request, _("Comment deleted successfully!"))
return HttpResponse()
@login_required
@hx_request_required
def announcement_single_view(request, anoun_id=None):
"""
This method is used to render single announcements.
"""
announcement_instance = Announcement.find(anoun_id)
instance_ids = request.GET.get("instance_ids")
instance_ids_list = json.loads(instance_ids) if instance_ids else []
previous_instance_id, next_instance_id = (
closest_numbers(instance_ids_list, anoun_id)
if instance_ids_list
else (None, None)
)
if announcement_instance:
announcement_view_obj, _ = AnnouncementView.objects.get_or_create(
user=request.user, announcement=announcement_instance
)
announcement_view_obj.viewed = True
announcement_view_obj.save()
context = {
"announcement": announcement_instance,
"instance_ids": instance_ids,
"previous_instance_id": previous_instance_id,
"next_instance_id": next_instance_id,
}
return render(request, "announcement/announcement_one.html", context)
@login_required
@hx_request_required
@permission_required("base.view_announcement")
def viewed_by(request):
"""
This method is used to view the employees
"""
announcement_id = request.GET.get("announcement_id")
viewed_users = AnnouncementView.objects.filter(
announcement_id__id=announcement_id, viewed=True
)
return render(request, "announcement/viewed_by.html", {"viewed_by": viewed_users})

38
base/apps.py Normal file
View File

@@ -0,0 +1,38 @@
"""
This module contains the configuration for the 'base' app.
"""
from django.apps import AppConfig
class BaseConfig(AppConfig):
"""
Configuration class for the 'base' app.
"""
default_auto_field = "django.db.models.BigAutoField"
name = "base"
def ready(self) -> None:
from base import signals
super().ready()
try:
from base.models import EmployeeShiftDay
if not EmployeeShiftDay.objects.exists():
days = [
("monday", "Monday"),
("tuesday", "Tuesday"),
("wednesday", "Wednesday"),
("thursday", "Thursday"),
("friday", "Friday"),
("saturday", "Saturday"),
("sunday", "Sunday"),
]
EmployeeShiftDay.objects.bulk_create(
[EmployeeShiftDay(day=day[0]) for day in days]
)
except Exception as e:
pass

267
base/backends.py Normal file
View File

@@ -0,0 +1,267 @@
"""
email_backend.py
This module is used to write email backends
"""
import importlib
import logging
from django.core.cache import cache
from django.core.mail import EmailMessage
from django.core.mail.backends.smtp import EmailBackend
from base.models import DynamicEmailConfiguration, EmailLog
from horilla import settings
from horilla.horilla_middlewares import _thread_locals
logger = logging.getLogger(__name__)
class DefaultHorillaMailBackend(EmailBackend):
def __init__(
self,
host=None,
port=None,
username=None,
password=None,
use_tls=None,
fail_silently=None,
use_ssl=None,
timeout=None,
ssl_keyfile=None,
ssl_certfile=None,
**kwargs,
):
self.configuration = self.get_dynamic_email_config()
ssl_keyfile = (
getattr(self.configuration, "ssl_keyfile", None)
if self.configuration
else ssl_keyfile or getattr(settings, "ssl_keyfile", None)
)
ssl_certfile = (
getattr(self.configuration, "ssl_certfile", None)
if self.configuration
else ssl_certfile or getattr(settings, "ssl_certfile", None)
)
super().__init__(
host=self.dynamic_host,
port=self.dynamic_port,
username=self.dynamic_username,
password=self.dynamic_password,
use_tls=self.dynamic_use_tls,
fail_silently=self.dynamic_fail_silently,
use_ssl=self.dynamic_use_ssl,
timeout=self.dynamic_timeout,
ssl_keyfile=ssl_keyfile,
ssl_certfile=ssl_certfile,
**kwargs,
)
@staticmethod
def get_dynamic_email_config():
request = getattr(_thread_locals, "request", None)
company = None
if request and not request.user.is_anonymous:
company = request.user.employee_get.get_company()
configuration = DynamicEmailConfiguration.objects.filter(
company_id=company
).first()
if configuration is None:
configuration = DynamicEmailConfiguration.objects.filter(
is_primary=True
).first()
if configuration:
display_email_name = (
f"{configuration.display_name} <{configuration.from_email}>"
)
user_id = ""
if request:
if (
configuration.use_dynamic_display_name
and request.user.is_authenticated
):
display_email_name = f"{request.user.employee_get.get_full_name()} <{request.user.employee_get.get_email()}>"
if request.user.is_authenticated:
user_id = request.user.pk
reply_to = [
f"{request.user.employee_get.get_full_name()} <{request.user.employee_get.get_email()}>",
]
cache.set(f"reply_to{request.user.pk}", reply_to)
cache.set(f"dynamic_display_name{user_id}", display_email_name)
return configuration
@property
def dynamic_host(self):
return (
self.configuration.host
if self.configuration
else getattr(settings, "EMAIL_HOST", None)
)
@property
def dynamic_port(self):
return (
self.configuration.port
if self.configuration
else getattr(settings, "EMAIL_PORT", None)
)
@property
def dynamic_username(self):
return (
self.configuration.username
if self.configuration
else getattr(settings, "EMAIL_HOST_USER", None)
)
@property
def dynamic_mail_sent_from(self):
return (
self.configuration.from_email
if self.configuration
else getattr(settings, "DEFAULT_FROM_EMAIL", None)
)
@property
def dynamic_display_name(self):
return self.configuration.display_name if self.configuration else None
@property
def dynamic_from_email_with_display_name(self):
return (
f"{self.dynamic_display_name} <{self.dynamic_mail_sent_from}>"
if self.dynamic_display_name
else self.dynamic_mail_sent_from
)
@property
def dynamic_password(self):
return (
self.configuration.password
if self.configuration
else getattr(settings, "EMAIL_HOST_PASSWORD", None)
)
@property
def dynamic_use_tls(self):
return (
self.configuration.use_tls
if self.configuration
else getattr(settings, "EMAIL_USE_TLS", None)
)
@property
def dynamic_fail_silently(self):
return (
self.configuration.fail_silently
if self.configuration
else getattr(settings, "EMAIL_FAIL_SILENTLY", True)
)
@property
def dynamic_use_ssl(self):
return (
self.configuration.use_ssl
if self.configuration
else getattr(settings, "EMAIL_USE_SSL", None)
)
@property
def dynamic_timeout(self):
return (
self.configuration.timeout
if self.configuration
else getattr(settings, "EMAIL_TIMEOUT", None)
)
EMAIL_BACKEND = getattr(settings, "EMAIL_BACKEND", "")
BACKEND_CLASS: EmailBackend = DefaultHorillaMailBackend
default = "base.backends.ConfiguredEmailBackend"
setattr(BACKEND_CLASS, "send_messages", DefaultHorillaMailBackend.send_messages)
if EMAIL_BACKEND and EMAIL_BACKEND != default:
module_path, class_name = EMAIL_BACKEND.rsplit(".", 1)
module = importlib.import_module(module_path)
BACKEND_CLASS = getattr(module, class_name)
class ConfiguredEmailBackend(BACKEND_CLASS):
def send_messages(self, email_messages):
response = super(BACKEND_CLASS, self).send_messages(email_messages)
for message in email_messages:
email_log = EmailLog(
subject=message.subject,
from_email=self.dynamic_from_email_with_display_name,
to=message.to,
body=message.body,
status="sent" if response else "failed",
)
email_log.save()
return response
if EMAIL_BACKEND != default:
from_mail = getattr(settings, "DEFAULT_FROM_EMAIL", "example@gmail.com")
username = getattr(settings, "EMAIL_HOST_USER", "example@gmail.com")
ConfiguredEmailBackend.dynamic_username = from_mail
ConfiguredEmailBackend.dynamic_from_email_with_display_name = from_mail
__all__ = ["ConfiguredEmailBackend"]
message_init = EmailMessage.__init__
def new_init(
self,
subject="",
body="",
from_email=None,
to=None,
bcc=None,
connection=None,
attachments=None,
headers=None,
cc=None,
reply_to=None,
):
"""
custom __init_method to override
"""
request = getattr(_thread_locals, "request", None)
DefaultHorillaMailBackend()
user_id = ""
if request and request.user and request.user.is_authenticated:
user_id = request.user.pk
reply_to = cache.get(f"reply_to{user_id}") if not reply_to else reply_to
if not from_email:
from_email = cache.get(f"dynamic_display_name{user_id}")
message_init(
self,
subject=subject,
body=body,
from_email=from_email,
to=to,
bcc=bcc,
connection=connection,
attachments=attachments,
headers=headers,
cc=cc,
reply_to=reply_to,
)
EmailMessage.__init__ = new_init

301
base/context_processors.py Normal file
View File

@@ -0,0 +1,301 @@
"""
context_processor.py
This module is used to register context processor`
"""
import re
from django.apps import apps
from django.contrib import messages
from django.http import HttpResponse
from django.urls import path, reverse
from django.utils.translation import gettext_lazy as _
from base.models import Company, TrackLateComeEarlyOut
from base.urls import urlpatterns
from employee.models import (
Employee,
EmployeeGeneralSetting,
EmployeeWorkInformation,
ProfileEditFeature,
)
from horilla import horilla_apps
from horilla.decorators import hx_request_required, login_required, permission_required
from horilla.methods import get_horilla_model_class
class AllCompany:
"""
Dummy class
"""
class Urls:
url = "https://ui-avatars.com/api/?name=All+Company&background=random"
company = "All Company"
icon = Urls()
text = "All companies"
id = None
def get_last_section(path):
# Remove any trailing slash and split the path
segments = path.strip("/").split("/")
# Get the last section (the ID)
last_section = segments[-1] if segments else None
return last_section
def get_companies(request):
"""
This method will return the history additional field form
"""
companies = list(
[company.id, company.company, company.icon.url, False]
for company in Company.objects.all()
)
companies = [
[
"all",
"All Company",
"https://ui-avatars.com/api/?name=All+Company&background=random",
False,
],
] + companies
selected_company = request.session.get("selected_company")
company_selected = False
if selected_company and selected_company == "all":
companies[0][3] = True
company_selected = True
else:
for company in companies:
if str(company[0]) == selected_company:
company[3] = True
company_selected = True
return {"all_companies": companies, "company_selected": company_selected}
@login_required
@hx_request_required
@permission_required("base.change_company")
def update_selected_company(request):
"""
This method is used to update the selected company on the session
"""
company_id = request.GET.get("company_id")
user = request.user.employee_get
user_company = getattr(
getattr(user, "employee_work_info", None), "company_id", None
)
request.session["selected_company"] = company_id
company = (
AllCompany()
if company_id == "all"
else (
Company.objects.filter(id=company_id).first()
if Company.objects.filter(id=company_id).first()
else AllCompany()
)
)
previous_path = request.GET.get("next", "/")
# Define the regex pattern for the path
pattern = r"^/employee/employee-view/\d+/$"
# Check if the previous path matches the pattern
if company_id != "all":
if re.match(pattern, previous_path):
employee_id = get_last_section(previous_path)
employee = Employee.objects.filter(id=employee_id).first()
emp_company = getattr(
getattr(employee, "employee_work_info", None), "company_id", None
)
if emp_company != company:
text = "Other Company"
if company_id == user_company:
text = "My Company"
company = {
"company": company.company,
"icon": company.icon.url,
"text": text,
"id": company.id,
}
messages.error(
request, _("Employee is not working in the selected company.")
)
request.session["selected_company_instance"] = company
return HttpResponse(
f"""
<script>window.location.href = `{reverse("employee-view")}`</script>
"""
)
if company_id == "all":
text = "All companies"
elif company_id == user_company:
text = "My Company"
else:
text = "Other Company"
company = {
"company": company.company,
"icon": company.icon.url,
"text": text,
"id": company.id,
}
request.session["selected_company_instance"] = company
return HttpResponse("<script>window.location.reload();</script>")
urlpatterns.append(
path(
"update-selected-company",
update_selected_company,
name="update-selected-company",
)
)
def white_labelling_company(request):
white_labelling = getattr(horilla_apps, "WHITE_LABELLING", False)
if white_labelling:
hq = Company.objects.filter(hq=True).last()
try:
company = (
request.user.employee_get.get_company()
if request.user.employee_get.get_company()
else hq
)
except:
company = hq
return {
"white_label_company_name": company.company if company else "Horilla",
"white_label_company": company,
}
else:
return {
"white_label_company_name": "Horilla",
"white_label_company": None,
}
def resignation_request_enabled(request):
"""
Check weather resignation_request enabled of not in offboarding
"""
enabled_resignation_request = False
first = None
if apps.is_installed("offboarding"):
OffboardingGeneralSetting = get_horilla_model_class(
app_label="offboarding", model="offboardinggeneralsetting"
)
first = OffboardingGeneralSetting.objects.first()
if first:
enabled_resignation_request = first.resignation_request
return {"enabled_resignation_request": enabled_resignation_request}
def timerunner_enabled(request):
"""
Check weather resignation_request enabled of not in offboarding
"""
first = None
enabled_timerunner = True
if apps.is_installed("attendance"):
AttendanceGeneralSetting = get_horilla_model_class(
app_label="attendance", model="attendancegeneralsetting"
)
first = AttendanceGeneralSetting.objects.first()
if first:
enabled_timerunner = first.time_runner
return {"enabled_timerunner": enabled_timerunner}
def intial_notice_period(request):
"""
Check weather resignation_request enabled of not in offboarding
"""
initial = 30
first = None
if apps.is_installed("payroll"):
PayrollGeneralSetting = get_horilla_model_class(
app_label="payroll", model="payrollgeneralsetting"
)
first = PayrollGeneralSetting.objects.first()
if first:
initial = first.notice_period
return {"get_initial_notice_period": initial}
def check_candidate_self_tracking(request):
"""
This method is used to get the candidate self tracking is enabled or not
"""
candidate_self_tracking = False
if apps.is_installed("recruitment"):
RecruitmentGeneralSetting = get_horilla_model_class(
app_label="recruitment", model="recruitmentgeneralsetting"
)
first = RecruitmentGeneralSetting.objects.first()
else:
first = None
if first:
candidate_self_tracking = first.candidate_self_tracking
return {"check_candidate_self_tracking": candidate_self_tracking}
def check_candidate_self_tracking_rating(request):
"""
This method is used to check enabled/disabled of rating option
"""
rating_option = False
if apps.is_installed("recruitment"):
RecruitmentGeneralSetting = get_horilla_model_class(
app_label="recruitment", model="recruitmentgeneralsetting"
)
first = RecruitmentGeneralSetting.objects.first()
else:
first = None
if first:
rating_option = first.show_overall_rating
return {"check_candidate_self_tracking_rating": rating_option}
def get_initial_prefix(request):
"""
This method is used to get the initial prefix
"""
settings = EmployeeGeneralSetting.objects.first()
instance_id = None
prefix = "PEP"
if settings:
instance_id = settings.id
prefix = settings.badge_id_prefix
return {"get_initial_prefix": prefix, "prefix_instance_id": instance_id}
def biometric_app_exists(request):
from django.conf import settings
biometric_app_exists = "biometric" in settings.INSTALLED_APPS
return {"biometric_app_exists": biometric_app_exists}
def enable_late_come_early_out_tracking(request):
tracking = TrackLateComeEarlyOut.objects.first()
enable = tracking.is_enable if tracking else True
return {"tracking": enable, "late_come_early_out_tracking": enable}
def enable_profile_edit(request):
from accessibility.accessibility import ACCESSBILITY_FEATURE
profile_edit = ProfileEditFeature.objects.filter().first()
enable = True if profile_edit and profile_edit.is_enabled else False
if enable:
if not any(item[0] == "profile_edit" for item in ACCESSBILITY_FEATURE):
ACCESSBILITY_FEATURE.append(("profile_edit", _("Profile Edit Access")))
return {"profile_edit_enabled": enable}

855
base/countries.py Normal file
View File

@@ -0,0 +1,855 @@
# Countries
country_arr = [
"Afghanistan",
"Albania",
"Algeria",
"American Samoa",
"Angola",
"Anguilla",
"Antartica",
"Antigua and Barbuda",
"Argentina",
"Armenia",
"Aruba",
"Ashmore and Cartier Island",
"Australia",
"Austria",
"Azerbaijan",
"Bahamas",
"Bahrain",
"Bangladesh",
"Barbados",
"Belarus",
"Belgium",
"Belize",
"Benin",
"Bermuda",
"Bhutan",
"Bolivia",
"Bosnia and Herzegovina",
"Botswana",
"Brazil",
"British Virgin Islands",
"Brunei",
"Bulgaria",
"Burkina Faso",
"Burma",
"Burundi",
"Cambodia",
"Cameroon",
"Canada",
"Cape Verde",
"Cayman Islands",
"Central African Republic",
"Chad",
"Chile",
"China",
"Christmas Island",
"Clipperton Island",
"Cocos (Keeling) Islands",
"Colombia",
"Comoros",
"Congo, Democratic Republic of the",
"Congo, Republic of the",
"Cook Islands",
"Costa Rica",
"Cote d'Ivoire",
"Croatia",
"Cuba",
"Cyprus",
"Czeck Republic",
"Denmark",
"Djibouti",
"Dominica",
"Dominican Republic",
"Ecuador",
"Egypt",
"El Salvador",
"Equatorial Guinea",
"Eritrea",
"Estonia",
"Ethiopia",
"Europa Island",
"Falkland Islands (Islas Malvinas)",
"Faroe Islands",
"Fiji",
"Finland",
"France",
"French Guiana",
"French Polynesia",
"French Southern and Antarctic Lands",
"Gabon",
"Gambia, The",
"Gaza Strip",
"Georgia",
"Germany",
"Ghana",
"Gibraltar",
"Glorioso Islands",
"Greece",
"Greenland",
"Grenada",
"Guadeloupe",
"Guam",
"Guatemala",
"Guernsey",
"Guinea",
"Guinea-Bissau",
"Guyana",
"Haiti",
"Heard Island and McDonald Islands",
"Holy See (Vatican City)",
"Honduras",
"Hong Kong",
"Howland Island",
"Hungary",
"Iceland",
"India",
"Indonesia",
"Iran",
"Iraq",
"Ireland",
"Ireland, Northern",
"Israel",
"Italy",
"Jamaica",
"Jan Mayen",
"Japan",
"Jarvis Island",
"Jersey",
"Johnston Atoll",
"Jordan",
"Juan de Nova Island",
"Kazakhstan",
"Kenya",
"Kiribati",
"Korea, North",
"Korea, South",
"Kuwait",
"Kyrgyzstan",
"Laos",
"Latvia",
"Lebanon",
"Lesotho",
"Liberia",
"Libya",
"Liechtenstein",
"Lithuania",
"Luxembourg",
"Macau",
"Macedonia, Former Yugoslav Republic of",
"Madagascar",
"Malawi",
"Malaysia",
"Maldives",
"Mali",
"Malta",
"Man, Isle of",
"Marshall Islands",
"Martinique",
"Mauritania",
"Mauritius",
"Mayotte",
"Mexico",
"Micronesia, Federated States of",
"Midway Islands",
"Moldova",
"Monaco",
"Mongolia",
"Montserrat",
"Morocco",
"Mozambique",
"Namibia",
"Nauru",
"Nepal",
"Netherlands",
"Netherlands Antilles",
"New Caledonia",
"New Zealand",
"Nicaragua",
"Niger",
"Nigeria",
"Niue",
"Norfolk Island",
"Northern Mariana Islands",
"Norway",
"Oman",
"Pakistan",
"Palau",
"Panama",
"Papua New Guinea",
"Paraguay",
"Peru",
"Philippines",
"Pitcaim Islands",
"Poland",
"Portugal",
"Puerto Rico",
"Qatar",
"Reunion",
"Romainia",
"Russia",
"Rwanda",
"Saint Helena",
"Saint Kitts and Nevis",
"Saint Lucia",
"Saint Pierre and Miquelon",
"Saint Vincent and the Grenadines",
"Samoa",
"San Marino",
"Sao Tome and Principe",
"Saudi Arabia",
"Scotland",
"Senegal",
"Seychelles",
"Sierra Leone",
"Singapore",
"Slovakia",
"Slovenia",
"Solomon Islands",
"Somalia",
"South Africa",
"South Georgia and South Sandwich Islands",
"Spain",
"Spratly Islands",
"Sri Lanka",
"Sudan",
"Suriname",
"Svalbard",
"Swaziland",
"Sweden",
"Switzerland",
"Syria",
"Taiwan",
"Tajikistan",
"Tanzania",
"Thailand",
"Tobago",
"Toga",
"Tokelau",
"Tonga",
"Trinidad",
"Tunisia",
"Turkey",
"Turkmenistan",
"Tuvalu",
"Uganda",
"Ukraine",
"United Arab Emirates",
"United Kingdom",
"Uruguay",
"USA",
"Uzbekistan",
"Vanuatu",
"Venezuela",
"Vietnam",
"Virgin Islands",
"Wales",
"Wallis and Futuna",
"West Bank",
"Western Sahara",
"Yemen",
"Yugoslavia",
"Zambia",
"Zimbabwe",
]
# States
s_a = []
s_a.append(
"Badakhshan|Badghis|Baghlan|Balkh|Bamian|Farah|Faryab|Ghazni|Ghowr|Helmand|Herat|Jowzjan|Kabol|Kandahar|Kapisa|Konar|Kondoz|Laghman|Lowgar|Nangarhar|Nimruz|Oruzgan|Paktia|Paktika|Parvan|Samangan|Sar-e Pol|Takhar|Vardak|Zabol"
)
s_a.append(
"Berat|Bulqize|Delvine|Devoll (Bilisht)|Diber (Peshkopi)|Durres|Elbasan|Fier|Gjirokaster|Gramsh|Has (Krume)|Kavaje|Kolonje (Erseke)|Korce|Kruje|Kucove|Kukes|Kurbin|Lezhe|Librazhd|Lushnje|Malesi e Madhe (Koplik)|Mallakaster (Ballsh)|Mat (Burrel)|Mirdite (Rreshen)|Peqin|Permet|Pogradec|Puke|Sarande|Shkoder|Skrapar (Corovode)|Tepelene|Tirane (Tirana)|Tirane (Tirana)|Tropoje (Bajram Curri)|Vlore"
)
s_a.append(
"Adrar|Ain Defla|Ain Temouchent|Alger|Annaba|Batna|Bechar|Bejaia|Biskra|Blida|Bordj Bou Arreridj|Bouira|Boumerdes|Chlef|Constantine|Djelfa|El Bayadh|El Oued|El Tarf|Ghardaia|Guelma|Illizi|Jijel|Khenchela|Laghouat|M'Sila|Mascara|Medea|Mila|Mostaganem|Naama|Oran|Ouargla|Oum el Bouaghi|Relizane|Saida|Setif|Sidi Bel Abbes|Skikda|Souk Ahras|Tamanghasset|Tebessa|Tiaret|Tindouf|Tipaza|Tissemsilt|Tizi Ouzou|Tlemcen"
)
s_a.append("Eastern|Manu'a|Rose Island|Swains Island|Western")
s_a.append(
"Andorra la Vella|Bengo|Benguela|Bie|Cabinda|Canillo|Cuando Cubango|Cuanza Norte|Cuanza Sul|Cunene|Encamp|Escaldes-Engordany|Huambo|Huila|La Massana|Luanda|Lunda Norte|Lunda Sul|Malanje|Moxico|Namibe|Ordino|Sant Julia de Loria|Uige|Zaire"
)
s_a.append("Anguilla")
s_a.append("Antartica")
s_a.append(
"Barbuda|Redonda|Saint George|Saint John|Saint Mary|Saint Paul|Saint Peter|Saint Philip"
)
s_a.append(
"Antartica e Islas del Atlantico Sur|Buenos Aires|Buenos Aires Capital Federal|Catamarca|Chaco|Chubut|Cordoba|Corrientes|Entre Rios|Formosa|Jujuy|La Pampa|La Rioja|Mendoza|Misiones|Neuquen|Rio Negro|Salta|San Juan|San Luis|Santa Cruz|Santa Fe|Santiago del Estero|Tierra del Fuego|Tucuman"
)
s_a.append(
"Aragatsotn|Ararat|Armavir|Geghark'unik'|Kotayk'|Lorri|Shirak|Syunik'|Tavush|Vayots' Dzor|Yerevan"
)
s_a.append("Aruba")
s_a.append("Ashmore and Cartier Island")
s_a.append(
"Australian Capital Territory|New South Wales|Northern Territory|Queensland|South Australia|Tasmania|Victoria|Western Australia"
)
s_a.append(
"Burgenland|Kaernten|Niederoesterreich|Oberoesterreich|Salzburg|Steiermark|Tirol|Vorarlberg|Wien"
)
s_a.append(
"Abseron Rayonu|Agcabadi Rayonu|Agdam Rayonu|Agdas Rayonu|Agstafa Rayonu|Agsu Rayonu|Ali Bayramli Sahari|Astara Rayonu|Baki Sahari|Balakan Rayonu|Barda Rayonu|Beylaqan Rayonu|Bilasuvar Rayonu|Cabrayil Rayonu|Calilabad Rayonu|Daskasan Rayonu|Davaci Rayonu|Fuzuli Rayonu|Gadabay Rayonu|Ganca Sahari|Goranboy Rayonu|Goycay Rayonu|Haciqabul Rayonu|Imisli Rayonu|Ismayilli Rayonu|Kalbacar Rayonu|Kurdamir Rayonu|Lacin Rayonu|Lankaran Rayonu|Lankaran Sahari|Lerik Rayonu|Masalli Rayonu|Mingacevir Sahari|Naftalan Sahari|Naxcivan Muxtar Respublikasi|Neftcala Rayonu|Oguz Rayonu|Qabala Rayonu|Qax Rayonu|Qazax Rayonu|Qobustan Rayonu|Quba Rayonu|Qubadli Rayonu|Qusar Rayonu|Saatli Rayonu|Sabirabad Rayonu|Saki Rayonu|Saki Sahari|Salyan Rayonu|Samaxi Rayonu|Samkir Rayonu|Samux Rayonu|Siyazan Rayonu|Sumqayit Sahari|Susa Rayonu|Susa Sahari|Tartar Rayonu|Tovuz Rayonu|Ucar Rayonu|Xacmaz Rayonu|Xankandi Sahari|Xanlar Rayonu|Xizi Rayonu|Xocali Rayonu|Xocavand Rayonu|Yardimli Rayonu|Yevlax Rayonu|Yevlax Sahari|Zangilan Rayonu|Zaqatala Rayonu|Zardab Rayonu"
)
s_a.append(
"Acklins and Crooked Islands|Bimini|Cat Island|Exuma|Freeport|Fresh Creek|Governor's Harbour|Green Turtle Cay|Harbour Island|High Rock|Inagua|Kemps Bay|Long Island|Marsh Harbour|Mayaguana|New Providence|Nicholls Town and Berry Islands|Ragged Island|Rock Sound|San Salvador and Rum Cay|Sandy Point"
)
s_a.append(
"Al Hadd|Al Manamah|Al Mintaqah al Gharbiyah|Al Mintaqah al Wusta|Al Mintaqah ash Shamaliyah|Al Muharraq|Ar Rifa' wa al Mintaqah al Janubiyah|Jidd Hafs|Juzur Hawar|Madinat 'Isa|Madinat Hamad|Sitrah"
)
s_a.append(
"Barguna|Barisal|Bhola|Jhalokati|Patuakhali|Pirojpur|Bandarban|Brahmanbaria|Chandpur|Chittagong|Comilla|Cox's Bazar|Feni|Khagrachari|Lakshmipur|Noakhali|Rangamati|Dhaka|Faridpur|Gazipur|Gopalganj|Jamalpur|Kishoreganj|Madaripur|Manikganj|Munshiganj|Mymensingh|Narayanganj|Narsingdi|Netrokona|Rajbari|Shariatpur|Sherpur|Tangail|Bagerhat|Chuadanga|Jessore|Jhenaidah|Khulna|Kushtia|Magura|Meherpur|Narail|Satkhira|Bogra|Dinajpur|Gaibandha|Jaipurhat|Kurigram|Lalmonirhat|Naogaon|Natore|Nawabganj|Nilphamari|Pabna|Panchagarh|Rajshahi|Rangpur|Sirajganj|Thakurgaon|Habiganj|Maulvi bazar|Sunamganj|Sylhet"
)
s_a.append(
"Bridgetown|Christ Church|Saint Andrew|Saint George|Saint James|Saint John|Saint Joseph|Saint Lucy|Saint Michael|Saint Peter|Saint Philip|Saint Thomas"
)
s_a.append(
"Brestskaya (Brest)|Homyel'skaya (Homyel')|Horad Minsk|Hrodzyenskaya (Hrodna)|Mahilyowskaya (Mahilyow)|Minskaya|Vitsyebskaya (Vitsyebsk)"
)
s_a.append(
"Antwerpen|Brabant Wallon|Brussels Capitol Region|Hainaut|Liege|Limburg|Luxembourg|Namur|Oost-Vlaanderen|Vlaams Brabant|West-Vlaanderen"
)
s_a.append("Belize|Cayo|Corozal|Orange Walk|Stann Creek|Toledo")
s_a.append(
"Alibori|Atakora|Atlantique|Borgou|Collines|Couffo|Donga|Littoral|Mono|Oueme|Plateau|Zou"
)
s_a.append(
"Devonshire|Hamilton|Hamilton|Paget|Pembroke|Saint George|Saint Georges|Sandys|Smiths|Southampton|Warwick"
)
s_a.append(
"Bumthang|Chhukha|Chirang|Daga|Geylegphug|Ha|Lhuntshi|Mongar|Paro|Pemagatsel|Punakha|Samchi|Samdrup Jongkhar|Shemgang|Tashigang|Thimphu|Tongsa|Wangdi Phodrang"
)
s_a.append("Beni|Chuquisaca|Cochabamba|La Paz|Oruro|Pando|Potosi|Santa Cruz|Tarija")
s_a.append("Federation of Bosnia and Herzegovina|Republika Srpska")
s_a.append(
"Central|Chobe|Francistown|Gaborone|Ghanzi|Kgalagadi|Kgatleng|Kweneng|Lobatse|Ngamiland|North-East|Selebi-Pikwe|South-East|Southern"
)
s_a.append(
"Acre|Alagoas|Amapa|Amazonas|Bahia|Ceara|Distrito Federal|Espirito Santo|Goias|Maranhao|Mato Grosso|Mato Grosso do Sul|Minas Gerais|Para|Paraiba|Parana|Pernambuco|Piaui|Rio de Janeiro|Rio Grande do Norte|Rio Grande do Sul|Rondonia|Roraima|Santa Catarina|Sao Paulo|Sergipe|Tocantins"
)
s_a.append("Anegada|Jost Van Dyke|Tortola|Virgin Gorda")
s_a.append("Belait|Brunei and Muara|Temburong|Tutong")
s_a.append(
"Blagoevgrad|Burgas|Dobrich|Gabrovo|Khaskovo|Kurdzhali|Kyustendil|Lovech|Montana|Pazardzhik|Pernik|Pleven|Plovdiv|Razgrad|Ruse|Shumen|Silistra|Sliven|Smolyan|Sofiya|Sofiya-Grad|Stara Zagora|Turgovishte|Varna|Veliko Turnovo|Vidin|Vratsa|Yambol"
)
s_a.append(
"Bale|Bam|Banwa|Bazega|Bougouriba|Boulgou|Boulkiemde|Comoe|Ganzourgou|Gnagna|Gourma|Houet|Ioba|Kadiogo|Kenedougou|Komandjari|Kompienga|Kossi|Koupelogo|Kouritenga|Kourweogo|Leraba|Loroum|Mouhoun|Nahouri|Namentenga|Naumbiel|Nayala|Oubritenga|Oudalan|Passore|Poni|Samentenga|Sanguie|Seno|Sissili|Soum|Sourou|Tapoa|Tuy|Yagha|Yatenga|Ziro|Zondomo|Zoundweogo"
)
s_a.append(
"Ayeyarwady|Bago|Chin State|Kachin State|Kayah State|Kayin State|Magway|Mandalay|Mon State|Rakhine State|Sagaing|Shan State|Tanintharyi|Yangon"
)
s_a.append(
"Bubanza|Bujumbura|Bururi|Cankuzo|Cibitoke|Gitega|Karuzi|Kayanza|Kirundo|Makamba|Muramvya|Muyinga|Mwaro|Ngozi|Rutana|Ruyigi"
)
s_a.append(
"Banteay Mean Cheay|Batdambang|Kampong Cham|Kampong Chhnang|Kampong Spoe|Kampong Thum|Kampot|Kandal|Kaoh Kong|Keb|Kracheh|Mondol Kiri|Otdar Mean Cheay|Pailin|Phnum Penh|Pouthisat|Preah Seihanu (Sihanoukville)|Preah Vihear|Prey Veng|Rotanah Kiri|Siem Reab|Stoeng Treng|Svay Rieng|Takev"
)
s_a.append(
"Adamaoua|Centre|Est|Extreme-Nord|Littoral|Nord|Nord-Ouest|Ouest|Sud|Sud-Ouest"
)
s_a.append(
"Alberta|British Columbia|Manitoba|New Brunswick|Newfoundland|Northwest Territories|Nova Scotia|Nunavut|Ontario|Prince Edward Island|Quebec|Saskatchewan|Yukon Territory"
)
s_a.append(
"Boa Vista|Brava|Maio|Mosteiros|Paul|Porto Novo|Praia|Ribeira Grande|Sal|Santa Catarina|Santa Cruz|Sao Domingos|Sao Filipe|Sao Nicolau|Sao Vicente|Tarrafal"
)
s_a.append("Creek|Eastern|Midland|South Town|Spot Bay|Stake Bay|West End|Western")
s_a.append(
"Bamingui-Bangoran|Bangui|Basse-Kotto|Gribingui|Haut-Mbomou|Haute-Kotto|Haute-Sangha|Kemo-Gribingui|Lobaye|Mbomou|Nana-Mambere|Ombella-Mpoko|Ouaka|Ouham|Ouham-Pende|Sangha|Vakaga"
)
s_a.append(
"Batha|Biltine|Borkou-Ennedi-Tibesti|Chari-Baguirmi|Guera|Kanem|Lac|Logone Occidental|Logone Oriental|Mayo-Kebbi|Moyen-Chari|Ouaddai|Salamat|Tandjile"
)
s_a.append(
"Aisen del General Carlos Ibanez del Campo|Antofagasta|Araucania|Atacama|Bio-Bio|Coquimbo|Libertador General Bernardo O'Higgins|Los Lagos|Magallanes y de la Antartica Chilena|Maule|Region Metropolitana (Santiago)|Tarapaca|Valparaiso"
)
s_a.append(
"Anhui|Beijing|Chongqing|Fujian|Gansu|Guangdong|Guangxi|Guizhou|Hainan|Hebei|Heilongjiang|Henan|Hubei|Hunan|Jiangsu|Jiangxi|Jilin|Liaoning|Nei Mongol|Ningxia|Qinghai|Shaanxi|Shandong|Shanghai|Shanxi|Sichuan|Tianjin|Xinjiang|Xizang (Tibet)|Yunnan|Zhejiang"
)
s_a.append("Christmas Island")
s_a.append("Clipperton Island")
s_a.append(
"Direction Island|Home Island|Horsburgh Island|North Keeling Island|South Island|West Island"
)
s_a.append(
"Amazonas|Antioquia|Arauca|Atlantico|Bolivar|Boyaca|Caldas|Caqueta|Casanare|Cauca|Cesar|Choco|Cordoba|Cundinamarca|Distrito Capital de Santa Fe de Bogota|Guainia|Guaviare|Huila|La Guajira|Magdalena|Meta|Narino|Norte de Santander|Putumayo|Quindio|Risaralda|San Andres y Providencia|Santander|Sucre|Tolima|Valle del Cauca|Vaupes|Vichada"
)
s_a.append(
"Anjouan (Nzwani)|Domoni|Fomboni|Grande Comore (Njazidja)|Moheli (Mwali)|Moroni|Moutsamoudou"
)
s_a.append(
"Bandundu|Bas-Congo|Equateur|Kasai-Occidental|Kasai-Oriental|Katanga|Kinshasa|Maniema|Nord-Kivu|Orientale|Sud-Kivu"
)
s_a.append(
"Bouenza|Brazzaville|Cuvette|Kouilou|Lekoumou|Likouala|Niari|Plateaux|Pool|Sangha"
)
s_a.append(
"Aitutaki|Atiu|Avarua|Mangaia|Manihiki|Manuae|Mauke|Mitiaro|Nassau Island|Palmerston|Penrhyn|Pukapuka|Rakahanga|Rarotonga|Suwarrow|Takutea"
)
s_a.append("Alajuela|Cartago|Guanacaste|Heredia|Limon|Puntarenas|San Jose")
s_a.append(
"Abengourou|Abidjan|Aboisso|Adiake'|Adzope|Agboville|Agnibilekrou|Ale'pe'|Bangolo|Beoumi|Biankouma|Bocanda|Bondoukou|Bongouanou|Bouafle|Bouake|Bouna|Boundiali|Dabakala|Dabon|Daloa|Danane|Daoukro|Dimbokro|Divo|Duekoue|Ferkessedougou|Gagnoa|Grand Bassam|Grand-Lahou|Guiglo|Issia|Jacqueville|Katiola|Korhogo|Lakota|Man|Mankono|Mbahiakro|Odienne|Oume|Sakassou|San-Pedro|Sassandra|Seguela|Sinfra|Soubre|Tabou|Tanda|Tiassale|Tiebissou|Tingrela|Touba|Toulepleu|Toumodi|Vavoua|Yamoussoukro|Zuenoula"
)
s_a.append(
"Bjelovarsko-Bilogorska Zupanija|Brodsko-Posavska Zupanija|Dubrovacko-Neretvanska Zupanija|Istarska Zupanija|Karlovacka Zupanija|Koprivnicko-Krizevacka Zupanija|Krapinsko-Zagorska Zupanija|Licko-Senjska Zupanija|Medimurska Zupanija|Osjecko-Baranjska Zupanija|Pozesko-Slavonska Zupanija|Primorsko-Goranska Zupanija|Sibensko-Kninska Zupanija|Sisacko-Moslavacka Zupanija|Splitsko-Dalmatinska Zupanija|Varazdinska Zupanija|Viroviticko-Podravska Zupanija|Vukovarsko-Srijemska Zupanija|Zadarska Zupanija|Zagreb|Zagrebacka Zupanija"
)
s_a.append(
"Camaguey|Ciego de Avila|Cienfuegos|Ciudad de La Habana|Granma|Guantanamo|Holguin|Isla de la Juventud|La Habana|Las Tunas|Matanzas|Pinar del Rio|Sancti Spiritus|Santiago de Cuba|Villa Clara"
)
s_a.append("Famagusta|Kyrenia|Larnaca|Limassol|Nicosia|Paphos")
s_a.append(
"Brnensky|Budejovicky|Jihlavsky|Karlovarsky|Kralovehradecky|Liberecky|Olomoucky|Ostravsky|Pardubicky|Plzensky|Praha|Stredocesky|Ustecky|Zlinsky"
)
s_a.append(
"Arhus|Bornholm|Fredericksberg|Frederiksborg|Fyn|Kobenhavn|Kobenhavns|Nordjylland|Ribe|Ringkobing|Roskilde|Sonderjylland|Storstrom|Vejle|Vestsjalland|Viborg"
)
s_a.append("'Ali Sabih|Dikhil|Djibouti|Obock|Tadjoura")
s_a.append(
"Saint Andrew|Saint David|Saint George|Saint John|Saint Joseph|Saint Luke|Saint Mark|Saint Patrick|Saint Paul|Saint Peter"
)
s_a.append(
"Azua|Baoruco|Barahona|Dajabon|Distrito Nacional|Duarte|El Seibo|Elias Pina|Espaillat|Hato Mayor|Independencia|La Altagracia|La Romana|La Vega|Maria Trinidad Sanchez|Monsenor Nouel|Monte Cristi|Monte Plata|Pedernales|Peravia|Puerto Plata|Salcedo|Samana|San Cristobal|San Juan|San Pedro de Macoris|Sanchez Ramirez|Santiago|Santiago Rodriguez|Valverde"
)
s_a.append(
"Azuay|Bolivar|Canar|Carchi|Chimborazo|Cotopaxi|El Oro|Esmeraldas|Galapagos|Guayas|Imbabura|Loja|Los Rios|Manabi|Morona-Santiago|Napo|Orellana|Pastaza|Pichincha|Sucumbios|Tungurahua|Zamora-Chinchipe"
)
s_a.append(
"Ad Daqahliyah|Al Bahr al Ahmar|Al Buhayrah|Al Fayyum|Al Gharbiyah|Al Iskandariyah|Al Isma'iliyah|Al Jizah|Al Minufiyah|Al Minya|Al Qahirah|Al Qalyubiyah|Al Wadi al Jadid|As Suways|Ash Sharqiyah|Aswan|Asyut|Bani Suwayf|Bur Sa'id|Dumyat|Janub Sina'|Kafr ash Shaykh|Matruh|Qina|Shamal Sina'|Suhaj"
)
s_a.append(
"Ahuachapan|Cabanas|Chalatenango|Cuscatlan|La Libertad|La Paz|La Union|Morazan|San Miguel|San Salvador|San Vicente|Santa Ana|Sonsonate|Usulutan"
)
s_a.append("Annobon|Bioko Norte|Bioko Sur|Centro Sur|Kie-Ntem|Litoral|Wele-Nzas")
s_a.append("Akale Guzay|Barka|Denkel|Hamasen|Sahil|Semhar|Senhit|Seraye")
s_a.append(
"Harjumaa (Tallinn)|Hiiumaa (Kardla)|Ida-Virumaa (Johvi)|Jarvamaa (Paide)|Jogevamaa (Jogeva)|Laane-Virumaa (Rakvere)|Laanemaa (Haapsalu)|Parnumaa (Parnu)|Polvamaa (Polva)|Raplamaa (Rapla)|Saaremaa (Kuessaare)|Tartumaa (Tartu)|Valgamaa (Valga)|Viljandimaa (Viljandi)|Vorumaa (Voru)"
)
s_a.append(
"Adis Abeba (Addis Ababa)|Afar|Amara|Dire Dawa|Gambela Hizboch|Hareri Hizb|Oromiya|Sumale|Tigray|YeDebub Biheroch Bihereseboch na Hizboch"
)
s_a.append("Europa Island")
s_a.append("Falkland Islands (Islas Malvinas)")
s_a.append("Bordoy|Eysturoy|Mykines|Sandoy|Skuvoy|Streymoy|Suduroy|Tvoroyri|Vagar")
s_a.append("Central|Eastern|Northern|Rotuma|Western")
s_a.append(
"Aland|Etela-Suomen Laani|Ita-Suomen Laani|Lansi-Suomen Laani|Lappi|Oulun Laani"
)
s_a.append(
"Alsace|Aquitaine|Auvergne|Basse-Normandie|Bourgogne|Bretagne|Centre|Champagne-Ardenne|Corse|Franche-Comte|Haute-Normandie|Ile-de-France|Languedoc-Roussillon|Limousin|Lorraine|Midi-Pyrenees|Nord-Pas-de-Calais|Pays de la Loire|Picardie|Poitou-Charentes|Provence-Alpes-Cote d'Azur|Rhone-Alpes"
)
s_a.append("French Guiana")
s_a.append(
"Archipel des Marquises|Archipel des Tuamotu|Archipel des Tubuai|Iles du Vent|Iles Sous-le-Vent"
)
s_a.append("Adelie Land|Ile Crozet|Iles Kerguelen|Iles Saint-Paul et Amsterdam")
s_a.append(
"Estuaire|Haut-Ogooue|Moyen-Ogooue|Ngounie|Nyanga|Ogooue-Ivindo|Ogooue-Lolo|Ogooue-Maritime|Woleu-Ntem"
)
s_a.append("Banjul|Central River|Lower River|North Bank|Upper River|Western")
s_a.append("Gaza Strip")
s_a.append(
"Abashis|Abkhazia or Ap'khazet'is Avtonomiuri Respublika (Sokhumi)|Adigenis|Ajaria or Acharis Avtonomiuri Respublika (Bat'umi)|Akhalgoris|Akhalk'alak'is|Akhalts'ikhis|Akhmetis|Ambrolauris|Aspindzis|Baghdat'is|Bolnisis|Borjomis|Ch'khorotsqus|Ch'okhatauris|Chiat'ura|Dedop'listsqaros|Dmanisis|Dushet'is|Gardabanis|Gori|Goris|Gurjaanis|Javis|K'arelis|K'ut'aisi|Kaspis|Kharagaulis|Khashuris|Khobis|Khonis|Lagodekhis|Lanch'khut'is|Lentekhis|Marneulis|Martvilis|Mestiis|Mts'khet'is|Ninotsmindis|Onis|Ozurget'is|P'ot'i|Qazbegis|Qvarlis|Rust'avi|Sach'kheris|Sagarejos|Samtrediis|Senakis|Sighnaghis|T'bilisi|T'elavis|T'erjolis|T'et'ritsqaros|T'ianet'is|Tqibuli|Ts'ageris|Tsalenjikhis|Tsalkis|Tsqaltubo|Vanis|Zestap'onis|Zugdidi|Zugdidis"
)
s_a.append(
"Baden-Wuerttemberg|Bayern|Berlin|Brandenburg|Bremen|Hamburg|Hessen|Mecklenburg-Vorpommern|Niedersachsen|Nordrhein-Westfalen|Rheinland-Pfalz|Saarland|Sachsen|Sachsen-Anhalt|Schleswig-Holstein|Thueringen"
)
s_a.append(
"Ashanti|Brong-Ahafo|Central|Eastern|Greater Accra|Northern|Upper East|Upper West|Volta|Western"
)
s_a.append("Gibraltar")
s_a.append("Ile du Lys|Ile Glorieuse")
s_a.append(
"Aitolia kai Akarnania|Akhaia|Argolis|Arkadhia|Arta|Attiki|Ayion Oros (Mt. Athos)|Dhodhekanisos|Drama|Evritania|Evros|Evvoia|Florina|Fokis|Fthiotis|Grevena|Ilia|Imathia|Ioannina|Irakleion|Kardhitsa|Kastoria|Kavala|Kefallinia|Kerkyra|Khalkidhiki|Khania|Khios|Kikladhes|Kilkis|Korinthia|Kozani|Lakonia|Larisa|Lasithi|Lesvos|Levkas|Magnisia|Messinia|Pella|Pieria|Preveza|Rethimni|Rodhopi|Samos|Serrai|Thesprotia|Thessaloniki|Trikala|Voiotia|Xanthi|Zakinthos"
)
s_a.append("Avannaa (Nordgronland)|Kitaa (Vestgronland)|Tunu (Ostgronland)")
s_a.append(
"Carriacou and Petit Martinique|Saint Andrew|Saint David|Saint George|Saint John|Saint Mark|Saint Patrick"
)
s_a.append(
"Basse-Terre|Grande-Terre|Iles de la Petite Terre|Iles des Saintes|Marie-Galante"
)
s_a.append("Guam")
s_a.append(
"Alta Verapaz|Baja Verapaz|Chimaltenango|Chiquimula|El Progreso|Escuintla|Guatemala|Huehuetenango|Izabal|Jalapa|Jutiapa|Peten|Quetzaltenango|Quiche|Retalhuleu|Sacatepequez|San Marcos|Santa Rosa|Solola|Suchitepequez|Totonicapan|Zacapa"
)
s_a.append(
"Castel|Forest|St. Andrew|St. Martin|St. Peter Port|St. Pierre du Bois|St. Sampson|St. Saviour|Torteval|Vale"
)
s_a.append(
"Beyla|Boffa|Boke|Conakry|Coyah|Dabola|Dalaba|Dinguiraye|Dubreka|Faranah|Forecariah|Fria|Gaoual|Gueckedou|Kankan|Kerouane|Kindia|Kissidougou|Koubia|Koundara|Kouroussa|Labe|Lelouma|Lola|Macenta|Mali|Mamou|Mandiana|Nzerekore|Pita|Siguiri|Telimele|Tougue|Yomou"
)
s_a.append("Bafata|Biombo|Bissau|Bolama-Bijagos|Cacheu|Gabu|Oio|Quinara|Tombali")
s_a.append(
"Barima-Waini|Cuyuni-Mazaruni|Demerara-Mahaica|East Berbice-Corentyne|Essequibo Islands-West Demerara|Mahaica-Berbice|Pomeroon-Supenaam|Potaro-Siparuni|Upper Demerara-Berbice|Upper Takutu-Upper Essequibo"
)
s_a.append("Artibonite|Centre|Grand'Anse|Nord|Nord-Est|Nord-Ouest|Ouest|Sud|Sud-Est")
s_a.append("Heard Island and McDonald Islands")
s_a.append("Holy See (Vatican City)")
s_a.append(
"Atlantida|Choluteca|Colon|Comayagua|Copan|Cortes|El Paraiso|Francisco Morazan|Gracias a Dios|Intibuca|Islas de la Bahia|La Paz|Lempira|Ocotepeque|Olancho|Santa Barbara|Valle|Yoro"
)
s_a.append("Hong Kong")
s_a.append("Howland Island")
s_a.append(
"Bacs-Kiskun|Baranya|Bekes|Bekescsaba|Borsod-Abauj-Zemplen|Budapest|Csongrad|Debrecen|Dunaujvaros|Eger|Fejer|Gyor|Gyor-Moson-Sopron|Hajdu-Bihar|Heves|Hodmezovasarhely|Jasz-Nagykun-Szolnok|Kaposvar|Kecskemet|Komarom-Esztergom|Miskolc|Nagykanizsa|Nograd|Nyiregyhaza|Pecs|Pest|Somogy|Sopron|Szabolcs-Szatmar-Bereg|Szeged|Szekesfehervar|Szolnok|Szombathely|Tatabanya|Tolna|Vas|Veszprem|Veszprem|Zala|Zalaegerszeg"
)
s_a.append(
"Akranes|Akureyri|Arnessysla|Austur-Bardhastrandarsysla|Austur-Hunavatnssysla|Austur-Skaftafellssysla|Borgarfjardharsysla|Dalasysla|Eyjafjardharsysla|Gullbringusysla|Hafnarfjordhur|Husavik|Isafjordhur|Keflavik|Kjosarsysla|Kopavogur|Myrasysla|Neskaupstadhur|Nordhur-Isafjardharsysla|Nordhur-Mulasys-la|Nordhur-Thingeyjarsysla|Olafsfjordhur|Rangarvallasysla|Reykjavik|Saudharkrokur|Seydhisfjordhur|Siglufjordhur|Skagafjardharsysla|Snaefellsnes-og Hnappadalssysla|Strandasysla|Sudhur-Mulasysla|Sudhur-Thingeyjarsysla|Vesttmannaeyjar|Vestur-Bardhastrandarsysla|Vestur-Hunavatnssysla|Vestur-Isafjardharsysla|Vestur-Skaftafellssysla"
)
s_a.append(
"Andaman and Nicobar Islands|Andhra Pradesh|Arunachal Pradesh|Assam|Bihar|Chandigarh|Chhattisgarh|Dadra and Nagar Haveli|Daman and Diu|Delhi|Goa|Gujarat|Haryana|Himachal Pradesh|Jammu and Kashmir|Jharkhand|Karnataka|Kerala|Lakshadweep|Madhya Pradesh|Maharashtra|Manipur|Meghalaya|Mizoram|Nagaland|Orissa|Pondicherry|Punjab|Rajasthan|Sikkim|Tamil Nadu|Telangana|Tripura|Uttar Pradesh|Uttaranchal|West Bengal"
)
s_a.append(
"Aceh|Bali|Banten|Bengkulu|East Timor|Gorontalo|Irian Jaya|Jakarta Raya|Jambi|Jawa Barat|Jawa Tengah|Jawa Timur|Kalimantan Barat|Kalimantan Selatan|Kalimantan Tengah|Kalimantan Timur|Kepulauan Bangka Belitung|Lampung|Maluku|Maluku Utara|Nusa Tenggara Barat|Nusa Tenggara Timur|Riau|Sulawesi Selatan|Sulawesi Tengah|Sulawesi Tenggara|Sulawesi Utara|Sumatera Barat|Sumatera Selatan|Sumatera Utara|Yogyakarta"
)
s_a.append(
"Ardabil|Azarbayjan-e Gharbi|Azarbayjan-e Sharqi|Bushehr|Chahar Mahall va Bakhtiari|Esfahan|Fars|Gilan|Golestan|Hamadan|Hormozgan|Ilam|Kerman|Kermanshah|Khorasan|Khuzestan|Kohgiluyeh va Buyer Ahmad|Kordestan|Lorestan|Markazi|Mazandaran|Qazvin|Qom|Semnan|Sistan va Baluchestan|Tehran|Yazd|Zanjan"
)
s_a.append(
"Al Anbar|Al Basrah|Al Muthanna|Al Qadisiyah|An Najaf|Arbil|As Sulaymaniyah|At Ta'mim|Babil|Baghdad|Dahuk|Dhi Qar|Diyala|Karbala'|Maysan|Ninawa|Salah ad Din|Wasit"
)
s_a.append(
"Carlow|Cavan|Clare|Cork|Donegal|Dublin|Galway|Kerry|Kildare|Kilkenny|Laois|Leitrim|Limerick|Longford|Louth|Mayo|Meath|Monaghan|Offaly|Roscommon|Sligo|Tipperary|Waterford|Westmeath|Wexford|Wicklow"
)
s_a.append(
"Antrim|Ards|Armagh|Ballymena|Ballymoney|Banbridge|Belfast|Carrickfergus|Castlereagh|Coleraine|Cookstown|Craigavon|Derry|Down|Dungannon|Fermanagh|Larne|Limavady|Lisburn|Magherafelt|Moyle|Newry and Mourne|Newtownabbey|North Down|Omagh|Strabane"
)
s_a.append("Central|Haifa|Jerusalem|Northern|Southern|Tel Aviv")
s_a.append(
"Abruzzo|Basilicata|Calabria|Campania|Emilia-Romagna|Friuli-Venezia Giulia|Lazio|Liguria|Lombardia|Marche|Molise|Piemonte|Puglia|Sardegna|Sicilia|Toscana|Trentino-Alto Adige|Umbria|Valle d'Aosta|Veneto"
)
s_a.append(
"Clarendon|Hanover|Kingston|Manchester|Portland|Saint Andrew|Saint Ann|Saint Catherine|Saint Elizabeth|Saint James|Saint Mary|Saint Thomas|Trelawny|Westmoreland"
)
s_a.append("Jan Mayen")
s_a.append(
"Aichi|Akita|Aomori|Chiba|Ehime|Fukui|Fukuoka|Fukushima|Gifu|Gumma|Hiroshima|Hokkaido|Hyogo|Ibaraki|Ishikawa|Iwate|Kagawa|Kagoshima|Kanagawa|Kochi|Kumamoto|Kyoto|Mie|Miyagi|Miyazaki|Nagano|Nagasaki|Nara|Niigata|Oita|Okayama|Okinawa|Osaka|Saga|Saitama|Shiga|Shimane|Shizuoka|Tochigi|Tokushima|Tokyo|Tottori|Toyama|Wakayama|Yamagata|Yamaguchi|Yamanashi"
)
s_a.append("Jarvis Island")
s_a.append("Jersey")
s_a.append("Johnston Atoll")
s_a.append(
"'Amman|Ajlun|Al 'Aqabah|Al Balqa'|Al Karak|Al Mafraq|At Tafilah|Az Zarqa'|Irbid|Jarash|Ma'an|Madaba"
)
s_a.append("Juan de Nova Island")
s_a.append(
"Almaty|Aqmola|Aqtobe|Astana|Atyrau|Batys Qazaqstan|Bayqongyr|Mangghystau|Ongtustik Qazaqstan|Pavlodar|Qaraghandy|Qostanay|Qyzylorda|Shyghys Qazaqstan|Soltustik Qazaqstan|Zhambyl"
)
s_a.append(
"Central|Coast|Eastern|Nairobi Area|North Eastern|Nyanza|Rift Valley|Western"
)
s_a.append(
"Abaiang|Abemama|Aranuka|Arorae|Banaba|Banaba|Beru|Butaritari|Central Gilberts|Gilbert Islands|Kanton|Kiritimati|Kuria|Line Islands|Line Islands|Maiana|Makin|Marakei|Nikunau|Nonouti|Northern Gilberts|Onotoa|Phoenix Islands|Southern Gilberts|Tabiteuea|Tabuaeran|Tamana|Tarawa|Tarawa|Teraina"
)
s_a.append(
"Chagang-do (Chagang Province)|Hamgyong-bukto (North Hamgyong Province)|Hamgyong-namdo (South Hamgyong Province)|Hwanghae-bukto (North Hwanghae Province)|Hwanghae-namdo (South Hwanghae Province)|Kaesong-si (Kaesong City)|Kangwon-do (Kangwon Province)|Namp'o-si (Namp'o City)|P'yongan-bukto (North P'yongan Province)|P'yongan-namdo (South P'yongan Province)|P'yongyang-si (P'yongyang City)|Yanggang-do (Yanggang Province)"
)
s_a.append(
"Ch'ungch'ong-bukto|Ch'ungch'ong-namdo|Cheju-do|Cholla-bukto|Cholla-namdo|Inch'on-gwangyoksi|Kangwon-do|Kwangju-gwangyoksi|Kyonggi-do|Kyongsang-bukto|Kyongsang-namdo|Pusan-gwangyoksi|Soul-t'ukpyolsi|Taegu-gwangyoksi|Taejon-gwangyoksi|Ulsan-gwangyoksi"
)
s_a.append("Al 'Asimah|Al Ahmadi|Al Farwaniyah|Al Jahra'|Hawalli")
s_a.append(
"Batken Oblasty|Bishkek Shaary|Chuy Oblasty (Bishkek)|Jalal-Abad Oblasty|Naryn Oblasty|Osh Oblasty|Talas Oblasty|Ysyk-Kol Oblasty (Karakol)"
)
s_a.append(
"Attapu|Bokeo|Bolikhamxai|Champasak|Houaphan|Khammouan|Louangnamtha|Louangphabang|Oudomxai|Phongsali|Salavan|Savannakhet|Viangchan|Viangchan|Xaignabouli|Xaisomboun|Xekong|Xiangkhoang"
)
s_a.append(
"Aizkraukles Rajons|Aluksnes Rajons|Balvu Rajons|Bauskas Rajons|Cesu Rajons|Daugavpils|Daugavpils Rajons|Dobeles Rajons|Gulbenes Rajons|Jekabpils Rajons|Jelgava|Jelgavas Rajons|Jurmala|Kraslavas Rajons|Kuldigas Rajons|Leipaja|Liepajas Rajons|Limbazu Rajons|Ludzas Rajons|Madonas Rajons|Ogres Rajons|Preilu Rajons|Rezekne|Rezeknes Rajons|Riga|Rigas Rajons|Saldus Rajons|Talsu Rajons|Tukuma Rajons|Valkas Rajons|Valmieras Rajons|Ventspils|Ventspils Rajons"
)
s_a.append("Beyrouth|Ech Chimal|Ej Jnoub|El Bekaa|Jabal Loubnane")
s_a.append(
"Berea|Butha-Buthe|Leribe|Mafeteng|Maseru|Mohales Hoek|Mokhotlong|Qacha's Nek|Quthing|Thaba-Tseka"
)
s_a.append(
"Bomi|Bong|Grand Bassa|Grand Cape Mount|Grand Gedeh|Grand Kru|Lofa|Margibi|Maryland|Montserrado|Nimba|River Cess|Sinoe"
)
s_a.append(
"Ajdabiya|Al 'Aziziyah|Al Fatih|Al Jabal al Akhdar|Al Jufrah|Al Khums|Al Kufrah|An Nuqat al Khams|Ash Shati'|Awbari|Az Zawiyah|Banghazi|Darnah|Ghadamis|Gharyan|Misratah|Murzuq|Sabha|Sawfajjin|Surt|Tarabulus|Tarhunah|Tubruq|Yafran|Zlitan"
)
s_a.append(
"Balzers|Eschen|Gamprin|Mauren|Planken|Ruggell|Schaan|Schellenberg|Triesen|Triesenberg|Vaduz"
)
s_a.append(
"Akmenes Rajonas|Alytaus Rajonas|Alytus|Anyksciu Rajonas|Birstonas|Birzu Rajonas|Druskininkai|Ignalinos Rajonas|Jonavos Rajonas|Joniskio Rajonas|Jurbarko Rajonas|Kaisiadoriu Rajonas|Kaunas|Kauno Rajonas|Kedainiu Rajonas|Kelmes Rajonas|Klaipeda|Klaipedos Rajonas|Kretingos Rajonas|Kupiskio Rajonas|Lazdiju Rajonas|Marijampole|Marijampoles Rajonas|Mazeikiu Rajonas|Moletu Rajonas|Neringa Pakruojo Rajonas|Palanga|Panevezio Rajonas|Panevezys|Pasvalio Rajonas|Plunges Rajonas|Prienu Rajonas|Radviliskio Rajonas|Raseiniu Rajonas|Rokiskio Rajonas|Sakiu Rajonas|Salcininku Rajonas|Siauliai|Siauliu Rajonas|Silales Rajonas|Silutes Rajonas|Sirvintu Rajonas|Skuodo Rajonas|Svencioniu Rajonas|Taurages Rajonas|Telsiu Rajonas|Traku Rajonas|Ukmerges Rajonas|Utenos Rajonas|Varenos Rajonas|Vilkaviskio Rajonas|Vilniaus Rajonas|Vilnius|Zarasu Rajonas"
)
s_a.append("Diekirch|Grevenmacher|Luxembourg")
s_a.append("Macau")
s_a.append(
"Aracinovo|Bac|Belcista|Berovo|Bistrica|Bitola|Blatec|Bogdanci|Bogomila|Bogovinje|Bosilovo|Brvenica|Cair (Skopje)|Capari|Caska|Cegrane|Centar (Skopje)|Centar Zupa|Cesinovo|Cucer-Sandevo|Debar|Delcevo|Delogozdi|Demir Hisar|Demir Kapija|Dobrusevo|Dolna Banjica|Dolneni|Dorce Petrov (Skopje)|Drugovo|Dzepciste|Gazi Baba (Skopje)|Gevgelija|Gostivar|Gradsko|Ilinden|Izvor|Jegunovce|Kamenjane|Karbinci|Karpos (Skopje)|Kavadarci|Kicevo|Kisela Voda (Skopje)|Klecevce|Kocani|Konce|Kondovo|Konopiste|Kosel|Kratovo|Kriva Palanka|Krivogastani|Krusevo|Kuklis|Kukurecani|Kumanovo|Labunista|Lipkovo|Lozovo|Lukovo|Makedonska Kamenica|Makedonski Brod|Mavrovi Anovi|Meseista|Miravci|Mogila|Murtino|Negotino|Negotino-Poloska|Novaci|Novo Selo|Oblesevo|Ohrid|Orasac|Orizari|Oslomej|Pehcevo|Petrovec|Plasnia|Podares|Prilep|Probistip|Radovis|Rankovce|Resen|Rosoman|Rostusa|Samokov|Saraj|Sipkovica|Sopiste|Sopotnika|Srbinovo|Star Dojran|Staravina|Staro Nagoricane|Stip|Struga|Strumica|Studenicani|Suto Orizari (Skopje)|Sveti Nikole|Tearce|Tetovo|Topolcani|Valandovo|Vasilevo|Veles|Velesta|Vevcani|Vinica|Vitoliste|Vranestica|Vrapciste|Vratnica|Vrutok|Zajas|Zelenikovo|Zileno|Zitose|Zletovo|Zrnovci"
)
s_a.append("Antananarivo|Antsiranana|Fianarantsoa|Mahajanga|Toamasina|Toliara")
s_a.append(
"Balaka|Blantyre|Chikwawa|Chiradzulu|Chitipa|Dedza|Dowa|Karonga|Kasungu|Likoma|Lilongwe|Machinga (Kasupe)|Mangochi|Mchinji|Mulanje|Mwanza|Mzimba|Nkhata Bay|Nkhotakota|Nsanje|Ntcheu|Ntchisi|Phalombe|Rumphi|Salima|Thyolo|Zomba"
)
s_a.append(
"Johor|Kedah|Kelantan|Labuan|Melaka|Negeri Sembilan|Pahang|Perak|Perlis|Pulau Pinang|Sabah|Sarawak|Selangor|Terengganu|Wilayah Persekutuan"
)
s_a.append(
"Alifu|Baa|Dhaalu|Faafu|Gaafu Alifu|Gaafu Dhaalu|Gnaviyani|Haa Alifu|Haa Dhaalu|Kaafu|Laamu|Lhaviyani|Maale|Meemu|Noonu|Raa|Seenu|Shaviyani|Thaa|Vaavu"
)
s_a.append("Gao|Kayes|Kidal|Koulikoro|Mopti|Segou|Sikasso|Tombouctou")
s_a.append("Valletta")
s_a.append("Man, Isle of")
s_a.append(
"Ailinginae|Ailinglaplap|Ailuk|Arno|Aur|Bikar|Bikini|Bokak|Ebon|Enewetak|Erikub|Jabat|Jaluit|Jemo|Kili|Kwajalein|Lae|Lib|Likiep|Majuro|Maloelap|Mejit|Mili|Namorik|Namu|Rongelap|Rongrik|Toke|Ujae|Ujelang|Utirik|Wotho|Wotje"
)
s_a.append("Martinique")
s_a.append(
"Adrar|Assaba|Brakna|Dakhlet Nouadhibou|Gorgol|Guidimaka|Hodh Ech Chargui|Hodh El Gharbi|Inchiri|Nouakchott|Tagant|Tiris Zemmour|Trarza"
)
s_a.append(
"Agalega Islands|Black River|Cargados Carajos Shoals|Flacq|Grand Port|Moka|Pamplemousses|Plaines Wilhems|Port Louis|Riviere du Rempart|Rodrigues|Savanne"
)
s_a.append("Mayotte")
s_a.append(
"Aguascalientes|Baja California|Baja California Sur|Campeche|Chiapas|Chihuahua|Coahuila de Zaragoza|Colima|Distrito Federal|Durango|Guanajuato|Guerrero|Hidalgo|Jalisco|Mexico|Michoacan de Ocampo|Morelos|Nayarit|Nuevo Leon|Oaxaca|Puebla|Queretaro de Arteaga|Quintana Roo|San Luis Potosi|Sinaloa|Sonora|Tabasco|Tamaulipas|Tlaxcala|Veracruz-Llave|Yucatan|Zacatecas"
)
s_a.append("Chuuk (Truk)|Kosrae|Pohnpei|Yap")
s_a.append("Midway Islands")
s_a.append(
"Balti|Cahul|Chisinau|Chisinau|Dubasari|Edinet|Gagauzia|Lapusna|Orhei|Soroca|Tighina|Ungheni"
)
s_a.append("Fontvieille|La Condamine|Monaco-Ville|Monte-Carlo")
s_a.append(
"Arhangay|Bayan-Olgiy|Bayanhongor|Bulgan|Darhan|Dornod|Dornogovi|Dundgovi|Dzavhan|Erdenet|Govi-Altay|Hentiy|Hovd|Hovsgol|Omnogovi|Ovorhangay|Selenge|Suhbaatar|Tov|Ulaanbaatar|Uvs"
)
s_a.append("Saint Anthony|Saint Georges|Saint Peter's")
s_a.append(
"Agadir|Al Hoceima|Azilal|Ben Slimane|Beni Mellal|Boulemane|Casablanca|Chaouen|El Jadida|El Kelaa des Srarhna|Er Rachidia|Essaouira|Fes|Figuig|Guelmim|Ifrane|Kenitra|Khemisset|Khenifra|Khouribga|Laayoune|Larache|Marrakech|Meknes|Nador|Ouarzazate|Oujda|Rabat-Sale|Safi|Settat|Sidi Kacem|Tan-Tan|Tanger|Taounate|Taroudannt|Tata|Taza|Tetouan|Tiznit"
)
s_a.append(
"Cabo Delgado|Gaza|Inhambane|Manica|Maputo|Nampula|Niassa|Sofala|Tete|Zambezia"
)
s_a.append(
"Caprivi|Erongo|Hardap|Karas|Khomas|Kunene|Ohangwena|Okavango|Omaheke|Omusati|Oshana|Oshikoto|Otjozondjupa"
)
s_a.append(
"Aiwo|Anabar|Anetan|Anibare|Baiti|Boe|Buada|Denigomodu|Ewa|Ijuw|Meneng|Nibok|Uaboe|Yaren"
)
s_a.append(
"Bagmati|Bheri|Dhawalagiri|Gandaki|Janakpur|Karnali|Kosi|Lumbini|Mahakali|Mechi|Narayani|Rapti|Sagarmatha|Seti"
)
s_a.append(
"Drenthe|Flevoland|Friesland|Gelderland|Groningen|Limburg|Noord-Brabant|Noord-Holland|Overijssel|Utrecht|Zeeland|Zuid-Holland"
)
s_a.append("Netherlands Antilles")
s_a.append("Iles Loyaute|Nord|Sud")
s_a.append(
"Akaroa|Amuri|Ashburton|Bay of Islands|Bruce|Buller|Chatham Islands|Cheviot|Clifton|Clutha|Cook|Dannevirke|Egmont|Eketahuna|Ellesmere|Eltham|Eyre|Featherston|Franklin|Golden Bay|Great Barrier Island|Grey|Hauraki Plains|Hawera|Hawke's Bay|Heathcote|Hikurangi|Hobson|Hokianga|Horowhenua|Hurunui|Hutt|Inangahua|Inglewood|Kaikoura|Kairanga|Kiwitea|Lake|Mackenzie|Malvern|Manaia|Manawatu|Mangonui|Maniototo|Marlborough|Masterton|Matamata|Mount Herbert|Ohinemuri|Opotiki|Oroua|Otamatea|Otorohanga|Oxford|Pahiatua|Paparua|Patea|Piako|Pohangina|Raglan|Rangiora|Rangitikei|Rodney|Rotorua|Runanga|Saint Kilda|Silverpeaks|Southland|Stewart Island|Stratford|Strathallan|Taranaki|Taumarunui|Taupo|Tauranga|Thames-Coromandel|Tuapeka|Vincent|Waiapu|Waiheke|Waihemo|Waikato|Waikohu|Waimairi|Waimarino|Waimate|Waimate West|Waimea|Waipa|Waipawa|Waipukurau|Wairarapa South|Wairewa|Wairoa|Waitaki|Waitomo|Waitotara|Wallace|Wanganui|Waverley|Westland|Whakatane|Whangarei|Whangaroa|Woodville"
)
s_a.append(
"Atlantico Norte|Atlantico Sur|Boaco|Carazo|Chinandega|Chontales|Esteli|Granada|Jinotega|Leon|Madriz|Managua|Masaya|Matagalpa|Nueva Segovia|Rio San Juan|Rivas"
)
s_a.append("Agadez|Diffa|Dosso|Maradi|Niamey|Tahoua|Tillaberi|Zinder")
s_a.append(
"Abia|Abuja Federal Capital Territory|Adamawa|Akwa Ibom|Anambra|Bauchi|Bayelsa|Benue|Borno|Cross River|Delta|Ebonyi|Edo|Ekiti|Enugu|Gombe|Imo|Jigawa|Kaduna|Kano|Katsina|Kebbi|Kogi|Kwara|Lagos|Nassarawa|Niger|Ogun|Ondo|Osun|Oyo|Plateau|Rivers|Sokoto|Taraba|Yobe|Zamfara"
)
s_a.append("Niue")
s_a.append("Norfolk Island")
s_a.append("Northern Islands|Rota|Saipan|Tinian")
s_a.append(
"Akershus|Aust-Agder|Buskerud|Finnmark|Hedmark|Hordaland|More og Romsdal|Nord-Trondelag|Nordland|Oppland|Oslo|Ostfold|Rogaland|Sogn og Fjordane|Sor-Trondelag|Telemark|Troms|Vest-Agder|Vestfold"
)
s_a.append(
"Ad Dakhiliyah|Al Batinah|Al Wusta|Ash Sharqiyah|Az Zahirah|Masqat|Musandam|Zufar"
)
s_a.append(
"Balochistan|Federally Administered Tribal Areas|Islamabad Capital Territory|North-West Frontier Province|Punjab|Sindh"
)
s_a.append(
"Aimeliik|Airai|Angaur|Hatobohei|Kayangel|Koror|Melekeok|Ngaraard|Ngarchelong|Ngardmau|Ngatpang|Ngchesar|Ngeremlengui|Ngiwal|Palau Island|Peleliu|Sonsoral|Tobi"
)
s_a.append(
"Bocas del Toro|Chiriqui|Cocle|Colon|Darien|Herrera|Los Santos|Panama|San Blas|Veraguas"
)
s_a.append(
"Bougainville|Central|Chimbu|East New Britain|East Sepik|Eastern Highlands|Enga|Gulf|Madang|Manus|Milne Bay|Morobe|National Capital|New Ireland|Northern|Sandaun|Southern Highlands|West New Britain|Western|Western Highlands"
)
s_a.append(
"Alto Paraguay|Alto Parana|Amambay|Asuncion (city)|Boqueron|Caaguazu|Caazapa|Canindeyu|Central|Concepcion|Cordillera|Guaira|Itapua|Misiones|Neembucu|Paraguari|Presidente Hayes|San Pedro"
)
s_a.append(
"Amazonas|Ancash|Apurimac|Arequipa|Ayacucho|Cajamarca|Callao|Cusco|Huancavelica|Huanuco|Ica|Junin|La Libertad|Lambayeque|Lima|Loreto|Madre de Dios|Moquegua|Pasco|Piura|Puno|San Martin|Tacna|Tumbes|Ucayali"
)
s_a.append(
"Abra|Agusan del Norte|Agusan del Sur|Aklan|Albay|Angeles|Antique|Aurora|Bacolod|Bago|Baguio|Bais|Basilan|Basilan City|Bataan|Batanes|Batangas|Batangas City|Benguet|Bohol|Bukidnon|Bulacan|Butuan|Cabanatuan|Cadiz|Cagayan|Cagayan de Oro|Calbayog|Caloocan|Camarines Norte|Camarines Sur|Camiguin|Canlaon|Capiz|Catanduanes|Cavite|Cavite City|Cebu|Cebu City|Cotabato|Dagupan|Danao|Dapitan|Davao City Davao|Davao del Sur|Davao Oriental|Dipolog|Dumaguete|Eastern Samar|General Santos|Gingoog|Ifugao|Iligan|Ilocos Norte|Ilocos Sur|Iloilo|Iloilo City|Iriga|Isabela|Kalinga-Apayao|La Carlota|La Union|Laguna|Lanao del Norte|Lanao del Sur|Laoag|Lapu-Lapu|Legaspi|Leyte|Lipa|Lucena|Maguindanao|Mandaue|Manila|Marawi|Marinduque|Masbate|Mindoro Occidental|Mindoro Oriental|Misamis Occidental|Misamis Oriental|Mountain|Naga|Negros Occidental|Negros Oriental|North Cotabato|Northern Samar|Nueva Ecija|Nueva Vizcaya|Olongapo|Ormoc|Oroquieta|Ozamis|Pagadian|Palawan|Palayan|Pampanga|Pangasinan|Pasay|Puerto Princesa|Quezon|Quezon City|Quirino|Rizal|Romblon|Roxas|Samar|San Carlos (in Negros Occidental)|San Carlos (in Pangasinan)|San Jose|San Pablo|Silay|Siquijor|Sorsogon|South Cotabato|Southern Leyte|Sultan Kudarat|Sulu|Surigao|Surigao del Norte|Surigao del Sur|Tacloban|Tagaytay|Tagbilaran|Tangub|Tarlac|Tawitawi|Toledo|Trece Martires|Zambales|Zamboanga|Zamboanga del Norte|Zamboanga del Sur"
)
s_a.append("Pitcaim Islands")
s_a.append(
"Dolnoslaskie|Kujawsko-Pomorskie|Lodzkie|Lubelskie|Lubuskie|Malopolskie|Mazowieckie|Opolskie|Podkarpackie|Podlaskie|Pomorskie|Slaskie|Swietokrzyskie|Warminsko-Mazurskie|Wielkopolskie|Zachodniopomorskie"
)
s_a.append(
"Acores (Azores)|Aveiro|Beja|Braga|Braganca|Castelo Branco|Coimbra|Evora|Faro|Guarda|Leiria|Lisboa|Madeira|Portalegre|Porto|Santarem|Setubal|Viana do Castelo|Vila Real|Viseu"
)
s_a.append(
"Adjuntas|Aguada|Aguadilla|Aguas Buenas|Aibonito|Anasco|Arecibo|Arroyo|Barceloneta|Barranquitas|Bayamon|Cabo Rojo|Caguas|Camuy|Canovanas|Carolina|Catano|Cayey|Ceiba|Ciales|Cidra|Coamo|Comerio|Corozal|Culebra|Dorado|Fajardo|Florida|Guanica|Guayama|Guayanilla|Guaynabo|Gurabo|Hatillo|Hormigueros|Humacao|Isabela|Jayuya|Juana Diaz|Juncos|Lajas|Lares|Las Marias|Las Piedras|Loiza|Luquillo|Manati|Maricao|Maunabo|Mayaguez|Moca|Morovis|Naguabo|Naranjito|Orocovis|Patillas|Penuelas|Ponce|Quebradillas|Rincon|Rio Grande|Sabana Grande|Salinas|San German|San Juan|San Lorenzo|San Sebastian|Santa Isabel|Toa Alta|Toa Baja|Trujillo Alto|Utuado|Vega Alta|Vega Baja|Vieques|Villalba|Yabucoa|Yauco"
)
s_a.append(
"Ad Dawhah|Al Ghuwayriyah|Al Jumayliyah|Al Khawr|Al Wakrah|Ar Rayyan|Jarayan al Batinah|Madinat ash Shamal|Umm Salal"
)
s_a.append("Reunion")
s_a.append(
"Alba|Arad|Arges|Bacau|Bihor|Bistrita-Nasaud|Botosani|Braila|Brasov|Bucuresti|Buzau|Calarasi|Caras-Severin|Cluj|Constanta|Covasna|Dimbovita|Dolj|Galati|Giurgiu|Gorj|Harghita|Hunedoara|Ialomita|Iasi|Maramures|Mehedinti|Mures|Neamt|Olt|Prahova|Salaj|Satu Mare|Sibiu|Suceava|Teleorman|Timis|Tulcea|Vaslui|Vilcea|Vrancea"
)
s_a.append(
"Adygeya (Maykop)|Aginskiy Buryatskiy (Aginskoye)|Altay (Gorno-Altaysk)|Altayskiy (Barnaul)|Amurskaya (Blagoveshchensk)|Arkhangel'skaya|Astrakhanskaya|Bashkortostan (Ufa)|Belgorodskaya|Bryanskaya|Buryatiya (Ulan-Ude)|Chechnya (Groznyy)|Chelyabinskaya|Chitinskaya|Chukotskiy (Anadyr')|Chuvashiya (Cheboksary)|Dagestan (Makhachkala)|Evenkiyskiy (Tura)|Ingushetiya (Nazran')|Irkutskaya|Ivanovskaya|Kabardino-Balkariya (Nal'chik)|Kaliningradskaya|Kalmykiya (Elista)|Kaluzhskaya|Kamchatskaya (Petropavlovsk-Kamchatskiy)|Karachayevo-Cherkesiya (Cherkessk)|Kareliya (Petrozavodsk)|Kemerovskaya|Khabarovskiy|Khakasiya (Abakan)|Khanty-Mansiyskiy (Khanty-Mansiysk)|Kirovskaya|Komi (Syktyvkar)|Komi-Permyatskiy (Kudymkar)|Koryakskiy (Palana)|Kostromskaya|Krasnodarskiy|Krasnoyarskiy|Kurganskaya|Kurskaya|Leningradskaya|Lipetskaya|Magadanskaya|Mariy-El (Yoshkar-Ola)|Mordoviya (Saransk)|Moskovskaya|Moskva (Moscow)|Murmanskaya|Nenetskiy (Nar'yan-Mar)|Nizhegorodskaya|Novgorodskaya|Novosibirskaya|Omskaya|Orenburgskaya|Orlovskaya (Orel)|Penzenskaya|Permskaya|Primorskiy (Vladivostok)|Pskovskaya|Rostovskaya|Ryazanskaya|Sakha (Yakutsk)|Sakhalinskaya (Yuzhno-Sakhalinsk)|Samarskaya|Sankt-Peterburg (Saint Petersburg)|Saratovskaya|Severnaya Osetiya-Alaniya [North Ossetia] (Vladikavkaz)|Smolenskaya|Stavropol'skiy|Sverdlovskaya (Yekaterinburg)|Tambovskaya|Tatarstan (Kazan')|Taymyrskiy (Dudinka)|Tomskaya|Tul'skaya|Tverskaya|Tyumenskaya|Tyva (Kyzyl)|Udmurtiya (Izhevsk)|Ul'yanovskaya|Ust'-Ordynskiy Buryatskiy (Ust'-Ordynskiy)|Vladimirskaya|Volgogradskaya|Vologodskaya|Voronezhskaya|Yamalo-Nenetskiy (Salekhard)|Yaroslavskaya|Yevreyskaya"
)
s_a.append(
"Butare|Byumba|Cyangugu|Gikongoro|Gisenyi|Gitarama|Kibungo|Kibuye|Kigali Rurale|Kigali-ville|Ruhengeri|Umutara"
)
s_a.append("Ascension|Saint Helena|Tristan da Cunha")
s_a.append(
"Christ Church Nichola Town|Saint Anne Sandy Point|Saint George Basseterre|Saint George Gingerland|Saint James Windward|Saint John Capisterre|Saint John Figtree|Saint Mary Cayon|Saint Paul Capisterre|Saint Paul Charlestown|Saint Peter Basseterre|Saint Thomas Lowland|Saint Thomas Middle Island|Trinity Palmetto Point"
)
s_a.append(
"Anse-la-Raye|Castries|Choiseul|Dauphin|Dennery|Gros Islet|Laborie|Micoud|Praslin|Soufriere|Vieux Fort"
)
s_a.append("Miquelon|Saint Pierre")
s_a.append("Charlotte|Grenadines|Saint Andrew|Saint David|Saint George|Saint Patrick")
s_a.append(
"A'ana|Aiga-i-le-Tai|Atua|Fa'asaleleaga|Gaga'emauga|Gagaifomauga|Palauli|Satupa'itea|Tuamasaga|Va'a-o-Fonoti|Vaisigano"
)
s_a.append(
"Acquaviva|Borgo Maggiore|Chiesanuova|Domagnano|Faetano|Fiorentino|Monte Giardino|San Marino|Serravalle"
)
s_a.append("Principe|Sao Tome")
s_a.append(
"'Asir|Al Bahah|Al Hudud ash Shamaliyah|Al Jawf|Al Madinah|Al Qasim|Ar Riyad|Ash Sharqiyah (Eastern Province)|Ha'il|Jizan|Makkah|Najran|Tabuk"
)
s_a.append(
"Aberdeen City|Aberdeenshire|Angus|Argyll and Bute|City of Edinburgh|Clackmannanshire|Dumfries and Galloway|Dundee City|East Ayrshire|East Dunbartonshire|East Lothian|East Renfrewshire|Eilean Siar (Western Isles)|Falkirk|Fife|Glasgow City|Highland|Inverclyde|Midlothian|Moray|North Ayrshire|North Lanarkshire|Orkney Islands|Perth and Kinross|Renfrewshire|Shetland Islands|South Ayrshire|South Lanarkshire|Stirling|The Scottish Borders|West Dunbartonshire|West Lothian"
)
s_a.append(
"Dakar|Diourbel|Fatick|Kaolack|Kolda|Louga|Saint-Louis|Tambacounda|Thies|Ziguinchor"
)
s_a.append(
"Anse aux Pins|Anse Boileau|Anse Etoile|Anse Louis|Anse Royale|Baie Lazare|Baie Sainte Anne|Beau Vallon|Bel Air|Bel Ombre|Cascade|Glacis|Grand' Anse (on Mahe)|Grand' Anse (on Praslin)|La Digue|La Riviere Anglaise|Mont Buxton|Mont Fleuri|Plaisance|Pointe La Rue|Port Glaud|Saint Louis|Takamaka"
)
s_a.append("Eastern|Northern|Southern|Western")
s_a.append("Singapore")
s_a.append(
"Banskobystricky|Bratislavsky|Kosicky|Nitriansky|Presovsky|Trenciansky|Trnavsky|Zilinsky"
)
s_a.append(
"Ajdovscina|Beltinci|Bled|Bohinj|Borovnica|Bovec|Brda|Brezice|Brezovica|Cankova-Tisina|Celje|Cerklje na Gorenjskem|Cerknica|Cerkno|Crensovci|Crna na Koroskem|Crnomelj|Destrnik-Trnovska Vas|Divaca|Dobrepolje|Dobrova-Horjul-Polhov Gradec|Dol pri Ljubljani|Domzale|Dornava|Dravograd|Duplek|Gorenja Vas-Poljane|Gorisnica|Gornja Radgona|Gornji Grad|Gornji Petrovci|Grosuplje|Hodos Salovci|Hrastnik|Hrpelje-Kozina|Idrija|Ig|Ilirska Bistrica|Ivancna Gorica|Izola|Jesenice|Jursinci|Kamnik|Kanal|Kidricevo|Kobarid|Kobilje|Kocevje|Komen|Koper|Kozje|Kranj|Kranjska Gora|Krsko|Kungota|Kuzma|Lasko|Lenart|Lendava|Litija|Ljubljana|Ljubno|Ljutomer|Logatec|Loska Dolina|Loski Potok|Luce|Lukovica|Majsperk|Maribor|Medvode|Menges|Metlika|Mezica|Miren-Kostanjevica|Mislinja|Moravce|Moravske Toplice|Mozirje|Murska Sobota|Muta|Naklo|Nazarje|Nova Gorica|Novo Mesto|Odranci|Ormoz|Osilnica|Pesnica|Piran|Pivka|Podcetrtek|Podvelka-Ribnica|Postojna|Preddvor|Ptuj|Puconci|Race-Fram|Radece|Radenci|Radlje ob Dravi|Radovljica|Ravne-Prevalje|Ribnica|Rogasevci|Rogaska Slatina|Rogatec|Ruse|Semic|Sencur|Sentilj|Sentjernej|Sentjur pri Celju|Sevnica|Sezana|Skocjan|Skofja Loka|Skofljica|Slovenj Gradec|Slovenska Bistrica|Slovenske Konjice|Smarje pri Jelsah|Smartno ob Paki|Sostanj|Starse|Store|Sveti Jurij|Tolmin|Trbovlje|Trebnje|Trzic|Turnisce|Velenje|Velike Lasce|Videm|Vipava|Vitanje|Vodice|Vojnik|Vrhnika|Vuzenica|Zagorje ob Savi|Zalec|Zavrc|Zelezniki|Ziri|Zrece"
)
s_a.append(
"Bellona|Central|Choiseul (Lauru)|Guadalcanal|Honiara|Isabel|Makira|Malaita|Rennell|Temotu|Western"
)
s_a.append(
"Awdal|Bakool|Banaadir|Bari|Bay|Galguduud|Gedo|Hiiraan|Jubbada Dhexe|Jubbada Hoose|Mudug|Nugaal|Sanaag|Shabeellaha Dhexe|Shabeellaha Hoose|Sool|Togdheer|Woqooyi Galbeed"
)
s_a.append(
"Eastern Cape|Free State|Gauteng|KwaZulu-Natal|Mpumalanga|North-West|Northern Cape|Northern Province|Western Cape"
)
s_a.append(
"Bird Island|Bristol Island|Clerke Rocks|Montagu Island|Saunders Island|South Georgia|Southern Thule|Traversay Islands"
)
s_a.append(
"Andalucia|Aragon|Asturias|Baleares (Balearic Islands)|Canarias (Canary Islands)|Cantabria|Castilla y Leon|Castilla-La Mancha|Cataluna|Ceuta|Communidad Valencian|Extremadura|Galicia|Islas Chafarinas|La Rioja|Madrid|Melilla|Murcia|Navarra|Pais Vasco (Basque Country)|Penon de Alhucemas|Penon de Velez de la Gomera"
)
s_a.append("Spratly Islands")
s_a.append(
"Central|Eastern|North Central|North Eastern|North Western|Northern|Sabaragamuwa|Southern|Uva|Western"
)
s_a.append(
"A'ali an Nil|Al Bahr al Ahmar|Al Buhayrat|Al Jazirah|Al Khartum|Al Qadarif|Al Wahdah|An Nil al Abyad|An Nil al Azraq|Ash Shamaliyah|Bahr al Jabal|Gharb al Istiwa'iyah|Gharb Bahr al Ghazal|Gharb Darfur|Gharb Kurdufan|Janub Darfur|Janub Kurdufan|Junqali|Kassala|Nahr an Nil|Shamal Bahr al Ghazal|Shamal Darfur|Shamal Kurdufan|Sharq al Istiwa'iyah|Sinnar|Warab"
)
s_a.append(
"Brokopondo|Commewijne|Coronie|Marowijne|Nickerie|Para|Paramaribo|Saramacca|Sipaliwini|Wanica"
)
s_a.append(
"Barentsoya|Bjornoya|Edgeoya|Hopen|Kvitoya|Nordaustandet|Prins Karls Forland|Spitsbergen"
)
s_a.append("Hhohho|Lubombo|Manzini|Shiselweni")
s_a.append(
"Blekinge|Dalarnas|Gavleborgs|Gotlands|Hallands|Jamtlands|Jonkopings|Kalmar|Kronobergs|Norrbottens|Orebro|Ostergotlands|Skane|Sodermanlands|Stockholms|Uppsala|Varmlands|Vasterbottens|Vasternorrlands|Vastmanlands|Vastra Gotalands"
)
s_a.append(
"Aargau|Ausser-Rhoden|Basel-Landschaft|Basel-Stadt|Bern|Fribourg|Geneve|Glarus|Graubunden|Inner-Rhoden|Jura|Luzern|Neuchatel|Nidwalden|Obwalden|Sankt Gallen|Schaffhausen|Schwyz|Solothurn|Thurgau|Ticino|Uri|Valais|Vaud|Zug|Zurich"
)
s_a.append(
"Al Hasakah|Al Ladhiqiyah|Al Qunaytirah|Ar Raqqah|As Suwayda'|Dar'a|Dayr az Zawr|Dimashq|Halab|Hamah|Hims|Idlib|Rif Dimashq|Tartus"
)
s_a.append(
"Chang-hua|Chi-lung|Chia-i|Chia-i|Chung-hsing-hsin-ts'un|Hsin-chu|Hsin-chu|Hua-lien|I-lan|Kao-hsiung|Kao-hsiung|Miao-li|Nan-t'ou|P'eng-hu|P'ing-tung|T'ai-chung|T'ai-chung|T'ai-nan|T'ai-nan|T'ai-pei|T'ai-pei|T'ai-tung|T'ao-yuan|Yun-lin"
)
s_a.append("Viloyati Khatlon|Viloyati Leninobod|Viloyati Mukhtori Kuhistoni Badakhshon")
s_a.append(
"Arusha|Dar es Salaam|Dodoma|Iringa|Kagera|Kigoma|Kilimanjaro|Lindi|Mara|Mbeya|Morogoro|Mtwara|Mwanza|Pemba North|Pemba South|Pwani|Rukwa|Ruvuma|Shinyanga|Singida|Tabora|Tanga|Zanzibar Central/South|Zanzibar North|Zanzibar Urban/West"
)
s_a.append(
"Amnat Charoen|Ang Thong|Buriram|Chachoengsao|Chai Nat|Chaiyaphum|Chanthaburi|Chiang Mai|Chiang Rai|Chon Buri|Chumphon|Kalasin|Kamphaeng Phet|Kanchanaburi|Khon Kaen|Krabi|Krung Thep Mahanakhon (Bangkok)|Lampang|Lamphun|Loei|Lop Buri|Mae Hong Son|Maha Sarakham|Mukdahan|Nakhon Nayok|Nakhon Pathom|Nakhon Phanom|Nakhon Ratchasima|Nakhon Sawan|Nakhon Si Thammarat|Nan|Narathiwat|Nong Bua Lamphu|Nong Khai|Nonthaburi|Pathum Thani|Pattani|Phangnga|Phatthalung|Phayao|Phetchabun|Phetchaburi|Phichit|Phitsanulok|Phra Nakhon Si Ayutthaya|Phrae|Phuket|Prachin Buri|Prachuap Khiri Khan|Ranong|Ratchaburi|Rayong|Roi Et|Sa Kaeo|Sakon Nakhon|Samut Prakan|Samut Sakhon|Samut Songkhram|Sara Buri|Satun|Sing Buri|Sisaket|Songkhla|Sukhothai|Suphan Buri|Surat Thani|Surin|Tak|Trang|Trat|Ubon Ratchathani|Udon Thani|Uthai Thani|Uttaradit|Yala|Yasothon"
)
s_a.append("Tobago")
s_a.append("De La Kara|Des Plateaux|Des Savanes|Du Centre|Maritime")
s_a.append("Atafu|Fakaofo|Nukunonu")
s_a.append("Ha'apai|Tongatapu|Vava'u")
s_a.append(
"Arima|Caroni|Mayaro|Nariva|Port-of-Spain|Saint Andrew|Saint David|Saint George|Saint Patrick|San Fernando|Victoria"
)
s_a.append(
"Ariana|Beja|Ben Arous|Bizerte|El Kef|Gabes|Gafsa|Jendouba|Kairouan|Kasserine|Kebili|Mahdia|Medenine|Monastir|Nabeul|Sfax|Sidi Bou Zid|Siliana|Sousse|Tataouine|Tozeur|Tunis|Zaghouan"
)
s_a.append(
"Adana|Adiyaman|Afyon|Agri|Aksaray|Amasya|Ankara|Antalya|Ardahan|Artvin|Aydin|Balikesir|Bartin|Batman|Bayburt|Bilecik|Bingol|Bitlis|Bolu|Burdur|Bursa|Canakkale|Cankiri|Corum|Denizli|Diyarbakir|Duzce|Edirne|Elazig|Erzincan|Erzurum|Eskisehir|Gaziantep|Giresun|Gumushane|Hakkari|Hatay|Icel|Igdir|Isparta|Istanbul|Izmir|Kahramanmaras|Karabuk|Karaman|Kars|Kastamonu|Kayseri|Kilis|Kirikkale|Kirklareli|Kirsehir|Kocaeli|Konya|Kutahya|Malatya|Manisa|Mardin|Mugla|Mus|Nevsehir|Nigde|Ordu|Osmaniye|Rize|Sakarya|Samsun|Sanliurfa|Siirt|Sinop|Sirnak|Sivas|Tekirdag|Tokat|Trabzon|Tunceli|Usak|Van|Yalova|Yozgat|Zonguldak"
)
s_a.append(
"Ahal Welayaty|Balkan Welayaty|Dashhowuz Welayaty|Lebap Welayaty|Mary Welayaty"
)
s_a.append("Tuvalu")
s_a.append(
"Adjumani|Apac|Arua|Bugiri|Bundibugyo|Bushenyi|Busia|Gulu|Hoima|Iganga|Jinja|Kabale|Kabarole|Kalangala|Kampala|Kamuli|Kapchorwa|Kasese|Katakwi|Kibale|Kiboga|Kisoro|Kitgum|Kotido|Kumi|Lira|Luwero|Masaka|Masindi|Mbale|Mbarara|Moroto|Moyo|Mpigi|Mubende|Mukono|Nakasongola|Nebbi|Ntungamo|Pallisa|Rakai|Rukungiri|Sembabule|Soroti|Tororo"
)
s_a.append(
"Avtonomna Respublika Krym (Simferopol')|Cherkas'ka (Cherkasy)|Chernihivs'ka (Chernihiv)|Chernivets'ka (Chernivtsi)|Dnipropetrovs'ka (Dnipropetrovs'k)|Donets'ka (Donets'k)|Ivano-Frankivs'ka (Ivano-Frankivs'k)|Kharkivs'ka (Kharkiv)|Khersons'ka (Kherson)|Khmel'nyts'ka (Khmel'nyts'kyy)|Kirovohrads'ka (Kirovohrad)|Kyyiv|Kyyivs'ka (Kiev)|L'vivs'ka (L'viv)|Luhans'ka (Luhans'k)|Mykolayivs'ka (Mykolayiv)|Odes'ka (Odesa)|Poltavs'ka (Poltava)|Rivnens'ka (Rivne)|Sevastopol'|Sums'ka (Sumy)|Ternopil's'ka (Ternopil')|Vinnyts'ka (Vinnytsya)|Volyns'ka (Luts'k)|Zakarpats'ka (Uzhhorod)|Zaporiz'ka (Zaporizhzhya)|Zhytomyrs'ka (Zhytomyr)"
)
s_a.append(
"'Ajman|Abu Zaby (Abu Dhabi)|Al Fujayrah|Ash Shariqah (Sharjah)|Dubayy (Dubai)|Ra's al Khaymah|Umm al Qaywayn"
)
s_a.append(
"Barking and Dagenham|Barnet|Barnsley|Bath and North East Somerset|Bedfordshire|Bexley|Birmingham|Blackburn with Darwen|Blackpool|Bolton|Bournemouth|Bracknell Forest|Bradford|Brent|Brighton and Hove|Bromley|Buckinghamshire|Bury|Calderdale|Cambridgeshire|Camden|Cheshire|City of Bristol|City of Kingston upon Hull|City of London|Cornwall|Coventry|Croydon|Cumbria|Darlington|Derby|Derbyshire|Devon|Doncaster|Dorset|Dudley|Durham|Ealing|East Riding of Yorkshire|East Sussex|Enfield|Essex|Gateshead|Gloucestershire|Greenwich|Hackney|Halton|Hammersmith and Fulham|Hampshire|Haringey|Harrow|Hartlepool|Havering|Herefordshire|Hertfordshire|Hillingdon|Hounslow|Isle of Wight|Islington|Kensington and Chelsea|Kent|Kingston upon Thames|Kirklees|Knowsley|Lambeth|Lancashire|Leeds|Leicester|Leicestershire|Lewisham|Lincolnshire|Liverpool|Luton|Manchester|Medway|Merton|Middlesbrough|Milton Keynes|Newcastle upon Tyne|Newham|Norfolk|North East Lincolnshire|North Lincolnshire|North Somerset|North Tyneside|North Yorkshire|Northamptonshire|Northumberland|Nottingham|Nottinghamshire|Oldham|Oxfordshire|Peterborough|Plymouth|Poole|Portsmouth|Reading|Redbridge|Redcar and Cleveland|Richmond upon Thames|Rochdale|Rotherham|Rutland|Salford|Sandwell|Sefton|Sheffield|Shropshire|Slough|Solihull|Somerset|South Gloucestershire|South Tyneside|Southampton|Southend-on-Sea|Southwark|St. Helens|Staffordshire|Stockport|Stockton-on-Tees|Stoke-on-Trent|Suffolk|Sunderland|Surrey|Sutton|Swindon|Tameside|Telford and Wrekin|Thurrock|Torbay|Tower Hamlets|Trafford|Wakefield|Walsall|Waltham Forest|Wandsworth|Warrington|Warwickshire|West Berkshire|West Sussex|Westminster|Wigan|Wiltshire|Windsor and Maidenhead|Wirral|Wokingham|Wolverhampton|Worcestershire|York"
)
s_a.append(
"Artigas|Canelones|Cerro Largo|Colonia|Durazno|Flores|Florida|Lavalleja|Maldonado|Montevideo|Paysandu|Rio Negro|Rivera|Rocha|Salto|San Jose|Soriano|Tacuarembo|Treinta y Tres"
)
s_a.append(
"Alabama|Alaska|Arizona|Arkansas|California|Colorado|Connecticut|Delaware|District of Columbia|Florida|Georgia|Hawaii|Idaho|Illinois|Indiana|Iowa|Kansas|Kentucky|Louisiana|Maine|Maryland|Massachusetts|Michigan|Minnesota|Mississippi|Missouri|Montana|Nebraska|Nevada|New Hampshire|New Jersey|New Mexico|New York|North Carolina|North Dakota|Ohio|Oklahoma|Oregon|Pennsylvania|Rhode Island|South Carolina|South Dakota|Tennessee|Texas|Utah|Vermont|Virginia|Washington|West Virginia|Wisconsin|Wyoming"
)
s_a.append(
"Andijon Wiloyati|Bukhoro Wiloyati|Farghona Wiloyati|Jizzakh Wiloyati|Khorazm Wiloyati (Urganch)|Namangan Wiloyati|Nawoiy Wiloyati|Qashqadaryo Wiloyati (Qarshi)|Qoraqalpoghiston (Nukus)|Samarqand Wiloyati|Sirdaryo Wiloyati (Guliston)|Surkhondaryo Wiloyati (Termiz)|Toshkent Shahri|Toshkent Wiloyati"
)
s_a.append("Malampa|Penama|Sanma|Shefa|Tafea|Torba")
s_a.append(
"Amazonas|Anzoategui|Apure|Aragua|Barinas|Bolivar|Carabobo|Cojedes|Delta Amacuro|Dependencias Federales|Distrito Federal|Falcon|Guarico|Lara|Merida|Miranda|Monagas|Nueva Esparta|Portuguesa|Sucre|Tachira|Trujillo|Vargas|Yaracuy|Zulia"
)
s_a.append(
"An Giang|Ba Ria-Vung Tau|Bac Giang|Bac Kan|Bac Lieu|Bac Ninh|Ben Tre|Binh Dinh|Binh Duong|Binh Phuoc|Binh Thuan|Ca Mau|Can Tho|Cao Bang|Da Nang|Dac Lak|Dong Nai|Dong Thap|Gia Lai|Ha Giang|Ha Nam|Ha Noi|Ha Tay|Ha Tinh|Hai Duong|Hai Phong|Ho Chi Minh|Hoa Binh|Hung Yen|Khanh Hoa|Kien Giang|Kon Tum|Lai Chau|Lam Dong|Lang Son|Lao Cai|Long An|Nam Dinh|Nghe An|Ninh Binh|Ninh Thuan|Phu Tho|Phu Yen|Quang Binh|Quang Nam|Quang Ngai|Quang Ninh|Quang Tri|Soc Trang|Son La|Tay Ninh|Thai Binh|Thai Nguyen|Thanh Hoa|Thua Thien-Hue|Tien Giang|Tra Vinh|Tuyen Quang|Vinh Long|Vinh Phuc|Yen Bai"
)
s_a.append("Saint Croix|Saint John|Saint Thomas")
s_a.append(
"Blaenau Gwent|Bridgend|Caerphilly|Cardiff|Carmarthenshire|Ceredigion|Conwy|Denbighshire|Flintshire|Gwynedd|Isle of Anglesey|Merthyr Tydfil|Monmouthshire|Neath Port Talbot|Newport|Pembrokeshire|Powys|Rhondda Cynon Taff|Swansea|The Vale of Glamorgan|Torfaen|Wrexham"
)
s_a.append("Alo|Sigave|Wallis")
s_a.append("West Bank")
s_a.append("Western Sahara")
s_a.append(
"'Adan|'Ataq|Abyan|Al Bayda'|Al Hudaydah|Al Jawf|Al Mahrah|Al Mahwit|Dhamar|Hadhramawt|Hajjah|Ibb|Lahij|Ma'rib|Sa'dah|San'a'|Ta'izz"
)
s_a.append("Kosovo|Montenegro|Serbia|Vojvodina")
s_a.append(
"Central|Copperbelt|Eastern|Luapula|Lusaka|North-Western|Northern|Southern|Western"
)
s_a.append(
"Bulawayo|Harare|ManicalandMashonaland Central|Mashonaland East|Mashonaland West|Masvingo|Matabeleland North|Matabeleland South|Midlands"
)
states = []
for state in s_a:
if "|" in state:
for item in state.split("|"):
states.append(item.replace("|", ""))
else:
states.append(state)

68
base/decorators.py Normal file
View File

@@ -0,0 +1,68 @@
"""
decorator functions for base
"""
from django.contrib import messages
from django.http import HttpResponseRedirect
from .models import ShiftRequest, WorkTypeRequest
decorator_with_arguments = (
lambda decorator: lambda *args, **kwargs: lambda func: decorator(
func, *args, **kwargs
)
)
@decorator_with_arguments
def shift_request_change_permission(function=None, *args, **kwargs):
def check_permission(
request,
shift_request_id=None,
*args,
**kwargs,
):
"""
This method is used to check the employee can change a shift request or not
"""
shift_request = ShiftRequest.objects.get(id=shift_request_id)
if (
request.user.has_perm("base.change_shiftrequest")
or request.user.employee_get
== shift_request.employee_id.employee_work_info.reporting_manager_id
or request.user.employee_get == shift_request.employee_id
):
return function(request, *args, shift_request_id=shift_request_id, **kwargs)
messages.info(request, "You dont have permission.")
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
# return function(request, *args, **kwargs)
return check_permission
@decorator_with_arguments
def work_type_request_change_permission(function=None, *args, **kwargs):
def check_permission(
request,
work_type_request_id=None,
*args,
**kwargs,
):
"""
This method is used to check the employee can change a shift request or not
"""
work_type_request = WorkTypeRequest.objects.get(id=work_type_request_id)
if (
request.user.has_perm("base.change_worktyperequest")
or request.user.employee_get
== work_type_request.employee_id.employee_work_info.reporting_manager_id
or request.user.employee_get == work_type_request.employee_id
):
return function(
request, *args, work_type_request_id=work_type_request_id, **kwargs
)
messages.info(request, "You dont have permission.")
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
# return function(request, *args, **kwargs)
return check_permission

404
base/filters.py Normal file
View File

@@ -0,0 +1,404 @@
"""
This module contains custom Django filters for filtering querysets related to Shift Requests,
Work Type Requests, Rotating Shift and Rotating Work Type Assign.
"""
import uuid
import django_filters
from django import forms
from django.utils.translation import gettext as __
from django_filters import CharFilter, DateFilter, filters
from base.models import (
CompanyLeaves,
Holidays,
PenaltyAccounts,
RotatingShiftAssign,
RotatingWorkTypeAssign,
ShiftRequest,
WorkTypeRequest,
)
from horilla.filters import FilterSet, filter_by_name
class ShiftRequestFilter(FilterSet):
"""
Custom filter for Shift Requests.
"""
requested_date = django_filters.DateFilter(
field_name="requested_date", widget=forms.DateInput(attrs={"type": "date"})
)
requested_date__gte = django_filters.DateFilter(
field_name="requested_date",
lookup_expr="gte",
widget=forms.DateInput(attrs={"type": "date"}),
)
requested_date__lte = django_filters.DateFilter(
field_name="requested_date",
lookup_expr="lte",
widget=forms.DateInput(attrs={"type": "date"}),
)
search = CharFilter(method=filter_by_name)
class Meta:
"""
A nested class that specifies the model and fields for the filter.
"""
fields = "__all__"
model = ShiftRequest
fields = [
"id",
"employee_id",
"requested_date",
"previous_shift_id",
"shift_id",
"requested_till",
"approved",
"canceled",
"employee_id__employee_first_name",
"employee_id__employee_last_name",
"employee_id__is_active",
"employee_id__gender",
"employee_id__employee_work_info__job_position_id",
"employee_id__employee_work_info__department_id",
"employee_id__employee_work_info__work_type_id",
"employee_id__employee_work_info__employee_type_id",
"employee_id__employee_work_info__job_role_id",
"employee_id__employee_work_info__reporting_manager_id",
"employee_id__employee_work_info__company_id",
"employee_id__employee_work_info__shift_id",
]
def __init__(self, data=None, queryset=None, *, request=None, prefix=None):
super().__init__(data=data, queryset=queryset, request=request, prefix=prefix)
for field in self.form.fields.keys():
self.form.fields[field].widget.attrs["id"] = f"{uuid.uuid4()}"
class WorkTypeRequestFilter(FilterSet):
"""
Custom filter for Work Type Requests.
"""
requested_date = django_filters.DateFilter(
field_name="requested_date", widget=forms.DateInput(attrs={"type": "date"})
)
requested_date__gte = django_filters.DateFilter(
field_name="requested_till",
lookup_expr="gte",
widget=forms.DateInput(attrs={"type": "date"}),
)
requested_date__lte = django_filters.DateFilter(
field_name="requested_till",
lookup_expr="lte",
widget=forms.DateInput(attrs={"type": "date"}),
)
search = CharFilter(method=filter_by_name)
class Meta:
"""
A nested class that specifies the model and fields for the filter.
"""
fields = "__all__"
model = WorkTypeRequest
fields = [
"id",
"employee_id",
"requested_date",
"previous_work_type_id",
"approved",
"work_type_id",
"canceled",
"employee_id__employee_first_name",
"employee_id__employee_last_name",
"employee_id__is_active",
"employee_id__gender",
"employee_id__employee_work_info__job_position_id",
"employee_id__employee_work_info__department_id",
"employee_id__employee_work_info__work_type_id",
"employee_id__employee_work_info__employee_type_id",
"employee_id__employee_work_info__job_role_id",
"employee_id__employee_work_info__reporting_manager_id",
"employee_id__employee_work_info__company_id",
"employee_id__employee_work_info__shift_id",
]
def __init__(self, data=None, queryset=None, *, request=None, prefix=None):
super().__init__(data=data, queryset=queryset, request=request, prefix=prefix)
for field in self.form.fields.keys():
self.form.fields[field].widget.attrs["id"] = f"{uuid.uuid4()}"
class RotatingShiftAssignFilters(FilterSet):
"""
Custom filter for Rotating Shift Assign.
"""
search = CharFilter(method=filter_by_name)
next_change_date = django_filters.DateFilter(
field_name="next_change_date", widget=forms.DateInput(attrs={"type": "date"})
)
start_date = django_filters.DateFilter(
field_name="start_date", widget=forms.DateInput(attrs={"type": "date"})
)
class Meta:
"""
A nested class that specifies the model and fields for the filter.
"""
fields = "__all__"
model = RotatingShiftAssign
fields = [
"employee_id",
"rotating_shift_id",
"next_change_date",
"start_date",
"based_on",
"rotate_after_day",
"rotate_every_weekend",
"rotate_every",
"current_shift",
"next_shift",
"is_active",
"employee_id__employee_work_info__job_position_id",
"employee_id__employee_work_info__department_id",
"employee_id__employee_work_info__work_type_id",
"employee_id__employee_work_info__employee_type_id",
"employee_id__employee_work_info__job_role_id",
"employee_id__employee_work_info__reporting_manager_id",
"employee_id__employee_work_info__company_id",
"employee_id__employee_work_info__shift_id",
]
class RotatingWorkTypeAssignFilter(FilterSet):
"""
Custom filter for Rotating Work Type Assign.
"""
search = CharFilter(method=filter_by_name)
next_change_date = django_filters.DateFilter(
field_name="next_change_date", widget=forms.DateInput(attrs={"type": "date"})
)
start_date = django_filters.DateFilter(
field_name="start_date", widget=forms.DateInput(attrs={"type": "date"})
)
class Meta:
"""
A nested class that specifies the model and fields for the filter.
"""
fields = "__all__"
model = RotatingWorkTypeAssign
fields = [
"employee_id",
"rotating_work_type_id",
"next_change_date",
"start_date",
"based_on",
"rotate_after_day",
"rotate_every_weekend",
"rotate_every",
"current_work_type",
"next_work_type",
"is_active",
"employee_id__employee_work_info__job_position_id",
"employee_id__employee_work_info__department_id",
"employee_id__employee_work_info__work_type_id",
"employee_id__employee_work_info__employee_type_id",
"employee_id__employee_work_info__job_role_id",
"employee_id__employee_work_info__reporting_manager_id",
"employee_id__employee_work_info__company_id",
"employee_id__employee_work_info__shift_id",
]
class ShiftRequestReGroup:
"""
Class to keep the field name for group by option
"""
fields = [
("", "Select"),
("employee_id", "Employee"),
("shift_id", "Requested Shift"),
("previous_shift_id", "Current Shift"),
("requested_date", "Requested Date"),
]
class WorkTypeRequestReGroup:
"""
Class to keep the field name for group by option
"""
fields = [
("", "Select"),
("employee_id", "Employee"),
("work_type_id", "Requested Work Type"),
("previous_work_type_id", "Current Work Type"),
("requested_date", "Requested Date"),
("employee_id__employee_work_info__department_id", "Department"),
("employee_id__employee_work_info__job_position_id", "Job Position"),
("employee_id__employee_work_info__reporting_manager_id", "Reporting Manager"),
]
class RotatingWorkTypeRequestReGroup:
"""
Class to keep the field name for group by option
"""
fields = [
("", "Select"),
("employee_id", "Employee"),
("rotating_work_type_id", "Rotating Work Type"),
("current_work_type", "Current Work Type"),
("based_on", "Based On"),
("employee_id__employee_work_info__department_id", "Department"),
("employee_id__employee_work_info__job_role_id", "Job Role"),
("employee_id__employee_work_info__reporting_manager_id", "Reporting Manager"),
]
class RotatingShiftRequestReGroup:
"""
Class to keep the field name for group by option
"""
fields = [
("", "Select"),
("employee_id", "Employee"),
("rotating_shift_id", "Rotating Shift"),
("based_on", "Based On"),
("employee_id__employee_work_info__department_id", "Department"),
("employee_id__employee_work_info__job_role_id", "Job Role"),
("employee_id__employee_work_info__reporting_manager_id", "Reporting Manager"),
]
class HolidayFilter(FilterSet):
"""
Filter class for Holidays model.
This filter allows searching Holidays objects based on name and date range.
"""
search = filters.CharFilter(field_name="name", lookup_expr="icontains")
from_date = DateFilter(
field_name="start_date",
lookup_expr="gte",
widget=forms.DateInput(attrs={"type": "date"}),
)
to_date = DateFilter(
field_name="end_date",
lookup_expr="lte",
widget=forms.DateInput(attrs={"type": "date"}),
)
start_date = DateFilter(
field_name="start_date",
lookup_expr="exact",
widget=forms.DateInput(attrs={"type": "date"}),
)
end_date = DateFilter(
field_name="end_date",
lookup_expr="exact",
widget=forms.DateInput(attrs={"type": "date"}),
)
class Meta:
"""
Meta class defines the model and fields to filter
"""
model = Holidays
fields = {
"recurring": ["exact"],
}
def __init__(self, data=None, queryset=None, *, request=None, prefix=None):
super().__init__(data=data, queryset=queryset, request=request, prefix=prefix)
for field in self.form.fields.keys():
self.form.fields[field].widget.attrs["id"] = f"{uuid.uuid4()}"
self.form.fields["from_date"].label = (
f"{self.Meta.model()._meta.get_field('start_date').verbose_name} From"
)
self.form.fields["to_date"].label = (
f"{self.Meta.model()._meta.get_field('end_date').verbose_name} Till"
)
class CompanyLeaveFilter(FilterSet):
"""
Filter class for CompanyLeaves model.
This filter allows searching CompanyLeaves objects based on
name, week day and based_on_week choices.
"""
name = filters.CharFilter(field_name="based_on_week_day", lookup_expr="icontains")
search = filters.CharFilter(method="filter_week_day")
class Meta:
""" "
Meta class defines the model and fields to filter
"""
model = CompanyLeaves
fields = {
"based_on_week": ["exact"],
"based_on_week_day": ["exact"],
}
def filter_week_day(self, queryset, _, value):
week_qry = CompanyLeaves.objects.none()
weekday_values = []
week_values = []
WEEK_DAYS = [
("0", __("Monday")),
("1", __("Tuesday")),
("2", __("Wednesday")),
("3", __("Thursday")),
("4", __("Friday")),
("5", __("Saturday")),
("6", __("Sunday")),
]
WEEKS = [
(None, __("All")),
("0", __("First Week")),
("1", __("Second Week")),
("2", __("Third Week")),
("3", __("Fourth Week")),
("4", __("Fifth Week")),
]
for day_value, day_name in WEEK_DAYS:
if value.lower() in day_name.lower():
weekday_values.append(day_value)
for day_value, day_name in WEEKS:
if value.lower() in day_name.lower() and value.lower() != __("All").lower():
week_values.append(day_value)
week_qry = queryset.filter(based_on_week__in=week_values)
elif value.lower() in __("All").lower():
week_qry = queryset.filter(based_on_week__isnull=True)
return queryset.filter(based_on_week_day__in=weekday_values) | week_qry
class PenaltyFilter(FilterSet):
"""
PenaltyFilter
"""
class Meta:
model = PenaltyAccounts
fields = "__all__"

2800
base/forms.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,112 @@
"""
horilla_company_manager.py
"""
import logging
from typing import Coroutine, Sequence
from django.db import models
from django.db.models.query import QuerySet
from horilla.horilla_middlewares import _thread_locals
from horilla.signals import post_bulk_update, pre_bulk_update
logger = logging.getLogger(__name__)
django_filter_update = QuerySet.update
def update(self, *args, **kwargs):
# pre_update signal
request = getattr(_thread_locals, "request", None)
self.request = request
pre_bulk_update.send(sender=self.model, queryset=self, args=args, kwargs=kwargs)
result = django_filter_update(self, *args, **kwargs)
# post_update signal
post_bulk_update.send(sender=self.model, queryset=self, args=args, kwargs=kwargs)
return result
setattr(QuerySet, "update", update)
class HorillaCompanyManager(models.Manager):
"""
HorillaCompanyManager
"""
def __init__(self, related_company_field=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.related_company_field = related_company_field
self.check_fields = [
"employee_id",
"requested_employee_id",
]
def get_queryset(self):
"""
get_queryset method
"""
queryset = super().get_queryset()
request = getattr(_thread_locals, "request", None)
selected_company = None
if request is not None:
selected_company = request.session.get("selected_company")
try:
queryset = (
queryset.filter(self.model.company_filter)
if selected_company != "all" and selected_company
else queryset
)
except Exception as e:
logger.error(e)
try:
has_duplicates = queryset.count() != queryset.distinct().count()
if has_duplicates:
queryset = queryset.distinct()
except:
pass
return queryset
def all(self):
"""
Override the all() method
"""
queryset = []
try:
queryset = self.get_queryset()
if queryset.exists():
try:
model_name = queryset.model._meta.model_name
if model_name == "employee":
request = getattr(_thread_locals, "request", None)
if not getattr(request, "is_filtering", None):
queryset = queryset.filter(is_active=True)
else:
for field in queryset.model._meta.fields:
if isinstance(field, models.ForeignKey):
if field.name in self.check_fields:
related_model_is_active_filter = {
f"{field.name}__is_active": True
}
queryset = queryset.filter(
**related_model_is_active_filter
)
except:
pass
except:
pass
return queryset
def filter(self, *args, **kwargs):
queryset = super().filter(*args, **kwargs)
setattr(_thread_locals, "queryset_filter", queryset)
return queryset
def entire(self):
"""
Fetch all datas from a model without applying any company filter.
"""
queryset = super().get_queryset()
return queryset # No filtering applied

1154
base/methods.py Normal file

File diff suppressed because it is too large Load Diff

249
base/middleware.py Normal file
View File

@@ -0,0 +1,249 @@
"""
middleware.py
"""
from django.apps import apps
from django.contrib import messages
from django.contrib.auth import logout
from django.core.cache import cache
from django.db.models import Q
from django.shortcuts import redirect
from django.utils.translation import gettext_lazy as _
from base.backends import ConfiguredEmailBackend
from base.context_processors import AllCompany
from base.horilla_company_manager import HorillaCompanyManager
from base.models import Company, ShiftRequest, WorkTypeRequest
from employee.models import (
DisciplinaryAction,
Employee,
EmployeeBankDetails,
EmployeeWorkInformation,
)
from horilla.horilla_apps import TWO_FACTORS_AUTHENTICATION
from horilla.horilla_settings import APPS
from horilla.methods import get_horilla_model_class
from horilla_documents.models import DocumentRequest
CACHE_KEY = "horilla_company_models_cache_key"
class CompanyMiddleware:
"""
Middleware to handle company-specific filtering for models.
"""
def __init__(self, get_response):
self.get_response = get_response
def _get_company_id(self, request):
"""
Retrieve the company ID from the request or session.
"""
if getattr(request, "user", False) and not request.user.is_anonymous:
try:
if com_id := request.session.get("selected_company", None):
return (
Company.objects.filter(id=com_id).first()
if com_id != "all"
else None
)
else:
return getattr(
request.user.employee_get.employee_work_info, "company_id", None
)
except AttributeError:
pass
return None
def _set_company_session(self, request, company_id):
"""
Set the company session data based on the company ID.
"""
try:
user = request.user.employee_get
except Exception:
logout(request)
messages.error(
request,
_("An employee related to this user's credentials does not exist."),
)
return redirect("login")
user_company_id = getattr(
getattr(user, "employee_work_info", None), "company_id", None
)
if company_id and request.session.get("selected_company") != "all":
if company_id == "all":
text = "All companies"
elif company_id == user_company_id:
text = "My Company"
else:
text = "Other Company"
request.session["selected_company"] = str(company_id.id)
request.session["selected_company_instance"] = {
"company": company_id.company,
"icon": company_id.icon.url,
"text": text,
"id": company_id.id,
}
else:
request.session["selected_company"] = "all"
all_company = AllCompany()
request.session["selected_company_instance"] = {
"company": all_company.company,
"icon": all_company.icon.url,
"text": all_company.text,
"id": all_company.id,
}
def _add_company_filter(self, model, company_id):
"""
Add company filter to the model if applicable.
"""
is_company_model = model in self._get_company_models()
company_field = getattr(model, "company_id", None)
is_horilla_manager = isinstance(model.objects, HorillaCompanyManager)
related_company_field = getattr(model.objects, "related_company_field", None)
if is_company_model:
if company_field:
model.add_to_class("company_filter", Q(company_id=company_id))
elif is_horilla_manager and related_company_field:
model.add_to_class(
"company_filter", Q(**{related_company_field: company_id})
)
else:
if company_field:
model.add_to_class(
"company_filter",
Q(company_id=company_id) | Q(company_id__isnull=True),
)
elif is_horilla_manager and related_company_field:
model.add_to_class(
"company_filter",
Q(**{related_company_field: company_id})
| Q(**{f"{related_company_field}__isnull": True}),
)
def _get_company_models(self):
"""
Retrieve the list of models that are company-specific.
"""
company_models = cache.get(CACHE_KEY)
if company_models is None:
company_models = [
Employee,
ShiftRequest,
WorkTypeRequest,
DocumentRequest,
DisciplinaryAction,
EmployeeBankDetails,
EmployeeWorkInformation,
]
app_model_mappings = {
"recruitment": ["recruitment", "candidate"],
"leave": [
"leaverequest",
"restrictleave",
"availableleave",
"leaveallocationrequest",
"compensatoryleaverequest",
],
"asset": ["assetassignment", "assetrequest"],
"attendance": [
"attendance",
"attendanceactivity",
"attendanceovertime",
"workrecords",
],
"payroll": [
"contract",
"loanaccount",
"payslip",
"reimbursement",
],
"helpdesk": ["ticket"],
"offboarding": ["offboarding"],
"pms": ["employeeobjective"],
}
for app_label, models in app_model_mappings.items():
if apps.is_installed(app_label):
company_models.extend(
[get_horilla_model_class(app_label, model) for model in models]
)
cache.set(CACHE_KEY, company_models)
return company_models
def __call__(self, request):
if getattr(request, "user", False) and not request.user.is_anonymous:
company_id = self._get_company_id(request)
self._set_company_session(request, company_id)
app_models = [
model for model in apps.get_models() if model._meta.app_label in APPS
]
for model in app_models:
self._add_company_filter(model, company_id)
response = self.get_response(request)
return response
class ForcePasswordChangeMiddleware:
"""
Middleware to force password change for new employees.
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
excluded_paths = ["/change-password", "/login", "/logout"]
if request.path.rstrip("/") in excluded_paths:
return self.get_response(request)
if hasattr(request, "user") and request.user.is_authenticated:
if getattr(request.user, "is_new_employee", True):
return redirect("change-password")
return self.get_response(request)
class TwoFactorAuthMiddleware:
"""
Middleware to enforce two-factor authentication for specific users.
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
excluded_paths = [
"/change-password",
"/login",
"/logout",
"/two-factor",
"/send-otp",
]
if request.path.rstrip("/") in excluded_paths:
return self.get_response(request)
if TWO_FACTORS_AUTHENTICATION:
try:
if ConfiguredEmailBackend().configuration is not None:
if hasattr(request, "user") and request.user.is_authenticated:
if not request.session.get("otp_code_verified", False):
return redirect("/two-factor")
else:
return self.get_response(request)
except Exception as e:
return self.get_response(request)
return self.get_response(request)

1865
base/models.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
"""
views.py
This module is used to map url patterns with request and approve methods in Dashboard.
"""
import json
from django.apps import apps
from django.shortcuts import render
from base.methods import filtersubordinates, paginator_qry
from base.models import ShiftRequest, WorkTypeRequest
from horilla.decorators import login_required
@login_required
def dashboard_shift_request(request):
page_number = request.GET.get("page")
previous_data = request.GET.urlencode()
requests = ShiftRequest.objects.filter(
approved=False, canceled=False, employee_id__is_active=True
)
requests = filtersubordinates(request, requests, "base.add_shiftrequest")
requests_ids = json.dumps([instance.id for instance in requests])
requests = paginator_qry(requests, page_number)
return render(
request,
"request_and_approve/shift_request.html",
{
"requests": requests,
"requests_ids": requests_ids,
"pd": previous_data,
},
)
@login_required
def dashboard_work_type_request(request):
page_number = request.GET.get("page")
previous_data = request.GET.urlencode()
requests = WorkTypeRequest.objects.filter(
approved=False, canceled=False, employee_id__is_active=True
)
requests = filtersubordinates(request, requests, "base.add_worktyperequest")
requests_ids = json.dumps([instance.id for instance in requests])
requests = paginator_qry(requests, page_number)
return render(
request,
"request_and_approve/work_type_request.html",
{
"requests": requests,
"requests_ids": requests_ids,
"pd": previous_data,
},
)

501
base/scheduler.py Normal file
View File

@@ -0,0 +1,501 @@
import calendar
import sys
from datetime import date, datetime, timedelta
from apscheduler.schedulers.background import BackgroundScheduler
from django.urls import reverse
from notifications.signals import notify
def update_rotating_work_type_assign(rotating_work_type, new_date):
"""
Here will update the employee work information details and send notification
"""
from django.contrib.auth.models import User
employee = rotating_work_type.employee_id
employee_work_info = employee.employee_work_info
work_type1 = rotating_work_type.rotating_work_type_id.work_type1
work_type2 = rotating_work_type.rotating_work_type_id.work_type2
additional_work_types = (
rotating_work_type.rotating_work_type_id.additional_work_types()
)
if additional_work_types is None:
total_rotate_work_types = [work_type1, work_type2]
else:
total_rotate_work_types = [work_type1, work_type2] + list(additional_work_types)
next_work_type_index = rotating_work_type.additional_data.get(
"next_work_type_index", 0
)
next_work_type = total_rotate_work_types[next_work_type_index]
if next_work_type_index < len(total_rotate_work_types) - 1:
next_work_type_index += 1
else:
next_work_type_index = 0
rotating_work_type.additional_data["next_work_type_index"] = next_work_type_index
employee_work_info.work_type_id = rotating_work_type.next_work_type
employee_work_info.save()
rotating_work_type.next_change_date = new_date
rotating_work_type.current_work_type = rotating_work_type.next_work_type
rotating_work_type.next_work_type = next_work_type
rotating_work_type.save()
bot = User.objects.filter(username="Horilla Bot").first()
if bot is not None:
employee = rotating_work_type.employee_id
notify.send(
bot,
recipient=employee.employee_user_id,
verb="Your Work Type has been changed.",
verb_ar="لقد تغير نوع عملك.",
verb_de="Ihre Art der Arbeit hat sich geändert.",
verb_es="Su tipo de trabajo ha sido cambiado.",
verb_fr="Votre type de travail a été modifié.",
icon="infinite",
redirect=reverse("employee-profile"),
)
return
def work_type_rotate_after(rotating_work_work_type):
"""
This method for rotate work type based on after day
"""
date_today = datetime.now()
switch_date = rotating_work_work_type.next_change_date
if switch_date.strftime("%Y-%m-%d") == date_today.strftime("%Y-%m-%d"):
new_date = date_today + timedelta(days=rotating_work_work_type.rotate_after_day)
update_rotating_work_type_assign(rotating_work_work_type, new_date)
return
def work_type_rotate_weekend(rotating_work_type):
"""
This method for rotate work type based on weekend
"""
date_today = datetime.now()
switch_date = rotating_work_type.next_change_date
if switch_date.strftime("%Y-%m-%d") == date_today.strftime("%Y-%m-%d"):
day = datetime.now().strftime("%A").lower()
switch_day = rotating_work_type.rotate_every_weekend
if day == switch_day:
new_date = date_today + timedelta(days=7)
update_rotating_work_type_assign(rotating_work_type, new_date)
return
def work_type_rotate_every(rotating_work_type):
"""
This method for rotate work type based on every month
"""
date_today = datetime.now()
switch_date = rotating_work_type.next_change_date
day_date = rotating_work_type.rotate_every
if switch_date.strftime("%Y-%m-%d") == date_today.strftime("%Y-%m-%d"):
if day_date == switch_date.strftime("%d").lstrip("0"):
new_date = date_today.replace(month=date_today.month + 1)
update_rotating_work_type_assign(rotating_work_type, new_date)
elif day_date == "last":
year = date_today.strftime("%Y")
month = date_today.strftime("%m")
last_day = calendar.monthrange(int(year), int(month) + 1)[1]
new_date = datetime(int(year), int(month) + 1, last_day)
update_rotating_work_type_assign(rotating_work_type, new_date)
return
def rotate_work_type():
"""
This method will identify the based on condition to the rotating shift assign
and redirect to the chunk method to execute.
"""
from base.models import RotatingWorkTypeAssign
rotating_work_types = RotatingWorkTypeAssign.objects.filter(is_active=True)
for rotating_work_type in rotating_work_types:
based_on = rotating_work_type.based_on
if based_on == "after":
work_type_rotate_after(rotating_work_type)
elif based_on == "weekly":
work_type_rotate_weekend(rotating_work_type)
elif based_on == "monthly":
work_type_rotate_every(rotating_work_type)
return
def update_rotating_shift_assign(rotating_shift, new_date):
"""
Here will update the employee work information and send notification
"""
from django.contrib.auth.models import User
next_shift_index = 0
employee = rotating_shift.employee_id
employee_work_info = employee.employee_work_info
rotating_shift_id = rotating_shift.rotating_shift_id
shift1 = rotating_shift_id.shift1
shift2 = rotating_shift_id.shift2
additional_shifts = rotating_shift_id.additional_shifts()
if additional_shifts is None:
total_rotate_shifts = [shift1, shift2]
else:
total_rotate_shifts = [shift1, shift2] + list(additional_shifts)
next_shift_index = rotating_shift.additional_data.get("next_shift_index")
next_shift = total_rotate_shifts[next_shift_index]
if next_shift_index < len(total_rotate_shifts) - 1:
next_shift_index += 1
else:
next_shift_index = 0 # Wrap around to the beginning of the list
rotating_shift.additional_data["next_shift_index"] = next_shift_index
employee_work_info.shift_id = rotating_shift.next_shift
employee_work_info.save()
rotating_shift.next_change_date = new_date
rotating_shift.current_shift = rotating_shift.next_shift
rotating_shift.next_shift = next_shift
rotating_shift.save()
bot = User.objects.filter(username="Horilla Bot").first()
if bot is not None:
employee = rotating_shift.employee_id
notify.send(
bot,
recipient=employee.employee_user_id,
verb="Your shift has been changed.",
verb_ar="تم تغيير التحول الخاص بك.",
verb_de="Ihre Schicht wurde geändert.",
verb_es="Tu turno ha sido cambiado.",
verb_fr="Votre quart de travail a été modifié.",
icon="infinite",
redirect=reverse("employee-profile"),
)
return
def shift_rotate_after_day(rotating_shift, today):
"""
This method for rotate shift based on after day
"""
switch_date = rotating_shift.next_change_date
if switch_date == today:
new_date = today + timedelta(days=rotating_shift.rotate_after_day)
update_rotating_shift_assign(rotating_shift, new_date)
return
def shift_rotate_weekend(rotating_shift, today):
"""
This method for rotate shift based on weekend
"""
switch_date = rotating_shift.next_change_date
if switch_date == today:
day = today.strftime("%A").lower()
switch_day = rotating_shift.rotate_every_weekend
if day == switch_day:
new_date = today + timedelta(days=7)
update_rotating_shift_assign(rotating_shift, new_date)
return
def shift_rotate_every(rotating_shift, today):
"""
This method for rotate shift based on every month
"""
switch_date = rotating_shift.next_change_date
day_date = rotating_shift.rotate_every
if switch_date == today:
if day_date == switch_date.strftime("%d").lstrip("0"):
new_date = today.replace(month=today.month + 1)
update_rotating_shift_assign(rotating_shift, new_date)
elif day_date == "last":
year = today.year
month = today.month
last_day = calendar.monthrange(int(year), int(month) + 1)[1]
new_date = datetime(int(year), int(month) + 1, last_day)
update_rotating_shift_assign(rotating_shift, new_date)
return
def rotate_shift():
"""
This method will identify the based on condition to the rotating shift assign
and redirect to the chunk method to execute.
"""
from base.models import RotatingShiftAssign
rotating_shifts = RotatingShiftAssign.objects.filter(is_active=True)
today = datetime.now().date()
r_shifts = rotating_shifts.filter(start_date__lte=today)
rotating_shifts_modified = None
for r_shift in r_shifts:
emp_shift = rotating_shifts.filter(
employee_id=r_shift.employee_id, start_date__lte=today
).exclude(id=r_shift.id)
rotating_shifts_modified = rotating_shifts.exclude(
id__in=emp_shift.values_list("id", flat=True)
)
emp_shift.update(is_active=False)
for rotating_shift in rotating_shifts_modified:
based_on = rotating_shift.based_on
# after day condition
if based_on == "after":
shift_rotate_after_day(rotating_shift, today)
# weekly condition
elif based_on == "weekly":
shift_rotate_weekend(rotating_shift, today)
# monthly condition
elif based_on == "monthly":
shift_rotate_every(rotating_shift, today)
return
def switch_shift():
"""
This method change employees shift information regards to the shift request
"""
from django.contrib.auth.models import User
from base.models import ShiftRequest
today = date.today()
shift_requests = ShiftRequest.objects.filter(
canceled=False, approved=True, requested_date__exact=today, shift_changed=False
)
if shift_requests:
for request in shift_requests:
work_info = request.employee_id.employee_work_info
# updating requested shift to the employee work information.
work_info.shift_id = request.shift_id
work_info.save()
request.approved = True
request.shift_changed = True
request.save()
bot = User.objects.filter(username="Horilla Bot").first()
if bot is not None:
employee = request.employee_id
notify.send(
bot,
recipient=employee.employee_user_id,
verb="Shift Changes notification",
verb_ar="التحول تغيير الإخطار",
verb_de="Benachrichtigung über Schichtänderungen",
verb_es="Notificación de cambios de turno",
verb_fr="Notification des changements de quart de travail",
icon="refresh",
redirect=reverse("employee-profile"),
)
return
def undo_shift():
"""
This method undo previous employees shift information regards to the shift request
"""
from django.contrib.auth.models import User
from base.models import ShiftRequest
today = date.today()
# here will get all the active shift requests
shift_requests = ShiftRequest.objects.filter(
canceled=False,
approved=True,
requested_till__lt=today,
is_active=True,
shift_changed=True,
)
if shift_requests:
for request in shift_requests:
work_info = request.employee_id.employee_work_info
work_info.shift_id = request.previous_shift_id
work_info.save()
# making the instance in-active
request.is_active = False
request.save()
bot = User.objects.filter(username="Horilla Bot").first()
if bot is not None:
employee = request.employee_id
notify.send(
bot,
recipient=employee.employee_user_id,
verb="Shift changes notification, Requested date expired.",
verb_ar="التحول يغير الإخطار ، التاريخ المطلوب انتهت صلاحيته.",
verb_de="Benachrichtigung über Schichtänderungen, gewünschtes Datum abgelaufen.",
verb_es="Notificación de cambios de turno, Fecha solicitada vencida.",
verb_fr="Notification de changement d'équipe, la date demandée a expiré.",
icon="refresh",
redirect=reverse("employee-profile"),
)
return
def switch_work_type():
"""
This method change employees work type information regards to the work type request
"""
from django.contrib.auth.models import User
from base.models import WorkTypeRequest
today = date.today()
work_type_requests = WorkTypeRequest.objects.filter(
canceled=False,
approved=True,
requested_date__exact=today,
work_type_changed=False,
)
for request in work_type_requests:
work_info = request.employee_id.employee_work_info
# updating requested work type to the employee work information.
work_info.work_type_id = request.work_type_id
work_info.save()
request.approved = True
request.work_type_changed = True
request.save()
bot = User.objects.filter(username="Horilla Bot").first()
if bot is not None:
employee = request.employee_id
notify.send(
bot,
recipient=employee.employee_user_id,
verb="Work Type Changes notification",
verb_ar="إخطار تغييرات نوع العمل",
verb_de="Benachrichtigung über Änderungen des Arbeitstyps",
verb_es="Notificación de cambios de tipo de trabajo",
verb_fr="Notification de changement de type de travail",
icon="swap-horizontal",
redirect=reverse("employee-profile"),
)
return
def undo_work_type():
"""
This method undo previous employees work type information regards to the work type request
"""
from django.contrib.auth.models import User
from base.models import WorkTypeRequest
today = date.today()
# here will get all the active work type requests
work_type_requests = WorkTypeRequest.objects.filter(
canceled=False,
approved=True,
requested_till__lt=today,
is_active=True,
work_type_changed=True,
)
for request in work_type_requests:
work_info = request.employee_id.employee_work_info
# updating employee work information's work type to previous work type
work_info.work_type_id = request.previous_work_type_id
work_info.save()
# making the instance is in-active
request.is_active = False
request.save()
bot = User.objects.filter(username="Horilla Bot").first()
if bot is not None:
employee = request.employee_id
notify.send(
bot,
recipient=employee.employee_user_id,
verb="Work type changes notification, Requested date expired.",
verb_ar="إعلام بتغيير نوع العمل ، انتهاء صلاحية التاريخ المطلوب.",
verb_de="Benachrichtigung über Änderungen des Arbeitstyps, angefordertes Datum abgelaufen.",
verb_es="Notificación de cambios de tipo de trabajo, fecha solicitada vencida.",
verb_fr="Notification de changement de type de travail, la date demandée a expiré.",
icon="swap-horizontal",
redirect=reverse("employee-profile"),
)
return
def recurring_holiday():
from .models import Holidays
recurring_holidays = Holidays.objects.filter(recurring=True)
today = datetime.now()
# Looping through all recurring holiday
for recurring_holiday in recurring_holidays:
start_date = recurring_holiday.start_date
end_date = recurring_holiday.end_date
new_start_date = date(start_date.year + 1, start_date.month, start_date.day)
new_end_date = date(end_date.year + 1, end_date.month, end_date.day)
# Checking that end date is not none
if end_date is None:
# checking if that start date is day before today
if start_date == (today - timedelta(days=1)).date():
recurring_holiday.start_date = new_start_date
elif end_date == (today - timedelta(days=1)).date():
recurring_holiday.start_date = new_start_date
recurring_holiday.end_date = new_end_date
recurring_holiday.save()
if not any(
cmd in sys.argv
for cmd in ["makemigrations", "migrate", "compilemessages", "flush", "shell"]
):
scheduler = BackgroundScheduler()
# Add jobs with next_run_time set to the end of the previous job
try:
scheduler.add_job(rotate_shift, "interval", hours=4, id="job1")
except:
pass
try:
scheduler.add_job(
rotate_work_type,
"interval",
hours=4,
id="job2",
)
except:
pass
try:
scheduler.add_job(
undo_shift,
"interval",
hours=4,
id="job3",
)
except:
pass
try:
scheduler.add_job(
switch_shift,
"interval",
hours=4,
id="job4",
)
except:
pass
try:
scheduler.add_job(
undo_work_type,
"interval",
hours=4,
id="job6",
)
except:
pass
try:
scheduler.add_job(
switch_work_type,
"interval",
hours=4,
id="job5",
)
except:
pass
scheduler.add_job(recurring_holiday, "interval", hours=4)
scheduler.start()

242
base/signals.py Normal file
View File

@@ -0,0 +1,242 @@
import logging
import os
import time
from datetime import datetime
from django.apps import apps
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.signals import user_login_failed
from django.db.models import Max, Q
from django.db.models.signals import m2m_changed, post_migrate, post_save
from django.dispatch import receiver
from django.http import Http404
from django.shortcuts import redirect, render
from base.models import Announcement, PenaltyAccounts
from horilla.methods import get_horilla_model_class
@receiver(post_save, sender=PenaltyAccounts)
def create_deduction_cutleave_from_penalty(sender, instance, created, **kwargs):
"""
This is post save method, used to create deduction and cut available leave days
"""
# only work when creating
if created:
penalty_amount = instance.penalty_amount
if apps.is_installed("payroll") and penalty_amount:
Deduction = get_horilla_model_class(app_label="payroll", model="deduction")
penalty = Deduction()
if instance.late_early_id:
penalty.title = f"{instance.late_early_id.get_type_display()} penalty"
penalty.one_time_date = (
instance.late_early_id.attendance_id.attendance_date
)
elif instance.leave_request_id:
penalty.title = f"Leave penalty {instance.leave_request_id.end_date}"
penalty.one_time_date = instance.leave_request_id.end_date
else:
penalty.title = f"Penalty on {datetime.today()}"
penalty.one_time_date = datetime.today()
penalty.include_active_employees = False
penalty.is_fixed = True
penalty.amount = instance.penalty_amount
penalty.only_show_under_employee = True
penalty.save()
penalty.include_active_employees = False
penalty.specific_employees.add(instance.employee_id)
penalty.save()
if (
apps.is_installed("leave")
and instance.leave_type_id
and instance.minus_leaves
):
available = instance.employee_id.available_leave.filter(
leave_type_id=instance.leave_type_id
).first()
unit = round(instance.minus_leaves * 2) / 2
if not instance.deduct_from_carry_forward:
available.available_days = max(0, (available.available_days - unit))
else:
available.carryforward_days = max(
0, (available.carryforward_days - unit)
)
available.save()
# @receiver(post_migrate)
def clean_work_records(sender, **kwargs):
if sender.label not in ["attendance"]:
return
from attendance.models import WorkRecords
latest_records = (
WorkRecords.objects.exclude(work_record_type="DFT")
.values("employee_id", "date")
.annotate(latest_id=Max("id"))
)
# Delete all but the latest WorkRecord
deleted_count = 0
for record in latest_records:
deleted_count += (
WorkRecords.objects.filter(
employee_id=record["employee_id"], date=record["date"]
)
.exclude(id=record["latest_id"])
.delete()[0]
)
@receiver(m2m_changed, sender=Announcement.employees.through)
def filtered_employees(sender, instance, action, **kwargs):
"""
filtered employees
"""
if action not in ["post_add", "post_remove", "post_clear"]:
return # Only run after M2M changes
employee_ids = list(instance.employees.values_list("id", flat=True))
department_ids = list(instance.department.values_list("id", flat=True))
job_position_ids = list(instance.job_position.values_list("id", flat=True))
employees = instance.model_employee.objects.filter(
Q(id__in=employee_ids)
| Q(employee_work_info__department_id__in=department_ids)
| Q(employee_work_info__job_position_id__in=job_position_ids)
)
instance.filtered_employees.set(employees)
# Logger setup
logger = logging.getLogger("django.security")
# Create a global dictionary to track login attempts and ban time per session
failed_attempts = {}
ban_time = {}
FAIL2BAN_LOG_ENABLED = os.path.exists(
"security.log"
) # Checking that any file is created for the details of the wrong logins.
# The file will be created only if you set the LOGGING in your settings.py
@receiver(user_login_failed)
def log_login_failed(sender, credentials, request, **kwargs):
"""
To ban the IP of user that enter wrong credentials for multiple times
you should add this section in your settings.py file. And also it creates the security file for deatils of wrong logins.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'security_file': {
'level': 'WARNING',
'class': 'logging.FileHandler',
'filename': '/var/log/django/security.log', # File Path for view the log details.
# Give the same path to the section FAIL2BAN_LOG_ENABLED = os.path.exists('security.log') in signals.py in Base.
},
},
'loggers': {
'django.security': {
'handlers': ['security_file'],
'level': 'WARNING',
'propagate': False,
},
},
}
# This section is for giving the maxtry and bantime
FAIL2BAN_MAX_RETRY = 3 # Same as maxretry in jail.local
FAIL2BAN_BAN_TIME = 300 # Same as bantime in jail.local (in seconds)
"""
# Checking that the file is created or not to initiate the ban functions.
if not FAIL2BAN_LOG_ENABLED:
return
max_attempts = getattr(settings, "FAIL2BAN_MAX_RETRY", 3)
ban_duration = getattr(settings, "FAIL2BAN_BAN_TIME", 300)
username = credentials.get("username", "unknown")
ip = request.META.get("REMOTE_ADDR", "unknown")
session_key = (
request.session.session_key or request.session._get_or_create_session_key()
)
# Check if currently banned
if session_key in ban_time and ban_time[session_key] > time.time():
banned_until = time.strftime("%H:%M", time.localtime(ban_time[session_key]))
messages.info(
request, f"You are banned until {banned_until}. Please try again later."
)
return redirect("/")
# If ban expired, reset counters
if session_key in ban_time and ban_time[session_key] <= time.time():
del ban_time[session_key]
if session_key in failed_attempts:
del failed_attempts[session_key]
# Initialize tracking if needed
if session_key not in failed_attempts:
failed_attempts[session_key] = 0
failed_attempts[session_key] += 1
attempts_left = max_attempts - failed_attempts[session_key]
logger.warning(f"Invalid login attempt for user '{username}' from {ip}")
if failed_attempts[session_key] >= max_attempts:
ban_time[session_key] = time.time() + ban_duration
messages.info(
request,
f"You have been banned for {ban_duration // 60} minutes due to multiple failed login attempts.",
)
return redirect("/")
messages.info(
request,
f"You have {attempts_left} login attempt(s) left before a temporary ban.",
)
return redirect("login")
class Fail2BanMiddleware:
"""
Middleware to force password change for new employees.
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
session_key = request.session.session_key
if not session_key:
request.session.create()
# Check ban and enforce it
if session_key in ban_time and ban_time[session_key] > time.time():
banned_until = time.strftime("%H:%M", time.localtime(ban_time[session_key]))
messages.info(
request, f"You are banned until {banned_until}. Please try again later."
)
return render(request, "403.html")
# If ban expired, clear counters
if session_key in ban_time and ban_time[session_key] <= time.time():
del ban_time[session_key]
if session_key in failed_attempts:
del failed_attempts[session_key]
return self.get_response(request)
settings.MIDDLEWARE.append("base.signals.Fail2BanMiddleware")

3
base/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

BIN
base/threading.py Normal file

Binary file not shown.

364
base/translator.py Normal file
View File

@@ -0,0 +1,364 @@
from django.utils.translation import gettext as _
_("monday"),
_("tuesday"),
_("wednesday"),
_("thursday"),
_("friday"),
_("saturday"),
_("sunday"),
_("after"),
_("weekly"),
_("monthly"),
_("Employee First Name"),
_("Employee Last Name"),
_("Bank Code #1"),
_("Bank Code #2"),
_("RECRUITMENT"),
_("ONBOARDING"),
_("EMPLOYEE"),
_("PAYROLL"),
_("ATTENDANCE"),
_("LEAVE"),
_("ASSET"),
_("Your asset request approved!."),
_("Your asset request rejected!."),
_("You are added to rotating work type"),
_("You are added to rotating shift"),
_("Your work type request has been canceled."),
_("Your work type request has been approved."),
_("Your work type request has been deleted."),
_("Your shift request has been canceled."),
_("Your shift request has been approved."),
_("Your shift request has been deleted."),
_("Your work details has been updated."),
_("You have a new leave request to validate."),
_("New leave type is assigned to you"),
_("Your Leave request has been cancelled"),
_("Your Leave request has been approved"),
_("You are chosen as onboarding stage manager"),
_("You are chosen as onboarding task manager"),
_("You got an OKR!."),
_("You have received feedback!"),
_("You have been assigned as a manager in a feedback!"),
_("You have been assigned as a subordinate in a feedback!"),
_("You have been assigned as a colleague in a feedback!"),
_("You are chosen as one of recruitment manager"),
_("Your attendance for the date "),
_(" is validated"),
_("Select"),
_("January"),
_("February"),
_("March"),
_("April"),
_("May"),
_("June"),
_("July"),
_("August"),
_("September"),
_("October"),
_("November"),
_("December"),
_("One time date"),
_("Is condition based"),
_("Is taxable"),
_("Is fixed"),
_("Value"),
_("If choice"),
_("Is tax"),
_("If amount"),
_("If condition"),
_("Employer rate"),
_("Contract name"),
_("Contract start date"),
_("Contract end date"),
_("Wage type"),
_("Calculate daily leave amount"),
_("Deduction for one leave amount"),
_("Deduct leave from basic pay"),
_("Job role"),
_("Work type"),
_("Pay frequency"),
_("Filing status"),
_("Contract status"),
_("Contract document"),
_("Is tax"),
_("Update compensation"),
_("Is pretax"),
_("DASHBOARD"),
_("SHIFT REQUESTS"),
_("WORK TYPE REQUESTS"),
_("ATTENDANCE"),
_("ASSET"),
_("Single"),
_("Married"),
_("Divorced"),
_("Description"),
_("Rotate every weekend"),
_("Rotate every"),
_("Request description"),
_("Attendance validated"),
_("Is validate request"),
_("Is validate request approved"),
_("Reporting Manager"),
_("Employment Type"),
_("Jan"),
_("Feb"),
_("Mar"),
_("Apr"),
_("May"),
_("Jun"),
_("Jul"),
_("Aug"),
_("Sep"),
_("Oct"),
_("Nov"),
_("Dec"),
_("Additional info"),
_("Schedule date"),
_("Is active"),
_("End date"),
_("Recruitment managers"),
_("Stage managers"),
_("Stage type"),
_("Scheduled from"),
_("Scheduled till"),
_("Start from"),
_("End till"),
_("Employee first name"),
_("Employee last name"),
_("Reporting manager"),
_("Requested date"),
_("Previous shift"),
_("Gte"),
_("Lte"),
_("Previous work type"),
_("Current shift"),
_("Rotating shift"),
_("Next change date"),
_("Next shift"),
_("Current work type"),
_("Next work type"),
_("Start date from"),
_("Start date till"),
_("End date from"),
_("End date till"),
_("Location"),
_("Attendance clock in"),
_("Attendance clock out"),
_("Attendance overtime approve"),
_("Hour account"),
_("Clock out date"),
_("Clock in date"),
_("Shift day"),
_("Attendance date from"),
_("In from"),
_("Out from"),
_("Attendance date till"),
_("Out from"),
_("Out till"),
_("In till"),
_("Leave type"),
_("From date"),
_("To date"),
_("Assigned date"),
_("Based on week"),
_("Based on week day"),
_("Emp obj"),
_("Updated at"),
_("Created at"),
_("Created at date range"),
_("Review cycle"),
_("Asset list"),
_("Query"),
_("Asset category name"),
_("Asset category description"),
_("Asset name"),
_("Asset tracking"),
_("Asset purchase date"),
_("Asset purchase cost"),
_("Asset lot number"),
_("Asset category"),
_("Asset status"),
_("True"),
_("False"),
_("Onboarding Portal S…"),
_("Employee work information"),
_("Rotating work type assign"),
_("Employee shift schedule"),
_("Rotating shift assign"),
_("Onboarding portal"),
_("Start date breakdown"),
_("End date breakdown"),
_("Payment"),
_("dashboard"),
_("pipeline"),
_("recruitment-survey-question-template-view"),
_("candidate-view"),
_("recruitment-view"),
_("stage-view"),
_("view-onboarding-dashboard"),
_("onboarding-view"),
_("candidates-view"),
_("employee-profile"),
_("employee-view"),
_("shift-request-view"),
_("work-type-request-view"),
_("rotating-shift-assign"),
_("rotating-work-type-assign"),
_("view-payroll-dashboard"),
_("view-contract"),
_("view-allowance"),
_("view-deduction"),
_("view-payslip"),
_("filing-status-view"),
_("attendance-view"),
_("request-attendance-view"),
_("attendance-overtime-view"),
_("attendance-activity-view"),
_("late-come-early-out-view"),
_("view-my-attendance"),
_("leave-dashboard"),
_("leave-employee-dashboard"),
_("user-leave"),
_("user-request-view"),
_("type-view"),
_("assign-view"),
_("request-view"),
_("holiday-view"),
_("company-leave-view"),
_("dashboard-view"),
_("objective-list-view"),
_("feedback-view"),
_("period-view"),
_("question-template-view"),
_("asset-category-view"),
_("asset-request-allocation-view"),
_("recruitment"),
_("update-contract"),
_("update-allowance"),
_("update-deduction"),
_("type-update"),
_("type-creation"),
_("asset-batch-view"),
_("create-deduction"),
_("create-allowance"),
_("update-allowance"),
_("update-deduction"),
_("pms"),
_("asset"),
_("leave"),
_("attendance"),
_("payroll"),
_("employee"),
_("onboarding"),
_("recruitment"),
_("settings"),
_("department-view"),
_("job-position-view"),
_("job-role-view"),
_("work-type-view"),
_("rotating-work-type-view"),
_("employee-type-view"),
_("employee-shift-view"),
_("employee-shift-schedule-view"),
_("rotating-shift-view"),
_("attendance-settings-view"),
_("user-group-view"),
_("company-view"),
_("employee-permission-assign"),
_("currency"),
_("leave-allocation-request-view"),
_("employee-view-update"),
_("employee-bulk-update"),
_("not_set"),
_("objective-creation"),
_("feedback-creation"),
_("helpdesk"),
_("faq-category-view"),
_("faq-view"),
_("ticket-view"),
_("ticket-detail"),
_("ticket-type-view"),
_("tag-view"),
_("mail-server-conf"),
_("configuration"),
_("multiple-approval-condition"),
_("skill-zone-view"),
_("view-mail-templates"),
_("view-loan"),
_("view-reimbursement"),
_("department-manager-view"),
_("date-settings"),
_("reporting_manager"),
_("department"),
_("job_position"),
_("job_role"),
_("shift"),
_("work_type"),
_("company"),
_("employee-create-personal-info"),
_("offboarding"),
_("offboarding-pipeline"),
_("pagination-settings-view"),
_("organisation-chart"),
_("document-request-view"),
_("disciplinary-actions"),
_("view-policies"),
_("resignation-requests-view"),
_("action-type"),
_("general-settings"),
_("candidate-update"),
_("create-payslip"),
_("work-records"),
_("edit-profile"),
_("candidate-reject-reasons"),
_("employee-tag-view"),
_("grace-settings-view"),
_("helpdesk-tag-view"),
_("feedback-answer-view"),
_("requested"),
_("approved"),
_("cancelled"),
_("rejected"),
_("true"),
_("false"),
_("candidate-create"),
_("compensatory-leave-settings-view"),
_("view-compensatory-leave"),
_("interview-view"),
_("view-meetings"),
_("view-key-result"),
_("asset-history"),
_("restrict-view"),
_("auto-payslip-settings-view"),
_("bonus-point-setting"),
_("employee-past-leave-restriction"),
_("track-late-come-early-out"),
_("enable-biometric-attendance"),
_("allowed-ips"),
_("self-tracking-feature"),
_("candidate-reject-reasons"),
_("skills-view"),
_("employee-bonus-point"),
_("mail-automations"),
_("check-in-check-out-setting"),
_("user-accessibility"),
_("project"),
_("project-dashboard-view"),
_("project-view"),
_("task-view"),
_("task-all"),
_("view-time-sheet"),
_("backup"),
_("gdrive"),
_("horilla-theme"),
_("color-settings"),
_("report"),
_("recruitment-report"),
_("employee-report"),
_("attendance-report"),
_("leave-report"),
_("payroll-report"),
_("asset-report"),
_("pms-report"),

1077
base/urls.py Normal file

File diff suppressed because it is too large Load Diff

7553
base/views.py Normal file

File diff suppressed because it is too large Load Diff