feat(ticket): implement ticket generation on purchase payment and add related tests

This commit is contained in:
2026-07-21 11:23:17 -03:00
parent a928a2e848
commit c0978033c1
6 changed files with 186 additions and 3 deletions

View File

@@ -7,9 +7,11 @@ use App\Domains\Attachable\Models\Attachment;
use App\Domains\Auth\Models\User;
use App\Domains\Catalog\Enums\CatalogItemType;
use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Purchase\Models\Purchase;
use App\Domains\Tenant\Models\Tenant;
use App\Domains\Ticket\Exceptions\TicketGenerationException;
use App\Domains\Ticket\Services\TicketGeneratorService;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
@@ -121,6 +123,48 @@ class TicketGeneratorServiceTest extends TestCase
}
}
public function test_marking_a_purchase_as_paid_generates_its_tickets_once(): void
{
$item = $this->createTicketableItem('paid-ticket');
$purchase = $this->createPurchase($item, 2);
$purchase->setRelation('items', new EloquentCollection);
$purchase->markAsPaid();
$this->assertSame(Purchase::STATUS_PAID, $purchase->status);
$this->assertDatabaseCount('tickets', 2);
$purchase->markAsPaid();
$this->assertDatabaseCount('tickets', 2);
}
public function test_marking_a_purchase_as_paid_ignores_items_without_tickets(): void
{
$item = $this->createTicketableItem('regular-product');
$item->update(['has_tickets' => false]);
$purchase = $this->createPurchase($item->fresh(), 1);
$purchase->markAsPaid();
$this->assertSame(Purchase::STATUS_PAID, $purchase->status);
$this->assertDatabaseCount('tickets', 0);
}
public function test_paid_status_is_rolled_back_when_ticket_generation_fails(): void
{
$item = $this->createTicketableItem('expired-paid-ticket', maximumUseDate: now());
$purchase = $this->createPurchase($item, 1);
try {
$purchase->markAsPaid();
$this->fail('La generación debería haber fallado.');
} catch (TicketGenerationException) {
$this->assertSame(Purchase::STATUS_PENDING_PAYMENT, $purchase->fresh()->status);
$this->assertDatabaseCount('tickets', 0);
}
}
private function createTicketableItem(
string $slug,
mixed $minimumUseDate = null,
@@ -151,6 +195,35 @@ class TicketGeneratorServiceTest extends TestCase
]);
}
private function createPurchase(CatalogItem $catalogItem, int $quantity): Purchase
{
$purchase = Purchase::query()->create([
'tenant_codigo' => $this->tenant->codigo,
'user_id' => $this->user->id,
'status' => Purchase::STATUS_PENDING_PAYMENT,
'payment_method' => 'transfer',
'total' => 10 * $quantity,
]);
$purchase->items()->create([
'source_catalog_item_id' => $catalogItem->id,
'source_variant_id' => null,
'image_attachment_id' => null,
'nombre' => $catalogItem->nombre,
'descripcion' => $catalogItem->descripcion,
'slug' => $catalogItem->slug,
'item_nombre' => $catalogItem->nombre,
'variant_attributes' => [],
'cantidad' => $quantity,
'precio_unitario' => 10,
'discount_total' => null,
'tax_total' => null,
'total' => 10 * $quantity,
]);
return $purchase;
}
private function createTenant(): Tenant
{
$header = Attachment::query()->create([