Three bugs fixed: 1. TelegramBotService queried Cuentas by tarifa_id + estado=activo which never matched. Now uses CuentasHelper::contar/buscar — same date-range + historial-count logic as the web (pendiente for full accounts, activo + slot check for per-screen accounts). 2. efectivePrice in TelegramBotService and PublicChat used the Preferencial table (legacy) instead of Usuario_tarifa (used by the web admin panel). CuentasHelper::precio checks Usuario_tarifa first, Preferencial as fallback. 3. payWithSaldo compared saldo against tarifa->valor (base price) instead of the effective price stored in state. Also registered the purchase with the wrong amount. Extract shared logic to CuentasHelper (contar, buscar, precio) to avoid duplication between TelegramBotService and PublicChat. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
137 lines
4.7 KiB
PHP
137 lines
4.7 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Cuentas;
|
|
use App\Models\Historial_cuenta;
|
|
use App\Models\Preferencial;
|
|
use App\Models\Tarifas;
|
|
use App\Models\Usuario_tarifa;
|
|
|
|
class CuentasHelper
|
|
{
|
|
/**
|
|
* Cuenta cuentas disponibles para una tarifa, igual que la web.
|
|
*/
|
|
public static function contar(Tarifas $tarifa): int
|
|
{
|
|
$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')
|
|
->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;
|
|
}
|
|
}
|