create(['status' => BookingStatus::Confirmed]); $updated = (new AssignDriverAction)->handle($booking, new AssignDriverData( driverName: 'U Aung', driverPhone: '+959111222333', carPlateNumber: 'YGN-1234', carModel: 'Tesla Model Y', )); expect($updated->driver_name)->toBe('U Aung') ->and($updated->driver_phone)->toBe('+959111222333') ->and($updated->car_plate_number)->toBe('YGN-1234') ->and($updated->car_model)->toBe('Tesla Model Y') ->and($booking->refresh()->driver_name)->toBe('U Aung'); }); test('it dispatches DriverAssigned with isFirstAssignment true for a booking with no prior driver', function () { Event::fake([DriverAssigned::class]); $booking = Booking::factory()->create(['status' => BookingStatus::Confirmed]); (new AssignDriverAction)->handle($booking, new AssignDriverData( driverName: 'U Aung', driverPhone: '+959111222333', carPlateNumber: 'YGN-1234', )); Event::assertDispatched(DriverAssigned::class, fn (DriverAssigned $event) => $event->booking->is($booking) && $event->isFirstAssignment === true); }); test('it dispatches DriverAssigned with isFirstAssignment false when reassigning', function () { Event::fake([DriverAssigned::class]); $booking = Booking::factory()->create([ 'status' => BookingStatus::Confirmed, 'driver_name' => 'U Aung', 'driver_phone' => '+959111222333', 'car_plate_number' => 'YGN-1234', ]); (new AssignDriverAction)->handle($booking, new AssignDriverData( driverName: 'Daw Hla', driverPhone: '+959444555666', carPlateNumber: 'YGN-5678', )); Event::assertDispatched(DriverAssigned::class, fn (DriverAssigned $event) => $event->isFirstAssignment === false); }); test('it does not dispatch DriverAssigned again when resubmitted with identical driver/car details', function () { Event::fake([DriverAssigned::class]); $booking = Booking::factory()->create([ 'status' => BookingStatus::Confirmed, 'driver_name' => 'U Aung', 'driver_phone' => '+959111222333', 'car_plate_number' => 'YGN-1234', 'car_model' => 'Tesla Model Y', ]); (new AssignDriverAction)->handle($booking, new AssignDriverData( driverName: 'U Aung', driverPhone: '+959111222333', carPlateNumber: 'YGN-1234', carModel: 'Tesla Model Y', )); Event::assertNotDispatched(DriverAssigned::class); }); test('car_model is optional', function () { $booking = Booking::factory()->create(['status' => BookingStatus::Confirmed]); $updated = (new AssignDriverAction)->handle($booking, new AssignDriverData( driverName: 'U Aung', driverPhone: '+959111222333', carPlateNumber: 'YGN-1234', )); expect($updated->car_model)->toBeNull(); }); test('it guards against assigning a driver to a pending_payment booking', function () { $booking = Booking::factory()->create(['status' => BookingStatus::PendingPayment]); expect(fn () => (new AssignDriverAction)->handle($booking, new AssignDriverData( driverName: 'U Aung', driverPhone: '+959111222333', carPlateNumber: 'YGN-1234', )))->toThrow(DriverAssignmentNotAllowedException::class); expect($booking->refresh()->driver_name)->toBeNull(); }); test('it guards against assigning a driver when the travel date has already passed', function () { $booking = Booking::factory()->create([ 'status' => BookingStatus::Confirmed, 'travel_date' => today()->subDay(), ]); expect(fn () => (new AssignDriverAction)->handle($booking, new AssignDriverData( driverName: 'U Aung', driverPhone: '+959111222333', carPlateNumber: 'YGN-1234', )))->toThrow(DriverAssignmentNotAllowedException::class); expect($booking->refresh()->driver_name)->toBeNull(); }); test('it allows assigning a driver when the travel date is today', function () { $booking = Booking::factory()->create([ 'status' => BookingStatus::Confirmed, 'travel_date' => today(), ]); $updated = (new AssignDriverAction)->handle($booking, new AssignDriverData( driverName: 'U Aung', driverPhone: '+959111222333', carPlateNumber: 'YGN-1234', )); expect($updated->driver_name)->toBe('U Aung'); }); test('it guards against assigning a driver to a cancelled booking', function () { $booking = Booking::factory()->create(['status' => BookingStatus::Cancelled]); expect(fn () => (new AssignDriverAction)->handle($booking, new AssignDriverData( driverName: 'U Aung', driverPhone: '+959111222333', carPlateNumber: 'YGN-1234', )))->toThrow(DriverAssignmentNotAllowedException::class); }); test('reassigning a different driver on a still-confirmed booking overwrites the previous values', function () { $booking = Booking::factory()->create([ 'status' => BookingStatus::Confirmed, 'driver_name' => 'U Aung', 'driver_phone' => '+959111222333', 'car_plate_number' => 'YGN-1234', ]); (new AssignDriverAction)->handle($booking, new AssignDriverData( driverName: 'Daw Hla', driverPhone: '+959444555666', carPlateNumber: 'YGN-5678', )); expect($booking->refresh()->driver_name)->toBe('Daw Hla') ->and($booking->car_plate_number)->toBe('YGN-5678'); }); test('a round trip: assigning a driver to the outbound leg does not touch the linked return leg', function () { $outbound = Booking::factory()->create(['status' => BookingStatus::Confirmed]); $return = Booking::factory()->create([ 'status' => BookingStatus::Confirmed, 'is_return_leg' => true, 'linked_booking_id' => $outbound->id, ]); $outbound->update(['linked_booking_id' => $return->id]); (new AssignDriverAction)->handle($outbound, new AssignDriverData( driverName: 'U Aung', driverPhone: '+959111222333', carPlateNumber: 'YGN-1234', )); // Each leg has its own independent driver/vehicle slot — the return leg // can get a completely different (or no-yet-assigned) vehicle, per the // "next available vehicle" business rule (domain.md §2b). expect($outbound->refresh()->driver_name)->toBe('U Aung') ->and($return->refresh()->driver_name)->toBeNull(); });