Design a Booking State Workflow in PHP Laravel

Certainly! Adding an automatic cancellation mechanism for scenarios where the Partner doesn’t confirm a booking within a set time or the Renter fails to pay on time makes the workflow more robust and user-friendly. Here’s the updated Booking State Workflow:


Updated Booking States Workflow

StateDescription
PendingBooking created but awaiting Partner confirmation.
Auto-CancelledBooking automatically cancelled due to Partner’s inaction within 1 hour.
ConfirmedPartner has confirmed the booking.
Awaiting PaymentRenter has not completed payment within 1 hour of confirmation. Booking may auto-cancel.
PaidRenter has completed payment. THE MOMENT PARTNER make ORDER as PAID, Vehicle Ready
Vehicle ReadyPartner has prepared the vehicle for pick-up/delivery.
In ProgressVehicle has been handed over to the Renter.When Partner click on Picked up , then imm it would get into In In Progress
CompletedBooking successfully completed and vehicle returned. When Partner click on Returned , then imm it would get into In In Progress. Vehicle would ready automatically
CancelledBooking cancelled manually by Renter or Partner.
RefundedNA
Issue ReportedNA

State Transitions with Auto-Cancellation

Current StateTrigger/ActionNext StateTime ConstraintDescription
PendingPartner confirms bookingConfirmedWithin 1 hour of creationPartner must confirm booking within 1 hour.
PendingSystem checks timeoutAuto-CancelledExceeds 1 hourBooking is auto-cancelled if not confirmed.
ConfirmedRenter completes paymentPaidWithin 1 hour of confirmationRenter must pay within 1 hour of confirmation.
ConfirmedSystem checks timeoutAuto-CancelledExceeds 1 hourBooking is auto-cancelled if payment isn’t made.
PaidPartner marks vehicle readyVehicle ReadyN/AVehicle is prepared for handover.
Vehicle ReadyRenter picks up the vehicleIn ProgressN/AThe vehicle is handed over to the Renter.
In ProgressRenter returns the vehicleCompletedN/ABooking is finalized after vehicle return and inspection.
Any StateManual cancellation by Renter or PartnerCancelledN/ABooking is cancelled manually.
CancelledSystem processes refundRefundedN/ARefund initiated for eligible cancellations.
In ProgressRenter or Partner reports an issueIssue ReportedN/AA damage, delay, or other issue is flagged for resolution.
Issue ReportedIssue is resolvedCompletedN/ABooking finalized after issue resolution.

Updated Workflow with Auto-Cancellation

Step 1: Booking Creation

  • State: Pending
  • Trigger: Renter creates a booking.
  • Time Constraint: If Partner does not confirm within 1 hour, the booking transitions to Auto-Cancelled.

Step 2: Booking Confirmation

  • State: Confirmed
  • Trigger: Partner confirms the booking.
  • Time Constraint: If Renter does not pay within 1 hour, the booking transitions to Auto-Cancelled.

Step 3: Payment

  • State: Paid
  • Trigger: Renter completes payment.
  • Transition: The booking progresses to Vehicle Ready once the Partner prepares the vehicle.

Step 4: Auto-Cancellation Conditions

  1. Pending to Auto-Cancelled: No confirmation from the Partner within 1 hour.
  2. Confirmed to Auto-Cancelled: No payment from the Renter within 1 hour.

Implementation Details

Database Changes

Add a column to track auto-cancellation deadlines:

ALTER TABLE bookings ADD COLUMN auto_cancel_at TIMESTAMP NULL;

Auto-Cancellation Logic

Schedule a background task (e.g., Laravel Scheduler) to handle time-based state transitions.

Example Code for Auto-Cancellation Job:

namespace App\Jobs;

use App\Models\Booking;
use Illuminate\Support\Facades\Log;

class AutoCancelBookings extends Job
{
    public function handle()
    {
        // Fetch bookings eligible for auto-cancellation
        $now = now();
        $bookings = Booking::whereIn('status', ['Pending', 'Confirmed'])
            ->where('auto_cancel_at', '<=', $now)
            ->get();

        foreach ($bookings as $booking) {
            if ($booking->status === 'Pending') {
                $booking->update(['status' => 'Auto-Cancelled']);
                Log::info("Booking {$booking->id} auto-cancelled due to no Partner confirmation.");
            }

            if ($booking->status === 'Confirmed' && $booking->payment_status !== 'Paid') {
                $booking->update(['status' => 'Auto-Cancelled']);
                Log::info("Booking {$booking->id} auto-cancelled due to no Renter payment.");
            }
        }
    }
}

Schedule the Job in app/Console/Kernel.php:

protected function schedule(Schedule $schedule)
{
    $schedule->job(new AutoCancelBookings)->everyMinute();
}

Frontend Updates

For Renter Dashboard:

  1. Display Time Remaining:
    • Show a countdown for payment time if the booking is in Confirmed state.
    • Example: “Pay within 59 minutes to confirm your booking.”
  2. Auto-Cancellation Notification:
    • Notify the Renter if the booking is auto-cancelled.

