establishment; if ($establishment === null) { $machine->loadMissing('establishment'); $establishment = $machine->establishment; } if ($establishment === null) { throw new \RuntimeException('Établissement introuvable pour la machine.'); } $dayType = $this->resolveDayType($at); $time = $at->format('H:i:s'); $rules = PricingRule::query() ->where('establishment_id', $establishment->id) ->where('is_active', true) ->where(function ($query) use ($machine) { $query->whereNull('machine_id') ->orWhere('machine_id', $machine->id); }) ->where(function ($query) use ($machine) { $query->whereNull('machine_type') ->orWhere('machine_type', $machine->type); }) ->where(function ($query) use ($dayType) { $query->where('day_type', 'all') ->orWhere('day_type', $dayType); }) ->where('slot_start', '<=', $time) ->where('slot_end', '>', $time) ->orderBy('priority') ->orderByRaw('CASE WHEN machine_id IS NOT NULL THEN 0 WHEN machine_type IS NOT NULL THEN 1 ELSE 2 END') ->get(); $rule = $rules->first(); if ($rule === null) { throw new \RuntimeException('Aucune règle tarifaire active pour cette machine.'); } $basePrice = (float) $rule->price; return $this->applyPromotion($establishment->id, $machine->type, $at, $basePrice); } private function resolveDayType(CarbonInterface $at): string { if ($at->isWeekend()) { return 'weekend'; } return 'weekday'; } private function applyPromotion(int $establishmentId, string $machineType, CarbonInterface $at, float $basePrice): float { $promotion = Promotion::query() ->where('establishment_id', $establishmentId) ->where('is_active', true) ->where('starts_at', '<=', $at) ->where('ends_at', '>=', $at) ->where(function ($query) use ($machineType) { $query->where('machine_type', 'all') ->orWhere('machine_type', $machineType); }) ->orderByDesc('discount_value') ->first(); if ($promotion === null) { return round($basePrice, 2); } $discount = $promotion->discount_type === 'percent' ? $basePrice * ((float) $promotion->discount_value / 100) : (float) $promotion->discount_value; return round(max(0, $basePrice - $discount), 2); } }