feat(ticket): add entry reservation handling to ticket refund logic and tests
This commit is contained in:
@@ -7,6 +7,7 @@ use App\Domains\Commerce\Catalog\Models\Variant;
|
||||
use App\Domains\Commerce\Purchase\Models\PurchaseItem;
|
||||
use App\Domains\Core\Auth\Models\User;
|
||||
use App\Domains\Core\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticketing\Desfile\Models\EntryReservation;
|
||||
use App\Domains\Ticketing\Event\Models\Event;
|
||||
use App\Domains\Ticketing\Ticket\Services\ResolvedTicketValidity;
|
||||
use App\Domains\Ticketing\Ticket\Services\ResolvedValidityGroup;
|
||||
@@ -192,7 +193,9 @@ class Ticket extends Model
|
||||
|
||||
public function can_refund(): bool
|
||||
{
|
||||
return $this->is_active() && $this->allow_refund();
|
||||
return $this->is_active()
|
||||
&& $this->allow_refund()
|
||||
&& ! $this->hasEntryReservation();
|
||||
}
|
||||
|
||||
public function canRefund(): bool
|
||||
@@ -235,6 +238,12 @@ class Ticket extends Model
|
||||
return $this->hasOne(TicketRefund::class);
|
||||
}
|
||||
|
||||
/** @return HasOne<EntryReservation, $this> */
|
||||
public function entryReservation(): HasOne
|
||||
{
|
||||
return $this->hasOne(EntryReservation::class);
|
||||
}
|
||||
|
||||
/** @return BelongsTo<CatalogItem, $this> */
|
||||
public function sourceCatalogItem(): BelongsTo
|
||||
{
|
||||
@@ -247,6 +256,15 @@ class Ticket extends Model
|
||||
return $this->belongsTo(Variant::class, 'source_variant_id')->withTrashed();
|
||||
}
|
||||
|
||||
private function hasEntryReservation(): bool
|
||||
{
|
||||
if ($this->relationLoaded('entryReservation')) {
|
||||
return $this->getRelation('entryReservation') instanceof EntryReservation;
|
||||
}
|
||||
|
||||
return $this->exists && $this->entryReservation()->exists();
|
||||
}
|
||||
|
||||
public function isValid(): bool
|
||||
{
|
||||
if ($this->hasTerminalStatus() || $this->used_at !== null) {
|
||||
|
||||
@@ -27,6 +27,7 @@ class AdminAppTicketService
|
||||
'scannerUser',
|
||||
'sourceCatalogItem.category',
|
||||
'sourcePurchaseItem.purchase',
|
||||
'entryReservation',
|
||||
'refund.createdBy',
|
||||
];
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ use App\Domains\Core\Authorization\Enums\RoleCode;
|
||||
use App\Domains\Core\Menu\Models\Menu;
|
||||
use App\Domains\Core\Tenant\Models\AdminWebsiteType;
|
||||
use App\Domains\Core\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticketing\Desfile\Enums\EntryReservationPaymentType;
|
||||
use App\Domains\Ticketing\Desfile\Models\EntryReservation;
|
||||
use App\Domains\Ticketing\Ticket\Models\Ticket;
|
||||
use App\Domains\Ticketing\Ticket\Models\TicketRefund;
|
||||
use App\Shared\Attachable\Enums\AttachmentType;
|
||||
@@ -222,6 +224,54 @@ class AdminAppTicketControllerTest extends TestCase
|
||||
$this->assertSame(1, $purchaseItem->ticketRefunds()->count());
|
||||
}
|
||||
|
||||
public function test_it_does_not_refund_a_reserved_desfile_entry(): void
|
||||
{
|
||||
$tenant = $this->createTenant('desfile_pura_tendencia');
|
||||
$tenant->update([
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_total_refund' => true,
|
||||
]);
|
||||
$admin = $this->createAdminAppUser($tenant);
|
||||
$this->grantTicketsMenu($tenant);
|
||||
Sanctum::actingAs($admin);
|
||||
[$ticket, $purchaseItem] = $this->createRefundableTicket($tenant, $admin, '100.00');
|
||||
$inventory = $ticket->sourceCatalogItem->inventory;
|
||||
$variant = Variant::query()->create([
|
||||
'catalog_item_id' => $ticket->source_catalog_item_id,
|
||||
'inventory_id' => $inventory->id,
|
||||
'precio' => '100.00',
|
||||
]);
|
||||
$ticket->update(['source_variant_id' => $variant->id]);
|
||||
EntryReservation::query()->create([
|
||||
'variant_id' => $variant->id,
|
||||
'ticket_id' => $ticket->id,
|
||||
'inventory_id' => $inventory->id,
|
||||
'fecha_reserva' => now(),
|
||||
'importe' => '100.00',
|
||||
'tipo_pago' => EntryReservationPaymentType::Other,
|
||||
]);
|
||||
|
||||
$this->getJson('/api/v1/adminapp/tenant/tickets')
|
||||
->assertOk()
|
||||
->assertJsonPath('data.0.id', $ticket->id)
|
||||
->assertJsonPath('data.0.allow_refund', true)
|
||||
->assertJsonPath('data.0.can_refund', false);
|
||||
|
||||
$this->getJson("/api/v1/adminapp/tenant/tickets/{$ticket->id}/refund")
|
||||
->assertUnprocessable()
|
||||
->assertJsonValidationErrors('refund');
|
||||
|
||||
$this->postJson("/api/v1/adminapp/tenant/tickets/{$ticket->id}/refund", [
|
||||
'refund_type' => TicketRefund::TYPE_TOTAL,
|
||||
])
|
||||
->assertUnprocessable()
|
||||
->assertJsonValidationErrors('refund');
|
||||
|
||||
$this->assertNull($ticket->fresh()->refunded_at);
|
||||
$this->assertSame(0, $purchaseItem->ticketRefunds()->count());
|
||||
$this->assertSame(0, $inventory->fresh()->refunded_units);
|
||||
}
|
||||
|
||||
public function test_it_partially_refunds_a_ticket_using_the_tenant_percentage(): void
|
||||
{
|
||||
$tenant = $this->createTenant('ticket-partial-refund');
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
namespace Tests\Unit\Ticket;
|
||||
|
||||
use App\Domains\Core\Auth\Models\User;
|
||||
use App\Domains\Commerce\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Commerce\Catalog\Models\Variant;
|
||||
use App\Domains\Core\Auth\Models\User;
|
||||
use App\Domains\Core\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticketing\Desfile\Models\EntryReservation;
|
||||
use App\Domains\Ticketing\Ticket\Enums\ValidityTimeType;
|
||||
use App\Domains\Ticketing\Ticket\Models\Ticket;
|
||||
use App\Domains\Ticketing\Ticket\Models\ValidityTime;
|
||||
@@ -54,6 +55,7 @@ class TicketTest extends TestCase
|
||||
$this->assertInstanceOf(User::class, $ticket->scannerUser()->getRelated());
|
||||
$this->assertInstanceOf(CatalogItem::class, $ticket->sourceCatalogItem()->getRelated());
|
||||
$this->assertInstanceOf(Variant::class, $ticket->sourceVariant()->getRelated());
|
||||
$this->assertInstanceOf(EntryReservation::class, $ticket->entryReservation()->getRelated());
|
||||
}
|
||||
|
||||
public function test_unused_ticket_without_validity_time_is_valid(): void
|
||||
@@ -83,6 +85,21 @@ class TicketTest extends TestCase
|
||||
$this->assertFalse($active->can_refund());
|
||||
}
|
||||
|
||||
public function test_a_ticket_with_an_entry_reservation_cannot_be_refunded(): void
|
||||
{
|
||||
$tenant = new Tenant([
|
||||
'allow_ticket_refund' => true,
|
||||
'allow_ticket_total_refund' => true,
|
||||
]);
|
||||
$ticket = (new Ticket)
|
||||
->setRelation('tenant', $tenant)
|
||||
->setRelation('entryReservation', new EntryReservation);
|
||||
|
||||
$this->assertTrue($ticket->is_active());
|
||||
$this->assertTrue($ticket->allow_refund());
|
||||
$this->assertFalse($ticket->can_refund());
|
||||
}
|
||||
|
||||
public function test_fixed_window_controls_ticket_validity(): void
|
||||
{
|
||||
Carbon::setTestNow('2026-07-21 10:00:00');
|
||||
|
||||
Reference in New Issue
Block a user