-
Notifications
You must be signed in to change notification settings - Fork 393
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[PRO] Make it possible to 'snooze' tasks. #219
Comments
@emihir0 we already implemented this feature. I'll ask someone in my team to share the code here. |
@codingjoe Thanks, that would be much appreciated. Indeed this would be a nice feature to have in core. Are there any other 'cool' functionalities your team has implemented that you think should be in core? |
So essentially we have our custom Task model as well as a View mixin. Note that the view mixin requires the view to be saveable, see also http://viewflow-extensions.readthedocs.io/en/latest/views.html class SnoozeableViewActivationMixin:
_snooze = None
def get_form_class(self):
"""Field validation in Django 1.10 blocks the functionality of snoozing."""
form_class = super().get_form_class()
form_class.use_required_attribute = False
return form_class
def activation_done(self, *args, **kwargs):
if not self._snooze:
super().activation_done(*args, **kwargs)
def message_snooze(self, snooze_date):
activation = self.request.activation
hyperlink = activation.flow_task.get_task_url(activation.task)
msg = _('Task {hyperlink} has been snoozed until {snooze_date}.').format(
hyperlink=hyperlink, snooze_date=snooze_date.strftime("%d.%m.%Y %H:%M"))
messages.success(self.request, mark_safe(msg), fail_silently=True) # nosec
def post(self, request, *args, **kwargs):
self._snooze = request.POST.get('_snooze')
if self._snooze:
max_days = settings.VIEWFLOW_TASK_SNOOZE_MAX_DAYS
now = local_now()
snooze_date = self.compute_snooze_date(start_date=now, snooze=self._snooze)
if snooze_date - now > datetime.timedelta(days=max_days):
msg = _('You cannot postpone a task for more than {} days.').format(max_days)
return self.snooze_fail(msg)
if snooze_date < now:
return self.snooze_fail(_('The requested postpone date is in the past.'))
self.request.activation.task.snooze = snooze_date
self.save_task()
self.message_snooze(snooze_date)
return redirect(self.get_success_url())
return super().post(request, *args, *kwargs)
def snooze_fail(self, msg):
self.save_task()
messages.error(self.request, msg, fail_silently=True)
return redirect(self.request.get_full_path())
def get_success_url(self):
if self._snooze:
process = self.request.activation.task.process
return reverse('{}:detail'.format(process.flow_class.__name__), args=[process.pk])
return super().get_success_url()
@staticmethod
def compute_snooze_date(start_date, snooze):
day_start = dict(hour=7, minute=0, second=0)
hours = re.match(r'(\d+)h', snooze)
if hours:
return start_date + datetime.timedelta(hours=int(hours.group(1)))
if snooze == 'tomorrow':
return (start_date + datetime.timedelta(days=1)).replace(**day_start)
if snooze == 'day_after_tomorrow':
return (start_date + datetime.timedelta(days=2)).replace(**day_start)
if snooze == 'next_week':
days_ahead = 7 - start_date.weekday()
return (start_date + datetime.timedelta(days=days_ahead)).replace(**day_start)
if snooze == 'after_lunch':
after_lunch = start_date.replace(hour=13, minute=0, second=0)
if start_date < after_lunch:
return after_lunch
else:
return after_lunch + datetime.timedelta(days=1)
try:
days_ahead = int(snooze)
return (start_date + datetime.timedelta(days=days_ahead)).replace(**day_start)
except ValueError:
# custom date
return parser.parse(snooze).replace(**day_start, tzinfo=get_current_timezone()) class SnoozebleTask(AbstractTast):
"""
Like :class:`.viewflow.models.Task` but with an additional due date.
The default due date will be the time of instance creation but can
be changed to any future or past time.
"""
snooze = models.DateTimeField(_('snooze'), blank=True, null=True) We have a viewflow-extension package, where we usually keep all our custom features to share them across apps. Its open source, feel free to use it. In this particular case though, we haven't put the feature in there yet. But we should really do that 😉 |
Thanks! That's really useful. |
The thing that you're asking is called "Manual Event" in the BPMN systems. |
Very often tasks can take a long time - for example a simple flow can be:
It's pointless for
confirm_order
task to take up space in inbox (hence clutter it and more pressing tasks are not so visible) when we know the customer can take up to XX days until he responds. My suggestion is to let us be able to snooze task so it does not show up in inbox by default, but it can still be filtered to be shown there. Basically by default the snoozed tasks are filtered out.Hence, ideally, it should be possible to:
User
until later datetime.Assign
can be done directly in code.The only tricky part about this is that there must be some background process that switches the tasks from snoozed to non-snoozed when the datetime is reached.
Edit: There is no need for background process. There would only have to be a
snoozed_until
datetime field and if the current time is lower thansnoozed_until
, then the task is snoozed - simple as that.The text was updated successfully, but these errors were encountered: