feat: implement delete functionality for accommodations, entries, foods, and merchandise; enhance related services and tests

This commit is contained in:
2026-08-10 11:33:05 -03:00
parent 4aaa66dc38
commit 2693df2cbf
14 changed files with 263 additions and 0 deletions

View File

@@ -305,6 +305,39 @@ class CatalogService
});
}
public function deleteVariant(Variant $variant): void
{
DB::transaction(function () use ($variant): void {
$variant = Variant::query()
->with('attachments')
->lockForUpdate()
->findOrFail($variant->getKey());
$catalogItem = CatalogItem::query()
->lockForUpdate()
->findOrFail($variant->catalog_item_id);
$attachments = $variant->attachments;
$inventoryId = $variant->inventory_id;
$variant->attachments()->detach();
$variant->delete();
Inventory::query()->whereKey($inventoryId)->delete();
$minimumPrice = $catalogItem->variants()->min('precio');
if ($minimumPrice === null) {
$this->delete($catalogItem);
} else {
$catalogItem->update(['precio' => $minimumPrice]);
}
foreach ($attachments as $attachment) {
if (! DB::table('catalog_items_attachments')->where('attachment_id', $attachment->id)->exists()) {
$this->attachmentService->delete($attachment);
}
}
});
}
private function createInventory(int $realStock): Inventory
{
return Inventory::query()->create([

View File

@@ -7,6 +7,7 @@ use App\Domains\FiestaFutbolInfantil\Resources\AccommodationResource;
use App\Domains\FiestaFutbolInfantil\Services\AccommodationService;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class AccommodationController extends Controller
{
@@ -30,4 +31,14 @@ class AccommodationController extends Controller
)
);
}
public function destroy(Request $request, int $accommodation): Response
{
$this->accommodationService->delete(
$request->user()->tenant()->firstOrFail(),
$accommodation,
);
return response()->noContent();
}
}

View File

@@ -9,6 +9,7 @@ use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Http\Response;
class EntryController extends Controller
{
@@ -34,4 +35,14 @@ class EntryController extends Controller
->response()
->setStatusCode(200);
}
public function destroy(Request $request, int $entry): Response
{
$this->entryService->delete(
$request->user()->tenant()->firstOrFail(),
$entry,
);
return response()->noContent();
}
}

View File

@@ -7,6 +7,7 @@ use App\Domains\FiestaFutbolInfantil\Resources\FoodResource;
use App\Domains\FiestaFutbolInfantil\Services\FoodService;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class FoodController extends Controller
{
@@ -30,4 +31,14 @@ class FoodController extends Controller
)
);
}
public function destroy(Request $request, int $food): Response
{
$this->foodService->delete(
$request->user()->tenant()->firstOrFail(),
$food,
);
return response()->noContent();
}
}

View File

@@ -9,6 +9,7 @@ use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Http\Response;
class MerchandiseController extends Controller
{
@@ -33,4 +34,14 @@ class MerchandiseController extends Controller
->response()
->setStatusCode(200);
}
public function destroy(Request $request, int $merchandise): Response
{
$this->merchandiseService->delete(
$request->user()->tenant()->firstOrFail(),
$merchandise,
);
return response()->noContent();
}
}

View File

