feat(entry): refine variant selection logic to exclude replaced variants and add unit tests for replacement behavior
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -97,6 +97,7 @@ class EntryService
|
||||
|
||||
$variants = Variant::query()
|
||||
->where('catalog_item_id', $catalogItem->id)
|
||||
->whereNull('replaced_by_variant_id')
|
||||
->lockForUpdate()
|
||||
->get();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
45
tests/Unit/FiestaFutbolInfantil/EntryResourceTest.php
Normal file
45
tests/Unit/FiestaFutbolInfantil/EntryResourceTest.php
Normal 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('/'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user