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,949 @@
1
+ # Generated by Django 4.1.8 on 2023-04-17 11:31
2
+ import colorfield.fields
3
+ import django.contrib.postgres.constraints
4
+ import django.contrib.postgres.fields.ranges
5
+ import django.core.validators
6
+ import django.db.models.deletion
7
+ import django_fsm
8
+ import mptt.fields
9
+ import timezone_field.fields
10
+ import wbcore.contrib.color.fields
11
+ import wbcore.contrib.icons.models
12
+ import wbhuman_resources.models.kpi
13
+ from django.contrib.postgres.operations import BtreeGistExtension
14
+ from django.db import migrations, models
15
+
16
+
17
+ class Migration(migrations.Migration):
18
+ initial = True
19
+
20
+ dependencies = [
21
+ ("auth", "0012_alter_user_first_name_max_length"),
22
+ ("agenda", "0003_calendaritem_endpoint_basename"),
23
+ ("directory", "0002_auto_20230414_1553"),
24
+ ]
25
+
26
+ operations = [
27
+ BtreeGistExtension(),
28
+ migrations.CreateModel(
29
+ name="AbsenceRequest",
30
+ fields=[
31
+ (
32
+ "calendaritem_ptr",
33
+ models.OneToOneField(
34
+ auto_created=True,
35
+ on_delete=django.db.models.deletion.CASCADE,
36
+ parent_link=True,
37
+ primary_key=True,
38
+ serialize=False,
39
+ to="agenda.calendaritem",
40
+ ),
41
+ ),
42
+ (
43
+ "status",
44
+ django_fsm.FSMField(
45
+ choices=[
46
+ ("DRAFT", "Draft"),
47
+ ("PENDING", "Pending"),
48
+ ("APPROVED", "Approved"),
49
+ ("DENIED", "Denied"),
50
+ ("CANCELLED", "Cancelled"),
51
+ ],
52
+ default="DRAFT",
53
+ help_text="The request status (defaults to draft)",
54
+ max_length=50,
55
+ verbose_name="Status",
56
+ ),
57
+ ),
58
+ (
59
+ "notes",
60
+ models.TextField(
61
+ blank=True, help_text="A note to the HR administrator", null=True, verbose_name="Extra Notes"
62
+ ),
63
+ ),
64
+ (
65
+ "reason",
66
+ models.TextField(
67
+ blank=True,
68
+ help_text="The HR's response to this absence request",
69
+ null=True,
70
+ verbose_name="Reason",
71
+ ),
72
+ ),
73
+ (
74
+ "created",
75
+ models.DateTimeField(
76
+ auto_now_add=True, help_text="The request creation time", verbose_name="Created"
77
+ ),
78
+ ),
79
+ (
80
+ "attachment",
81
+ models.FileField(
82
+ blank=True,
83
+ help_text="Upload a file to document this absence request (e.g. medical certificate)",
84
+ max_length=256,
85
+ null=True,
86
+ upload_to="human_resources/absence_request/attachments",
87
+ verbose_name="Attachment",
88
+ ),
89
+ ),
90
+ ],
91
+ options={
92
+ "verbose_name": "Absence Request",
93
+ "verbose_name_plural": "Absence Requests",
94
+ "permissions": [("administrate_absencerequest", "Can administer Absence Requests")],
95
+ },
96
+ bases=("agenda.calendaritem",),
97
+ ),
98
+ migrations.CreateModel(
99
+ name="AbsenceRequestType",
100
+ fields=[
101
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
102
+ ("color", wbcore.contrib.color.fields.ColorField(default="#000000", verbose_name="Color")),
103
+ ("icon", wbcore.contrib.icons.models.IconField(default="EVENT", max_length=128, verbose_name="Icon")),
104
+ ("title", models.CharField(max_length=255, verbose_name="Title")),
105
+ (
106
+ "is_vacation",
107
+ models.BooleanField(
108
+ default=False,
109
+ help_text="If true, the days will be counted towards the employee's vacation balance",
110
+ verbose_name="Vacation",
111
+ ),
112
+ ),
113
+ (
114
+ "is_timeoff",
115
+ models.BooleanField(
116
+ default=False,
117
+ help_text="If true, the employee is considered as not working",
118
+ verbose_name="Time-Off",
119
+ ),
120
+ ),
121
+ (
122
+ "is_extensible",
123
+ models.BooleanField(
124
+ default=False,
125
+ help_text="If true, allow the associated request to be extended",
126
+ verbose_name="Extensible",
127
+ ),
128
+ ),
129
+ ("auto_approve", models.BooleanField(default=False, verbose_name="Auto Approve")),
130
+ ("days_in_advance", models.PositiveIntegerField(default=0, verbose_name="Days In Advance")),
131
+ ],
132
+ options={
133
+ "verbose_name": "Absence Request Type",
134
+ "verbose_name_plural": "Absence Request Types",
135
+ },
136
+ ),
137
+ migrations.CreateModel(
138
+ name="DayOffCalendar",
139
+ fields=[
140
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
141
+ ("title", models.CharField(max_length=255)),
142
+ (
143
+ "resource",
144
+ models.CharField(
145
+ blank=True, help_text="Used to fetch the days off from an API.", max_length=255, null=True
146
+ ),
147
+ ),
148
+ ("timezone", timezone_field.fields.TimeZoneField(default="UTC")),
149
+ ],
150
+ options={
151
+ "verbose_name": "Day Off Calendar",
152
+ "verbose_name_plural": "Days Off Calendar",
153
+ "unique_together": {("resource", "timezone")},
154
+ },
155
+ ),
156
+ migrations.CreateModel(
157
+ name="DefaultDailyPeriod",
158
+ fields=[
159
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
160
+ ("lower_time", models.TimeField()),
161
+ ("upper_time", models.TimeField()),
162
+ ("timespan", django.contrib.postgres.fields.ranges.DateTimeRangeField()),
163
+ ("title", models.CharField(max_length=128)),
164
+ ("total_hours", models.FloatField()),
165
+ (
166
+ "calendar",
167
+ models.ForeignKey(
168
+ on_delete=django.db.models.deletion.PROTECT,
169
+ related_name="default_periods",
170
+ to="wbhuman_resources.dayoffcalendar",
171
+ verbose_name="Calendar",
172
+ ),
173
+ ),
174
+ ],
175
+ options={
176
+ "verbose_name": "Default Daily Period",
177
+ "verbose_name_plural": "Default Daily Periods",
178
+ },
179
+ ),
180
+ migrations.CreateModel(
181
+ name="EmployeeHumanResource",
182
+ fields=[
183
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
184
+ ("computed_str", models.CharField(blank=True, max_length=512, null=True, verbose_name="Name")),
185
+ (
186
+ "is_active",
187
+ models.BooleanField(
188
+ default=True,
189
+ help_text="If false, the employee will be considered as not active but his absence requests will be preserved",
190
+ verbose_name="Is active",
191
+ ),
192
+ ),
193
+ (
194
+ "extra_days_frequency",
195
+ models.CharField(
196
+ choices=[("MONTHLY", "Monthly"), ("YEARLY", "Yearly")],
197
+ default="YEARLY",
198
+ help_text="The frequency at which an additional number of vacation days is enabled for this employee (defaults to yearly)",
199
+ max_length=16,
200
+ verbose_name="Extra Days Frequency",
201
+ ),
202
+ ),
203
+ (
204
+ "occupancy_rate",
205
+ models.FloatField(
206
+ default=1,
207
+ help_text="The occupation rate in percent, 100% being employed fulltime",
208
+ verbose_name="Occupation Rate",
209
+ ),
210
+ ),
211
+ (
212
+ "contract_type",
213
+ models.CharField(
214
+ choices=[("INTERNAL", "Internal"), ("EXTERNAL", "External")],
215
+ default="INTERNAL",
216
+ help_text="If Internal, the employee is considered a full-time employee and thus has employee access to the system.",
217
+ max_length=16,
218
+ verbose_name="Employee Type",
219
+ ),
220
+ ),
221
+ ("enrollment_at", models.DateField(verbose_name="Enrolled at")),
222
+ ("disenrollment_at", models.DateField(blank=True, null=True, verbose_name="Disenroll at")),
223
+ (
224
+ "calendar",
225
+ models.ForeignKey(
226
+ on_delete=django.db.models.deletion.PROTECT,
227
+ related_name="employees",
228
+ to="wbhuman_resources.dayoffcalendar",
229
+ ),
230
+ ),
231
+ (
232
+ "direct_manager",
233
+ models.ForeignKey(
234
+ blank=True,
235
+ null=True,
236
+ on_delete=django.db.models.deletion.SET_NULL,
237
+ related_name="managed_employees",
238
+ to="directory.person",
239
+ verbose_name="Direct Manager",
240
+ ),
241
+ ),
242
+ ],
243
+ options={
244
+ "verbose_name": "Employee Human Resource",
245
+ "verbose_name_plural": "Employee Human Resources",
246
+ },
247
+ ),
248
+ migrations.CreateModel(
249
+ name="Evaluation",
250
+ fields=[
251
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
252
+ ("evaluated_score", models.IntegerField(blank=True, null=True)),
253
+ ("evaluated_period", django.contrib.postgres.fields.ranges.DateRangeField()),
254
+ ("evaluation_date", models.DateField()),
255
+ (
256
+ "last_update",
257
+ models.DateTimeField(
258
+ auto_now=True,
259
+ help_text="Date of latest change (automatically computed)",
260
+ verbose_name="Last update",
261
+ ),
262
+ ),
263
+ ],
264
+ options={
265
+ "verbose_name": "Evaluation",
266
+ "verbose_name_plural": "Evaluations",
267
+ },
268
+ ),
269
+ migrations.CreateModel(
270
+ name="Review",
271
+ fields=[
272
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
273
+ ("computed_str", models.CharField(blank=True, max_length=512, null=True, verbose_name="Name")),
274
+ ("from_date", models.DateField(blank=True, null=True, verbose_name="From")),
275
+ ("to_date", models.DateField(blank=True, null=True, verbose_name="To")),
276
+ ("review_deadline", models.DateField(blank=True, null=True, verbose_name="Deadline")),
277
+ ("review", models.DateTimeField(blank=True, null=True, verbose_name="Review Date")),
278
+ ("auto_apply_deadline", models.BooleanField(default=True, verbose_name="Auto Apply Deadline")),
279
+ (
280
+ "year",
281
+ models.IntegerField(
282
+ blank=True,
283
+ null=True,
284
+ validators=[
285
+ django.core.validators.MinValueValidator(1000),
286
+ django.core.validators.MaxValueValidator(9999),
287
+ ],
288
+ verbose_name="Year",
289
+ ),
290
+ ),
291
+ (
292
+ "type",
293
+ models.CharField(
294
+ choices=[("ANNUAL", "Annual"), ("INTERMEDIARY", "Intermediary")],
295
+ default="ANNUAL",
296
+ max_length=32,
297
+ verbose_name="Type",
298
+ ),
299
+ ),
300
+ (
301
+ "status",
302
+ django_fsm.FSMField(
303
+ choices=[
304
+ ("PREPARATION_OF_REVIEW", "Stage 1: Preparation of review"),
305
+ ("FILL_IN_REVIEW", "Stage 2: Fill in review"),
306
+ ("REVIEW", "Stage 3: Review"),
307
+ ("EVALUATION", "Stage 4: Evalutation"),
308
+ ("VALIDATION", "Stage 5: Validation"),
309
+ ],
310
+ default="PREPARATION_OF_REVIEW",
311
+ help_text="Indicates one of the four stages defined by the workflow",
312
+ max_length=50,
313
+ verbose_name="Status",
314
+ ),
315
+ ),
316
+ ("is_template", models.BooleanField(default=False)),
317
+ ("feedback_reviewee", models.TextField(blank=True, default="", verbose_name="Feedback Reviewee")),
318
+ ("feedback_reviewer", models.TextField(blank=True, default="", verbose_name="Feedback Reviewer")),
319
+ ("editable_mode", models.BooleanField(default=True, verbose_name="Editable table mode")),
320
+ (
321
+ "signed_reviewee",
322
+ models.DateTimeField(blank=True, null=True, verbose_name="Date of reviewee's signature"),
323
+ ),
324
+ (
325
+ "signed_reviewer",
326
+ models.DateTimeField(blank=True, null=True, verbose_name="Date of reviewer's signature"),
327
+ ),
328
+ (
329
+ "completely_filled_reviewee",
330
+ models.DateTimeField(blank=True, null=True, verbose_name="Completely Filled Out Reviewee"),
331
+ ),
332
+ (
333
+ "completely_filled_reviewer",
334
+ models.DateTimeField(blank=True, null=True, verbose_name="Completely Filled Out Reviewer"),
335
+ ),
336
+ ("changed", models.DateTimeField(auto_now=True, null=True)),
337
+ (
338
+ "moderator",
339
+ models.ForeignKey(
340
+ blank=True,
341
+ null=True,
342
+ on_delete=django.db.models.deletion.SET_NULL,
343
+ related_name="moderator_reviews",
344
+ to="directory.person",
345
+ ),
346
+ ),
347
+ ],
348
+ options={
349
+ "verbose_name": "Review",
350
+ "verbose_name_plural": "Reviews",
351
+ "permissions": [
352
+ ("admin_review", "Can administer Reviews"),
353
+ ("global_review_readers", "Can view and read Review"),
354
+ ],
355
+ },
356
+ ),
357
+ migrations.CreateModel(
358
+ name="ReviewQuestionCategory",
359
+ fields=[
360
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
361
+ ("name", models.CharField(max_length=255, unique=True, verbose_name="Name")),
362
+ ("order", models.PositiveIntegerField(blank=True, null=True, verbose_name="Order")),
363
+ ("weight", models.DecimalField(decimal_places=1, default=1.0, max_digits=16, verbose_name="Weight")),
364
+ ],
365
+ options={
366
+ "verbose_name": "Review Question Category",
367
+ "verbose_name_plural": "Review Question Categories",
368
+ },
369
+ ),
370
+ migrations.CreateModel(
371
+ name="ReviewQuestion",
372
+ fields=[
373
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
374
+ ("computed_str", models.CharField(blank=True, max_length=512, null=True, verbose_name="Name")),
375
+ ("question", models.TextField(blank=True, default="", verbose_name="Question")),
376
+ ("mandatory", models.BooleanField(default=True, verbose_name="Mandatory")),
377
+ (
378
+ "answer_type",
379
+ models.CharField(
380
+ choices=[("TEXT", "Text"), ("RATING", "Rating")],
381
+ default="TEXT",
382
+ max_length=32,
383
+ verbose_name="Type",
384
+ ),
385
+ ),
386
+ ("for_reviewee", models.BooleanField(default=True, verbose_name="For Reviewee")),
387
+ ("for_reviewer", models.BooleanField(default=True, verbose_name="For Reviewer")),
388
+ ("for_department_peers", models.BooleanField(default=False, verbose_name="For Department Peers")),
389
+ ("for_company_peers", models.BooleanField(default=False, verbose_name="For Company Peers")),
390
+ ("order", models.PositiveIntegerField(blank=True, null=True, verbose_name="Order")),
391
+ ("weight", models.DecimalField(decimal_places=1, default=1.0, max_digits=16, verbose_name="Weight")),
392
+ (
393
+ "category",
394
+ models.ForeignKey(
395
+ blank=True,
396
+ null=True,
397
+ on_delete=django.db.models.deletion.SET_NULL,
398
+ related_name="questions_related",
399
+ to="wbhuman_resources.reviewquestioncategory",
400
+ verbose_name="Category",
401
+ ),
402
+ ),
403
+ (
404
+ "evaluation",
405
+ models.ForeignKey(
406
+ blank=True,
407
+ null=True,
408
+ on_delete=django.db.models.deletion.SET_NULL,
409
+ related_name="evaluation_questions",
410
+ to="wbhuman_resources.evaluation",
411
+ verbose_name="Evaluation",
412
+ ),
413
+ ),
414
+ (
415
+ "review",
416
+ models.ForeignKey(
417
+ on_delete=django.db.models.deletion.CASCADE,
418
+ related_name="questions",
419
+ to="wbhuman_resources.review",
420
+ verbose_name="Review",
421
+ ),
422
+ ),
423
+ ],
424
+ options={
425
+ "verbose_name": "Review Question",
426
+ "verbose_name_plural": "Review Questions",
427
+ },
428
+ ),
429
+ migrations.CreateModel(
430
+ name="ReviewGroup",
431
+ fields=[
432
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
433
+ ("name", models.CharField(max_length=255, verbose_name="Name")),
434
+ ("employees", models.ManyToManyField(blank=True, related_name="reviewgroups", to="directory.person")),
435
+ ],
436
+ options={
437
+ "verbose_name": "Review Group",
438
+ "verbose_name_plural": "Review Groups",
439
+ },
440
+ ),
441
+ migrations.CreateModel(
442
+ name="ReviewAnswer",
443
+ fields=[
444
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
445
+ (
446
+ "answered_anonymized",
447
+ models.CharField(blank=True, max_length=255, null=True, verbose_name="Answered Anonymized"),
448
+ ),
449
+ (
450
+ "answer_number",
451
+ models.PositiveIntegerField(
452
+ blank=True,
453
+ null=True,
454
+ validators=[
455
+ django.core.validators.MinValueValidator(1),
456
+ django.core.validators.MaxValueValidator(4),
457
+ ],
458
+ verbose_name="Rating",
459
+ ),
460
+ ),
461
+ ("answer_text", models.TextField(blank=True, null=True, verbose_name="Comment")),
462
+ (
463
+ "answered_by",
464
+ models.ForeignKey(
465
+ blank=True,
466
+ null=True,
467
+ on_delete=django.db.models.deletion.SET_NULL,
468
+ related_name="related_answers",
469
+ to="directory.person",
470
+ verbose_name="Answered By",
471
+ ),
472
+ ),
473
+ (
474
+ "question",
475
+ models.ForeignKey(
476
+ on_delete=django.db.models.deletion.CASCADE,
477
+ related_name="answers",
478
+ to="wbhuman_resources.reviewquestion",
479
+ verbose_name="Question",
480
+ ),
481
+ ),
482
+ ],
483
+ options={
484
+ "verbose_name": "Review Answer",
485
+ "verbose_name_plural": "Review Answers",
486
+ },
487
+ ),
488
+ migrations.AddField(
489
+ model_name="review",
490
+ name="review_group",
491
+ field=models.ForeignKey(
492
+ blank=True,
493
+ null=True,
494
+ on_delete=django.db.models.deletion.SET_NULL,
495
+ related_name="review_related",
496
+ to="wbhuman_resources.reviewgroup",
497
+ verbose_name="Group",
498
+ ),
499
+ ),
500
+ migrations.AddField(
501
+ model_name="review",
502
+ name="reviewee",
503
+ field=models.ForeignKey(
504
+ blank=True,
505
+ null=True,
506
+ on_delete=django.db.models.deletion.SET_NULL,
507
+ related_name="reviewee_reviews",
508
+ to="directory.person",
509
+ verbose_name="Reviewee",
510
+ ),
511
+ ),
512
+ migrations.AddField(
513
+ model_name="review",
514
+ name="reviewer",
515
+ field=models.ForeignKey(
516
+ blank=True,
517
+ null=True,
518
+ on_delete=django.db.models.deletion.SET_NULL,
519
+ related_name="reviewer_reviews",
520
+ to="directory.person",
521
+ verbose_name="Reviewer",
522
+ ),
523
+ ),
524
+ migrations.CreateModel(
525
+ name="Position",
526
+ fields=[
527
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
528
+ ("computed_str", models.CharField(blank=True, max_length=512, null=True, verbose_name="Name")),
529
+ (
530
+ "color",
531
+ colorfield.fields.ColorField(default="#FF0000", image_field=None, max_length=18, samples=None),
532
+ ),
533
+ ("name", models.CharField(max_length=256)),
534
+ ("height", models.IntegerField(default=0)),
535
+ ("is_internal", models.BooleanField(default=True, verbose_name="Internal Position")),
536
+ ("lft", models.PositiveIntegerField(editable=False)),
537
+ ("rght", models.PositiveIntegerField(editable=False)),
538
+ ("tree_id", models.PositiveIntegerField(db_index=True, editable=False)),
539
+ ("level", models.PositiveIntegerField(editable=False)),
540
+ (
541
+ "group",
542
+ models.OneToOneField(
543
+ blank=True,
544
+ null=True,
545
+ on_delete=django.db.models.deletion.SET_NULL,
546
+ related_name="human_resources_positions",
547
+ to="auth.group",
548
+ ),
549
+ ),
550
+ (
551
+ "manager",
552
+ models.ForeignKey(
553
+ blank=True,
554
+ null=True,
555
+ on_delete=django.db.models.deletion.SET_NULL,
556
+ related_name="managed_positions",
557
+ to="directory.person",
558
+ verbose_name="Department Manager",
559
+ ),
560
+ ),
561
+ (
562
+ "parent",
563
+ mptt.fields.TreeForeignKey(
564
+ blank=True,
565
+ null=True,
566
+ on_delete=django.db.models.deletion.CASCADE,
567
+ related_name="children",
568
+ to="wbhuman_resources.position",
569
+ verbose_name="Parent Positions",
570
+ ),
571
+ ),
572
+ ],
573
+ options={
574
+ "verbose_name": "Position",
575
+ "verbose_name_plural": "Positions",
576
+ },
577
+ ),
578
+ migrations.CreateModel(
579
+ name="KPI",
580
+ fields=[
581
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
582
+ ("name", models.CharField(max_length=255)),
583
+ ("goal", models.PositiveIntegerField(verbose_name="Goal")),
584
+ ("period", django.contrib.postgres.fields.ranges.DateRangeField(verbose_name="Period")),
585
+ (
586
+ "evaluated_intervals",
587
+ models.CharField(
588
+ choices=[
589
+ ("DAILY", "Daily"),
590
+ ("WEEKLY", "Weekly"),
591
+ ("MONTHLY", "Monthly"),
592
+ ("QUARTERLY", "Quarterly"),
593
+ ],
594
+ default="MONTHLY",
595
+ max_length=16,
596
+ verbose_name="Evaluated Intervals",
597
+ ),
598
+ ),
599
+ ("handler", models.CharField(max_length=255)),
600
+ ("additional_data", models.JSONField(default=wbhuman_resources.models.kpi.default_additional_data)),
601
+ (
602
+ "last_update",
603
+ models.DateTimeField(
604
+ auto_now=True,
605
+ help_text="Date of latest change (automatically computed)",
606
+ verbose_name="Last update",
607
+ ),
608
+ ),
609
+ ("individual_evaluation", models.BooleanField(default=True, verbose_name="Individual Evaluation")),
610
+ ("is_active", models.BooleanField(default=True, verbose_name="Is Active")),
611
+ (
612
+ "evaluated_persons",
613
+ models.ManyToManyField(
614
+ related_name="wbhuman_resources_kpis", to="directory.person", verbose_name="Evaluated Persons"
615
+ ),
616
+ ),
617
+ ],
618
+ options={
619
+ "verbose_name": "Key Performance Indicator",
620
+ "verbose_name_plural": "Key Performance Indicators",
621
+ "permissions": [("admin_kpi", "Can administer KPI")],
622
+ },
623
+ ),
624
+ migrations.AddField(
625
+ model_name="evaluation",
626
+ name="kpi",
627
+ field=models.ForeignKey(
628
+ on_delete=django.db.models.deletion.CASCADE,
629
+ related_name="evaluations",
630
+ to="wbhuman_resources.kpi",
631
+ verbose_name="KPI",
632
+ ),
633
+ ),
634
+ migrations.AddField(
635
+ model_name="evaluation",
636
+ name="person",
637
+ field=models.ForeignKey(
638
+ blank=True,
639
+ null=True,
640
+ on_delete=django.db.models.deletion.CASCADE,
641
+ related_name="wbhuman_resources_evaluations",
642
+ to="directory.person",
643
+ ),
644
+ ),
645
+ migrations.CreateModel(
646
+ name="EmployeeYearBalance",
647
+ fields=[
648
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
649
+ ("computed_str", models.CharField(blank=True, max_length=512, null=True, verbose_name="Name")),
650
+ ("year", models.IntegerField(verbose_name="Year")),
651
+ (
652
+ "extra_balance",
653
+ models.FloatField(
654
+ default=0,
655
+ help_text="The yearly extra balance (in hours)",
656
+ verbose_name="Extra Balance (in hours)",
657
+ ),
658
+ ),
659
+ (
660
+ "employee",
661
+ models.ForeignKey(
662
+ help_text="The employee having that year balance",
663
+ on_delete=django.db.models.deletion.CASCADE,
664
+ related_name="balances",
665
+ to="wbhuman_resources.employeehumanresource",
666
+ verbose_name="Employee",
667
+ ),
668
+ ),
669
+ ],
670
+ options={
671
+ "verbose_name": "Employee Year Balance",
672
+ "verbose_name_plural": "Employee Year Balances",
673
+ },
674
+ ),
675
+ migrations.CreateModel(
676
+ name="EmployeeWeeklyOffPeriods",
677
+ fields=[
678
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
679
+ ("computed_str", models.CharField(blank=True, max_length=512, null=True, verbose_name="Name")),
680
+ (
681
+ "weekday",
682
+ models.PositiveIntegerField(
683
+ validators=[
684
+ django.core.validators.MinValueValidator(0),
685
+ django.core.validators.MaxValueValidator(6),
686
+ ]
687
+ ),
688
+ ),
689
+ (
690
+ "employee",
691
+ models.ForeignKey(
692
+ on_delete=django.db.models.deletion.CASCADE,
693
+ related_name="default_periods_relationships",
694
+ to="wbhuman_resources.employeehumanresource",
695
+ verbose_name="Employee",
696
+ ),
697
+ ),
698
+ (
699
+ "period",
700
+ models.ForeignKey(
701
+ on_delete=django.db.models.deletion.CASCADE,
702
+ related_name="employees_relationships",
703
+ to="wbhuman_resources.defaultdailyperiod",
704
+ verbose_name="Off Period",
705
+ ),
706
+ ),
707
+ ],
708
+ options={
709
+ "verbose_name": "Employee Weekly off Period",
710
+ "verbose_name_plural": "Employee Weekly off Periods",
711
+ },
712
+ ),
713
+ migrations.AddField(
714
+ model_name="employeehumanresource",
715
+ name="position",
716
+ field=models.ForeignKey(
717
+ blank=True,
718
+ help_text="The position this employee belongs to",
719
+ limit_choices_to=models.Q(("height", 0)),
720
+ null=True,
721
+ on_delete=django.db.models.deletion.SET_NULL,
722
+ related_name="employees",
723
+ to="wbhuman_resources.position",
724
+ verbose_name="Position",
725
+ ),
726
+ ),
727
+ migrations.AddField(
728
+ model_name="employeehumanresource",
729
+ name="profile",
730
+ field=models.OneToOneField(
731
+ help_text="The CRM profile related to this employee",
732
+ on_delete=django.db.models.deletion.CASCADE,
733
+ related_name="human_resources",
734
+ to="directory.person",
735
+ verbose_name="Employee",
736
+ ),
737
+ ),
738
+ migrations.AddField(
739
+ model_name="employeehumanresource",
740
+ name="weekly_off_periods",
741
+ field=models.ManyToManyField(
742
+ related_name="employees_off",
743
+ through="wbhuman_resources.EmployeeWeeklyOffPeriods",
744
+ to="wbhuman_resources.defaultdailyperiod",
745
+ verbose_name="Weekly off periods",
746
+ ),
747
+ ),
748
+ migrations.CreateModel(
749
+ name="DayOff",
750
+ fields=[
751
+ (
752
+ "calendaritem_ptr",
753
+ models.OneToOneField(
754
+ auto_created=True,
755
+ on_delete=django.db.models.deletion.CASCADE,
756
+ parent_link=True,
757
+ primary_key=True,
758
+ serialize=False,
759
+ to="agenda.calendaritem",
760
+ ),
761
+ ),
762
+ ("date", models.DateField(verbose_name="Date")),
763
+ (
764
+ "count_as_holiday",
765
+ models.BooleanField(
766
+ default=True,
767
+ help_text="If true, there is no work but the day counts towards the employees' vacation balance",
768
+ verbose_name="Count as Holiday",
769
+ ),
770
+ ),
771
+ (
772
+ "calendar",
773
+ models.ForeignKey(
774
+ on_delete=django.db.models.deletion.PROTECT,
775
+ related_name="days_off",
776
+ to="wbhuman_resources.dayoffcalendar",
777
+ verbose_name="Calendar",
778
+ ),
779
+ ),
780
+ ],
781
+ options={
782
+ "verbose_name": "Day Off",
783
+ "verbose_name_plural": "Days Off",
784
+ },
785
+ bases=("agenda.calendaritem",),
786
+ ),
787
+ migrations.CreateModel(
788
+ name="BalanceHourlyAllowance",
789
+ fields=[
790
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
791
+ ("period_index", models.PositiveIntegerField()),
792
+ ("hourly_allowance", models.FloatField()),
793
+ (
794
+ "balance",
795
+ models.ForeignKey(
796
+ on_delete=django.db.models.deletion.CASCADE,
797
+ related_name="monthly_allowances",
798
+ to="wbhuman_resources.employeeyearbalance",
799
+ verbose_name="Balance",
800
+ ),
801
+ ),
802
+ ],
803
+ options={
804
+ "verbose_name": "Monthly Allowance",
805
+ "verbose_name_plural": "Monthly Allowance",
806
+ },
807
+ ),
808
+ migrations.CreateModel(
809
+ name="AbsenceRequestPeriods",
810
+ fields=[
811
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
812
+ ("date", models.DateField()),
813
+ ("timespan", django.contrib.postgres.fields.ranges.DateTimeRangeField(verbose_name="Timespan")),
814
+ (
815
+ "consecutive_hours_count",
816
+ models.IntegerField(
817
+ default=0,
818
+ help_text="The number of consecutive hours this absence request period spans",
819
+ verbose_name="Consecutive Absence Hours count",
820
+ ),
821
+ ),
822
+ (
823
+ "balance",
824
+ models.ForeignKey(
825
+ blank=True,
826
+ help_text="For which balance this absence will count towards",
827
+ null=True,
828
+ on_delete=django.db.models.deletion.PROTECT,
829
+ related_name="periods",
830
+ to="wbhuman_resources.employeeyearbalance",
831
+ verbose_name="Balance",
832
+ ),
833
+ ),
834
+ (
835
+ "default_period",
836
+ models.ForeignKey(
837
+ help_text="The associated period",
838
+ on_delete=django.db.models.deletion.PROTECT,
839
+ related_name="periods",
840
+ to="wbhuman_resources.defaultdailyperiod",
841
+ verbose_name="Period",
842
+ ),
843
+ ),
844
+ (
845
+ "employee",
846
+ models.ForeignKey(
847
+ help_text="The Requester",
848
+ on_delete=django.db.models.deletion.CASCADE,
849
+ related_name="periods",
850
+ to="wbhuman_resources.employeehumanresource",
851
+ verbose_name="Employee",
852
+ ),
853
+ ),
854
+ (
855
+ "request",
856
+ models.ForeignKey(
857
+ help_text="The associated request",
858
+ on_delete=django.db.models.deletion.CASCADE,
859
+ related_name="periods",
860
+ to="wbhuman_resources.absencerequest",
861
+ verbose_name="Request",
862
+ ),
863
+ ),
864
+ ],
865
+ options={
866
+ "verbose_name": "Absence Request Period",
867
+ "verbose_name_plural": "Absence Request Periods",
868
+ },
869
+ ),
870
+ migrations.AddField(
871
+ model_name="absencerequest",
872
+ name="employee",
873
+ field=models.ForeignKey(
874
+ help_text="The employee requesting the absence",
875
+ on_delete=django.db.models.deletion.CASCADE,
876
+ related_name="requests",
877
+ to="wbhuman_resources.employeehumanresource",
878
+ verbose_name="Employee",
879
+ ),
880
+ ),
881
+ migrations.AddField(
882
+ model_name="absencerequest",
883
+ name="type",
884
+ field=models.ForeignKey(
885
+ on_delete=django.db.models.deletion.PROTECT,
886
+ related_name="request",
887
+ to="wbhuman_resources.absencerequesttype",
888
+ verbose_name="Type",
889
+ ),
890
+ ),
891
+ migrations.AddIndex(
892
+ model_name="employeeyearbalance",
893
+ index=models.Index(fields=["employee", "year"], name="wbhuman_res_employe_b6cd2e_idx"),
894
+ ),
895
+ migrations.AlterUniqueTogether(
896
+ name="employeeyearbalance",
897
+ unique_together={("employee", "year")},
898
+ ),
899
+ migrations.AddIndex(
900
+ model_name="employeeweeklyoffperiods",
901
+ index=models.Index(fields=["employee", "period", "weekday"], name="wbhuman_res_employe_248df8_idx"),
902
+ ),
903
+ migrations.AlterUniqueTogether(
904
+ name="employeeweeklyoffperiods",
905
+ unique_together={("employee", "period", "weekday")},
906
+ ),
907
+ migrations.AddConstraint(
908
+ model_name="defaultdailyperiod",
909
+ constraint=models.CheckConstraint(
910
+ check=models.Q(("upper_time__gt", models.F("lower_time"))), name="check_lower_time_lt_upper_time"
911
+ ),
912
+ ),
913
+ migrations.AddConstraint(
914
+ model_name="defaultdailyperiod",
915
+ constraint=django.contrib.postgres.constraints.ExclusionConstraint(
916
+ expressions=[("timespan", "&&"), ("calendar", "=")], name="check_no_overlapping_default_periods_time"
917
+ ),
918
+ ),
919
+ migrations.AddConstraint(
920
+ model_name="dayoff",
921
+ constraint=models.UniqueConstraint(fields=("date", "calendar"), name="unique_date_for_calendar"),
922
+ ),
923
+ migrations.AddIndex(
924
+ model_name="balancehourlyallowance",
925
+ index=models.Index(fields=["balance"], name="wbhuman_res_balance_d67ba9_idx"),
926
+ ),
927
+ migrations.AddIndex(
928
+ model_name="balancehourlyallowance",
929
+ index=models.Index(fields=["balance", "period_index"], name="wbhuman_res_balance_35163a_idx"),
930
+ ),
931
+ migrations.AlterUniqueTogether(
932
+ name="balancehourlyallowance",
933
+ unique_together={("balance", "period_index")},
934
+ ),
935
+ migrations.AddIndex(
936
+ model_name="absencerequestperiods",
937
+ index=models.Index(fields=["employee", "default_period", "date"], name="wbhuman_res_employe_5eb827_idx"),
938
+ ),
939
+ migrations.AddConstraint(
940
+ model_name="absencerequestperiods",
941
+ constraint=django.contrib.postgres.constraints.ExclusionConstraint(
942
+ expressions=[("timespan", "&&"), ("employee", "=")], name="exclude_overlapping_periods"
943
+ ),
944
+ ),
945
+ migrations.AlterUniqueTogether(
946
+ name="absencerequestperiods",
947
+ unique_together={("employee", "default_period", "date")},
948
+ ),
949
+ ]