@@ -11,6 +11,7 @@ use App\Domains\Catalog\Models\Category;
use App\Domains\Catalog\Models\Inventory;
use App\Domains\Catalog\Models\ItemAttribute;
use App\Domains\Catalog\Models\Variant;
use App\Domains\Catalog\Services\CatalogService;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
@@ -20,6 +21,8 @@ class AccommodationService
{
private const ATTRIBUTE_CODE = 'tipo_alojamiento';
public function __construct(private readonly CatalogService $catalogService) {}
public function current(Tenant $tenant): ?CatalogItem
{
return CatalogItem::query()
@@ -86,6 +89,18 @@ class AccommodationService
});
}
public function delete(Tenant $tenant, int $accommodationId): void
{
$variant = Variant::query()
->whereKey($accommodationId)
->whereHas('catalogItem', fn ($query) => $query
->where('tenant_code', $tenant->codigo)
->where('slug', 'alojamiento'))
->firstOrFail();
$this->catalogService->deleteVariant($variant);
}
private function attribute(Tenant $tenant): Attribute
{
$attribute = Attribute::query()

View File

@@ -76,6 +76,18 @@ class EntryService
});
}
public function delete(Tenant $tenant, int $entryId): void
{
$entry = CatalogItem::query()
->whereKey($entryId)
->where('tenant_code', $tenant->codigo)
->where('event_product_type', EventProductType::Entry->value)
->whereHas('category', fn ($query) => $query->where('nombre', 'Entradas'))
->firstOrFail();
$this->catalogService->delete($entry);
}
/** @param array<string, mixed> $entry */
private function update(Tenant $tenant, Category $category, array $entry, int $index): CatalogItem
{

View File

@@ -11,6 +11,7 @@ use App\Domains\Catalog\Models\Category;
use App\Domains\Catalog\Models\Inventory;
use App\Domains\Catalog\Models\ItemAttribute;
use App\Domains\Catalog\Models\Variant;
use App\Domains\Catalog\Services\CatalogService;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
@@ -20,6 +21,8 @@ class FoodService
{
private const ATTRIBUTE_CODES = ['event_date', 'horario', 'servicio'];
public function __construct(private readonly CatalogService $catalogService) {}
public function current(Tenant $tenant): ?CatalogItem
{
return CatalogItem::query()
@@ -87,6 +90,18 @@ class FoodService
});
}
public function delete(Tenant $tenant, int $foodId): void
{
$variant = Variant::query()
->whereKey($foodId)
->whereHas('catalogItem', fn ($query) => $query
->where('tenant_code', $tenant->codigo)
->where('slug', 'comida'))
->firstOrFail();
$this->catalogService->deleteVariant($variant);
}
/** @return Collection<string, Attribute> */
private function attributes(Tenant $tenant): Collection
{

View File

@@ -11,6 +11,7 @@ use App\Domains\Catalog\Models\Category;
use App\Domains\Catalog\Models\Inventory;
use App\Domains\Catalog\Models\ItemAttribute;
use App\Domains\Catalog\Models\Variant;
use App\Domains\Catalog\Services\CatalogService;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
@@ -21,6 +22,8 @@ class MerchandiseService
{
private const ATTRIBUTE_CODES = ['color', 'talle'];
public function __construct(private readonly CatalogService $catalogService) {}
/** @return Collection<int, CatalogItem> */
public function all(Tenant $tenant): Collection
{
@@ -120,6 +123,20 @@ class MerchandiseService
});
}
public function delete(Tenant $tenant, int $merchandiseId): void
{
$variant = Variant::query()
->whereKey($merchandiseId)
->whereHas('catalogItem', fn ($query) => $query
->where('tenant_code', $tenant->codigo)
->where('event_product_type', EventProductType::Product->value)
->whereHas('category', fn ($categoryQuery) => $categoryQuery
->where('nombre', 'Merchandising')))
->firstOrFail();
$this->catalogService->deleteVariant($variant);
}
/** @return Collection<string, Attribute> */
private function attributes(Tenant $tenant): Collection
{

View File

@@ -15,22 +15,34 @@ Route::prefix('v1/adminapp/tenant')
Route::post('entries', [EntryController::class, 'store'])
->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.entradas')
->name('adminapp.fiesta-futbol-infantil.entries.store');
Route::delete('entries/{entry}', [EntryController::class, 'destroy'])
->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.entradas')
->name('adminapp.fiesta-futbol-infantil.entries.destroy');
Route::get('foods', [FoodController::class, 'index'])
->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.comida')
->name('adminapp.fiesta-futbol-infantil.foods.index');
Route::post('foods', [FoodController::class, 'store'])
->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.comida')
->name('adminapp.fiesta-futbol-infantil.foods.store');
Route::delete('foods/{food}', [FoodController::class, 'destroy'])
->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.comida')
->name('adminapp.fiesta-futbol-infantil.foods.destroy');
Route::get('accommodations', [AccommodationController::class, 'index'])
->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.alojamientos')
->name('adminapp.fiesta-futbol-infantil.accommodations.index');
Route::post('accommodations', [AccommodationController::class, 'store'])
->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.alojamientos')
->name('adminapp.fiesta-futbol-infantil.accommodations.store');
Route::delete('accommodations/{accommodation}', [AccommodationController::class, 'destroy'])
->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.alojamientos')
->name('adminapp.fiesta-futbol-infantil.accommodations.destroy');
Route::get('merchandise', [MerchandiseController::class, 'index'])
->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.merchandising')
->name('adminapp.fiesta-futbol-infantil.merchandise.index');
Route::post('merchandise', [MerchandiseController::class, 'store'])
->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.merchandising')
->name('adminapp.fiesta-futbol-infantil.merchandise.store');
Route::delete('merchandise/{merchandise}', [MerchandiseController::class, 'destroy'])
->middleware('tenant.menu:adminapp.fiesta-futbol-infantil.merchandising')
->name('adminapp.fiesta-futbol-infantil.merchandise.destroy');
});