/
DATKAI
/
ITCUP
Обзор
Документация
Войти
/
DATKAI
/
ITCUP
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
app/Models/License.php
148 строк
4 KB
DATKAI
feat(licenses): уведомления, email, тип 1С:Предприятие/ИТС, продление с историей
02 июл 2026, 11:04
02 июл 2026, 11:04
ce115fc
Код
Авторство
О чём код?
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; class License extends Model { protected $fillable = [ 'name', 'license_type_id', 'number', 'vendor', 'issued_at', 'expires_at', 'is_perpetual', 'owner_user_id', 'asset_id', 'cost', 'seats', 'status', 'notified_expiring_at', 'notified_expired_at', 'custom_field_values', 'attachments', 'notes', ]; protected $casts = [ 'issued_at' => 'date', 'expires_at' => 'date', 'is_perpetual' => 'boolean', 'cost' => 'decimal:2', 'seats' => 'integer', 'notified_expiring_at' => 'date', 'notified_expired_at' => 'date', 'custom_field_values' => 'array', 'attachments' => 'array', ]; protected static function booted(): void { static::saving(function (License $license) { // При изменении срока сбрасываем флаги уведомлений и оживляем статус if ($license->isDirty('expires_at')) { $license->notified_expiring_at = null; $license->notified_expired_at = null; if ($license->status === 'expired' && !$license->isExpired()) { $license->status = 'active'; } } }); } public const STATUSES = [ 'active' => 'Действует', 'expired' => 'Истекла', 'revoked' => 'Отозвана', 'archived' => 'Архив', ]; public const STATUS_COLORS = [ 'active' => 'success', 'expired' => 'danger', 'revoked' => 'warning', 'archived' => 'gray', ]; public function type(): BelongsTo { return $this->belongsTo(LicenseType::class, 'license_type_id'); } public function owner(): BelongsTo { return $this->belongsTo(User::class, 'owner_user_id'); } public function asset(): BelongsTo { return $this->belongsTo(Asset::class); } public function isExpired(): bool { if ($this->is_perpetual) { return false; } return $this->expires_at && $this->expires_at->isPast(); } public function isExpiringSoon(?int $days = null): bool { if ($this->is_perpetual || !$this->expires_at) { return false; } if ($this->expires_at->isPast()) { return false; } $threshold = $days ?? $this->type?->notify_days_before ?? 30; return $this->expires_at->diffInDays(now()) <= $threshold; } public function daysUntilExpiry(): ?int { if ($this->is_perpetual || !$this->expires_at) { return null; } return (int) now()->startOfDay()->diffInDays($this->expires_at->startOfDay(), false); } public function computedStatus(): string { if (in_array($this->status, ['revoked', 'archived'])) { return $this->status; } if ($this->isExpired()) { return 'expired'; } return 'active'; } public function renewals(): HasMany { return $this->hasMany(LicenseRenewal::class)->latest('new_expires_at'); } /** Продлить лицензию: записать историю, обновить срок и оживить статус */ public function renew(string $newExpiresAt, ?float $cost = null, ?string $note = null, ?int $userId = null): LicenseRenewal { $renewal = $this->renewals()->create([ 'old_expires_at' => $this->expires_at, 'new_expires_at' => $newExpiresAt, 'cost' => $cost, 'note' => $note, 'user_id' => $userId, ]); // saving-хук сам сбросит флаги уведомлений и вернёт статус active $this->expires_at = $newExpiresAt; $this->is_perpetual = false; $this->save(); return $renewal; } }