File: /var/www/api-talleres.bradford/app/Models/ClubOrderItem.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ClubOrderItem extends Model
{
use HasFactory;
protected $table = 'club_order_items';
protected $primaryKey = 'id';
protected $fillable = [
'club_order_id',
'student_id',
'club_id',
'club_period_id',
'price_snapshot',
'club_title_snapshot',
'cancelled_at',
'cancelled_by',
'cancellation_reason',
'deleted',
'deleted_at',
'user_created',
'user_updated',
'user_deleted',
];
protected $hidden = [
'deleted',
'deleted_at',
'user_deleted',
];
protected $casts = [
'price_snapshot' => 'decimal:0',
'cancelled_at' => 'datetime',
];
// =========================================================================
// RELACIONES
// =========================================================================
/**
* Pedido al que pertenece este item.
*/
public function order()
{
return $this->belongsTo(ClubOrder::class, 'club_order_id');
}
/**
* Alias de order() para compatibilidad.
*/
public function clubOrder()
{
return $this->belongsTo(ClubOrder::class, 'club_order_id');
}
/**
* Alumno inscrito.
*/
public function student()
{
return $this->belongsTo(Student::class, 'student_id');
}
/**
* Taller seleccionado.
*/
public function club()
{
return $this->belongsTo(Club::class, 'club_id');
}
/**
* Relación club-periodo para control de cupos.
*/
public function clubPeriod()
{
return $this->belongsTo(ClubPeriod::class, 'club_period_id');
}
/**
* Usuario que canceló el item.
*/
public function cancelledBy()
{
return $this->belongsTo(User::class, 'cancelled_by');
}
public function createdBy()
{
return $this->belongsTo(User::class, 'user_created');
}
public function updatedBy()
{
return $this->belongsTo(User::class, 'user_updated');
}
public function deletedBy()
{
return $this->belongsTo(User::class, 'user_deleted');
}
// =========================================================================
// HELPERS
// =========================================================================
/**
* Verifica si el item está cancelado administrativamente.
*/
public function isCancelled(): bool
{
return $this->cancelled_at !== null;
}
/**
* Verifica si el item es gratuito.
*/
public function isFree(): bool
{
return $this->price_snapshot == 0;
}
/**
* Obtiene el estado efectivo del item (hereda del pedido o cancelado).
*/
public function getEffectiveStatus(): string
{
if ($this->isCancelled()) {
return 'cancelled';
}
return $this->order->status ?? 'unknown';
}
// =========================================================================
// SCOPES
// =========================================================================
/**
* Items no cancelados.
*/
public function scopeNotCancelled($query)
{
return $query->whereNull('cancelled_at');
}
/**
* Items cancelados.
*/
public function scopeCancelled($query)
{
return $query->whereNotNull('cancelled_at');
}
/**
* Items de un alumno específico.
*/
public function scopeForStudent($query, int $studentId)
{
return $query->where('student_id', $studentId);
}
/**
* Items de un taller específico.
*/
public function scopeForClub($query, int $clubId)
{
return $query->where('club_id', $clubId);
}
/**
* Items no eliminados.
*/
public function scopeNotDeleted($query)
{
return $query->where('deleted', 0);
}
}