feat(entry): refine variant selection logic to exclude replaced variants and add unit tests for replacement behavior

This commit is contained in:
2026-09-16 09:34:02 -03:00
parent 8ad9b3a4e3
commit 3d6548ce4a
4 changed files with 108 additions and 1 deletions

View File

@@ -12,7 +12,7 @@ class EntryResource extends JsonResource
/** @return array<string, mixed> */
public function toArray(Request $request): array
{
$variant = $this->variants->sole();
$variant = $this->variants->whereNull('replaced_by_variant_id')->sole();
return [
'id' => $this->id,

View File

@@ -97,6 +97,7 @@ class EntryService
$variants = Variant::query()
->where('catalog_item_id', $catalogItem->id)
->whereNull('replaced_by_variant_id')
->lockForUpdate()
->get();

View File

@@ -7,6 +7,7 @@ use App\Domains\Authorization\Enums\RoleCode;
use App\Domains\Catalog\Models\Attribute;
use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Catalog\Models\Category;
use App\Domains\Catalog\Models\Inventory;
use App\Domains\Catalog\Models\Variant;
use App\Domains\Menu\Models\Menu;
use App\Domains\Shared\Enums\FieldType;
@@ -221,6 +222,66 @@ class EntryControllerTest extends TestCase
]);
}
public function test_it_reads_and_edits_the_latest_replacement_even_when_sales_are_disabled(): void
{
$tenant = $this->createFiestaTenant();
$this->createEventDateAttribute($tenant);
$date = $tenant->eventDates()->create([
'date' => '2027-10-09',
'time_start' => '00:00',
'time_end' => '23:59',
]);
$otherDate = $tenant->eventDates()->create([
'date' => '2027-10-10',
'time_start' => '00:00',
'time_end' => '23:59',
]);
Sanctum::actingAs($this->createAdminAppUser($tenant));
$entryId = $this->postJson('/api/v1/adminapp/tenant/entries', [
'entries' => [[
'title' => 'Abono',
'event_date_ids' => [$date->id],
'stock' => 10,
'price' => 100,
]],
])->assertOk()->json('data.0.id');
$original = Variant::query()->where('catalog_item_id', $entryId)->sole();
$intermediate = $original->replicate();
$intermediate->save();
$replacement = $original->replicate();
$replacement->inventory_id = Inventory::query()->create(['real_stock' => 20])->id;
$replacement->event_date_id = $otherDate->id;
$replacement->sales_disabled_at = now();
$replacement->save();
$replacement->eventDates()->sync([$otherDate->id]);
$original->update(['replaced_by_variant_id' => $intermediate->id, 'sales_disabled_at' => now()]);
$intermediate->update(['replaced_by_variant_id' => $replacement->id, 'sales_disabled_at' => now()]);
$this->getJson('/api/v1/adminapp/tenant/entries')
->assertOk()
->assertJsonPath('data.0.stock', 20)
->assertJsonPath('data.0.event_date_ids', [$otherDate->id]);
$this->postJson('/api/v1/adminapp/tenant/entries', [
'entries' => [[
'id' => $entryId,
'title' => 'Abono editado',
'event_date_ids' => [$date->id, $otherDate->id],
'stock' => 30,
'price' => 200,
]],
])->assertOk()
->assertJsonPath('data.0.stock', 30)
->assertJsonPath('data.0.event_date_ids', [$date->id, $otherDate->id]);
$this->assertSame(10, $original->fresh()->inventory->real_stock);
$this->assertSame([$date->id], $original->fresh()->selectedEventDates()->pluck('id')->all());
$this->assertSame(30, $replacement->fresh()->inventory->real_stock);
$this->assertNotNull($replacement->fresh()->sales_disabled_at);
$this->assertDatabaseCount('variantes', 3);
}
public function test_it_deletes_an_entry_and_its_inventory(): void
{
$tenant = $this->createFiestaTenant();

View File

@@ -0,0 +1,45 @@
<?php
namespace Tests\Unit\FiestaFutbolInfantil;
use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Catalog\Models\Inventory;
use App\Domains\Catalog\Models\Variant;
use App\Domains\Event\Models\EventDate;
use App\Domains\FiestaFutbolInfantil\Resources\EntryResource;
use Illuminate\Http\Request;
use Illuminate\Support\MultipleItemsFoundException;
use Tests\TestCase;
class EntryResourceTest extends TestCase
{
public function test_it_reads_the_final_replacement_even_with_disabled_sales(): void
{
$original = new Variant(['replaced_by_variant_id' => 2]);
$intermediate = new Variant(['replaced_by_variant_id' => 3]);
$current = new Variant(['sales_disabled_at' => now()]);
$date = new EventDate;
$date->id = 13;
$current->setRelation('eventDates', collect([$date]));
$current->setRelation('inventory', new Inventory(['real_stock' => 20]));
$entry = new CatalogItem(['nombre' => 'Abono', 'precio' => 100]);
$entry->setRelation('variants', collect([$original, $intermediate, $current]));
$data = (new EntryResource($entry))->resolve(Request::create('/'));
$this->assertSame([13], $data['event_date_ids']->all());
$this->assertSame(20, $data['stock']);
$this->assertSame('Abono', $data['title']);
$this->assertNotNull($current->sales_disabled_at);
}
public function test_it_does_not_choose_arbitrarily_between_current_variants(): void
{
$entry = new CatalogItem;
$entry->setRelation('variants', collect([new Variant, new Variant]));
$this->expectException(MultipleItemsFoundException::class);
(new EntryResource($entry))->resolve(Request::create('/'));
}
}