<?php
 namespace App\Services\Fraud\Checks; use App\Models\Order; use App\Models\OrderFraudCheck; use App\Models\Setting; use Carbon\Carbon; class VelocityCheck extends BaseFraudCheck { protected int $priority = 10; public function getName(): string { return 'Velocity Check'; } public function getType(): string { return OrderFraudCheck::TYPE_VELOCITY_CLIENT; } public function getDescription(): string { return 'Checks order frequency from same client and IP address'; } public function isEnabled(): bool { if (!empty($this->moduleConfig)) { return !empty($this->moduleConfig['velocity_check_enabled']); } return (bool) Setting::getValue('fraud_velocity_check_enabled', true); } public function check(Order $order): array { $now = Carbon::now(); $clientId = $order->client_id; $ipAddress = $order->ip_address; if (!empty($this->moduleConfig)) { $maxClientOrdersPerHour = (int) ($this->moduleConfig['velocity_max_orders_per_hour'] ?? 5); $maxClientOrdersPerDay = (int) ($this->moduleConfig['velocity_max_orders_per_day'] ?? 10); $maxIpOrdersPerDay = (int) ($this->moduleConfig['velocity_max_orders_same_ip'] ?? 3); } else { $maxClientOrdersPerHour = (int) Setting::getValue('fraud_velocity_max_orders_per_hour', 5); $maxClientOrdersPerDay = (int) Setting::getValue('fraud_velocity_max_orders_per_day', 10); $maxIpOrdersPerDay = (int) Setting::getValue('fraud_velocity_max_orders_same_ip', 3); } $clientOrdersLastHour = Order::where('client_id', $clientId) ->where('created_at', '>=', $now->copy()->subHour()) ->where('id', '!=', $order->id) ->count(); $clientOrdersLast24h = Order::where('client_id', $clientId) ->where('created_at', '>=', $now->copy()->subDay()) ->where('id', '!=', $order->id) ->count(); $ipOrdersLast24h = 0; if ($ipAddress) { $ipOrdersLast24h = Order::where('ip_address', $ipAddress) ->where('created_at', '>=', $now->copy()->subDay()) ->where('id', '!=', $order->id) ->count(); } $data = [ 'client_orders_last_hour' => $clientOrdersLastHour, 'client_orders_last_24h' => $clientOrdersLast24h, 'ip_orders_last_24h' => $ipOrdersLast24h, 'thresholds' => [ 'max_client_per_hour' => $maxClientOrdersPerHour, 'max_client_per_day' => $maxClientOrdersPerDay, 'max_ip_per_day' => $maxIpOrdersPerDay, ], ]; if ($clientOrdersLastHour >= $maxClientOrdersPerHour) { return $this->failed( 90, "Client exceeded maximum orders per hour: {$clientOrdersLastHour}/{$maxClientOrdersPerHour}", $data ); } if ($clientOrdersLast24h >= $maxClientOrdersPerDay) { return $this->warning( 60, "Client exceeded maximum orders per day: {$clientOrdersLast24h}/{$maxClientOrdersPerDay}", $data ); } if ($ipOrdersLast24h >= $maxIpOrdersPerDay) { return $this->warning( 55, "IP exceeded maximum orders per day: {$ipOrdersLast24h}/{$maxIpOrdersPerDay}", $data ); } if ($clientOrdersLastHour >= ($maxClientOrdersPerHour * 0.6)) { return $this->warning( 30, "Client has high order frequency: {$clientOrdersLastHour} orders in last hour", $data ); } return $this->passed('Order velocity is normal', $data); } } 