Files
backend/app/Http/Controllers/Supervisor/PricingPageController.php
T

205 lines
7.5 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\PricingRule;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
class PricingPageController extends Controller
{
use ScopesSupervisorResources;
public function index(Request $request): Response
{
$query = PricingRule::query()
->with(['establishment:id,name', 'machine:id,uuid,name']);
$this->scopeEstablishmentQuery($query);
$this->applyEstablishmentFilter($request, $query);
if ($request->filled('machine_type')) {
$query->where('machine_type', $request->string('machine_type'));
}
if ($request->filled('day_type')) {
$query->where('day_type', $request->string('day_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('label', 'like', "%{$search}%");
}
$rules = $query
->tap(fn ($builder) => $this->applySort($request, $builder, [
'establishment' => fn ($builder, string $direction) => $this->sortByRelatedEstablishment(
$builder,
'pricing_rules',
'establishment_id',
$direction,
),
'slot_start' => 'slot_start',
'machine_type' => 'machine_type',
'price' => 'price',
'priority' => 'priority',
'is_active' => 'is_active',
], 'priority', 'asc'))
->paginate($this->supervisorListPerPage($request))
->withQueryString()
->through(fn (PricingRule $rule) => $this->formatRule($rule));
return Inertia::render('Supervisor/Pricing/Index', [
'rules' => $rules,
'establishments' => $this->establishmentOptions(),
'machineTypes' => $this->machineTypeOptions(),
'dayTypes' => $this->dayTypeOptions(),
'filters' => [
'establishment_id' => $request->filled('establishment_id') ? (int) $request->input('establishment_id') : null,
'machine_type' => $request->string('machine_type')->toString() ?: null,
'day_type' => $request->string('day_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() ?: 'priority',
'direction' => $request->string('direction')->toString() === 'desc' ? 'desc' : 'asc',
'per_page' => $this->supervisorListPerPage($request),
],
]);
}
public function store(Request $request): RedirectResponse
{
$validated = $this->validateRule($request);
$this->assertEstablishmentAccessible((int) $validated['establishment_id']);
PricingRule::query()->create($validated);
return redirect()->route('supervisor.pricing.index')
->with('success', 'Règle tarifaire créée.');
}
public function update(Request $request, int $id): RedirectResponse
{
$rule = $this->findAccessibleRule($id);
$validated = $this->validateRule($request);
$this->assertEstablishmentAccessible((int) $validated['establishment_id']);
$rule->update($validated);
return redirect()->route('supervisor.pricing.index')
->with('success', 'Règle tarifaire mise à jour.');
}
public function destroy(int $id): RedirectResponse
{
$rule = $this->findAccessibleRule($id);
$rule->delete();
return redirect()->route('supervisor.pricing.index')
->with('success', 'Règle tarifaire supprimée.');
}
/**
* @return array<string, mixed>
*/
private function validateRule(Request $request): array
{
return $request->validate([
'establishment_id' => ['required', 'integer', 'exists:establishments,id'],
'machine_id' => ['nullable', 'integer', 'exists:machines,id'],
'machine_type' => ['nullable', 'in:washer_small,washer_large,dryer_small,dryer_large'],
'day_type' => ['required', 'in:weekday,weekend,holiday,all'],
'slot_start' => ['required', 'date_format:H:i'],
'slot_end' => ['required', 'date_format:H:i', 'after:slot_start'],
'price' => ['required', 'numeric', 'min:0'],
'label' => ['nullable', 'string', 'max:100'],
'requires_app' => ['boolean'],
'priority' => ['integer', 'min:0'],
'is_active' => ['boolean'],
]);
}
private function findAccessibleRule(int $id): PricingRule
{
$query = PricingRule::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 formatRule(PricingRule $rule): array
{
return [
'id' => $rule->id,
'establishment_id' => $rule->establishment_id,
'establishment_name' => $rule->establishment?->name,
'machine_id' => $rule->machine_id,
'machine_name' => $rule->machine?->name,
'machine_type' => $rule->machine_type,
'machine_type_label' => $rule->machine_type ? ($this->machineTypeOptions()[$rule->machine_type] ?? $rule->machine_type) : null,
'day_type' => $rule->day_type,
'day_type_label' => $this->dayTypeOptions()[$rule->day_type] ?? $rule->day_type,
'slot_start' => $rule->slot_start ? substr((string) $rule->slot_start, 0, 5) : null,
'slot_end' => $rule->slot_end ? substr((string) $rule->slot_end, 0, 5) : null,
'price' => (float) $rule->price,
'label' => $rule->label,
'requires_app' => $rule->requires_app,
'priority' => $rule->priority,
'is_active' => $rule->is_active,
];
}
/**
* @return array<string, string>
*/
private function machineTypeOptions(): array
{
return [
'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 dayTypeOptions(): array
{
return [
'all' => 'Tous les jours',
'weekday' => 'Semaine',
'weekend' => 'Week-end',
'holiday' => 'Jours fériés',
];
}
}