• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

chiefonboarding / ChiefOnboarding / 6712092385

31 Oct 2023 08:26PM UTC coverage: 93.672% (+0.01%) from 93.66%
6712092385

Pull #383

github

web-flow
Merge 10f692848 into fb838f71e
Pull Request #383: Add offboarding sequences

6262 of 6685 relevant lines covered (93.67%)

0.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.97
back/admin/sequences/forms.py
1
from crispy_forms.helper import FormHelper
1✔
2
from crispy_forms.layout import Div, Field, Layout
1✔
3
from django import forms
1✔
4
from django.core.exceptions import ValidationError
1✔
5
from django.utils.translation import gettext_lazy as _
1✔
6

7
from admin.templates.forms import MultiSelectField, WYSIWYGField
1✔
8
from admin.to_do.models import ToDo
1✔
9
from users.models import User
1✔
10

11
from .models import (
1✔
12
    Condition,
13
    ExternalMessage,
14
    PendingAdminTask,
15
    PendingEmailMessage,
16
    PendingSlackMessage,
17
    PendingTextMessage,
18
)
19

20

21
class ConditionForm(forms.ModelForm):
1✔
22
    condition_to_do = forms.ModelMultipleChoiceField(
1✔
23
        queryset=ToDo.templates.defer_content().all(),
24
        to_field_name="id",
25
        required=False,
26
    )
27
    condition_admin_tasks = forms.ModelMultipleChoiceField(
1✔
28
        queryset=PendingAdminTask.objects.all(),
29
        to_field_name="id",
30
        required=False,
31
    )
32

33
    def __init__(self, *args, **kwargs):
1✔
34
        sequence = kwargs.pop("sequence")
1✔
35
        super().__init__(*args, **kwargs)
1✔
36
        self.helper = FormHelper()
1✔
37
        self.helper.form_tag = False
1✔
38
        self.helper.layout = Layout(
1✔
39
            Field("condition_type"),
40
            Div(
41
                MultiSelectField("condition_to_do"),
42
                css_class="" if self.instance.based_on_to_do else "d-none",
43
            ),
44
            Div(
45
                Field("days"),
46
                Field("time"),
47
                css_class="" if self.instance.based_on_time else "d-none",
48
            ),
49
            Div(
50
                Field("condition_admin_tasks"),
51
                css_class="" if self.instance.based_on_admin_task else "d-none",
52
            ),
53
        )
54
        self.fields["time"].required = False
1✔
55
        self.fields["days"].required = False
1✔
56
        self.fields["condition_to_do"].required = False
1✔
57
        pending_tasks = PendingAdminTask.objects.filter(condition__sequence=sequence)
1✔
58
        self.fields["condition_admin_tasks"].queryset = pending_tasks
1✔
59
        # Remove last option, which will only be one of
60
        self.fields["condition_type"].choices = tuple(
1✔
61
            x for x in Condition.Type.choices if x[0] != 3
62
        )
63

64
    class Meta:
1✔
65
        model = Condition
1✔
66
        fields = [
1✔
67
            "condition_type",
68
            "days",
69
            "time",
70
            "condition_to_do",
71
            "condition_admin_tasks",
72
        ]
73
        widgets = {
1✔
74
            "time": forms.TimeInput(attrs={"type": "time", "step": 300}),
75
        }
76
        help_texts = {
1✔
77
            "time": _("Must be in a 5 minute interval."),
78
        }
79

80
    def clean_days(self):
1✔
81
        day = self.cleaned_data["days"]
1✔
82
        if day is None:
1✔
83
            # Handled in clean() function
84
            return day
1✔
85
        if (
1✔
86
            self.cleaned_data["condition_type"]
87
            in [Condition.Type.AFTER, Condition.Type.BEFORE]
88
            and day <= 0
89
        ):
90
            raise ValidationError(
1✔
91
                _(
92
                    "You cannot use 0 or less. The day before starting is 1 and the "
93
                    "first workday is 1"
94
                )
95
            )
96

97
        return day
1✔
98

99
    def clean_time(self):
1✔
100
        time = self.cleaned_data["time"]
1✔
101
        if time is None:
1✔
102
            # Handled in clean() function
103
            return time
1✔
104
        if time.minute % 10 not in [0, 5] and self.cleaned_data["condition_type"] in [
1✔
105
            Condition.Type.BEFORE,
106
            Condition.Type.AFTER,
107
        ]:
