fix: account lookup now uses real availability logic (servicio_id + pantallas)
- Replace tarifa_id+estado='ocupado' query with the same logic used in ShowServicios: filter by servicio_id, date range, historiales_count - Full-account plans (pantallas == completa): look for estado='pendiente' accounts without assigned profiles - Partial plans (screen sharing): look for estado='activo' accounts with remaining slots (historiales_count <= pantallas_servicio - pantallas) - Wrap purchase in DB::transaction to avoid race conditions - Remove incorrect cuenta->update(['estado' => 'ocupado']) — availability is now tracked via historial_cuentas count, not a flag - Use effective price (Preferencial override) for saldo deduction Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
26953c9dd5
commit
b4624db056
@@ -6,6 +6,7 @@ use App\Mail\ChatOtpMail;
|
||||
use App\Models\Role;
|
||||
use App\Models\Cuentas;
|
||||
use App\Models\ChatContact;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Models\ChatConversation;
|
||||
use App\Models\ChatMessage;
|
||||
use App\Models\Historiale;
|
||||
@@ -593,8 +594,7 @@ class PublicChat extends Component
|
||||
return;
|
||||
}
|
||||
|
||||
$disponibles = Cuentas::where('tarifa_id', $tarifaId)->where('estado', 'activo')->count();
|
||||
if ($disponibles < 1) {
|
||||
if ($this->contarDisponibles($tarifa) < 1) {
|
||||
$this->guardarMensajeBot($this->convId, "Sin cuentas disponibles para este plan. Intenta con otro.");
|
||||
$this->volver('servicios.listar');
|
||||
return;
|
||||
@@ -614,7 +614,7 @@ class PublicChat extends Component
|
||||
$detalle = $tarifa->servicio->por_tiempo
|
||||
? "{$tarifa->dias} dias"
|
||||
: "{$tarifa->pantallas} pantalla(s) / {$tarifa->dias} dias";
|
||||
$saldoInsuficiente = ! $this->userId || ($this->saldoUsuario < $precio);
|
||||
$saldoInsuficiente = ! $this->userId || ((float) $this->saldoUsuario < $precio);
|
||||
|
||||
ChatMessage::create([
|
||||
'conversation_id' => $this->convId,
|
||||
@@ -646,42 +646,46 @@ class PublicChat extends Component
|
||||
return;
|
||||
}
|
||||
|
||||
$user = User::with('saldo')->find($this->userId);
|
||||
$saldo = $user->saldo;
|
||||
$user = User::with('saldo')->find($this->userId);
|
||||
$saldo = $user->saldo;
|
||||
$precio = (float) ($this->flujoData['valor'] ?? $tarifa->valor);
|
||||
|
||||
if (! $saldo || $saldo->valor < $tarifa->valor) {
|
||||
if (! $saldo || $saldo->valor < $precio) {
|
||||
$this->guardarMensajeBot(
|
||||
$this->convId,
|
||||
"Saldo insuficiente. Tienes $" . number_format($saldo?->valor ?? 0) .
|
||||
" y el plan cuesta $" . number_format($tarifa->valor) . "."
|
||||
" y el plan cuesta $" . number_format($precio) . "."
|
||||
);
|
||||
$this->volver('menu.principal');
|
||||
return;
|
||||
}
|
||||
|
||||
$cuenta = Cuentas::where('tarifa_id', $tarifa->id)->where('estado', 'activo')->first();
|
||||
$cuenta = $this->buscarCuentaDisponible($tarifa);
|
||||
if (! $cuenta) {
|
||||
$this->guardarMensajeBot($this->convId, "No hay cuentas disponibles en este momento.");
|
||||
$this->guardarMensajeBot($this->convId, "No hay cuentas disponibles en este momento. Intenta más tarde o contacta a un asesor.");
|
||||
return;
|
||||
}
|
||||
|
||||
$historial = Historiale::create([
|
||||
'fecha_inicio' => now(),
|
||||
'fecha_final' => now()->addDays($tarifa->dias),
|
||||
'valor' => $tarifa->valor,
|
||||
'utilidad' => $tarifa->utilidad ?? 0,
|
||||
'tipo_pago' => 'saldo',
|
||||
'estado' => 'entregado',
|
||||
'vendedor_id' => $this->userId,
|
||||
'tarifa_id' => $tarifa->id,
|
||||
'cliente_id' => $this->userId,
|
||||
'nombre_cliente' => $user->name,
|
||||
]);
|
||||
$nuevoSaldo = $saldo->valor - $precio;
|
||||
|
||||
Historial_cuenta::create(['historial_id' => $historial->id, 'cuenta_id' => $cuenta->id]);
|
||||
$cuenta->update(['estado' => 'ocupado']);
|
||||
$saldo->update(['valor' => $saldo->valor - $tarifa->valor]);
|
||||
$this->saldoUsuario = $saldo->valor - $tarifa->valor;
|
||||
DB::transaction(function () use ($tarifa, $user, $saldo, $cuenta, $precio, $nuevoSaldo) {
|
||||
$historial = Historiale::create([
|
||||
'fecha_inicio' => now(),
|
||||
'fecha_final' => now()->addDays($tarifa->dias),
|
||||
'valor' => $precio,
|
||||
'utilidad' => $tarifa->utilidad ?? 0,
|
||||
'tipo_pago' => 'saldo',
|
||||
'estado' => 'entregado',
|
||||
'vendedor_id' => $this->userId,
|
||||
'tarifa_id' => $tarifa->id,
|
||||
'cliente_id' => $this->userId,
|
||||
'nombre_cliente' => $user->name,
|
||||
]);
|
||||
Historial_cuenta::create(['historial_id' => $historial->id, 'cuenta_id' => $cuenta->id]);
|
||||
$saldo->update(['valor' => $nuevoSaldo]);
|
||||
});
|
||||
|
||||
$this->saldoUsuario = $nuevoSaldo;
|
||||
|
||||
ChatMessage::create([
|
||||
'conversation_id' => $this->convId,
|
||||
@@ -1284,6 +1288,100 @@ class PublicChat extends Component
|
||||
]);
|
||||
}
|
||||
|
||||
private function contarDisponibles(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');
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
private function buscarCuentaDisponible(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');
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
$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();
|
||||
|
||||
if (! $cuenta) {
|
||||
$suma2 = $servicio->pantallas - $tarifa->pantallas;
|
||||
$baseQ2 = Cuentas::select('*')
|
||||
->where('servicio_id', $servicio->id)
|
||||
->whereDate('inicio', '>=', $fechaBase)
|
||||
->whereDate('vencimiento', '>=', $fechaMin)
|
||||
->whereDate('vencimiento', '<=', $fechaMax)
|
||||
->withCount('historiales')
|
||||
->where('estado', 'activo')
|
||||
->orderBy('inicio', 'ASC');
|
||||
|
||||
$cuenta = Cuentas::fromSub($baseQ2, 'alias')
|
||||
->where('historiales_count', '<=', $suma2)
|
||||
->orderBy('inicio', 'ASC')
|
||||
->lockForUpdate()
|
||||
->first();
|
||||
}
|
||||
|
||||
return $cuenta;
|
||||
}
|
||||
|
||||
private function efectivePrice(int $tarifaId, ?int $userId, float $base): float
|
||||
{
|
||||
if ($userId) {
|
||||
|
||||
Reference in New Issue
Block a user