190 lines
7.0 KiB
PHP
190 lines
7.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Supervisor;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Controllers\Supervisor\Concerns\ScopesSupervisorResources;
|
|
use App\Models\Establishment;
|
|
use App\Models\Promotion;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Inertia\Inertia;
|
|
use Inertia\Response;
|
|
|
|
class PromotionPageController extends Controller
|
|
{
|
|
use ScopesSupervisorResources;
|
|
|
|
public function index(Request $request): Response
|
|
{
|
|
$query = Promotion::query()->with('establishment:id,name');
|
|
$this->scopeEstablishmentQuery($query);
|
|
$this->applyEstablishmentFilter($request, $query);
|
|
|
|
if ($request->filled('machine_type')) {
|
|
$query->where('machine_type', $request->string('machine_type'));
|
|
}
|
|
|
|
if ($request->has('is_active') && $request->string('is_active')->toString() !== '') {
|
|
$query->where('is_active', $request->boolean('is_active'));
|
|
}
|
|
|
|
if ($request->filled('search')) {
|
|
$search = $request->string('search');
|
|
$query->where('description', 'like', "%{$search}%");
|
|
}
|
|
|
|
$promotions = $query
|
|
->tap(fn ($builder) => $this->applySort($request, $builder, [
|
|
'establishment' => fn ($builder, string $direction) => $this->sortByRelatedEstablishment(
|
|
$builder,
|
|
'promotions',
|
|
'establishment_id',
|
|
$direction,
|
|
),
|
|
'discount_value' => 'discount_value',
|
|
'starts_at' => 'starts_at',
|
|
'ends_at' => 'ends_at',
|
|
'machine_type' => 'machine_type',
|
|
'is_active' => 'is_active',
|
|
], 'starts_at', 'desc'))
|
|
->paginate($this->supervisorListPerPage($request))
|
|
->withQueryString()
|
|
->through(fn (Promotion $promotion) => $this->formatPromotion($promotion));
|
|
|
|
return Inertia::render('Supervisor/Promotions/Index', [
|
|
'promotions' => $promotions,
|
|
'establishments' => $this->establishmentOptions(),
|
|
'machineTypes' => $this->machineTypeOptions(),
|
|
'discountTypes' => $this->discountTypeOptions(),
|
|
'filters' => [
|
|
'establishment_id' => $request->filled('establishment_id') ? (int) $request->input('establishment_id') : null,
|
|
'machine_type' => $request->string('machine_type')->toString() ?: null,
|
|
'is_active' => $request->has('is_active') && $request->string('is_active')->toString() !== ''
|
|
? ($request->boolean('is_active') ? '1' : '0')
|
|
: null,
|
|
'search' => $request->string('search')->toString() ?: null,
|
|
'sort' => $request->string('sort')->toString() ?: 'starts_at',
|
|
'direction' => $request->string('direction')->toString() === 'desc' ? 'desc' : 'asc',
|
|
'per_page' => $this->supervisorListPerPage($request),
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function store(Request $request): RedirectResponse
|
|
{
|
|
$validated = $this->validatePromotion($request);
|
|
$this->assertEstablishmentAccessible((int) $validated['establishment_id']);
|
|
|
|
Promotion::query()->create($validated);
|
|
|
|
return redirect()->route('supervisor.promotions.index')
|
|
->with('success', 'Promotion créée.');
|
|
}
|
|
|
|
public function update(Request $request, int $id): RedirectResponse
|
|
{
|
|
$promotion = $this->findAccessiblePromotion($id);
|
|
$validated = $this->validatePromotion($request);
|
|
$this->assertEstablishmentAccessible((int) $validated['establishment_id']);
|
|
|
|
$promotion->update($validated);
|
|
|
|
return redirect()->route('supervisor.promotions.index')
|
|
->with('success', 'Promotion mise à jour.');
|
|
}
|
|
|
|
public function destroy(int $id): RedirectResponse
|
|
{
|
|
$promotion = $this->findAccessiblePromotion($id);
|
|
$promotion->delete();
|
|
|
|
return redirect()->route('supervisor.promotions.index')
|
|
->with('success', 'Promotion supprimée.');
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function validatePromotion(Request $request): array
|
|
{
|
|
return $request->validate([
|
|
'establishment_id' => ['required', 'integer', 'exists:establishments,id'],
|
|
'machine_type' => ['required', 'in:washer_small,washer_large,dryer_small,dryer_large,all'],
|
|
'discount_type' => ['required', 'in:percent,fixed'],
|
|
'discount_value' => ['required', 'numeric', 'min:0'],
|
|
'starts_at' => ['required', 'date'],
|
|
'ends_at' => ['required', 'date', 'after:starts_at'],
|
|
'description' => ['nullable', 'string', 'max:500'],
|
|
'is_active' => ['boolean'],
|
|
]);
|
|
}
|
|
|
|
private function findAccessiblePromotion(int $id): Promotion
|
|
{
|
|
$query = Promotion::query()->where('id', $id);
|
|
$this->scopeEstablishmentQuery($query);
|
|
|
|
return $query->firstOrFail();
|
|
}
|
|
|
|
private function assertEstablishmentAccessible(int $establishmentId): void
|
|
{
|
|
$supervisor = $this->supervisor();
|
|
|
|
$exists = Establishment::query()
|
|
->where('id', $establishmentId)
|
|
->where('organization_id', $supervisor->organization_id)
|
|
->when($supervisor->establishment_id, fn ($q) => $q->where('id', $supervisor->establishment_id))
|
|
->exists();
|
|
|
|
abort_unless($exists, 403);
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function formatPromotion(Promotion $promotion): array
|
|
{
|
|
return [
|
|
'id' => $promotion->id,
|
|
'establishment_id' => $promotion->establishment_id,
|
|
'establishment_name' => $promotion->establishment?->name,
|
|
'machine_type' => $promotion->machine_type,
|
|
'machine_type_label' => $this->machineTypeOptions()[$promotion->machine_type] ?? $promotion->machine_type,
|
|
'discount_type' => $promotion->discount_type,
|
|
'discount_type_label' => $this->discountTypeOptions()[$promotion->discount_type] ?? $promotion->discount_type,
|
|
'discount_value' => (float) $promotion->discount_value,
|
|
'starts_at' => $promotion->starts_at?->format('Y-m-d\TH:i'),
|
|
'ends_at' => $promotion->ends_at?->format('Y-m-d\TH:i'),
|
|
'description' => $promotion->description,
|
|
'is_active' => $promotion->is_active,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array<string, string>
|
|
*/
|
|
private function machineTypeOptions(): array
|
|
{
|
|
return [
|
|
'all' => 'Toutes les machines',
|
|
'washer_small' => 'Lave-linge petit',
|
|
'washer_large' => 'Lave-linge grand',
|
|
'dryer_small' => 'Sèche-linge petit',
|
|
'dryer_large' => 'Sèche-linge grand',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array<string, string>
|
|
*/
|
|
private function discountTypeOptions(): array
|
|
{
|
|
return [
|
|
'percent' => 'Pourcentage',
|
|
'fixed' => 'Montant fixe',
|
|
];
|
|
}
|
|
}
|