For Partner Dashboard:

  1. Display Time Remaining:
    • Show a countdown for confirmation if the booking is in Pending state.
    • Example: “Confirm this booking within 30 minutes.”

Notifications

For Renter:

  • Pending → Auto-Cancelled: “Your booking was cancelled because the Partner did not confirm within 1 hour.”
  • Confirmed → Auto-Cancelled: “Your booking was cancelled because payment was not completed on time.”

For Partner:

  • Pending → Auto-Cancelled: “The booking request was cancelled as you did not confirm within 1 hour.”

Example State Transition Flow

Case 1: Renter Creates Booking

  1. Initial State: Pending.
  2. Partner Confirms in 40 Minutes: Transition to Confirmed.
  3. Renter Pays in 20 Minutes: Transition to Paid.

Case 2: No Partner Confirmation

  1. Initial State: Pending.
  2. Timeout (1 Hour): Transition to Auto-Cancelled.

Case 3: No Renter Payment

  1. Initial State: PendingConfirmed.
  2. Timeout (1 Hour): Transition to Auto-Cancelled.

This updated workflow ensures that bookings are not left in limbo, providing a better experience for both Renters and Partners while maintaining operational efficiency for MotoShare.in. Let me know if you’d like further customization!

To implement a workflow feature like the one described in Laravel, the best approach is to design a state machine that tracks the booking’s state transitions. Here’s how you can implement it step-by-step:


1. State Machine Design in Laravel

A state machine is a programming paradigm that defines states, transitions, and the rules for moving between states. In Laravel, this can be implemented efficiently using:

  1. State Pattern: Build your custom state machine classes.
  2. State Machine Packages: Use a Laravel package for managing workflows, such as:

2. Database Design for State Management

Add a status column and a auto_cancel_at column in your bookings table to track the booking state and cancellation deadlines.

Example Migration:

Schema::table('bookings', function (Blueprint $table) {
    $table->enum('status', [
        'Pending',
        'Auto-Cancelled',
        'Confirmed',
        'Awaiting Payment',
        'Paid',
        'Vehicle Ready',
        'In Progress',
        'Completed',
        'Cancelled',
        'Refunded',
        'Issue Reported',
    ])->default('Pending');

    $table->timestamp('auto_cancel_at')->nullable();
});

3. State Machine Implementation

Option A: Using Laravel State Machine Package

  1. Install Laravel State Machine: composer require wix-incubator/laravel-state-machine
  2. Define Booking States and Transitions: Create a BookingStateMachine
namespace App\StateMachines;

use Asantibanez\LaravelEloquentStateMachines\StateMachines\StateMachine;

class BookingStateMachine extends StateMachine
{
    public function transitions(): array
    {
        return [
            'Pending' => ['Confirmed', 'Auto-Cancelled'],
            'Confirmed' => ['Paid', 'Auto-Cancelled'],
            'Paid' => ['Vehicle Ready'],
            'Vehicle Ready' => ['In Progress'],
            'In Progress' => ['Completed', 'Issue Reported'],
            'Cancelled' => ['Refunded'],
        ];
    }

    public function defaultState(): ?string
    {
        return 'Pending';
    }
}
  1. Attach State Machine to Booking Model:
namespace App\Models;

use Asantibanez\LaravelEloquentStateMachines\Traits\HasStateMachines;
use Illuminate\Database\Eloquent\Model;

class Booking extends Model
{
    use HasStateMachines;

    public $stateMachines = [
        'status' => BookingStateMachine::class,
    ];
}

  1. Use Transitions in Code:
$booking = Booking::find(1);

if ($booking->canTransitionTo('Confirmed')) {
    $booking->transitionTo('Confirmed');
}

if ($booking->status === 'Confirmed' && now()->greaterThan($booking->auto_cancel_at)) {
    $booking->transitionTo('Auto-Cancelled');
}

Option B: Custom State Machine Without a Package

  1. Create a State Machine Service: Create a service class to handle state transitions.
namespace App\Services;

use App\Models\Booking;

class BookingStateMachine
{
    private $transitions = [
        'Pending' => ['Confirmed', 'Auto-Cancelled'],
        'Confirmed' => ['Paid', 'Auto-Cancelled'],
        'Paid' => ['Vehicle Ready'],
        'Vehicle Ready' => ['In Progress'],
        'In Progress' => ['Completed', 'Issue Reported'],
        'Cancelled' => ['Refunded'],
    ];

    public function canTransition(Booking $booking, string $newState): bool
    {
        $currentState = $booking->status;

        return in_array($newState, $this->transitions[$currentState] ?? []);
    }

    public function transition(Booking $booking, string $newState)
    {
        if (!$this->canTransition($booking, $newState)) {
            throw new \Exception("Cannot transition from {$booking->status} to {$newState}");
        }

        $booking->status = $newState;
        $booking->save();
    }
}
  1. Use the State Machine Service:
$stateMachine = new \App\Services\BookingStateMachine();

$booking = Booking::find(1);

if ($stateMachine->canTransition($booking, 'Confirmed')) {
    $stateMachine->transition($booking, 'Confirmed');
}

4. Implementing Auto-Cancellation

Step 1: Add Logic to Handle Timeouts

