Files
portal/app/app/Models/SupplierProject.php
T
Дмитрий 62aa55f033 feat(models): add SupplierProject Eloquent model + factory + tests
- app/Models/SupplierProject.php — fillable + casts (jsonb arrays + datetime)
  + scopes: active() (inactive_since IS NULL), staleSince(N days),
  forSignal(signal_type, unique_key)
- database/factories/SupplierProjectFactory.php — корректно учитывает
  chk_supplier_projects_b1_not_for_sms (B1 не порождает SMS-проекты)
- tests/Feature/Models/SupplierProjectTest.php — 6 тестов: factory,
  array casts (workdays + regions), scopeActive, scopeStaleSince,
  scopeForSignal (3 платформы на один домен — UNIQUE (platform,unique_key))

ide-helper:models -W -M -N перегенерил docblocks для 4 существующих моделей
(SaasAdminAuditLog, SystemSetting, UserRecoveryCode, ImpersonationToken) —
синхронизировал @property после schema v8.16.

Pest: 451 / 449 passed / 2 skipped (было 443+6 новых от Task 6 = 449).
Larastan: 0 errors. Pint: passed.

Spec: §2.2
Plan: Task 6

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 13:59:39 +03:00

89 lines
2.5 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Models;
use Database\Factories\SupplierProjectFactory;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
/**
* Supplier-уровневый агрегат проекта у поставщика crm.bp-gr.ru.
*
* Sharing-model: один supplier_project разделяется между несколькими Лидерра-tenant'ами
* (см. spec §2.2). НЕ tenant-scoped — RLS НЕ применяется.
*
* Уникальность: (platform, unique_key). Для site/call: unique_key = домен/номер.
* Для sms: B2 ключ — sender+keyword (конкатенация), B3 — только sender.
*
* Spec: docs/superpowers/specs/2026-05-10-supplier-integration-design.md §2.2
*
* @mixin IdeHelperSupplierProject
*/
class SupplierProject extends Model
{
/** @use HasFactory<SupplierProjectFactory> */
use HasFactory;
protected $table = 'supplier_projects';
protected $fillable = [
'platform',
'signal_type',
'unique_key',
'supplier_external_id',
'current_limit',
'current_workdays',
'current_regions',
'sync_status',
'last_synced_at',
'inactive_since',
];
protected function casts(): array
{
return [
'current_workdays' => 'array',
'current_regions' => 'array',
'current_limit' => 'integer',
'last_synced_at' => 'datetime',
'inactive_since' => 'datetime',
];
}
/**
* @param Builder<SupplierProject> $query
* @return Builder<SupplierProject>
*/
public function scopeActive(Builder $query): Builder
{
return $query->whereNull('inactive_since');
}
/**
* @param Builder<SupplierProject> $query
* @return Builder<SupplierProject>
*/
public function scopeStaleSince(Builder $query, int $days): Builder
{
return $query->whereNotNull('inactive_since')
->where('inactive_since', '<=', now()->subDays($days));
}
/**
* @param Builder<SupplierProject> $query
* @return Builder<SupplierProject>
*/
public function scopeForSignal(Builder $query, string $signalType, string $uniqueKey): Builder
{
return $query->where('signal_type', $signalType)->where('unique_key', $uniqueKey);
}
protected static function newFactory(): SupplierProjectFactory
{
return SupplierProjectFactory::new();
}
}