feat: duplicate an accommodation booking into a new draft

addresses #869f6z44f
This commit is contained in:
fromme committed 2026-09-28 08:55:01 +02:00
1 parent 2aa98b81fe
commit 29f295abf6
9 files changed
+470

No files matched your search

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Tests\Entity\Groups;
use App\Entity\Groups\AccommodationBooking;
use App\Entity\User;
use App\Enum\Groups\AccommodationBookingOrigin;
use App\Enum\Groups\AccommodationBookingStatus;
use App\Exception\ImplausibleBookingPriceException;
@@ -131,4 +132,117 @@ class AccommodationBookingTest extends TestCase
self::assertSame('Buchung', $booking->recordLabel(), $origin->value);
}
}
public function testACopyGetsItsOwnIdentityAndAccessLinkToken(): void
{
// Two records behind one uuid would mean two records behind one customer access link.
$booking = $this->confirmedBooking();
$copy = clone $booking;
self::assertNull($copy->getId());
self::assertNotSame($booking->getUuid(), $copy->getUuid());
}
public function testACopyStartsAsAFreshOfficeDraftThatNobodyHasSeen(): void
{
$booking = $this->confirmedBooking();
$copy = clone $booking;
self::assertSame(AccommodationBookingStatus::Draft, $copy->getStatus());
self::assertSame(AccommodationBookingOrigin::Offer, $copy->getOrigin());
self::assertNull($copy->getAccessLinkIssuedAt());
self::assertNull($copy->getAcceptedAt());
self::assertNull($copy->getConfirmedAt());
self::assertNull($copy->getUpdatedAt());
self::assertNull($copy->getCreatedBy());
self::assertNull($copy->getUpdatedBy());
self::assertSame('Angebot', $copy->recordLabel());
}
public function testACopyCarriesThePricingAndTheDiscountsVerbatim(): void
{
// The copy is a variation of an offer that was already quoted, so it shows the same
// numbers rather than a re-quote at today's catalog prices.
$booking = $this->confirmedBooking();
$copy = clone $booking;
self::assertSame($booking->getPriceBreakdown(), $copy->getPriceBreakdown());
self::assertSame($booking->getTotalPrice(), $copy->getTotalPrice());
self::assertSame($booking->getPricingCurrency(), $copy->getPricingCurrency());
self::assertSame($booking->getPricingVersion(), $copy->getPricingVersion());
self::assertSame(10, $copy->getAccommodationDiscount());
self::assertSame(5, $copy->getBoardServiceDiscount());
self::assertSame(20, $copy->getAdditionalServicesDiscount());
self::assertSame(2500, $copy->getTotalDiscountAmount());
self::assertSame('Treuerabatt', $copy->getTotalDiscountLabel());
}
public function testACopyKeepsWhatTheOfficeWouldOtherwiseKeyInAgain(): void
{
$booking = $this->confirmedBooking();
$copy = clone $booking;
self::assertSame($booking->getDateFrom(), $copy->getDateFrom());
self::assertSame($booking->getDateTo(), $copy->getDateTo());
self::assertSame(42, $copy->getPaxCount());
self::assertSame('Vollpension', $copy->getBoardServiceLabel());
self::assertSame(1900, $copy->getBoardServicePrice());
self::assertSame(7, $copy->getBoardServiceOriginalId());
self::assertSame($booking->getAdditionalServices(), $copy->getAdditionalServices());
self::assertSame('Skiclub Nord', $copy->getGroupName());
self::assertSame('[email protected]', $copy->getEmail());
}
public function testCloningLeavesTheOriginalAlone(): void
{
$booking = $this->confirmedBooking();
clone $booking;
self::assertSame(AccommodationBookingStatus::Confirmed, $booking->getStatus());
self::assertNotNull($booking->getAcceptedAt());
self::assertNotNull($booking->getConfirmedAt());
self::assertSame('Skiclub Nord', $booking->getGroupName());
}
/**
* A record that has been all the way through the lifecycle, so a copy of it has the most
* to reset.
*/
private function confirmedBooking(): AccommodationBooking
{
$now = new \DateTimeImmutable('2026-01-15 10:00:00');
$booking = new AccommodationBooking();
$booking->setStatus(AccommodationBookingStatus::Confirmed);
$booking->setOrigin(AccommodationBookingOrigin::Direct);
$booking->setAccessLinkIssuedAt($now);
$booking->setAcceptedAt($now);
$booking->setConfirmedAt($now);
$booking->setCreatedAt($now);
$booking->setUpdatedAt($now);
$booking->setCreatedBy(new User('[email protected]'));
$booking->setUpdatedBy(new User('[email protected]'));
$booking->setDateFrom(new \DateTimeImmutable('2026-03-01'));
$booking->setDateTo(new \DateTimeImmutable('2026-03-08'));
$booking->setPaxCount(42);
$booking->setGroupName('Skiclub Nord');
$booking->setEmail('[email protected]');
$booking->setBoardServiceLabel('Vollpension');
$booking->setBoardServicePrice(1900);
$booking->setBoardServiceOriginalId(7);
$booking->addAdditionalServiceSnapshot('Skipass', 12000, 'per_person', 3);
$booking->setAccommodationDiscount(10);
$booking->setBoardServiceDiscount(5);
$booking->setAdditionalServicesDiscount(20);
$booking->setTotalDiscountAmount(2500);
$booking->setTotalDiscountLabel('Treuerabatt');
$booking->setPriceSnapshot(['total' => 500000], 480000, 'EUR', 1);
return $booking;
}
}