Use a Laravel Scheduled Job to periodically check and auto-cancel bookings.

Create Job:

namespace App\Jobs;

use App\Models\Booking;

class AutoCancelBookings extends Job
{
    public function handle()
    {
        // Auto-cancel Pending bookings not confirmed in time
        Booking::where('status', 'Pending')
            ->where('auto_cancel_at', '<=', now())
            ->update(['status' => 'Auto-Cancelled']);

        // Auto-cancel Confirmed bookings not paid in time
        Booking::where('status', 'Confirmed')
            ->where('auto_cancel_at', '<=', now())
            ->update(['status' => 'Auto-Cancelled']);
    }
}

Schedule Job: Add the job to app/Console/Kernel.php:

protected function schedule(Schedule $schedule)
{
    $schedule->job(new AutoCancelBookings)->everyMinute();
}

Step 2: Set Auto-Cancellation Deadline

Set the auto_cancel_at timestamp when the booking enters Pending or Confirmed state.

Example:

$booking = Booking::create([
    'status' => 'Pending',
    'auto_cancel_at' => now()->addHour(),
]);

// If Partner confirms:
$booking->update([
    'status' => 'Confirmed',
    'auto_cancel_at' => now()->addHour(),
]);

5. Notifications

Use Laravel Notifications for real-time updates to Renters and Partners.

  1. Create Notifications: php artisan make:notification BookingStatusChanged
  2. Send Notifications:
Notification::send($booking->renter, new BookingStatusChanged($booking));
Notification::send($booking->partner, new BookingStatusChanged($booking));

6. Frontend Representation

Display the Current State:

Use badges or a progress bar to show the booking state:

<div>
    <span class="badge bg-primary">{{ $booking->status }}</span>
</div>

Show Countdown Timer:

For time-sensitive states like Pending or Awaiting Payment:

<div>
    <p>Time remaining: <span id="countdown"></span></p>
</div>

<script>
    const deadline = new Date("{{ $booking->auto_cancel_at }}").getTime();
    const countdownElement = document.getElementById("countdown");

    setInterval(() => {
        const now = new Date().getTime();
        const distance = deadline - now;

        if (distance <= 0) {
            countdownElement.innerText = "Expired";
        } else {
            const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
            const seconds = Math.floor((distance % (1000 * 60)) / 1000);
            countdownElement.innerText = `${minutes}m ${seconds}s`;
        }
    }, 1000);
</script>

This approach provides a clean, extensible, and maintainable way to manage workflows in Laravel, ensuring automatic cancellations and real-time updates for MotoShare.in. Let me know if you’d like further elaboration or assistance!

Here’s a professional concept you can use to create the Booking Workflow Diagram in a tool like Lucidchart, Draw.io, or PowerPoint:


Steps to Create the Diagram

  1. Diagram Tool: Open a diagramming tool such as Lucidchart, Draw.io, or Microsoft PowerPoint.
  2. Nodes (States): Add rounded rectangles for each state. Use the colors listed earlier for distinction.
  3. Transitions: Draw directional arrows between the states with labels explaining the trigger.

Text Representation to Guide Your Diagram

State Layout

  • Top Layer:
    • Pending → (to the right) Confirmed
    • Pending → (down) Auto-Cancelled
  • Middle Layer:
    • Confirmed → (to the right) Paid
    • Confirmed → (down) Auto-Cancelled
  • Lower Layers:
    • PaidVehicle ReadyIn ProgressCompleted
    • In Progress → (down) Issue Reported
    • Issue Reported → (back up) Completed
    • Any State → CancelledRefunded

Workflow States (Diagram Elements)

State NameColorPositionConnected To
PendingGreyTop centerConfirmed, Auto-Cancelled
Auto-CancelledYellowBelow PendingTrigger: No confirmation within 1 hour
ConfirmedBlueRight of PendingPaid, Auto-Cancelled
Awaiting PaymentOrangeBelow ConfirmedTrigger: Awaiting payment (optional; before Paid)
PaidGreenRight of ConfirmedVehicle Ready
Vehicle ReadyPurpleRight of PaidIn Progress
In ProgressCyanRight of Vehicle ReadyCompleted, Issue Reported
CompletedDark GreenRight of In ProgressFinal State
CancelledRedBottom centerTrigger: Manual cancellation
RefundedLight BlueBelow CancelledTrigger: Refund after cancellation
Issue ReportedOrange-RedBelow In ProgressTrigger: Any issues (damage, delay)

Example Triggers for Arrows

  • Pending → Confirmed: “Partner Confirms Booking.”
  • Pending → Auto-Cancelled: “No confirmation within 1 hour.”
  • Confirmed → Paid: “Payment Completed.”
  • Confirmed → Auto-Cancelled: “No payment within 1 hour.”
  • In Progress → Issue Reported: “Issue Raised by Renter/Partner.”
  • Issue Reported → Completed: “Issue Resolved.”

Final Touches

  • Include a Legend for color-coding (e.g., Completed = Green, Auto-Cancelled = Yellow).
  • Add a Title: “Booking Workflow for MotoShare.in.”
  • Annotate arrows for clarity.

Let me know if you need more assistance or adjustments!