wbhuman_resources 1.54.7__py2.py3-none-any.whl → 1.61.5__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 (43) hide show
  1. wbhuman_resources/factories/absence.py +1 -0
  2. wbhuman_resources/factories/calendars.py +1 -0
  3. wbhuman_resources/factories/employee.py +3 -0
  4. wbhuman_resources/factories/kpi.py +2 -0
  5. wbhuman_resources/filters/calendars.py +0 -1
  6. wbhuman_resources/locale/de/LC_MESSAGES/django.mo +0 -0
  7. wbhuman_resources/locale/de/LC_MESSAGES/django.po +252 -257
  8. wbhuman_resources/locale/en/LC_MESSAGES/django.po +248 -252
  9. wbhuman_resources/locale/fr/LC_MESSAGES/django.po +251 -256
  10. wbhuman_resources/migrations/0023_alter_employeehumanresource_weekly_off_periods.py +18 -0
  11. wbhuman_resources/migrations/0024_alter_absencerequestperiods_unique_together_and_more.py +49 -0
  12. wbhuman_resources/models/absence.py +19 -3
  13. wbhuman_resources/models/calendars.py +6 -6
  14. wbhuman_resources/models/employee.py +65 -18
  15. wbhuman_resources/models/kpi.py +17 -1
  16. wbhuman_resources/models/review.py +35 -26
  17. wbhuman_resources/permissions/backend.py +2 -4
  18. wbhuman_resources/serializers/__init__.py +1 -0
  19. wbhuman_resources/serializers/absence.py +5 -0
  20. wbhuman_resources/serializers/calendars.py +2 -1
  21. wbhuman_resources/serializers/employee.py +3 -3
  22. wbhuman_resources/signals.py +4 -0
  23. wbhuman_resources/tasks.py +37 -31
  24. wbhuman_resources/tests/test_permission.py +19 -15
  25. wbhuman_resources/utils.py +4 -1
  26. wbhuman_resources/viewsets/absence.py +18 -26
  27. wbhuman_resources/viewsets/absence_charts.py +4 -6
  28. wbhuman_resources/viewsets/buttons/kpis.py +3 -3
  29. wbhuman_resources/viewsets/buttons/review.py +3 -3
  30. wbhuman_resources/viewsets/display/calendars.py +2 -3
  31. wbhuman_resources/viewsets/display/kpis.py +1 -1
  32. wbhuman_resources/viewsets/display/review.py +5 -5
  33. wbhuman_resources/viewsets/endpoints/absence.py +4 -1
  34. wbhuman_resources/viewsets/kpi.py +2 -2
  35. wbhuman_resources/viewsets/menu/absence.py +11 -7
  36. wbhuman_resources/viewsets/menu/calendars.py +4 -5
  37. wbhuman_resources/viewsets/menu/employee.py +5 -6
  38. wbhuman_resources/viewsets/menu/kpis.py +2 -3
  39. wbhuman_resources/viewsets/menu/review.py +12 -13
  40. wbhuman_resources/viewsets/review.py +12 -14
  41. {wbhuman_resources-1.54.7.dist-info → wbhuman_resources-1.61.5.dist-info}/METADATA +2 -2
  42. {wbhuman_resources-1.54.7.dist-info → wbhuman_resources-1.61.5.dist-info}/RECORD +43 -40
  43. {wbhuman_resources-1.54.7.dist-info → wbhuman_resources-1.61.5.dist-info}/WHEEL +1 -1
@@ -11,16 +11,19 @@ from django.template.loader import get_template
11
11
  from django.utils.translation import gettext
12
12
  from django.utils.translation import gettext_lazy as _
13
13
  from dynamic_preferences.registries import global_preferences_registry
14
+ from wbcore.contrib.directory.models import Person
14
15
  from wbcore.contrib.notifications.dispatch import send_notification
15
16
  from wbcore.utils.date import current_month_date_end
16
17
  from wbcore.utils.html import convert_html2text
18
+ from wbcore.workers import Queue
17
19
 
18
20
  from wbhuman_resources.models import KPI, DayOffCalendar, EmployeeHumanResource, Review
19
21
 
20
22
  from .models.preferences import get_previous_year_balance_expiration_date
23
+ from .signals import add_employee_activity_to_daily_brief
21
24
 
22
25
 
23
- @shared_task
26
+ @shared_task(queue=Queue.BACKGROUND.value)
24
27
  def create_future_public_holiday(today: date | None = None, forecast_year: int = 5):
25
28
  if not today:
26
29
  today = date.today()
