Add BilletOrder entity, PDF generation, email with QR codes, public order page
- BilletOrder entity: individual tickets with unique ETICKET-XXXX reference,
billetBuyer link, billet link, isScanned, scannedAt for entry control
- BilletOrderService: generates tickets after payment, creates A4 PDF with
BilletDesign colors if present (default otherwise), real QR code via
endroid/qr-code, event poster + org logo as base64, sends confirmation
email with all ticket PDFs attached
- PDF template (pdf/billet.html.twig): A4 layout matching preview design,
real QR code linking to /ticket/verify/{reference}
- Email template: order recap table, ticket references list, link to
/ma-commande/{reference}
- Public order page /ma-commande/{reference}: no auth required, shows
order details, ticket list with individual PDF download links
- Ticket verification page /ticket/verify/{reference}: shows valid/scanned
status with ticket and event details
- Download route /ma-commande/{ref}/billet/{ticketRef}: generates PDF on-the-fly
- Migration for billet_order table with unique reference index
- BilletOrderTest: 8 tests, 24 assertions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:04:45 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Tests\Entity;
|
|
|
|
|
|
|
|
|
|
use App\Entity\Billet;
|
|
|
|
|
use App\Entity\BilletBuyer;
|
|
|
|
|
use App\Entity\BilletOrder;
|
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
|
|
|
|
|
|
class BilletOrderTest extends TestCase
|
|
|
|
|
{
|
|
|
|
|
public function testDefaults(): void
|
|
|
|
|
{
|
|
|
|
|
$ticket = new BilletOrder();
|
|
|
|
|
|
|
|
|
|
self::assertNull($ticket->getId());
|
|
|
|
|
self::assertNull($ticket->getBilletBuyer());
|
|
|
|
|
self::assertNull($ticket->getBillet());
|
|
|
|
|
self::assertNull($ticket->getBilletName());
|
|
|
|
|
self::assertSame(0, $ticket->getUnitPriceHT());
|
|
|
|
|
self::assertSame(0.0, $ticket->getUnitPriceHTDecimal());
|
2026-03-21 14:15:32 +01:00
|
|
|
self::assertSame(BilletOrder::STATE_VALID, $ticket->getState());
|
|
|
|
|
self::assertTrue($ticket->isValid());
|
2026-03-21 16:43:59 +01:00
|
|
|
self::assertSame('', $ticket->getSecurityKey());
|
2026-03-21 16:36:29 +01:00
|
|
|
self::assertNull($ticket->isInvitation());
|
2026-03-21 14:15:32 +01:00
|
|
|
self::assertNull($ticket->getFirstScannedAt());
|
Add BilletOrder entity, PDF generation, email with QR codes, public order page
- BilletOrder entity: individual tickets with unique ETICKET-XXXX reference,
billetBuyer link, billet link, isScanned, scannedAt for entry control
- BilletOrderService: generates tickets after payment, creates A4 PDF with
BilletDesign colors if present (default otherwise), real QR code via
endroid/qr-code, event poster + org logo as base64, sends confirmation
email with all ticket PDFs attached
- PDF template (pdf/billet.html.twig): A4 layout matching preview design,
real QR code linking to /ticket/verify/{reference}
- Email template: order recap table, ticket references list, link to
/ma-commande/{reference}
- Public order page /ma-commande/{reference}: no auth required, shows
order details, ticket list with individual PDF download links
- Ticket verification page /ticket/verify/{reference}: shows valid/scanned
status with ticket and event details
- Download route /ma-commande/{ref}/billet/{ticketRef}: generates PDF on-the-fly
- Migration for billet_order table with unique reference index
- BilletOrderTest: 8 tests, 24 assertions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:04:45 +01:00
|
|
|
self::assertMatchesRegularExpression('/^ETICKET-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/', $ticket->getReference());
|
|
|
|
|
self::assertInstanceOf(\DateTimeImmutable::class, $ticket->getCreatedAt());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testSetAndGetBilletBuyer(): void
|
|
|
|
|
{
|
|
|
|
|
$ticket = new BilletOrder();
|
|
|
|
|
$buyer = new BilletBuyer();
|
|
|
|
|
$result = $ticket->setBilletBuyer($buyer);
|
|
|
|
|
|
|
|
|
|
self::assertSame($buyer, $ticket->getBilletBuyer());
|
|
|
|
|
self::assertSame($ticket, $result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testSetAndGetBillet(): void
|
|
|
|
|
{
|
|
|
|
|
$ticket = new BilletOrder();
|
|
|
|
|
$billet = new Billet();
|
|
|
|
|
$result = $ticket->setBillet($billet);
|
|
|
|
|
|
|
|
|
|
self::assertSame($billet, $ticket->getBillet());
|
|
|
|
|
self::assertSame($ticket, $result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testSetAndGetBilletName(): void
|
|
|
|
|
{
|
|
|
|
|
$ticket = new BilletOrder();
|
|
|
|
|
$result = $ticket->setBilletName('Entree VIP');
|
|
|
|
|
|
|
|
|
|
self::assertSame('Entree VIP', $ticket->getBilletName());
|
|
|
|
|
self::assertSame($ticket, $result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testSetAndGetUnitPriceHT(): void
|
|
|
|
|
{
|
|
|
|
|
$ticket = new BilletOrder();
|
|
|
|
|
$result = $ticket->setUnitPriceHT(1500);
|
|
|
|
|
|
|
|
|
|
self::assertSame(1500, $ticket->getUnitPriceHT());
|
|
|
|
|
self::assertSame(15.0, $ticket->getUnitPriceHTDecimal());
|
|
|
|
|
self::assertSame($ticket, $result);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-21 14:15:32 +01:00
|
|
|
public function testSetAndGetState(): void
|
Add BilletOrder entity, PDF generation, email with QR codes, public order page
- BilletOrder entity: individual tickets with unique ETICKET-XXXX reference,
billetBuyer link, billet link, isScanned, scannedAt for entry control
- BilletOrderService: generates tickets after payment, creates A4 PDF with
BilletDesign colors if present (default otherwise), real QR code via
endroid/qr-code, event poster + org logo as base64, sends confirmation
email with all ticket PDFs attached
- PDF template (pdf/billet.html.twig): A4 layout matching preview design,
real QR code linking to /ticket/verify/{reference}
- Email template: order recap table, ticket references list, link to
/ma-commande/{reference}
- Public order page /ma-commande/{reference}: no auth required, shows
order details, ticket list with individual PDF download links
- Ticket verification page /ticket/verify/{reference}: shows valid/scanned
status with ticket and event details
- Download route /ma-commande/{ref}/billet/{ticketRef}: generates PDF on-the-fly
- Migration for billet_order table with unique reference index
- BilletOrderTest: 8 tests, 24 assertions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:04:45 +01:00
|
|
|
{
|
|
|
|
|
$ticket = new BilletOrder();
|
2026-03-21 14:15:32 +01:00
|
|
|
$result = $ticket->setState(BilletOrder::STATE_INVALID);
|
Add BilletOrder entity, PDF generation, email with QR codes, public order page
- BilletOrder entity: individual tickets with unique ETICKET-XXXX reference,
billetBuyer link, billet link, isScanned, scannedAt for entry control
- BilletOrderService: generates tickets after payment, creates A4 PDF with
BilletDesign colors if present (default otherwise), real QR code via
endroid/qr-code, event poster + org logo as base64, sends confirmation
email with all ticket PDFs attached
- PDF template (pdf/billet.html.twig): A4 layout matching preview design,
real QR code linking to /ticket/verify/{reference}
- Email template: order recap table, ticket references list, link to
/ma-commande/{reference}
- Public order page /ma-commande/{reference}: no auth required, shows
order details, ticket list with individual PDF download links
- Ticket verification page /ticket/verify/{reference}: shows valid/scanned
status with ticket and event details
- Download route /ma-commande/{ref}/billet/{ticketRef}: generates PDF on-the-fly
- Migration for billet_order table with unique reference index
- BilletOrderTest: 8 tests, 24 assertions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:04:45 +01:00
|
|
|
|
2026-03-21 14:15:32 +01:00
|
|
|
self::assertSame(BilletOrder::STATE_INVALID, $ticket->getState());
|
|
|
|
|
self::assertFalse($ticket->isValid());
|
Add BilletOrder entity, PDF generation, email with QR codes, public order page
- BilletOrder entity: individual tickets with unique ETICKET-XXXX reference,
billetBuyer link, billet link, isScanned, scannedAt for entry control
- BilletOrderService: generates tickets after payment, creates A4 PDF with
BilletDesign colors if present (default otherwise), real QR code via
endroid/qr-code, event poster + org logo as base64, sends confirmation
email with all ticket PDFs attached
- PDF template (pdf/billet.html.twig): A4 layout matching preview design,
real QR code linking to /ticket/verify/{reference}
- Email template: order recap table, ticket references list, link to
/ma-commande/{reference}
- Public order page /ma-commande/{reference}: no auth required, shows
order details, ticket list with individual PDF download links
- Ticket verification page /ticket/verify/{reference}: shows valid/scanned
status with ticket and event details
- Download route /ma-commande/{ref}/billet/{ticketRef}: generates PDF on-the-fly
- Migration for billet_order table with unique reference index
- BilletOrderTest: 8 tests, 24 assertions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:04:45 +01:00
|
|
|
self::assertSame($ticket, $result);
|
2026-03-21 14:15:32 +01:00
|
|
|
|
|
|
|
|
$ticket->setState(BilletOrder::STATE_EXPIRED);
|
|
|
|
|
self::assertSame(BilletOrder::STATE_EXPIRED, $ticket->getState());
|
|
|
|
|
self::assertFalse($ticket->isValid());
|
|
|
|
|
|
|
|
|
|
$ticket->setState(BilletOrder::STATE_VALID);
|
|
|
|
|
self::assertTrue($ticket->isValid());
|
Add BilletOrder entity, PDF generation, email with QR codes, public order page
- BilletOrder entity: individual tickets with unique ETICKET-XXXX reference,
billetBuyer link, billet link, isScanned, scannedAt for entry control
- BilletOrderService: generates tickets after payment, creates A4 PDF with
BilletDesign colors if present (default otherwise), real QR code via
endroid/qr-code, event poster + org logo as base64, sends confirmation
email with all ticket PDFs attached
- PDF template (pdf/billet.html.twig): A4 layout matching preview design,
real QR code linking to /ticket/verify/{reference}
- Email template: order recap table, ticket references list, link to
/ma-commande/{reference}
- Public order page /ma-commande/{reference}: no auth required, shows
order details, ticket list with individual PDF download links
- Ticket verification page /ticket/verify/{reference}: shows valid/scanned
status with ticket and event details
- Download route /ma-commande/{ref}/billet/{ticketRef}: generates PDF on-the-fly
- Migration for billet_order table with unique reference index
- BilletOrderTest: 8 tests, 24 assertions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:04:45 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-21 16:43:59 +01:00
|
|
|
public function testSetAndGetSecurityKey(): void
|
|
|
|
|
{
|
|
|
|
|
$ticket = new BilletOrder();
|
|
|
|
|
$result = $ticket->setSecurityKey('ABC123');
|
|
|
|
|
|
|
|
|
|
self::assertSame('ABC123', $ticket->getSecurityKey());
|
|
|
|
|
self::assertSame($ticket, $result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testGenerateSecurityKey(): void
|
|
|
|
|
{
|
|
|
|
|
$key = BilletOrder::generateSecurityKey('ETICKET-ABCD-1234-EFGH', 'my-secret');
|
|
|
|
|
|
|
|
|
|
self::assertSame(16, \strlen($key));
|
|
|
|
|
self::assertMatchesRegularExpression('/^[A-F0-9]{16}$/', $key);
|
|
|
|
|
|
|
|
|
|
$key2 = BilletOrder::generateSecurityKey('ETICKET-ABCD-1234-EFGH', 'my-secret');
|
|
|
|
|
self::assertSame($key, $key2);
|
|
|
|
|
|
|
|
|
|
$key3 = BilletOrder::generateSecurityKey('ETICKET-XXXX-YYYY-ZZZZ', 'my-secret');
|
|
|
|
|
self::assertNotSame($key, $key3);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-21 16:36:29 +01:00
|
|
|
public function testSetAndGetIsInvitation(): void
|
|
|
|
|
{
|
|
|
|
|
$ticket = new BilletOrder();
|
|
|
|
|
$result = $ticket->setIsInvitation(true);
|
|
|
|
|
|
|
|
|
|
self::assertTrue($ticket->isInvitation());
|
|
|
|
|
self::assertSame($ticket, $result);
|
|
|
|
|
|
|
|
|
|
$ticket->setIsInvitation(null);
|
|
|
|
|
self::assertNull($ticket->isInvitation());
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-21 14:15:32 +01:00
|
|
|
public function testSetAndGetFirstScannedAt(): void
|
Add BilletOrder entity, PDF generation, email with QR codes, public order page
- BilletOrder entity: individual tickets with unique ETICKET-XXXX reference,
billetBuyer link, billet link, isScanned, scannedAt for entry control
- BilletOrderService: generates tickets after payment, creates A4 PDF with
BilletDesign colors if present (default otherwise), real QR code via
endroid/qr-code, event poster + org logo as base64, sends confirmation
email with all ticket PDFs attached
- PDF template (pdf/billet.html.twig): A4 layout matching preview design,
real QR code linking to /ticket/verify/{reference}
- Email template: order recap table, ticket references list, link to
/ma-commande/{reference}
- Public order page /ma-commande/{reference}: no auth required, shows
order details, ticket list with individual PDF download links
- Ticket verification page /ticket/verify/{reference}: shows valid/scanned
status with ticket and event details
- Download route /ma-commande/{ref}/billet/{ticketRef}: generates PDF on-the-fly
- Migration for billet_order table with unique reference index
- BilletOrderTest: 8 tests, 24 assertions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:04:45 +01:00
|
|
|
{
|
|
|
|
|
$ticket = new BilletOrder();
|
|
|
|
|
$date = new \DateTimeImmutable();
|
2026-03-21 14:15:32 +01:00
|
|
|
$result = $ticket->setFirstScannedAt($date);
|
Add BilletOrder entity, PDF generation, email with QR codes, public order page
- BilletOrder entity: individual tickets with unique ETICKET-XXXX reference,
billetBuyer link, billet link, isScanned, scannedAt for entry control
- BilletOrderService: generates tickets after payment, creates A4 PDF with
BilletDesign colors if present (default otherwise), real QR code via
endroid/qr-code, event poster + org logo as base64, sends confirmation
email with all ticket PDFs attached
- PDF template (pdf/billet.html.twig): A4 layout matching preview design,
real QR code linking to /ticket/verify/{reference}
- Email template: order recap table, ticket references list, link to
/ma-commande/{reference}
- Public order page /ma-commande/{reference}: no auth required, shows
order details, ticket list with individual PDF download links
- Ticket verification page /ticket/verify/{reference}: shows valid/scanned
status with ticket and event details
- Download route /ma-commande/{ref}/billet/{ticketRef}: generates PDF on-the-fly
- Migration for billet_order table with unique reference index
- BilletOrderTest: 8 tests, 24 assertions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:04:45 +01:00
|
|
|
|
2026-03-21 14:15:32 +01:00
|
|
|
self::assertSame($date, $ticket->getFirstScannedAt());
|
Add BilletOrder entity, PDF generation, email with QR codes, public order page
- BilletOrder entity: individual tickets with unique ETICKET-XXXX reference,
billetBuyer link, billet link, isScanned, scannedAt for entry control
- BilletOrderService: generates tickets after payment, creates A4 PDF with
BilletDesign colors if present (default otherwise), real QR code via
endroid/qr-code, event poster + org logo as base64, sends confirmation
email with all ticket PDFs attached
- PDF template (pdf/billet.html.twig): A4 layout matching preview design,
real QR code linking to /ticket/verify/{reference}
- Email template: order recap table, ticket references list, link to
/ma-commande/{reference}
- Public order page /ma-commande/{reference}: no auth required, shows
order details, ticket list with individual PDF download links
- Ticket verification page /ticket/verify/{reference}: shows valid/scanned
status with ticket and event details
- Download route /ma-commande/{ref}/billet/{ticketRef}: generates PDF on-the-fly
- Migration for billet_order table with unique reference index
- BilletOrderTest: 8 tests, 24 assertions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:04:45 +01:00
|
|
|
self::assertSame($ticket, $result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testUniqueReferences(): void
|
|
|
|
|
{
|
|
|
|
|
$t1 = new BilletOrder();
|
|
|
|
|
$t2 = new BilletOrder();
|
|
|
|
|
|
|
|
|
|
self::assertNotSame($t1->getReference(), $t2->getReference());
|
|
|
|
|
}
|
|
|
|
|
}
|