Internal
Public Access
Implement recurring tasks functionality
Adds automatic creation of next task instance when recurring tasks are completed. - Add calculate_next_due_date() and create_next_recurrence() methods to Task model - Update task completion handlers in views and sync API to create next recurrence - Add hourly Celery task to process any missed recurring tasks - Support daily, weekly, biweekly, monthly, yearly recurrence patterns - Respect recurrence_end_date limits 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.5
parent
c51fd846a2
commit
1d6b07bfed
@@ -236,3 +236,51 @@ def schedule_task_reminder(task_id):
|
||||
task=task,
|
||||
remind_at=remind_at
|
||||
)
|
||||
|
||||
|
||||
@shared_task
|
||||
def process_recurring_tasks():
|
||||
"""
|
||||
Process completed recurring tasks and create next instances.
|
||||
This runs periodically as a safety net to catch any tasks that weren't
|
||||
automatically handled when marked as completed.
|
||||
Runs every hour via Celery Beat.
|
||||
"""
|
||||
from tasks.models import Task
|
||||
|
||||
# Find completed recurring tasks that don't have a next instance created yet
|
||||
# We look for tasks completed in the last 24 hours to avoid reprocessing old tasks
|
||||
yesterday = timezone.now() - timedelta(days=1)
|
||||
|
||||
completed_recurring_tasks = Task.objects.filter(
|
||||
status='completed',
|
||||
recurrence__in=['daily', 'weekly', 'biweekly', 'monthly', 'yearly', 'custom'],
|
||||
completed_at__gte=yesterday
|
||||
).exclude(recurrence='none')
|
||||
|
||||
tasks_created = 0
|
||||
for task in completed_recurring_tasks:
|
||||
# Check if a next recurrence already exists
|
||||
# Look for pending tasks with the same title, user, and recurrence pattern
|
||||
next_due_date = task.calculate_next_due_date()
|
||||
if next_due_date:
|
||||
# Check if we already created this recurrence
|
||||
existing = Task.objects.filter(
|
||||
user=task.user,
|
||||
title=task.title,
|
||||
due_date=next_due_date,
|
||||
recurrence=task.recurrence,
|
||||
status='pending'
|
||||
).exists()
|
||||
|
||||
if not existing:
|
||||
# Create the next recurrence
|
||||
new_task = task.create_next_recurrence()
|
||||
if new_task:
|
||||
tasks_created += 1
|
||||
logger.info(f"Created recurring task: {new_task.title} (due: {new_task.due_date})")
|
||||
|
||||
if tasks_created > 0:
|
||||
logger.info(f"Created {tasks_created} recurring task instances")
|
||||
|
||||
return tasks_created
|
||||
|
||||
Reference in New Issue
Block a user