@@ -29,31 +32,7 @@ def create_future_public_holiday(today: date | None = None, forecast_year: int =
29
32
  calendar.create_public_holidays(year)
30
33
 
31
34
 
32
- @shared_task
33
- def daily_birthday(today=None):
34
- """
35
- Cron task supposed to be ran every day. Check and notify employee about a colleague's birthday.
36
- """
37
- day = "today"
38
- if not today:
39
- # Notify employee the day before
40
- today = datetime.today() + timedelta(days=1)
41
- day = "tomorrow"
42
- for birthday_employee in EmployeeHumanResource.active_internal_employees.filter(
43
- Q(profile__birthday__day=today.day) & Q(profile__birthday__month=today.month)
44
- ).all():
45
- for employee in EmployeeHumanResource.active_internal_employees.exclude(id=birthday_employee.id):
46
- send_notification(
47
- code="wbhuman_resources.employeehumanresource.birthday",
48
- title=_("{} {}'s birthday is {}!").format(
49
- birthday_employee.profile.first_name, birthday_employee.profile.last_name, day
50
- ),
51
- body=_("Wish her/him a happy birthday!"),
52
- user=employee.profile.user_account,
53
- )
54
-
55
-
56
- @shared_task
35
+ @shared_task(queue=Queue.BACKGROUND.value)
57
36
  def assign_balance(today=None):
58
37
  """
59
38
  Yearly periodic cron tasks that increase for an employee
@@ -68,7 +47,7 @@ def assign_balance(today=None):
68
47
  employee.assign_vacation_allowance_from_range(start_period.date(), end_period.date())
69
48
 
70
49
 
71
- @shared_task
50
+ @shared_task(queue=Queue.BACKGROUND.value)
72
51
  def check_and_warn_user_with_previous_year_available_balance(year=None):
73
52
  """
74
53
  When this task run, it will send a reminder Notification to user with still available balance for the previous year
@@ -91,7 +70,7 @@ def check_and_warn_user_with_previous_year_available_balance(year=None):
91
70
  )
92
71
 
93
72
 
94
- @shared_task
73
+ @shared_task(queue=Queue.BACKGROUND.value)
95
74
  def send_mail_to_accounting():
96
75
  global_preferences = global_preferences_registry.manager()
