servicio; $fechaBase = now()->subDays(8)->format('Y-m-d'); $fechaMin = now()->addDays($tarifa->dias - 15)->format('Y-m-d'); $fechaMax = now()->addDays($tarifa->dias + 15)->format('Y-m-d'); // Cuenta completa if ((int) $tarifa->pantallas === (int) $servicio->completa) { return Cuentas::where('servicio_id', $servicio->id) ->whereDate('vencimiento', '>=', $fechaMin) ->whereDate('vencimiento', '<=', $fechaMax) ->where('estado', 'pendiente') ->doesntHave('perfil') ->count(); } // Cuenta por pantalla $suma = $servicio->pantallas - $tarifa->pantallas; $baseQ = Cuentas::select('*') ->where('servicio_id', $servicio->id) ->whereDate('inicio', '>=', $fechaBase) ->whereDate('vencimiento', '>=', $fechaMin) ->whereDate('vencimiento', '<=', $fechaMax) ->where('estado', 'activo') ->withCount('historiales'); $cuentas = Cuentas::fromSub($baseQ, 'alias') ->where('historiales_count', '<=', $suma) ->get(); if ($cuentas->isEmpty()) { return 0; } $tomadas = Historial_cuenta::whereIn('cuenta_id', $cuentas->pluck('id')) ->whereNotNull('historial_id') ->count(); return (int) floor((($cuentas->count() * $servicio->pantallas) - $tomadas) / $tarifa->pantallas); } /** * Busca la primera cuenta disponible para una tarifa. */ public static function buscar(Tarifas $tarifa): ?Cuentas { $servicio = $tarifa->servicio; $fechaBase = now()->subDays(8)->format('Y-m-d'); $fechaMin = now()->addDays($tarifa->dias - 15)->format('Y-m-d'); $fechaMax = now()->addDays($tarifa->dias + 15)->format('Y-m-d'); // Cuenta completa if ((int) $tarifa->pantallas === (int) $servicio->completa) { return Cuentas::where('servicio_id', $servicio->id) ->whereDate('vencimiento', '>=', $fechaMin) ->whereDate('vencimiento', '<=', $fechaMax) ->where('estado', 'pendiente') ->doesntHave('perfil') ->orderBy('inicio', 'ASC') ->first(); } // Cuenta por pantalla — intento normal $suma = $servicio->pantallas - $tarifa->pantallas; $baseQ = Cuentas::select('*') ->where('servicio_id', $servicio->id) ->whereDate('inicio', '>=', $fechaBase) ->whereDate('vencimiento', '>=', $fechaMin) ->whereDate('vencimiento', '<=', $fechaMax) ->where('estado', 'activo') ->withCount('historiales') ->orderBy('inicio', 'ASC'); $cuenta = Cuentas::fromSub($baseQ, 'alias') ->where('historiales_count', '<=', $suma) ->orderBy('inicio', 'ASC') ->lockForUpdate() ->first(); // Segundo intento sin filtro de inicio if (! $cuenta) { $baseQ2 = Cuentas::select('*') ->where('servicio_id', $servicio->id) ->whereDate('vencimiento', '>=', $fechaMin) ->whereDate('vencimiento', '<=', $fechaMax) ->where('estado', 'activo') ->withCount('historiales') ->orderBy('inicio', 'ASC'); $cuenta = Cuentas::fromSub($baseQ2, 'alias') ->where('historiales_count', '<=', $suma) ->orderBy('inicio', 'ASC') ->lockForUpdate() ->first(); } return $cuenta; } /** * Precio efectivo para un usuario y tarifa. * Prioridad: Usuario_tarifa (web) → Preferencial (legacy) → precio base. */ public static function precio(int $tarifaId, ?int $userId, float $base): float { if ($userId) { $ut = Usuario_tarifa::where('usuario_id', $userId)->where('tarifa_id', $tarifaId)->first(); if ($ut) { return (float) $ut->precio; } $pref = Preferencial::where('usuario_id', $userId)->where('tarifa_id', $tarifaId)->first(); if ($pref) { return (float) $pref->valor; } } return (float) $base; } }