with(['establishment:id,name', 'machine:id,uuid,name']); $this->scopeEstablishmentQuery($query); $rules = $query ->orderBy('priority') ->orderBy('slot_start') ->get() ->map(fn (PricingRule $rule) => $this->formatRule($rule)); return Inertia::render('Supervisor/Pricing/Index', [ 'rules' => $rules, 'establishments' => $this->establishmentOptions(), 'machineTypes' => $this->machineTypeOptions(), 'dayTypes' => $this->dayTypeOptions(), ]); } 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 */ 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 */ 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 */ private function establishmentOptions(): array { $supervisor = $this->supervisor(); return Establishment::query() ->where('organization_id', $supervisor->organization_id) ->when($supervisor->establishment_id, fn ($q) => $q->where('id', $supervisor->establishment_id)) ->orderBy('name') ->get(['id', 'name']) ->map(fn (Establishment $e) => ['id' => $e->id, 'name' => $e->name]) ->all(); } /** * @return array */ 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 */ private function dayTypeOptions(): array { return [ 'all' => 'Tous les jours', 'weekday' => 'Semaine', 'weekend' => 'Week-end', 'holiday' => 'Jours fériés', ]; } }