Add citas module: scheduling, calendar, blocked schedules
This commit is contained in:
176
app/Models/Cita.php
Normal file
176
app/Models/Cita.php
Normal file
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Cita extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'citas';
|
||||
|
||||
protected $fillable = [
|
||||
'mensaje_id',
|
||||
'nombre_cliente',
|
||||
'email_cliente',
|
||||
'telefono_cliente',
|
||||
'servicio',
|
||||
'fecha',
|
||||
'hora_inicio',
|
||||
'hora_fin',
|
||||
'duracion',
|
||||
'estado',
|
||||
'notas',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'fecha' => 'date',
|
||||
'hora_inicio' => 'datetime:H:i',
|
||||
'hora_fin' => 'datetime:H:i',
|
||||
'duracion' => 'integer',
|
||||
];
|
||||
|
||||
/**
|
||||
* Relación con Mensaje
|
||||
*/
|
||||
public function mensaje(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Mensaje::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope para filtrar citas pendientes
|
||||
*/
|
||||
public function scopePendiente(Builder $query): Builder
|
||||
{
|
||||
return $query->where('estado', 'pendiente');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope para filtrar citas confirmadas
|
||||
*/
|
||||
public function scopeConfirmada(Builder $query): Builder
|
||||
{
|
||||
return $query->where('estado', 'confirmada');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope para filtrar citas completadas
|
||||
*/
|
||||
public function scopeCompletada(Builder $query): Builder
|
||||
{
|
||||
return $query->where('estado', 'completada');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope para filtrar citas canceladas
|
||||
*/
|
||||
public function scopeCancelada(Builder $query): Builder
|
||||
{
|
||||
return $query->where('estado', 'cancelada');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope para filtrar citas por fecha específica
|
||||
*/
|
||||
public function scopePorFecha(Builder $query, $fecha): Builder
|
||||
{
|
||||
return $query->whereDate('fecha', $fecha);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope para filtrar citas entre dos fechas
|
||||
*/
|
||||
public function scopeEntreFechas(Builder $query, $inicio, $fin): Builder
|
||||
{
|
||||
return $query->whereBetween('fecha', [$inicio, $fin]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcular hora_fin basado en hora_inicio + duracion
|
||||
*/
|
||||
public function calcularHoraFin(): string
|
||||
{
|
||||
$horaInicio = Carbon::parse($this->hora_inicio);
|
||||
$horaFin = $horaInicio->addMinutes($this->duracion);
|
||||
|
||||
$this->hora_fin = $horaFin->format('H:i:s');
|
||||
|
||||
return $this->hora_fin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener estado formateado para mostrar
|
||||
*/
|
||||
public function getEstadoFormateadoAttribute(): string
|
||||
{
|
||||
$estados = [
|
||||
'pendiente' => 'Pendiente',
|
||||
'confirmada' => 'Confirmada',
|
||||
'completada' => 'Completada',
|
||||
'cancelada' => 'Cancelada',
|
||||
];
|
||||
|
||||
return $estados[$this->estado] ?? $this->estado;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener hora de inicio formateada
|
||||
*/
|
||||
public function getHoraInicioFormatAttribute(): string
|
||||
{
|
||||
return Carbon::parse($this->hora_inicio)->format('H:i');
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener hora de fin formateada
|
||||
*/
|
||||
public function getHoraFinFormatAttribute(): string
|
||||
{
|
||||
return Carbon::parse($this->hora_fin)->format('H:i');
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener duración formateada (horas y minutos)
|
||||
*/
|
||||
public function getDuracionFormatAttribute(): string
|
||||
{
|
||||
$horas = floor($this->duracion / 60);
|
||||
$minutos = $this->duracion % 60;
|
||||
|
||||
if ($horas > 0 && $minutos > 0) {
|
||||
return "{$horas}h {$minutos}min";
|
||||
} elseif ($horas > 0) {
|
||||
return "{$horas}h";
|
||||
} else {
|
||||
return "{$minutos}min";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verificar si la cita está activa (no cancelada ni completada)
|
||||
*/
|
||||
public function isActiva(): bool
|
||||
{
|
||||
return in_array($this->estado, ['pendiente', 'confirmada']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cambiar estado de la cita
|
||||
*/
|
||||
public function cambiarEstado(string $nuevoEstado): bool
|
||||
{
|
||||
$estadosValidos = ['pendiente', 'confirmada', 'completada', 'cancelada'];
|
||||
|
||||
if (! in_array($nuevoEstado, $estadosValidos)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->update(['estado' => $nuevoEstado]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user