108
            raise ValidationError(
1✔
109
                _(
110
                    "Time must be in an interval of 5 minutes. %(minutes)s must end in "
111
                    "0 or 5."
112
                )
113
                % {"minutes": time.minute}
114
            )
115

116
        return time
1✔
117

118
    def clean(self):
1✔
119
        cleaned_data = super().clean()
1✔
120
        condition_type = cleaned_data.get("condition_type", None)
1✔
121
        time = cleaned_data.get("time", None)
1✔
122
        days = cleaned_data.get("days", None)
1✔
123
        condition_to_do = cleaned_data.get("condition_to_do", None)
1✔
124
        condition_admin_tasks = cleaned_data.get("condition_admin_tasks", None)
1✔
125
        if condition_type == Condition.Type.TODO and (
1✔
126
            condition_to_do is None or len(condition_to_do) == 0
127
        ):
128
            raise ValidationError(_("You must add at least one to do item"))
1✔
129
        if condition_type == Condition.Type.ADMIN_TASK and (
1✔
130
            condition_admin_tasks is None or len(condition_admin_tasks) == 0
131
        ):
132
            raise ValidationError(_("You must add at least one admin task"))
1✔
133
        if condition_type in [Condition.Type.AFTER, Condition.Type.BEFORE] and (
1✔
134
            time is None or days is None
135
        ):
136
            raise ValidationError(_("Both the time and days have to be filled in."))
1✔
137
        return cleaned_data
1✔
138

139

140
class OffboardingConditionForm(ConditionForm):
1✔
141
    def __init__(self, *args, **kwargs):
1✔
142
        super().__init__(*args, **kwargs)
1✔
143
        # use different labels for the type
144
        self.fields["condition_type"].choices = [
1✔
145
            (2, _("On/Before employee's last day")),
146
            (1, _("Based on one or more to do items")),
147
            (4, _("Based on one or more admin tasks")),
148
        ]
149
        self.fields["days"].help_text = _("Enter 0 for the last day")
1✔
150
        self.fields["days"].label = _("Amount of days before")
1✔
151

152
    def clean_days(self):
1✔
153
        day = self.cleaned_data["days"]
1✔
154
        if day is None:
1✔
155
            # Handled in clean() function
156
            return day
1✔
157
        if self.cleaned_data["condition_type"] == Condition.Type.BEFORE and day < 0:
1✔
158
            raise ValidationError(_("Their last day is 0. You cannot go below that."))
1✔
159
        return day
×
160

161

162
class PendingAdminTaskForm(forms.ModelForm):
1✔
163
    assigned_to = forms.ModelChoiceField(
1✔
164
        queryset=User.managers_and_admins.all(), required=False
165
    )
166
    slack_user = forms.ModelChoiceField(
1✔
167
        queryset=User.objects.exclude(slack_user_id=""),
168
        required=False,
169
    )
170
    date = forms.DateField(
1✔
171
        label=_("Due date"),
172
        required=False,
173
        widget=forms.DateInput(attrs={"type": "date"}, format=("%Y-%m-%d")),
174
    )
175

176
    def __init__(self, *args, **kwargs):
1✔
177
        super().__init__(*args, **kwargs)
1✔
178
        self.fields["option"].initial = PendingAdminTask.Notification.NO
1✔
179
        self.fields["comment"].required = True
1✔
180
        self.helper = FormHelper()
1✔
181
        self.helper.form_tag = False
1✔
182

183
        # Check if assigned_to field should be hidden
184
        hide_assigned_to = "d-none"
1✔
185
        if (
1✔
186
            self.instance is not None
187
            and self.instance.person_type == PendingAdminTask.PersonType.CUSTOM
188
        ):
189
            hide_assigned_to = ""
1✔
190

191
        self.helper.layout = Layout(
1✔
192
            Div(
193
                Field("name"),
194
                Field("person_type"),
195
                Div(
196
                    Field("assigned_to"),
197
                    css_class=hide_assigned_to,
198
                ),
199
                Field("date"),
200
                Field("priority"),
201
                Field("comment"),
202
                Field("option"),
203
                Field("slack_user"),
204
                Field("email"),
205
            ),
206
        )
207

208
    class Meta:
1✔
209
        model = PendingAdminTask
1✔
210
        fields = [
1✔
211
            "name",
212
            "person_type",
213
            "assigned_to",
214
            "date",
215
            "priority",
216
            "comment",
217
            "option",
218
            "slack_user",
219
            "email",
220
        ]
221

222
    def clean(self):
1✔
223
        cleaned_data = super().clean()
×
224
        assigned_to = cleaned_data.get("assigned_to", None)
