wbhuman_resources 1.58.4__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. wbhuman_resources/__init__.py +1 -0
  2. wbhuman_resources/admin/__init__.py +5 -0
  3. wbhuman_resources/admin/absence.py +113 -0
  4. wbhuman_resources/admin/calendars.py +37 -0
  5. wbhuman_resources/admin/employee.py +109 -0
  6. wbhuman_resources/admin/kpi.py +21 -0
  7. wbhuman_resources/admin/review.py +157 -0
  8. wbhuman_resources/apps.py +23 -0
  9. wbhuman_resources/dynamic_preferences_registry.py +119 -0
  10. wbhuman_resources/factories/__init__.py +38 -0
  11. wbhuman_resources/factories/absence.py +109 -0
  12. wbhuman_resources/factories/calendars.py +60 -0
  13. wbhuman_resources/factories/employee.py +80 -0
  14. wbhuman_resources/factories/kpi.py +155 -0
  15. wbhuman_resources/filters/__init__.py +20 -0
  16. wbhuman_resources/filters/absence.py +109 -0
  17. wbhuman_resources/filters/absence_graphs.py +85 -0
  18. wbhuman_resources/filters/calendars.py +28 -0
  19. wbhuman_resources/filters/employee.py +81 -0
  20. wbhuman_resources/filters/kpi.py +35 -0
  21. wbhuman_resources/filters/review.py +134 -0
  22. wbhuman_resources/filters/signals.py +27 -0
  23. wbhuman_resources/locale/de/LC_MESSAGES/django.mo +0 -0
  24. wbhuman_resources/locale/de/LC_MESSAGES/django.po +2207 -0
  25. wbhuman_resources/locale/de/LC_MESSAGES/django.po.translated +2456 -0
  26. wbhuman_resources/locale/en/LC_MESSAGES/django.mo +0 -0
  27. wbhuman_resources/locale/en/LC_MESSAGES/django.po +2091 -0
  28. wbhuman_resources/locale/fr/LC_MESSAGES/django.mo +0 -0
  29. wbhuman_resources/locale/fr/LC_MESSAGES/django.po +2093 -0
  30. wbhuman_resources/management/__init__.py +23 -0
  31. wbhuman_resources/migrations/0001_initial_squashed_squashed_0015_alter_absencerequest_calendaritem_ptr_and_more.py +949 -0
  32. wbhuman_resources/migrations/0016_alter_employeehumanresource_options.py +20 -0
  33. wbhuman_resources/migrations/0017_absencerequest_crossborder_country_and_more.py +55 -0
  34. wbhuman_resources/migrations/0018_remove_position_group_position_groups.py +32 -0
  35. wbhuman_resources/migrations/0019_alter_absencerequest_options_alter_kpi_options_and_more.py +44 -0
  36. wbhuman_resources/migrations/0020_alter_employeeyearbalance_year_alter_review_year.py +27 -0
  37. wbhuman_resources/migrations/0021_alter_position_color.py +18 -0
  38. wbhuman_resources/migrations/0022_remove_review_editable_mode.py +64 -0
  39. wbhuman_resources/migrations/__init__.py +0 -0
  40. wbhuman_resources/models/__init__.py +23 -0
  41. wbhuman_resources/models/absence.py +903 -0
  42. wbhuman_resources/models/calendars.py +370 -0
  43. wbhuman_resources/models/employee.py +1241 -0
  44. wbhuman_resources/models/kpi.py +199 -0
  45. wbhuman_resources/models/preferences.py +40 -0
  46. wbhuman_resources/models/review.py +982 -0
  47. wbhuman_resources/permissions/__init__.py +0 -0
  48. wbhuman_resources/permissions/backend.py +26 -0
  49. wbhuman_resources/serializers/__init__.py +49 -0
  50. wbhuman_resources/serializers/absence.py +308 -0
  51. wbhuman_resources/serializers/calendars.py +73 -0
  52. wbhuman_resources/serializers/employee.py +267 -0
  53. wbhuman_resources/serializers/kpi.py +80 -0
  54. wbhuman_resources/serializers/review.py +415 -0
  55. wbhuman_resources/signals.py +4 -0
  56. wbhuman_resources/tasks.py +195 -0
  57. wbhuman_resources/templates/review/review_report.html +322 -0
  58. wbhuman_resources/tests/__init__.py +1 -0
  59. wbhuman_resources/tests/conftest.py +96 -0
  60. wbhuman_resources/tests/models/__init__.py +0 -0
  61. wbhuman_resources/tests/models/test_absences.py +478 -0
  62. wbhuman_resources/tests/models/test_calendars.py +209 -0
  63. wbhuman_resources/tests/models/test_employees.py +502 -0
  64. wbhuman_resources/tests/models/test_review.py +103 -0
  65. wbhuman_resources/tests/models/test_utils.py +110 -0
  66. wbhuman_resources/tests/signals.py +108 -0
  67. wbhuman_resources/tests/test_permission.py +64 -0
  68. wbhuman_resources/tests/test_tasks.py +74 -0
  69. wbhuman_resources/urls.py +221 -0
  70. wbhuman_resources/utils.py +43 -0
  71. wbhuman_resources/viewsets/__init__.py +61 -0
  72. wbhuman_resources/viewsets/absence.py +312 -0
  73. wbhuman_resources/viewsets/absence_charts.py +328 -0
  74. wbhuman_resources/viewsets/buttons/__init__.py +7 -0
  75. wbhuman_resources/viewsets/buttons/absence.py +32 -0
  76. wbhuman_resources/viewsets/buttons/employee.py +44 -0
  77. wbhuman_resources/viewsets/buttons/kpis.py +16 -0
  78. wbhuman_resources/viewsets/buttons/review.py +195 -0
  79. wbhuman_resources/viewsets/calendars.py +103 -0
  80. wbhuman_resources/viewsets/display/__init__.py +39 -0
  81. wbhuman_resources/viewsets/display/absence.py +334 -0
  82. wbhuman_resources/viewsets/display/calendars.py +83 -0
  83. wbhuman_resources/viewsets/display/employee.py +254 -0
  84. wbhuman_resources/viewsets/display/kpis.py +92 -0
  85. wbhuman_resources/viewsets/display/review.py +429 -0
  86. wbhuman_resources/viewsets/employee.py +210 -0
  87. wbhuman_resources/viewsets/endpoints/__init__.py +42 -0
  88. wbhuman_resources/viewsets/endpoints/absence.py +57 -0
  89. wbhuman_resources/viewsets/endpoints/calendars.py +18 -0
  90. wbhuman_resources/viewsets/endpoints/employee.py +51 -0
  91. wbhuman_resources/viewsets/endpoints/kpis.py +53 -0
  92. wbhuman_resources/viewsets/endpoints/review.py +191 -0
  93. wbhuman_resources/viewsets/kpi.py +280 -0
  94. wbhuman_resources/viewsets/menu/__init__.py +22 -0
  95. wbhuman_resources/viewsets/menu/absence.py +50 -0
  96. wbhuman_resources/viewsets/menu/administration.py +15 -0
  97. wbhuman_resources/viewsets/menu/calendars.py +33 -0
  98. wbhuman_resources/viewsets/menu/employee.py +44 -0
  99. wbhuman_resources/viewsets/menu/kpis.py +18 -0
  100. wbhuman_resources/viewsets/menu/review.py +97 -0
  101. wbhuman_resources/viewsets/mixins.py +14 -0
  102. wbhuman_resources/viewsets/review.py +837 -0
  103. wbhuman_resources/viewsets/titles/__init__.py +18 -0
  104. wbhuman_resources/viewsets/titles/absence.py +30 -0
  105. wbhuman_resources/viewsets/titles/employee.py +18 -0
  106. wbhuman_resources/viewsets/titles/kpis.py +15 -0
  107. wbhuman_resources/viewsets/titles/review.py +62 -0
  108. wbhuman_resources/viewsets/utils.py +28 -0
  109. wbhuman_resources-1.58.4.dist-info/METADATA +8 -0
  110. wbhuman_resources-1.58.4.dist-info/RECORD +111 -0
  111. wbhuman_resources-1.58.4.dist-info/WHEEL +5 -0
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
@@ -0,0 +1,5 @@
1
+ from .absence import *
2
+ from .calendars import *
3
+ from .employee import *
4
+ from .kpi import *
5
+ from .review import *
@@ -0,0 +1,113 @@
1
+ from io import StringIO
2
+
3
+ import pandas as pd
4
+ from django.contrib import admin
5
+ from django.shortcuts import redirect, render
6
+ from django.utils.translation import gettext_lazy as _
7
+ from reversion.errors import RevertError
8
+ from wbcore.admin import CsvImportForm, ImportCsvMixin
9
+
10
+ from ..models.absence import AbsenceRequest, AbsenceRequestPeriods, AbsenceRequestType
11
+
12
+
13
+ class CustomImportCsvMixin(ImportCsvMixin):
14
+ def _import_csv(self, request, _sep=";"):
15
+ if request.method == "POST":
16
+ csv_file = request.FILES["csv_file"]
17
+
18
+ str_text = ""
19
+ for line in csv_file:
20
+ str_text = str_text + line.decode()
21
+ # Import csv as df
22
+ df = pd.read_csv(StringIO(str_text), sep=_sep)
23
+ # Sanitize dataframe
24
+ df = df.where(pd.notnull(df), None)
25
+ df = df.drop(df.columns.difference(self.get_import_fields()), axis=1)
26
+
27
+ # Overide this function if there is foreign key ids in the dataframe
28
+ df = self.manipulate_df(df)
29
+ errors = 0
30
+ revert_errors = 0
31
+ nb_added = 0
32
+ for model in df.to_dict("records"):
33
+ # by default, process the modela as a create request. Can be override to change the behavior
34
+ try:
35
+ nb_added += self.process_model(model)
36
+ # https://django-reversion.readthedocs.io/en/stable/common-problems.html
37
+ except RevertError:
38
+ revert_errors += 1
39
+ except Exception as e:
40
+ print(e) # noqa: T201
41
+ errors += 1
42
+ self.message_user(
43
+ request,
44
+ _(
45
+ "Your CSV file has been imported : {} imported ({} added, {} updated), {} errors, {} revert errors found due to failure to restore old versions"
46
+ ).format(
47
+ df.shape[0] - errors - revert_errors,
48
+ nb_added,
49
+ df.shape[0] - errors - revert_errors - nb_added,
50
+ errors,
51
+ revert_errors,
52
+ ),
53
+ )
54
+ return redirect("..")
55
+ form = CsvImportForm()
56
+ payload = {"form": form}
57
+ return render(request, "wbcore/admin/csv_form.html", payload)
58
+
59
+
60
+ @admin.register(AbsenceRequestType)
61
+ class AbsenceRequestTypeAdmin(admin.ModelAdmin):
62
+ list_display = [
63
+ "title",
64
+ "is_vacation",
65
+ "is_timeoff",
66
+ "is_extensible",
67
+ "auto_approve",
68
+ "days_in_advance",
69
+ ]
70
+
71
+ autocomplete_fields = ["crossborder_countries", "extra_notify_groups"]
72
+
73
+
74
+ class AbsenceRequestPeriodsInline(admin.TabularInline):
75
+ model = AbsenceRequestPeriods
76
+ ordering = ("timespan__startswith",)
77
+ extra = 0
78
+ raw_id_fields = ["balance", "request"]
79
+
80
+
81
+ @admin.register(AbsenceRequest)
82
+ class AbsenceRequestAdmin(admin.ModelAdmin):
83
+ list_display = ["status", "employee", "period", "type", "_total_hours", "_total_vacation_hours"]
84
+
85
+ fieldsets = (
86
+ (
87
+ "",
88
+ {
89
+ "fields": (
90
+ ("status", "type"),
91
+ ("period", "employee"),
92
+ "attachment",
93
+ )
94
+ },
95
+ ),
96
+ (
97
+ _("Notes"),
98
+ {"fields": ("notes", "reason")},
99
+ ),
100
+ )
101
+ inlines = (AbsenceRequestPeriodsInline,)
102
+ autocomplete_fields = ["employee"]
103
+ list_filter = ["type__is_vacation"]
104
+
105
+ def _total_hours(self, obj):
106
+ return obj._total_hours
107
+
108
+ def _total_vacation_hours(self, obj):
109
+ return obj._total_vacation_hours
110
+
111
+ #
112
+ # def get_queryset(self, request):
113
+ # return super().get_queryset().
@@ -0,0 +1,37 @@
1
+ from django.contrib import admin
2
+
3
+ from ..models import (
4
+ DayOff,
5
+ DayOffCalendar,
6
+ DefaultDailyPeriod,
7
+ EmployeeWeeklyOffPeriods,
8
+ )
9
+
10
+
11
+ @admin.register(DayOffCalendar)
12
+ class DayOffCalendarModelAdmin(admin.ModelAdmin):
13
+ pass
14
+
15
+
16
+ @admin.register(DayOff)
17
+ class DayOffAdmin(admin.ModelAdmin):
18
+ list_display = ["date", "title", "count_as_holiday", "calendar"]
19
+ ordering = ["date"]
20
+
21
+
22
+ @admin.register(DefaultDailyPeriod)
23
+ class DefaultDailyPeriodAdmin(admin.ModelAdmin):
24
+ list_display = ["lower_time", "upper_time", "title", "total_hours"]
25
+ ordering = ["lower_time"]
26
+
27
+
28
+ class EmployeeWeeklyOffPeriodsInLine(admin.TabularInline):
29
+ model = EmployeeWeeklyOffPeriods
30
+ fields = [
31
+ "period",
32
+ "weekday",
33
+ ]
34
+ fk_name = "employee"
35
+ extra = 0
36
+ raw_id_fields = ["employee"]
37
+ ordering = ("weekday", "period__lower_time")
@@ -0,0 +1,109 @@
1
+ from django.contrib import admin
2
+
3
+ from ..models.employee import (
4
+ BalanceHourlyAllowance,
5
+ EmployeeHumanResource,
6
+ EmployeeYearBalance,
7
+ Position,
8
+ )
9
+ from .calendars import EmployeeWeeklyOffPeriodsInLine
10
+
11
+
12
+ class PositionInline(admin.TabularInline):
13
+ model = Position
14
+ extra = 0
15
+
16
+
17
+ @admin.register(Position)
18
+ class PositionAdmin(admin.ModelAdmin):
19
+ search_fields = ("name",)
20
+ list_display = ("name", "height", "manager")
21
+
22
+ raw_id_fields = ["groups", "manager"]
23
+ autocomplete_fields = ["groups", "manager"]
24
+
25
+
26
+ class BalanceHourlyAllowanceTabularAdmin(admin.TabularInline):
27
+ model = BalanceHourlyAllowance
28
+ fk_name = "balance"
29
+
30
+
31
+ @admin.register(EmployeeYearBalance)
32
+ class EmployeeYearBalanceAdmin(admin.ModelAdmin):
33
+ inlines = [BalanceHourlyAllowanceTabularAdmin]
34
+
35
+
36
+ class EmployeeYearBalanceInline(admin.TabularInline):
37
+ model = EmployeeYearBalance
38
+ fields = (
39
+ "year",
40
+ "balance",
41
+ "daily_hours",
42
+ "number_mandatory_days_off",
43
+ "total_vacation_hourly_usage",
44
+ "total_vacation_hourly_balance",
45
+ "balance_in_days",
46
+ "number_mandatory_days_off_in_days",
47
+ "total_vacation_hourly_usage_in_days",
48
+ "total_vacation_hourly_balance_in_days",
49
+ )
50
+ readonly_fields = [
51
+ "balance",
52
+ "daily_hours",
53
+ "number_mandatory_days_off",
54
+ "total_vacation_hourly_usage",
55
+ "total_vacation_hourly_balance",
56
+ "balance_in_days",
57
+ "number_mandatory_days_off_in_days",
58
+ "total_vacation_hourly_usage_in_days",
59
+ "total_vacation_hourly_balance_in_days",
60
+ ]
61
+ extra = 0
62
+ ordering = ("-year",)
63
+ show_change_link = True
64
+
65
+ def _number_mandatory_days_off(self, obj):
66
+ return obj._number_mandatory_days_off
67
+
68
+ def _total_vacation_hourly_usage(self, obj):
69
+ return obj._total_vacation_hourly_usage
70
+
71
+ def _total_vacation_hourly_balance(self, obj):
72
+ return obj._total_vacation_hourly_balance
73
+
74
+ def _balance_in_days(self, obj):
75
+ return obj._balance_in_days
76
+
77
+ def _number_mandatory_days_off_in_days(self, obj):
78
+ return obj._number_mandatory_days_off_in_days
79
+
80
+ def _total_vacation_hourly_usage_in_days(self, obj):
81
+ return obj._total_vacation_hourly_usage_in_days
82
+
83
+ def _total_vacation_hourly_balance_in_days(self, obj):
84
+ return obj._total_vacation_hourly_balance_in_days
85
+
86
+
87
+ @admin.register(EmployeeHumanResource)
88
+ class EmployeeHumanResourceAdmin(admin.ModelAdmin):
89
+ fieldsets = (
90
+ (
91
+ "",
92
+ {
93
+ "fields": (
94
+ "profile",
95
+ "is_active",
96
+ "extra_days_frequency",
97
+ "occupancy_rate",
98
+ "contract_type",
99
+ "position",
100
+ "enrollment_at",
101
+ "calendar",
102
+ )
103
+ },
104
+ ),
105
+ )
106
+ raw_id_fields = ("profile",)
107
+ search_fields = ("profile__computed_str",)
108
+ list_display = ("profile", "contract_type", "position", "calendar")
109
+ inlines = (EmployeeYearBalanceInline, EmployeeWeeklyOffPeriodsInLine)
@@ -0,0 +1,21 @@
1
+ from django.contrib import admin
2
+
3
+ from ..models.kpi import KPI, Evaluation
4
+
5
+
6
+ @admin.register(Evaluation)
7
+ class KEvaluationAdmin(admin.ModelAdmin):
8
+ list_display = ["id", "person", "evaluated_score", "evaluation_date", "evaluated_period"]
9
+
10
+
11
+ class EvaluationInline(admin.TabularInline):
12
+ model = Evaluation
13
+ extra = 0
14
+ raw_id_fields = ["kpi", "person"]
15
+
16
+
17
+ @admin.register(KPI)
18
+ class KPIAdmin(admin.ModelAdmin):
19
+ list_display = ["name", "period", "goal"]
20
+ inlines = (EvaluationInline,)
21
+ raw_id_fields = ["evaluated_persons"]
@@ -0,0 +1,157 @@
1
+ from io import StringIO
2
+
3
+ import pandas as pd
4
+ from django.contrib import admin
5
+ from django.shortcuts import redirect, render
6
+ from django.utils.translation import gettext_lazy as _
7
+ from reversion.errors import RevertError
8
+ from wbcore.admin import CsvImportForm, ExportCsvMixin, ImportCsvMixin
9
+
10
+ from ..models.review import (
11
+ Review,
12
+ ReviewAnswer,
13
+ ReviewGroup,
14
+ ReviewQuestion,
15
+ ReviewQuestionCategory,
16
+ )
17
+
18
+
19
+ class CustomImportCsvMixin(ImportCsvMixin):
20
+ def _import_csv(self, request, _sep=";"):
21
+ if request.method == "POST":
22
+ csv_file = request.FILES["csv_file"]
23
+
24
+ str_text = ""
25
+ for line in csv_file:
26
+ str_text = str_text + line.decode()
27
+ # Import csv as df
28
+ df = pd.read_csv(StringIO(str_text), sep=_sep)
29
+ # Sanitize dataframe
30
+ df = df.where(pd.notnull(df), None)
31
+ df = df.drop(df.columns.difference(self.get_import_fields()), axis=1)
32
+
33
+ # Overide this function if there is foreign key ids in the dataframe
34
+ df = self.manipulate_df(df)
35
+ errors = 0
36
+ revert_errors = 0
37
+ nb_added = 0
38
+ for model in df.to_dict("records"):
39
+ # by default, process the modela as a create request. Can be override to change the behavior
40
+ try:
41
+ nb_added += self.process_model(model)
42
+ # https://django-reversion.readthedocs.io/en/stable/common-problems.html
43
+ except RevertError:
44
+ revert_errors += 1
45
+ except Exception as e:
46
+ print(e) # noqa: T201
47
+ errors += 1
48
+ self.message_user(
49
+ request,
50
+ _(
51
+ "Your CSV file has been imported : {} imported ({} added, {} updated), {} errors, {} revert errors found due to failure to restore old versions"
52
+ ).format(
53
+ df.shape[0] - errors - revert_errors,
54
+ nb_added,
55
+ df.shape[0] - errors - revert_errors - nb_added,
56
+ errors,
57
+ revert_errors,
58
+ ),
59
+ )
60
+ return redirect("..")
61
+ form = CsvImportForm()
62
+ payload = {"form": form}
63
+ return render(request, "wbcore/admin/csv_form.html", payload)
64
+
65
+
66
+ @admin.register(ReviewGroup)
67
+ class ReviewGroupAdmin(admin.ModelAdmin):
68
+ list_display = ["name"]
69
+
70
+
71
+ @admin.register(Review)
72
+ class ReviewAdmin(admin.ModelAdmin):
73
+ list_display = [
74
+ "id",
75
+ "year",
76
+ "type",
77
+ "from_date",
78
+ "to_date",
79
+ "review_deadline",
80
+ "review",
81
+ "auto_apply_deadline",
82
+ "status",
83
+ "reviewee",
84
+ "reviewer",
85
+ "moderator",
86
+ "review_group",
87
+ "is_template",
88
+ ]
89
+
90
+
91
+ @admin.register(ReviewQuestionCategory)
92
+ class ReviewQuestionCategoryAdmin(ExportCsvMixin, CustomImportCsvMixin, admin.ModelAdmin):
93
+ list_display = ["name", "order", "weight"]
94
+
95
+ def manipulate_df(self, df):
96
+ return df
97
+
98
+ def get_import_fields(self):
99
+ return ["name", "order", "weight"]
100
+
101
+ def process_model(self, model):
102
+ if category_name := model.get("name"):
103
+ _, created = self.model.objects.update_or_create(
104
+ name=category_name,
105
+ defaults={
106
+ "order": model.get("order"),
107
+ "weight": model.get("weight"),
108
+ },
109
+ )
110
+ return 1 if created else 0
111
+ return 0
112
+
113
+
114
+ @admin.register(ReviewQuestion)
115
+ class ReviewQuestion(ExportCsvMixin, CustomImportCsvMixin, admin.ModelAdmin):
116
+ list_display = [
117
+ "id",
118
+ "question",
119
+ "review",
120
+ "category",
121
+ "mandatory",
122
+ "answer_type",
123
+ "for_reviewee",
124
+ "for_reviewer",
125
+ "for_department_peers",
126
+ "for_company_peers",
127
+ "order",
128
+ "weight",
129
+ ]
130
+
131
+ def manipulate_df(self, df):
132
+ df["review"] = df["review_id"].apply(lambda x: Review.objects.get(id=x))
133
+ df["category"] = df["category_name"].apply(lambda x: ReviewQuestionCategory.objects.filter(name=x).first())
134
+ return df
135
+
136
+ def get_import_fields(self):
137
+ return ["review_id", "category_name", "answer_type", "order", "weight", "question"]
138
+
139
+ def process_model(self, model):
140
+ if review := model.get("review"):
141
+ _, created = self.model.objects.update_or_create(
142
+ review=review,
143
+ question=model.get("question"),
144
+ defaults={
145
+ "category": model.get("category"),
146
+ "answer_type": model.get("answer_type"),
147
+ "order": model.get("order"),
148
+ "weight": model.get("weight"),
149
+ },
150
+ )
151
+ return 1 if created else 0
152
+ return 0
153
+
154
+
155
+ @admin.register(ReviewAnswer)
156
+ class ReviewAnswerAdmin(admin.ModelAdmin):
157
+ list_display = ["question", "answered_by", "answer_number", "answered_anonymized"]
@@ -0,0 +1,23 @@
1
+ from django.apps import AppConfig, apps
2
+ from django.db.models.signals import post_migrate
3
+
4
+
5
+ class WbhumanResourcesConfig(AppConfig):
6
+ name = "wbhuman_resources"
7
+
8
+ def ready(self) -> None:
9
+ from wbcore.signals.filters import add_filters
10
+
11
+ from wbhuman_resources.management import initialize_task
12
+
13
+ from .filters.signals import add_position_filter
14
+
15
+ if apps.is_installed("wbcrm"):
16
+ from wbcrm.filters import ActivityFilter
17
+
18
+ add_filters.connect(add_position_filter, sender=ActivityFilter)
19
+
20
+ post_migrate.connect(
21
+ initialize_task,
22
+ dispatch_uid="wbhuman_resources.initialize_task",
23
+ )
@@ -0,0 +1,119 @@
1
+ from django.conf import settings
2
+ from django.forms import ValidationError
3
+ from django.utils.translation import gettext as _
4
+ from dynamic_preferences.preferences import Section
5
+ from dynamic_preferences.registries import global_preferences_registry
6
+ from dynamic_preferences.types import (
7
+ BooleanPreference,
8
+ IntegerPreference,
9
+ LongStringPreference,
10
+ ModelChoicePreference,
11
+ StringPreference,
12
+ )
13
+
14
+ from wbhuman_resources.models.calendars import DayOffCalendar
15
+
16
+ human_resources = Section("wbhuman_resources")
17
+
18
+ # Employee dynamic preferences
19
+
20
+
21
+ @global_preferences_registry.register
22
+ class EmployeeDefaultCalendarEntry(ModelChoicePreference):
23
+ section = human_resources
24
+ name = "employee_default_calendar"
25
+ queryset = DayOffCalendar.objects.all()
26
+ default = None
27
+
28
+
29
+ @global_preferences_registry.register
30
+ class DefaultVacationDaysPreference(IntegerPreference):
31
+ section = human_resources
32
+ name = "default_vacation_days"
33
+ default = 25
34
+
35
+ verbose_name = _("Default employee vacation days")
36
+ help_text = _("The number of vacation days allocated to an employee working full time")
37
+
38
+ def validate(self, value):
39
+ if not isinstance(value, int) or value <= 1:
40
+ raise ValidationError(_("Only positive natural numbers allowed."))
41
+
42
+
43
+ @global_preferences_registry.register
44
+ class DefaultFromEmailAddressPreference(StringPreference):
45
+ section = human_resources
46
+ name = "default_from_email_address"
47
+ default = settings.DEFAULT_FROM_EMAIL
48
+
49
+ verbose_name = "The default from email address"
50
+ help_text = "The default from email address used to send hr related emails"
51
+
52
+
53
+ @global_preferences_registry.register
54
+ class NumberOfMonthsBeforeBalanceExpiration(IntegerPreference):
55
+ section = human_resources
56
+ name = "number_of_month_before_balance_expiration"
57
+ default = 12 * 5 # Default to 5 years
58
+ verbose_name = _("The number of month before yearly balance expiration")
59
+ help_text = _(
60
+ "The number of months before any yearly balance is considered expired. The count starts the first day of the next balance year"
61
+ )
62
+
63
+
64
+ @global_preferences_registry.register
65
+ class LongVacationNumberOfDaysPreference(IntegerPreference):
66
+ section = human_resources
67
+ name = "long_vacation_number_of_days"
68
+ default = 10
69
+ help_text = _("The number of days after which a vacation is considered a long vacation.")
70
+ verbose_name = _("Long Vacation Number of days")
71
+
72
+
73
+ # Monthly report accounting preference
74
+
75
+
76
+ @global_preferences_registry.register
77
+ class AccountingCompanyEmails(LongStringPreference):
78
+ section = human_resources
79
+ name = "accounting_company_emails"
80
+ default = "no-reply@stainly-bench.com;"
81
+ verbose_name = _("Accounting email destination")
82
+ help_text = _("The accounting company emails to send automatic reports to, as a comma separated list")
83
+
84
+
85
+ # Calendar preferences
86
+
87
+
88
+ @global_preferences_registry.register
89
+ class CalendarDefaultPublicHolidayPackagePreference(StringPreference):
90
+ section = human_resources
91
+ name = "calendar_default_public_holiday_package"
92
+ default = "europe.Switzerland"
93
+
94
+ verbose_name = _("Default calendar Public holiday package")
95
+ help_text = _("Package where the correct public holidays are found. Defaults to Europe Switzerland")
96
+
97
+ def validate(self, value):
98
+ if len(value.split(".")) != 2:
99
+ raise ValidationError(_("The preference has to be in the format of <continent>.<region>"))
100
+
101
+
102
+ @global_preferences_registry.register
103
+ class CalendarDefaultTimezonePreference(StringPreference):
104
+ section = human_resources
105
+ name = "calendar_default_timezone"
106
+ default = "UTC"
107
+
108
+ verbose_name = _("Default calendar timezone")
109
+ help_text = _("The default calendar timezone")
110
+
111
+
112
+ @global_preferences_registry.register
113
+ class AreExternalEmployeesConsideredAsInternal(BooleanPreference):
114
+ section = human_resources
115
+ name = "is_external_considered_as_internal"
116
+ default = False
117
+
118
+ verbose_name = _("Are external employee considered as internal?")
119
+ help_text = _("If True, will consider the external employee (and any related logic) as internal employee")
@@ -0,0 +1,38 @@
1
+ from .absence import (
2
+ AbsenceRequestFactory,
3
+ AbsenceRequestPeriodsFactory,
4
+ AbsenceRequestTypeFactory,
5
+ TimeOffRequestFactory,
6
+ TimeOffTypeFactory,
7
+ VacationRequestFactory,
8
+ VacationTypeFactory,
9
+ )
10
+ from .calendars import (
11
+ BaseDayOffCalendarFactory,
12
+ DayOffCalendarFactory,
13
+ DayOffFactory,
14
+ DefaultDailyPeriodFactory,
15
+ )
16
+ from .employee import (
17
+ BalanceHourlyAllowanceFactory,
18
+ EmployeeHumanResourceFactory,
19
+ EmployeeWeeklyOffPeriodsFactory,
20
+ EmployeeYearBalanceFactory,
21
+ PositionFactory,
22
+ )
23
+ from .kpi import (
24
+ CompletedFilledReviewFactory,
25
+ DefaultPersonKPIFactory,
26
+ EvaluationFactory,
27
+ KPIFactory,
28
+ ReviewAbstractFactory,
29
+ ReviewAnswerFactory,
30
+ ReviewAnswerNoCategoryFactory,
31
+ ReviewFactory,
32
+ ReviewGroupFactory,
33
+ ReviewQuestionCategoryFactory,
34
+ ReviewQuestionFactory,
35
+ ReviewQuestionNoCategoryFactory,
36
+ ReviewTemplateFactory,
37
+ SignedReviewFactory,
38
+ )