feat: refactored accommodation booking status model
This commit is contained in:
@@ -6,8 +6,8 @@ namespace App\Tests\Controller\Admin\AccommodationBooking;
|
||||
|
||||
use App\Controller\Admin\AccommodationBooking\EditController;
|
||||
use App\Entity\Groups\AccommodationBooking;
|
||||
use App\Enum\Groups\AccommodationBookingStatus;
|
||||
use App\Entity\User;
|
||||
use App\Enum\Groups\AccommodationBookingStatus;
|
||||
use App\Repository\Groups\AdditionalServiceRepository;
|
||||
use App\Repository\Groups\BoardServiceRepository;
|
||||
use App\Repository\UserRepository;
|
||||
@@ -20,79 +20,47 @@ use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Covers the status transition side effects only — the service and form behaviour
|
||||
* they build on is tested in AccommodationBookingServiceTest.
|
||||
* Covers what editing must NOT do — it never moves the booking on and never mails the
|
||||
* customer — plus the Betreuer choices. The transitions themselves belong to the named
|
||||
* actions and are tested in AccommodationBookingServiceTest and the action controllers.
|
||||
*/
|
||||
class EditControllerTest extends TestCase
|
||||
{
|
||||
public function testTransitionToOpenIssuesAccessLinkAndSendsCustomerEmail(): void
|
||||
{
|
||||
$bookingService = $this->assertNotified(AccommodationBookingStatus::Open);
|
||||
|
||||
$this->submitStatusChange(AccommodationBookingStatus::Draft, AccommodationBookingStatus::Open, $bookingService);
|
||||
}
|
||||
|
||||
public function testTransitionToConfirmedSendsNothing(): void
|
||||
{
|
||||
// The binding confirmation only ever goes out through the explicit confirm action,
|
||||
// never as a side effect of editing the status.
|
||||
$bookingService = $this->assertNotNotified();
|
||||
|
||||
$this->submitStatusChange(AccommodationBookingStatus::Received, AccommodationBookingStatus::Confirmed, $bookingService);
|
||||
}
|
||||
|
||||
public function testTransitionToDiscardedSendsNothing(): void
|
||||
{
|
||||
$bookingService = $this->assertNotNotified();
|
||||
|
||||
$this->submitStatusChange(AccommodationBookingStatus::Open, AccommodationBookingStatus::Discarded, $bookingService);
|
||||
}
|
||||
|
||||
public function testSavingWithoutStatusChangeSendsNothing(): void
|
||||
{
|
||||
$bookingService = $this->assertNotNotified();
|
||||
|
||||
$this->submitStatusChange(AccommodationBookingStatus::Confirmed, AccommodationBookingStatus::Confirmed, $bookingService);
|
||||
}
|
||||
|
||||
private function assertNotified(AccommodationBookingStatus $expected): AccommodationBookingService
|
||||
{
|
||||
$bookingService = $this->createMock(AccommodationBookingService::class);
|
||||
$bookingService->expects(self::once())->method('refreshPriceSnapshot');
|
||||
$bookingService
|
||||
->expects(self::once())
|
||||
->method('issueAccessLink')
|
||||
->with(self::callback(static fn (AccommodationBooking $booking) => $expected === $booking->getStatus()));
|
||||
$bookingService->expects(self::once())->method('sendCustomerConfirmationEmail');
|
||||
|
||||
return $bookingService;
|
||||
}
|
||||
|
||||
private function assertNotNotified(): AccommodationBookingService
|
||||
/**
|
||||
* @dataProvider everyStatus
|
||||
*/
|
||||
public function testSavingNeverNotifiesTheCustomer(AccommodationBookingStatus $status): void
|
||||
{
|
||||
// Sending used to be a side effect of saving a status change, which is how an inquiry
|
||||
// that arrived already Offen could never be offered at all. Editing is now inert.
|
||||
$bookingService = $this->createMock(AccommodationBookingService::class);
|
||||
$bookingService->expects(self::once())->method('refreshPriceSnapshot');
|
||||
$bookingService->expects(self::never())->method('issueAccessLink');
|
||||
$bookingService->expects(self::never())->method('sendCustomerConfirmationEmail');
|
||||
$bookingService->expects(self::never())->method('sendOffer');
|
||||
|
||||
return $bookingService;
|
||||
$booking = new AccommodationBooking();
|
||||
$booking->setStatus($status);
|
||||
|
||||
$this->submitEdit($booking, $bookingService);
|
||||
|
||||
self::assertSame($status, $booking->getStatus(), 'editing leaves the status where it was');
|
||||
}
|
||||
|
||||
private function submitStatusChange(
|
||||
AccommodationBookingStatus $from,
|
||||
AccommodationBookingStatus $to,
|
||||
AccommodationBookingService $bookingService,
|
||||
): void {
|
||||
$booking = new AccommodationBooking();
|
||||
$booking->setStatus($from);
|
||||
/**
|
||||
* @return iterable<string, array{AccommodationBookingStatus}>
|
||||
*/
|
||||
public static function everyStatus(): iterable
|
||||
{
|
||||
foreach (AccommodationBookingStatus::cases() as $status) {
|
||||
yield $status->value => [$status];
|
||||
}
|
||||
}
|
||||
|
||||
// The form is what moves the entity to its new status during handleRequest().
|
||||
private function submitEdit(AccommodationBooking $booking, AccommodationBookingService $bookingService): void
|
||||
{
|
||||
$form = $this->createMock(FormInterface::class);
|
||||
$form->method('handleRequest')->willReturnCallback(static function () use ($booking, $to, $form) {
|
||||
$booking->setStatus($to);
|
||||
|
||||
return $form;
|
||||
});
|
||||
$form->method('handleRequest')->willReturn($form);
|
||||
$form->method('isSubmitted')->willReturn(true);
|
||||
$form->method('isValid')->willReturn(true);
|
||||
$form->method('has')->willReturn(false);
|
||||
|
||||
Reference in New Issue
Block a user