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

Status lifecycle

Status is a guarded state machine. Legal transitions persist and fire AppointmentStatusChanged; illegal ones throw InvalidStatusTransitionException; moving to the current status is a silent no-op:

use RoundlyConsulting\Appointments\Enums\Status;
use RoundlyConsulting\Appointments\Facades\Appointments;

Appointments::for($appointment)->confirm();      // pending → confirmed
Appointments::for($appointment)->cancel();       // pending/confirmed → cancelled
Appointments::for($appointment)->complete();     // confirmed → completed
Appointments::for($appointment)->decline();      // pending → declined
Appointments::for($appointment)->markNoShow();   // confirmed → no_show
Appointments::for($appointment)->transition(Status::Confirmed);   // the generic form

// the same shortcuts on the model — they go through the facade's manager too
$appointment->confirm();
$appointment->transitionTo(Status::Confirmed);

Allowed transitions

StatusValueColourCan move to
Status::Pendingpendingamberconfirmed, declined, cancelled
Status::Confirmedconfirmedbluecompleted, cancelled, no_show
Status::Cancelledcancelledgray— (final)
Status::Completedcompletedgreen— (final)
Status::Declineddeclinedred— (final)
Status::NoShowno_showorange— (final)

The handle’s shortcuts and the model’s confirm(), cancel(), complete(), decline(), markNoShow() and transitionTo() all end in Appointments::for($appointment)->transition() on the manager, which runs TransitionAppointmentAction — so Appointments::fake() records them wherever they are called.

Inspecting the machine

Ask the enum what’s possible — handy for showing only the buttons that make sense:

use RoundlyConsulting\Appointments\Enums\Status;

$appointment->status;                                    // Status enum (cast)
$appointment->status->transitions();                     // e.g. [Status::Completed, Status::Cancelled, Status::NoShow]
$appointment->status->canTransitionTo(Status::Pending);  // false
$appointment->status->isFinal();                         // true for cancelled, completed, declined, no_show
Status::default();                                       // Status::Pending

Handling illegal moves

use RoundlyConsulting\Appointments\Exceptions\InvalidStatusTransitionException;

try {
    $appointment->complete();       // still pending
} catch (InvalidStatusTransitionException $e) {
    $e->from;                       // Status::Pending
    $e->to;                         // Status::Completed
    $e->getMessage();               // Cannot transition appointment status from "pending" to "completed".
}

Labels, colours and options

Status, ParticipantRole and Frequency carry the enums-for-laravel Helpers trait, so they come ready for UI and validation. color() is specific to Status:

use RoundlyConsulting\Appointments\Enums\Status;

$appointment->status->label();   // "Confirmed" (from the enums Helpers trait)
$appointment->status->color();   // a colour token for UI badges, e.g. "blue"
Status::values();                // Collection: 'pending', 'confirmed', …
Status::labels();                // Collection: "Pending", "Confirmed", …
Status::options();               // value/label/name option DTOs for a <select>
Status::validationRule();        // "in:pending,confirmed,cancelled,completed,declined,no_show"

label() passes the headlined value through Laravel’s __() — Pending, Confirmed, No Show — so you translate labels with a JSON translation file such as lang/sk.json:

{
    "Pending": "Čaká na potvrdenie",
    "Confirmed": "Potvrdený",
    "No Show": "Neprítomnosť"
}

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.