97
76
  accounting_company_emails = list(
@@ -133,7 +112,7 @@ def send_mail_to_accounting():
133
112
  msg.send()
134
113
 
135
114
 
136
- @shared_task
115
+ @shared_task(queue=Queue.BACKGROUND.value)
137
116
  def daily_automatic_application_deadline():
138
117
  for review in Review.objects.filter(
139
118
  Q(status=Review.Status.FILL_IN_REVIEW) & Q(review_deadline__lte=datetime.now().date())
@@ -172,8 +151,8 @@ def daily_automatic_application_deadline():
172
151
  )
173
152
 
174
153
 
175
- @shared_task
176
- def periodic_updating_kpi_task(kpi_id=[], start=None, end=None):
154
+ @shared_task(queue=Queue.BACKGROUND.value)
155
+ def periodic_updating_kpi_task(kpi_id: list | None = None, start=None, end=None):
177
156
  intervals = {elt.name: KPI.Interval.get_frequence_correspondance(elt.name) for elt in KPI.Interval}
178
157
  for key, value in intervals.items():
179
158
  kpis = (
@@ -188,3 +167,30 @@ def periodic_updating_kpi_task(kpi_id=[], start=None, end=None):
188
167
  end = kpi.period.upper
189
168
  for date_evaluation in pd.date_range(start=start, end=end, freq=value):
190
169
  kpi.generate_evaluation(date_evaluation.date())
170
+
171
+
172
+ @shared_task(queue=Queue.BACKGROUND.value)
173
+ def daily_brief(today: date | None = None, **kwargs):
174
+ """Creates a summary of the daily brief for all internal employees
175
+ Args:
176
+ today (date | None, optional): Date of today. Defaults to None.
177
+ """
178
+
179
+ if not today:
180
+ today = date.today()
181
+ for employee in EmployeeHumanResource.active_internal_employees.filter(profile__user_account__isnull=False):
182
+ daily_brief = ""
183
+ for receiver, res in add_employee_activity_to_daily_brief.send( # noqa: B007
184
+ sender=Person, instance=employee.profile, val_date=today, **kwargs
185
+ ):
186
+ if res:
187
+ title, html = res
188
+ daily_brief += f"<h2 text-align: center;>{title}</h2>\n<div style='margin-bottom: 1.5em; text-align: left;'>{html}</div>\n"
189
+
190
+ if daily_brief:
191
+ send_notification(
192
+ code="wbcrm.activity.daily_brief",
193
+ title=_("Your Daily Brief"),
194
+ body=daily_brief,
195
+ user=employee.profile.user_account,
196
+ )
@@ -1,15 +1,13 @@
1
1
  import pytest
2
- from django.contrib.auth import get_user_model
3
2
  from dynamic_preferences.registries import global_preferences_registry
4
3
  from faker import Faker
5
4
  from rest_framework.test import APIRequestFactory
6
5
  from wbcore.contrib.authentication.factories import UserFactory
7
- from wbcore.permissions.shortcuts import is_internal_user
6
+ from wbcore.contrib.permission.internal.registry import UserBackendRegistry
8
7
 
9
8
  from wbhuman_resources.factories.employee import EmployeeHumanResourceFactory
10
9
  from wbhuman_resources.models.employee import EmployeeHumanResource
11
10
 
12
- User = get_user_model()
13
11
  fake = Faker()
14
12
 
15
13
 
@@ -17,48 +15,54 @@ fake = Faker()
17
15
  class TestPermissionTasks:
18
16
  @pytest.fixture
19
17
  def request_user_external(self):
20
- request = APIRequestFactory()
21
18
  user = UserFactory()
22
19
  EmployeeHumanResourceFactory.create(
23
20
  profile=user.profile, contract_type=EmployeeHumanResource.ContractType.EXTERNAL
24
21
  )
22
+ UserBackendRegistry().refresh_users()
23
+
24
+ user.refresh_from_db()
25
+ request = APIRequestFactory()
25
26
  request.user = user
26
27
  return request
27
28
 
28
29
  @pytest.fixture
29
30
  def request_user_active_internal(self):
30
- request = APIRequestFactory()
31
31
  user = UserFactory()
32
32
  EmployeeHumanResourceFactory.create(
33
33
  profile=user.profile, contract_type=EmployeeHumanResource.ContractType.INTERNAL
34
34
  )
35
+ UserBackendRegistry().refresh_users()
36
+
37
+ user.refresh_from_db()
38
+ request = APIRequestFactory()
35
39
  request.user = user
36
40
  return request
37
41
 
38
42
  @pytest.fixture
39
43
  def request_user_inactive_internal(self):
40
- request = APIRequestFactory()
41
- user = UserFactory()
44
+ user = UserFactory.create()
42
45
  EmployeeHumanResourceFactory.create(
43
46
  profile=user.profile, contract_type=EmployeeHumanResource.ContractType.INTERNAL, is_active=False
44
47
  )
48
+ UserBackendRegistry().refresh_users()
49
+ user.refresh_from_db()
50
+ request = APIRequestFactory()
45
51
  request.user = user
46
52
  return request
47
53
 
48
54
  def test_permission_active_internal(self, request_user_active_internal):
49
- assert is_internal_user(request_user_active_internal.user) is True
55
+ assert request_user_active_internal.user.is_internal is True
50
56
 
51
57
  def test_permission_inactive_internal(self, request_user_inactive_internal):
52
- assert is_internal_user(request_user_inactive_internal.user) is False
58
+ assert request_user_inactive_internal.user.is_internal is False
53
59
 
54
60
  def test_permission_external(self, request_user_external):
55
- assert is_internal_user(request_user_external.user) is False
61
+ assert request_user_external.user.is_internal is False
56
62
 
57
63
  def test_permission_external_but_considered_internal(self, request_user_external):
58
- from wbcore.permissions.registry import user_registry
59
-
60
64
  user = request_user_external.user
61
65
  global_preferences_registry.manager()["wbhuman_resources__is_external_considered_as_internal"] = True
62
- user = User.objects.get(id=user.id) # reload to reset cached property
63
- user_registry.reset_cache()
64
- assert is_internal_user(user) is True
66
+ UserBackendRegistry().refresh_users()
67
+ user.refresh_from_db()
68
+ assert user.is_internal
@@ -6,8 +6,11 @@ from django.utils import timezone
6
6
 
7
7
 
8
8
  def get_number_of_hours_between_dates(
9
- d1, d2, list_employee_dayoffs, list_public_holidays=False, hours_range=range(0, 23), granularity=12
9
+ d1, d2, list_employee_dayoffs, list_public_holidays=False, hours_range=None, granularity=12
10
10
  ):
11
+ if hours_range is None:
12
+ hours_range = range(0, 23)
13
+
11
14
  def convert_days_from_hours(hours, granularity, hours_per_day):
12
15
  return int(hours / granularity) * granularity / hours_per_day
13
16
 
@@ -1,11 +1,10 @@
1
- import wbcore.serializers as wb_serializers
2
1
  from django.contrib.messages import info, warning
3
2
  from django.db.models import Case, CharField, F, Q, Sum, Value, When
4
3
  from django.db.models.functions import Concat, Extract
5
4
  from django.shortcuts import get_object_or_404
6
5
  from django.utils import timezone
7
6
  from django.utils.functional import cached_property
8
- from django.utils.translation import gettext as _
7
+ from django.utils.translation import gettext
9
8
  from rest_framework import filters
10
9
  from rest_framework.decorators import action
11
10
  from rest_framework.response import Response
@@ -33,6 +32,7 @@ from wbhuman_resources.serializers import (
33
32
  AbsenceRequestTypeModelSerializer,
34
33
  AbsenceRequestTypeRepresentationSerializer,
35
34
  EmployeeAbsenceDaysModelSerializer,
35
+ ReadOnlyAbsenceRequestModelSerializer,
36
36
  )
37
37
  from wbhuman_resources.viewsets.buttons import AbsenceRequestButtonConfig
38
38
  from wbhuman_resources.viewsets.display import (
@@ -55,12 +55,7 @@ from wbhuman_resources.viewsets.titles import (
55
55
  AbsenceTypeCountEmployeeTitleConfig,
56
56
  )
57
57
 
58
- from ..models.absence import can_validate_or_deny_request
59
- from ..serializers.absence import (
60
- CurrentUserDefaultPeriodDateTimeRange,
61
- get_lower_time_choices,
62
- get_upper_time_choices,
63
- )
58
+ from ..models.absence import can_edit_request, can_validate_or_deny_request
64
59
  from .mixins import EmployeeViewMixin
65
60
 
66
61
 
@@ -114,19 +109,16 @@ class AbsenceRequestModelViewSet(EmployeeViewMixin, viewsets.ModelViewSet):
114
109
  return can_validate_or_deny_request(obj, self.request.user)
115
110
  return False
116
111
 
117
- def get_serializer_class(self):
118
- if employee := getattr(self.request.user.profile, "human_resources", None):
119
-
120
- class Serializer(AbsenceRequestModelSerializer):
121
- period = wb_serializers.DateTimeRangeField(
122
- default_timezone=employee.calendar.timezone,
123
- default=CurrentUserDefaultPeriodDateTimeRange(),
124
- lower_time_choices=get_lower_time_choices,
125
- upper_time_choices=get_upper_time_choices,
126
- )
112
+ @cached_property
113
+ def can_edit_request(self) -> bool:
114
+ if "pk" in self.kwargs and (obj := self.get_object()):
115
+ return can_edit_request(obj, self.request.user)
116
+ return True
127
117
 
128
- return Serializer
129
- return AbsenceRequestModelSerializer
118
+ def get_serializer_class(self):
119
+ if self.can_edit_request:
120
+ return AbsenceRequestModelSerializer
121
+ return ReadOnlyAbsenceRequestModelSerializer
130
122
 
131
123
  def add_messages(
132
124
  self,
@@ -143,7 +135,7 @@ class AbsenceRequestModelViewSet(EmployeeViewMixin, viewsets.ModelViewSet):
143
135
  ).exclude(id=instance.id)
144
136
  activities_title = qs.values_list("title", flat=True)
145
137
  if len(activities_title) > 0:
146
- message = _("<p>During this absence, you already have these events:</p><ul>")
138
+ message = gettext("<p>During this absence, you already have these events:</p><ul>")
147
139
  for activity_title in activities_title:
148
140
  message += f"<li>{activity_title}</li>"
149
141
  message += "</ul>"
@@ -169,11 +161,11 @@ class AbsenceRequestModelViewSet(EmployeeViewMixin, viewsets.ModelViewSet):
169
161
  available_hourly_balance_in_days = (
170
162
  available_hourly_balance / instance.employee.calendar.get_daily_hours()
171
163
  )
172
- message = _(
164
+ message = gettext(
173
165
  "After this request, you will have {} days ({} hours) left for the balance {}</b>"
174
166
  ).format(available_hourly_balance_in_days, available_hourly_balance, current_balance.year)
175
167
  if other_pending_hours > 0:
176
- message += _(
168
+ message += gettext(
177
169
  " (not including <b>{pending_hours}</b> hours from other pending/draft absence requests)"
178
170
  ).format(pending_hours=other_pending_hours)
179
171
  if available_hourly_balance < 0:
@@ -185,7 +177,7 @@ class AbsenceRequestModelViewSet(EmployeeViewMixin, viewsets.ModelViewSet):
185
177
  )
186
178
  if day_offs:
187
179
  day_offs_messages = [
188
- _("{holiday} not counted ({title})").format(
180
+ gettext("{holiday} not counted ({title})").format(
189
181
  holiday=holiday.date.strftime("%d.%m.%Y"), title=holiday.title
190
182
  )
191
183
  for holiday in day_offs
@@ -236,7 +228,7 @@ class AbsenceRequestModelViewSet(EmployeeViewMixin, viewsets.ModelViewSet):
236
228
  def increaseday(self, request, pk=None):
237
229
  absence_request = get_object_or_404(AbsenceRequest, id=pk)
238
230
  if absence_request.type.is_extensible and (number_days := int(request.POST.get("number_days", 1))):
239
- for i in range(number_days):
231
+ for _ in range(number_days):
240
232
  if next_extensible_period := absence_request.next_extensible_period:
241
233
  absence_request.period = next_extensible_period
242
234
  absence_request.save()
@@ -254,7 +246,7 @@ class AbsenceRequestTypeModelViewSet(viewsets.ModelViewSet):
254
246
 
255
247
 
256
248
  class AbsenceTypeCountEmployeeModelViewSet(viewsets.ModelViewSet):
257
- READ_ONLY = True
249
+ ONLY_READ_ONLY_ENDPOINT = True
258
250
  queryset = AbsenceRequestPeriods.objects.all()
259
251
  serializer_class = EmployeeAbsenceDaysModelSerializer
260
252
 
@@ -10,8 +10,8 @@ from django.utils import timezone
10
10
  from django.utils.dateparse import parse_date
11
11
  from django.utils.translation import gettext as _
12
12
  from wbcore import viewsets
13
- from wbcore.pandas import fields as pf
14
- from wbcore.pandas.views import PandasAPIViewSet
13
+ from wbcore.contrib.pandas import fields as pf
14
+ from wbcore.contrib.pandas.views import PandasAPIViewSet
15
15
  from wbcore.utils.date import get_date_interval_from_request
16
16
 
17
17
  from wbhuman_resources.filters import AbsenceRequestPlannerFilter, AbsenceTableFilter
@@ -104,8 +104,7 @@ def update_layoute(fig, start, end):
104
104
  )
105
105
  ],
106
106
  yaxis=dict(
107
- title="",
108
- titlefont=dict(color="#000000"),
107
+ title=dict(text="", font=dict(color="#000000")),
109
108
  tickfont=dict(size=11, family="Courier", color="#000000"),
110
109
  anchor="x",
111
110
  side="left",
@@ -120,8 +119,7 @@ def update_layoute(fig, start, end):
120
119
  spikethickness=1,
121
120
  ),
122
121
  xaxis=dict(
123
- title="",
124
- titlefont=dict(color="#000000"),
122
+ title=dict(text="", font=dict(color="#000000")),
125
123
  tickfont=dict(color="#000000"),
126
124
  showline=False,
127
125
  linewidth=0.5,
@@ -5,12 +5,12 @@ from wbcore.metadata.configs import buttons as bt
5
5
 
6
6
  class KPIButtonConfig(bt.ButtonViewConfig):
7
7
  def get_custom_instance_buttons(self):
8
- BUTTONS = []
8
+ buttons = []
9
9
  if self.view.kwargs.get("pk", None):
10
- BUTTONS += [
10
+ buttons += [
11
11
  bt.WidgetButton(
12
12
  key="evaluationgraph", label=_("Evaluation Graph"), icon=WBIcon.CHART_BARS_HORIZONTAL.icon
13
13
  ),
14
14
  bt.WidgetButton(key="kpievaluationpandas", label=_("Latest Evaluations"), icon=WBIcon.DATA_GRID.icon),
15
15
  ]
16
- return {*BUTTONS}
16
+ return {*buttons}
@@ -32,7 +32,7 @@ class ReviewButtonConfig(bt.ButtonViewConfig):
32
32
  return self.get_custom_instance_buttons()
33
33
 
34
34
  def get_custom_instance_buttons(self):
35
- BUTTONS = [
35
+ buttons = [
36
36
  bt.WidgetButton(key="progress", label=_("Progress"), icon=WBIcon.CHART_BARS_HORIZONTAL.icon),
37
37
  bt.ActionButton(
38
38
  method=RequestType.PATCH,
@@ -132,7 +132,7 @@ class ReviewButtonConfig(bt.ButtonViewConfig):
132
132
  "include_kpi",
133
133
  )
134
134
 
135
- BUTTONS.append(
135
+ buttons.append(
136
136
  bt.ActionButton(
137
137
  method=RequestType.PATCH,
138
138
  identifiers=("wbhuman_resources:review",),
@@ -158,7 +158,7 @@ class ReviewButtonConfig(bt.ButtonViewConfig):
158
158
  ),
159
159
  )
160
160
  )
161
- return {*BUTTONS}
161
+ return {*buttons}
162
162
 
163
163
 
164
164
  class ReviewGroupButtonConfig(bt.ButtonViewConfig):
@@ -73,12 +73,11 @@ class DefaultDailyPeriodDayOffCalendarDisplayConfig(DisplayViewConfig):
73
73
  def get_list_display(self):
74
74
  return dp.ListDisplay(
75
75
  fields=[
76
- dp.Field(key="lower_time", label=_("Start")),
77
- dp.Field(key="upper_time", label=_("End")),
76
+ dp.Field(key="timespan", label=_("Time Range")),
78
77
  dp.Field(key="title", label=_("Title")),
79
78
  dp.Field(key="total_hours", label=_("Total Hours")),
80
79
  ]
81
80
  )
82
81
 
83
82
  def get_instance_display(self) -> Display:
84
- return create_simple_display([["lower_time", "upper_time", "title", "total_hours"]])
83
+ return create_simple_display([["title", "title"], ["timespan", "total_hours"]])
@@ -42,7 +42,7 @@ class KPIDisplayConfig(DisplayViewConfig):
42
42
  create_simple_section("parameters_section", _("Parameters"), handler.get_display_grid()),
43
43
  create_simple_section("evaluation_section", _("Evaluations"), [["evaluations"]], "evaluations"),
44
44
  ]
45
- grid_fields.extend(["parameters_section", "evaluation_section"])
45
+ grid_fields.extend([["parameters_section", "evaluation_section"]])
46
46
  return create_simple_display(grid_fields, sections)
47
47
 
48
48
 
@@ -303,24 +303,24 @@ class ReviewQuestionReviewDisplayConfig(ReviewQuestionDisplayConfig):
303
303
 
304
304
  class ReviewAnswerDisplayConfig(DisplayViewConfig):
305
305
  def get_list_display(self) -> Optional[dp.ListDisplay]:
306
- FIELDS = [
306
+ fields = [
307
307
  dp.Field(key="question_name", label=_("Question"), width=Unit.PIXEL(720)),
308
308
  dp.Field(key="mandatory", label=_("Mandatory"), width=Unit.PIXEL(80)),
309
309
  ]
310
310
  if self.view.get_queryset().filter(question__answer_type=ReviewQuestion.ANSWERTYPE.RATING):
311
- FIELDS += [dp.Field(key="answer_number", label=_("Rating"), width=Unit.PIXEL(170))]
311
+ fields += [dp.Field(key="answer_number", label=_("Rating"), width=Unit.PIXEL(170))]
312
312
 
313
- FIELDS += [dp.Field(key="answer_text", label=_("Comment"), width=Unit.PIXEL(720))]
313
+ fields += [dp.Field(key="answer_text", label=_("Comment"), width=Unit.PIXEL(720))]
314
314
 
315
315
  if review_id := self.view.kwargs.get("review_id"):
316
316
  review = Review.objects.get(id=review_id)
317
317
  if review.status in [Review.Status.EVALUATION, Review.Status.VALIDATION]:
318
- FIELDS = [
318
+ fields = [
319
319
  dp.Field(key="question_name", label=_("Question"), width=Unit.PIXEL(740)),
320
320
  dp.Field(key="answered_by", label=_("Answered By"), width=Unit.PIXEL(140)),
321
321
  dp.Field(key="answer_text", label=_("Comment"), width=Unit.PIXEL(740)),
322
322
  ]
323
- return dp.ListDisplay(fields=FIELDS)
323
+ return dp.ListDisplay(fields=fields)
324
324
 
325
325
  def get_instance_display(self) -> Display:
326
326
  grid_fields = [[repeat_field(2, "question_name")], ["mandatory", "."]]
@@ -2,6 +2,7 @@ from rest_framework.reverse import reverse
2
2
  from wbcore.metadata.configs.endpoints import EndpointViewConfig
3
3
 
4
4
  from wbhuman_resources.models import AbsenceRequest, EmployeeHumanResource
5
+ from wbhuman_resources.models.absence import get_valid_employee_human_resource
5
6
 
6
7
 
7
8
  class AbsenceRequestEndpointConfig(EndpointViewConfig):
@@ -18,7 +19,9 @@ class AbsenceRequestEndpointConfig(EndpointViewConfig):
18
19
  return self.get_endpoint()
19
20
 
20
21
  def get_create_endpoint(self, **kwargs):
21
- return self.get_endpoint()
22
+ if get_valid_employee_human_resource(self.request.user) is not None:
23
+ return self.get_endpoint()
24
+ return None
22
25
 
23
26
  def get_delete_endpoint(self, **kwargs):
24
27
  if self.instance:
@@ -9,9 +9,9 @@ from django.utils.translation import gettext
9
9
  from django.utils.translation import gettext_lazy as _
10
10
  from rest_framework import filters
11
11
  from wbcore import viewsets
12
+ from wbcore.contrib.pandas import fields as pf
13
+ from wbcore.contrib.pandas.views import PandasAPIViewSet
12
14
  from wbcore.filters import DjangoFilterBackend
13
- from wbcore.pandas import fields as pf
14
- from wbcore.pandas.views import PandasAPIViewSet
15
15
  from wbcore.serializers.serializers import ModelSerializer
16
16
  from wbcore.utils.strings import format_number
17
17
 
@@ -1,12 +1,13 @@
1
1
  from django.utils.translation import gettext as _
2
2
  from wbcore.menus import ItemPermission, MenuItem
3
- from wbcore.permissions.shortcuts import is_internal_user
3
+
4
+ from wbhuman_resources.models.absence import get_valid_employee_human_resource
4
5
 
5
6
  ABSENCEPLANNER_MENUITEM = MenuItem(
6
7
  label=_("Absence Graph"),
7
8
  endpoint="wbhuman_resources:absenceplanner-list",
8
9
  permission=ItemPermission(
9
- method=lambda request: is_internal_user(request.user), permissions=["wbhuman_resources.view_absencerequest"]
10
+ method=lambda request: request.user.is_internal, permissions=["wbhuman_resources.view_absencerequest"]
10
11
  ),
11
12
  )
12
13
 
@@ -14,7 +15,7 @@ ABSENCETABLE_MENUITEM = MenuItem(
14
15
  label=_("Presence Table"),
15
16
  endpoint="wbhuman_resources:absencetable-list",
16
17
  permission=ItemPermission(
17
- method=lambda request: is_internal_user(request.user), permissions=["wbhuman_resources.view_absencerequest"]
18
+ method=lambda request: request.user.is_internal, permissions=["wbhuman_resources.view_absencerequest"]
18
19
  ),
19
20
  )
20
21
 
@@ -22,13 +23,16 @@ ABSENCEREQUEST_MENUITEM = MenuItem(
22
23
  label=_("Requests"),
23
24
  endpoint="wbhuman_resources:absencerequest-list",
24
25
  permission=ItemPermission(
25
- method=lambda request: is_internal_user(request.user), permissions=["wbhuman_resources.view_absencerequest"]
26
+ method=lambda request: request.user.is_internal, permissions=["wbhuman_resources.view_absencerequest"]
26
27
  ),
27
28
  add=MenuItem(
28
29
  label=_("Add Requests"),
29
30
  endpoint="wbhuman_resources:absencerequest-list",
30
31
  permission=ItemPermission(
31
- method=lambda request: is_internal_user(request.user), permissions=["wbhuman_resources.add_absencerequest"]
32
+ method=lambda request: request.user.is_internal
33
+ and get_valid_employee_human_resource(request.user) is not None,
34
+ permissions=["wbhuman_resources.add_absencerequest"],
35
+ include_superuser=False,
32
36
  ),
33
37
  ),
34
38
  )
@@ -37,13 +41,13 @@ ABSENCEREQUESTTYPE_MENUITEM = MenuItem(
37
41
  label=_("Request Types"),
38
42
  endpoint="wbhuman_resources:absencerequesttype-list",
39
43
  permission=ItemPermission(
40
- method=lambda request: is_internal_user(request.user), permissions=["wbhuman_resources.view_absencerequesttpe"]
44
+ method=lambda request: request.user.is_internal, permissions=["wbhuman_resources.view_absencerequesttpe"]
41
45
  ),
42
46
  add=MenuItem(
43
47
  label=_("Add Request Types"),
44
48
  endpoint="wbhuman_resources:absencerequesttype-list",
45
49
  permission=ItemPermission(
46
- method=lambda request: is_internal_user(request.user),
50
+ method=lambda request: request.user.is_internal,
47
51
  permissions=["wbhuman_resources.add_absencerequesttype"],
48
52
  ),
49
53
  ),
@@ -1,18 +1,17 @@
1
1
  from django.utils.translation import gettext as _
2
2
  from wbcore.menus import ItemPermission, MenuItem
3
- from wbcore.permissions.shortcuts import is_internal_user
4
3
 
5
4
  DAYOFF_MENUITEM = MenuItem(
6
5
  label=_("Days Off"),
7
6
  endpoint="wbhuman_resources:dayoff-list",
8
7
  permission=ItemPermission(
9
- method=lambda request: is_internal_user(request.user), permissions=["wbhuman_resources.view_dayoff"]
8
+ method=lambda request: request.user.is_internal, permissions=["wbhuman_resources.view_dayoff"]
10
9
  ),
11
10
  add=MenuItem(
12
11
  label=_("Add Day Off"),
13
12
  endpoint="wbhuman_resources:dayoff-list",
14
13
  permission=ItemPermission(
15
- method=lambda request: is_internal_user(request.user), permissions=["wbhuman_resources.add_dayoff"]
14
+ method=lambda request: request.user.is_internal, permissions=["wbhuman_resources.add_dayoff"]
16
15
  ),
17
16
  ),
18
17
  )
@@ -21,13 +20,13 @@ DAYOFFCALENDAR_MENUITEM = MenuItem(
21
20
  label=_("Calendars"),
22
21
  endpoint="wbhuman_resources:dayoffcalendar-list",
23
22
  permission=ItemPermission(
24
- method=lambda request: is_internal_user(request.user), permissions=["wbhuman_resources.view_dayoffcalendar"]
23
+ method=lambda request: request.user.is_internal, permissions=["wbhuman_resources.view_dayoffcalendar"]
25
24
  ),
26
25
  add=MenuItem(
27
26
  label=_("Add Calendar"),
28
27
  endpoint="wbhuman_resources:dayoffcalendar-list",
29
28
  permission=ItemPermission(
30
- method=lambda request: is_internal_user(request.user), permissions=["wbhuman_resources.add_dayoffcalendar"]
29
+ method=lambda request: request.user.is_internal, permissions=["wbhuman_resources.add_dayoffcalendar"]
31
30
  ),
32
31
  ),
33
32
  )
@@ -1,12 +1,11 @@
1
1
  from django.utils.translation import gettext as _
2
2
  from wbcore.menus import ItemPermission, MenuItem
3
- from wbcore.permissions.shortcuts import is_internal_user
4
3
 
5
4
  EMPLOYEEHUMANRESOURCE_MENUITEM = MenuItem(
6
5
  label=_("Balance & Usage"),
7
6
  endpoint="wbhuman_resources:employeebalance-list",
8
7
  permission=ItemPermission(
9
- method=lambda request: is_internal_user(request.user),
8
+ method=lambda request: request.user.is_internal,
10
9
  permissions=["wbhuman_resources.view_employeehumanresource"],
11
10
  ),
12
11
  )
@@ -15,14 +14,14 @@ EMPLOYEE_MENUITEM = MenuItem(
15
14
  label=_("Employees"),
16
15
  endpoint="wbhuman_resources:employee-list",
17
16
  permission=ItemPermission(
18
- method=lambda request: is_internal_user(request.user),
17
+ method=lambda request: request.user.is_internal,
19
18
  permissions=["wbhuman_resources.view_employeehumanresource"],
20
19
  ),
21
20
  add=MenuItem(
22
21
  label=_("Add Employee"),
23
22
  endpoint="wbhuman_resources:employee-list",
24
23
  permission=ItemPermission(
25
- method=lambda request: is_internal_user(request.user),
24
+ method=lambda request: request.user.is_internal,
26
25
  permissions=["wbhuman_resources.add_employeehumanresource"],
27
26
  ),
28
27
  ),
@@ -32,13 +31,13 @@ POSITION_MENUITEM = MenuItem(
32
31
  label=_("Positions"),
33
32
  endpoint="wbhuman_resources:position-list",
34
33
  permission=ItemPermission(
35
- method=lambda request: is_internal_user(request.user), permissions=["wbhuman_resources.view_position"]
34
+ method=lambda request: request.user.is_internal, permissions=["wbhuman_resources.view_position"]
36
35
  ),
37
36
  add=MenuItem(
38
37
  label=_("Add Position"),
39
38
  endpoint="wbhuman_resources:position-list",
40
39
  permission=ItemPermission(
41
- method=lambda request: is_internal_user(request.user), permissions=["wbhuman_resources.add_position"]
40
+ method=lambda request: request.user.is_internal, permissions=["wbhuman_resources.add_position"]
42
41
  ),
43
42
  ),
44
43
  )