register(PaymentMethod::KbzMiniApp, FakeCancelRefundGateway::class); }); test('it cancels a pending_payment booking directly', function () { $booking = Booking::factory()->create(['status' => BookingStatus::PendingPayment]); $cancelled = app(CancelBookingAction::class)->handle($booking); expect($cancelled->status)->toBe(BookingStatus::Cancelled) ->and($booking->refresh()->status)->toBe(BookingStatus::Cancelled); }); test('it cancels a confirmed booking by refunding it in full', function () { $booking = Booking::factory()->create(['status' => BookingStatus::Confirmed, 'price' => 15000]); Payment::factory()->completed()->create([ 'booking_id' => $booking->id, 'gateway' => PaymentMethod::KbzMiniApp, 'amount' => 15000, 'gateway_transaction_id' => 'EVB-CANCEL-TEST-1', ]); $cancelled = app(CancelBookingAction::class)->handle($booking); expect($cancelled->status)->toBe(BookingStatus::Cancelled) ->and(FakeCancelRefundGateway::$lastAmount)->toBe('15000.00'); }); test('it guards against cancelling an already cancelled booking', function () { $booking = Booking::factory()->create(['status' => BookingStatus::Cancelled]); expect(fn () => app(CancelBookingAction::class)->handle($booking)) ->toThrow(BookingCannotBeCancelledException::class); }); test('it guards against cancelling an expired booking', function () { $booking = Booking::factory()->create(['status' => BookingStatus::Expired]); expect(fn () => app(CancelBookingAction::class)->handle($booking)) ->toThrow(BookingCannotBeCancelledException::class); });