NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Tickets for Laravel

Due dates and the sweep

The due date is manual: given at creation, set later, or filled at creation by the Contracts\DueDateResolver (default: now plus the nearest category’s default_due_in) — the seam an SLA layer plugs into:

Tickets::for($ticket)->due(now()->addHours(4));   // TicketDueDateChanged; clears both flags
Tickets::for($ticket)->due(null);                 // no due date
Ticket::query()->overdue()->get();                // past due and unresolved (Waiting counts)

$result = Tickets::sweep();   // SweepResult { overdue: 3, dueSoon: 1 }

The sweep

Tickets::sweep() — and php artisan tickets:sweep, every five minutes — walks the unresolved tickets in id-ordered chunks:

  • Past the due date → TicketOverdue, an overdue activity entry and the overdue notification.
  • Within tickets.due.soon_window (PT4H; off = never) → TicketDueSoon and the due_soon notification (no activity entry).
  • Each fires exactly once per due date: a compare-and-set on overdue_notified_at / due_soon_notified_at that also matches the due_at the sweep read, so two concurrent sweeps flag a ticket once and a sweep that read the old date never flags a moved one.
  • Moving the due date re-arms both flags. A ticket swept late (already past due) is flagged overdue only.
  • The sweep never closes tickets — auto-close is lifecycle:sweep.
$result = Tickets::sweep();   // SweepResult
$result->overdue;             // int — tickets this sweep flagged overdue
$result->dueSoon;             // int — tickets this sweep flagged due soon
$result->total();             // int — both added up

SweepResult counts the tickets this sweep flagged. Waiting tickets still count as overdue. The PHP API accepts a past due date (for imports); the HTTP API requires after:now.

Your own due-date rule

Bind a Contracts\DueDateResolver (dueAt(Ticket): ?CarbonImmutable) through tickets.due.resolver or the container. It is asked when a ticket is created without a due date, on the stored ticket — with its category loaded — before its custom fields, tags and watchers are written.

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.