initial commit

This commit is contained in:
bastien
2026-06-28 12:29:53 +02:00
parent 03e85d2f9d
commit b2443b654c
220 changed files with 24969 additions and 1 deletions
+95
View File
@@ -0,0 +1,95 @@
<?php
namespace App\Services;
use App\Models\Machine;
use App\Models\PricingRule;
use App\Models\Promotion;
use Carbon\Carbon;
use Carbon\CarbonInterface;
class PricingService
{
public function getActivePrice(Machine $machine, ?CarbonInterface $at = null): float
{
$at = Carbon::instance($at ?? now());
$establishment = $machine->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);
}
}