BIN
base/.DS_Store
vendored
Normal file
BIN
base/.DS_Store
vendored
Normal file
Binary file not shown.
1
base/__init__.py
Normal file
1
base/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import scheduler
|
||||
72
base/admin.py
Normal file
72
base/admin.py
Normal 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
416
base/announcement.py
Normal 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
38
base/apps.py
Normal 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
267
base/backends.py
Normal 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
301
base/context_processors.py
Normal 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
855
base/countries.py
Normal 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
68
base/decorators.py
Normal 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
404
base/filters.py
Normal 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
2800
base/forms.py
Normal file
File diff suppressed because it is too large
Load Diff
112
base/horilla_company_manager.py
Normal file
112
base/horilla_company_manager.py
Normal 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
1154
base/methods.py
Normal file
File diff suppressed because it is too large
Load Diff
249
base/middleware.py
Normal file
249
base/middleware.py
Normal 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
1865
base/models.py
Normal file
File diff suppressed because it is too large
Load Diff
56
base/request_and_approve.py
Normal file
56
base/request_and_approve.py
Normal 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
501
base/scheduler.py
Normal 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
242
base/signals.py
Normal 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
3
base/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
BIN
base/threading.py
Normal file
BIN
base/threading.py
Normal file
Binary file not shown.
364
base/translator.py
Normal file
364
base/translator.py
Normal 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
1077
base/urls.py
Normal file
File diff suppressed because it is too large
Load Diff
7553
base/views.py
Normal file
7553
base/views.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user