×
225
        person_type = cleaned_data["person_type"]
×
226
        if person_type == PendingAdminTask.PersonType.CUSTOM and assigned_to is None:
×
227
            self.add_error("assigned_to", _("This field is required"))
×
228
        return cleaned_data
×
229

230

231
class PendingSlackMessageForm(forms.ModelForm):
1✔
232
    def __init__(self, *args, **kwargs):
1✔
233
        super().__init__(*args, **kwargs)
1✔
234
        self.helper = FormHelper()
1✔
235
        self.helper.form_tag = False
1✔
236

237
        # Check if send_to field should be hidden
238
        hide_send_to = "d-none"
1✔
239
        if (
1✔
240
            self.instance is not None
241
            and self.instance.person_type == ExternalMessage.PersonType.CUSTOM
242
        ):
243
            hide_send_to = ""
×
244

245
        hide_send_to_channel = "d-none"
1✔
246
        if (
1✔
247
            self.instance is not None
248
            and self.instance.person_type == ExternalMessage.PersonType.SLACK_CHANNEL
249
        ):
250
            hide_send_to_channel = ""
×
251

252
        self.helper.layout = Layout(
1✔
253
            Div(
254
                Field("name"),
255
                WYSIWYGField("content_json"),
256
                Field("person_type"),
257
                Div(
258
                    Field("send_to"),
259
                    css_class=hide_send_to,
260
                ),
261
                Div(
262
                    Field("send_to_channel"),
263
                    css_class=hide_send_to_channel,
264
                ),
265
            ),
266
        )
267

268
    class Meta:
1✔
269
        model = PendingSlackMessage
1✔
270
        fields = [
1✔
271
            "name",
272
            "content_json",
273
            "person_type",
274
            "send_to",
275
            "send_to_channel",
276
        ]
277

278

279
class PendingTextMessageForm(forms.ModelForm):
1✔
280
    def __init__(self, *args, **kwargs):
1✔
281
        super().__init__(*args, **kwargs)
1✔
282
        self.helper = FormHelper()
1✔
283
        self.helper.form_tag = False
1✔
284

285
        # Check if send_to field should be hidden
286
        hide_send_to = "d-none"
1✔
287
        if (
1✔
288
            self.instance is not None
289
            and self.instance.person_type == ExternalMessage.PersonType.CUSTOM
290
        ):
291
            hide_send_to = ""
×
292

293
        # Remove the Slack channel options
294
        self.fields["person_type"].choices = PendingAdminTask.PersonType.choices
1✔
295
        self.fields["person_type"].widget.choices = PendingAdminTask.PersonType.choices
1✔
296

297
        self.helper.layout = Layout(
1✔
298
            Div(
299
                Field("name"),
300
                Field("content"),
301
                Field("person_type"),
302
                Div(
303
                    Field("send_to"),
304
                    css_class=hide_send_to,
305
                ),
306
            ),
307
        )
308

309
    class Meta:
1✔
310
        model = PendingTextMessage
1✔
311
        fields = [
1✔
312
            "name",
313
            "content",
314
            "person_type",
315
            "send_to",
316
        ]
317

318

319
class PendingEmailMessageForm(forms.ModelForm):
1✔
320
    def __init__(self, *args, **kwargs):
1✔
321
        super().__init__(*args, **kwargs)
1✔
322
        self.helper = FormHelper()
1✔
323
        self.helper.form_tag = False
1✔
324

325
        # Check if send_to field should be hidden
326
        hide_send_to = "d-none"
1✔
327
        if (
1✔
328
            self.instance is not None
329
            and self.instance.person_type == ExternalMessage.PersonType.CUSTOM
330
        ):
331
            hide_send_to = ""
×
332

333
        # Remove the Slack channel options
334
        self.fields["person_type"].choices = PendingAdminTask.PersonType.choices
1✔
335
        self.fields["person_type"].widget.choices = PendingAdminTask.PersonType.choices
1✔
336

337
        self.helper.layout = Layout(
1✔
338
            Div(
339
                Field("name"),
340
                Field("subject"),
341
                WYSIWYGField("content_json"),
342
                Field("person_type"),
343
                Div(
344
                    Field("send_to"),
345
                    css_class=hide_send_to,
346
                ),
347
            ),
348
        )
349

350
    class Meta:
1✔
351
        model = PendingEmailMessage
1✔
352
        fields = [
1✔
353
            "name",
354
            "subject",
355
            "content_json",
356
            "person_type",
357
            "send_to",
358
        ]
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc