Replace isScanned with state (valid/invalid/expired) and firstScannedAt on BilletOrder

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Serreau Jovann
2026-03-21 14:15:32 +01:00
parent 2b48d2081f
commit 2efb5f176a
4 changed files with 75 additions and 21 deletions

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260321200000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Replace isScanned with state and firstScannedAt on billet_order';
}
public function up(Schema $schema): void
{
$this->addSql("ALTER TABLE billet_order ADD COLUMN IF NOT EXISTS state VARCHAR(20) DEFAULT 'valid' NOT NULL");
$this->addSql('ALTER TABLE billet_order ADD COLUMN IF NOT EXISTS first_scanned_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('ALTER TABLE billet_order DROP COLUMN IF EXISTS is_scanned');
$this->addSql('ALTER TABLE billet_order DROP COLUMN IF EXISTS scanned_at');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE billet_order ADD COLUMN IF NOT EXISTS is_scanned BOOLEAN DEFAULT false NOT NULL');
$this->addSql('ALTER TABLE billet_order ADD COLUMN IF NOT EXISTS scanned_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('ALTER TABLE billet_order DROP COLUMN IF EXISTS state');
$this->addSql('ALTER TABLE billet_order DROP COLUMN IF EXISTS first_scanned_at');
}
}

View File

@@ -30,11 +30,15 @@ class BilletOrder
#[ORM\Column]
private int $unitPriceHT = 0;
#[ORM\Column]
private bool $isScanned = false;
public const STATE_VALID = 'valid';
public const STATE_INVALID = 'invalid';
public const STATE_EXPIRED = 'expired';
#[ORM\Column(length: 20)]
private string $state = self::STATE_VALID;
#[ORM\Column(nullable: true)]
private ?\DateTimeImmutable $scannedAt = null;
private ?\DateTimeImmutable $firstScannedAt = null;
#[ORM\Column]
private \DateTimeImmutable $createdAt;
@@ -108,26 +112,31 @@ class BilletOrder
return $this->unitPriceHT / 100;
}
public function isScanned(): bool
public function getState(): string
{
return $this->isScanned;
return $this->state;
}
public function setIsScanned(bool $isScanned): static
public function setState(string $state): static
{
$this->isScanned = $isScanned;
$this->state = $state;
return $this;
}
public function getScannedAt(): ?\DateTimeImmutable
public function isValid(): bool
{
return $this->scannedAt;
return self::STATE_VALID === $this->state;
}
public function setScannedAt(?\DateTimeImmutable $scannedAt): static
public function getFirstScannedAt(): ?\DateTimeImmutable
{
$this->scannedAt = $scannedAt;
return $this->firstScannedAt;
}
public function setFirstScannedAt(?\DateTimeImmutable $firstScannedAt): static
{
$this->firstScannedAt = $firstScannedAt;
return $this;
}

View File

@@ -41,8 +41,12 @@
<p class="text-xs font-mono text-gray-400">{{ ticket.reference }}</p>
</div>
<span class="font-black text-sm text-indigo-600">{{ ticket.unitPriceHTDecimal|number_format(2, ',', ' ') }} &euro;</span>
{% if ticket.scanned %}
<span class="badge-yellow text-[10px] font-black uppercase">Scanne</span>
{% if ticket.state == 'valid' %}
<span class="badge-green text-[10px] font-black uppercase">Valide</span>
{% elseif ticket.state == 'expired' %}
<span class="badge-yellow text-[10px] font-black uppercase">Expire</span>
{% else %}
<span class="badge-red text-[10px] font-black uppercase">Invalide</span>
{% endif %}
<a href="{{ path('app_order_download_ticket', {reference: order.reference, ticketReference: ticket.reference}) }}" class="px-3 py-1 border-2 border-gray-900 bg-white text-xs font-black uppercase hover:bg-indigo-600 hover:text-white transition-all" target="_blank">
Telecharger PDF

View File

@@ -19,8 +19,9 @@ class BilletOrderTest extends TestCase
self::assertNull($ticket->getBilletName());
self::assertSame(0, $ticket->getUnitPriceHT());
self::assertSame(0.0, $ticket->getUnitPriceHTDecimal());
self::assertFalse($ticket->isScanned());
self::assertNull($ticket->getScannedAt());
self::assertSame(BilletOrder::STATE_VALID, $ticket->getState());
self::assertTrue($ticket->isValid());
self::assertNull($ticket->getFirstScannedAt());
self::assertMatchesRegularExpression('/^ETICKET-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/', $ticket->getReference());
self::assertInstanceOf(\DateTimeImmutable::class, $ticket->getCreatedAt());
}
@@ -64,22 +65,30 @@ class BilletOrderTest extends TestCase
self::assertSame($ticket, $result);
}
public function testSetAndGetIsScanned(): void
public function testSetAndGetState(): void
{
$ticket = new BilletOrder();
$result = $ticket->setIsScanned(true);
$result = $ticket->setState(BilletOrder::STATE_INVALID);
self::assertTrue($ticket->isScanned());
self::assertSame(BilletOrder::STATE_INVALID, $ticket->getState());
self::assertFalse($ticket->isValid());
self::assertSame($ticket, $result);
$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());
}
public function testSetAndGetScannedAt(): void
public function testSetAndGetFirstScannedAt(): void
{
$ticket = new BilletOrder();
$date = new \DateTimeImmutable();
$result = $ticket->setScannedAt($date);
$result = $ticket->setFirstScannedAt($date);
self::assertSame($date, $ticket->getScannedAt());
self::assertSame($date, $ticket->getFirstScannedAt());
self::assertSame($ticket, $result);
}