Files
portal/app/app/Models/Deal.php
T

122 lines
3.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace App\Models;
use Database\Factories\DealFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Сделка (лид) — основная транзакционная сущность.
*
* Tenant-aware модель с RLS: SELECT/INSERT/UPDATE/DELETE фильтруются
* политикой `tenant_isolation` по `current_setting('app.current_tenant_id')`.
*
* Композитный PRIMARY KEY: (id, received_at). Таблица партиционирована
* по received_at. Все save/update/delete операции должны включать
* received_at в WHERE — иначе planner не сможет применить partition
* pruning. Eloquent не поддерживает composite PK нативно, поэтому
* setKeysForSaveQuery() переопределён.
*
* Идемпотентность webhook'ов реализована через отдельную таблицу
* webhook_dedup_keys (v8.6, CTO-17): UNIQUE на партиционированной deals
* без partition key невозможен. См. §5.5 narrative ТЗ.
*
* Источник: db/schema.sql v8.6 §5, table `deals`.
*
* @mixin IdeHelperDeal
*/
class Deal extends Model
{
/** @use HasFactory<DealFactory> */
use HasFactory, SoftDeletes;
protected $fillable = [
'id',
'tenant_id',
'source_crm_id',
'project_id',
'phone',
'phones',
'status',
'contact_name',
'comment',
'manager_id',
'assigned_at',
'escalated_count',
'duplicate_of_id',
'utm_source',
'utm_medium',
'utm_campaign',
'utm_content',
'region_code',
'subject_code',
'city',
'time_in_form_seconds',
'lead_score',
'is_test',
'received_at',
'deleted_at',
// Lead region resolution (Session 1, 31.05.2026).
'phone_operator',
'region_substituted',
];
protected function casts(): array
{
return [
'tenant_id' => 'integer',
'source_crm_id' => 'integer',
'project_id' => 'integer',
'manager_id' => 'integer',
'duplicate_of_id' => 'integer',
'escalated_count' => 'integer',
'time_in_form_seconds' => 'integer',
'subject_code' => 'integer',
'lead_score' => 'decimal:2',
'phones' => 'array',
'is_test' => 'boolean',
'region_substituted' => 'boolean',
'assigned_at' => 'datetime',
'received_at' => 'datetime',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
];
}
/**
* Composite PK: WHERE id = ? AND received_at = ? для save/update/delete.
* Без переопределения Eloquent сгенерил бы только WHERE id = ?, что
* заставило бы planner сканировать все партиции (partition pruning не работает).
*/
protected function setKeysForSaveQuery($query)
{
return $query
->where('id', $this->getAttribute('id'))
->where('received_at', $this->getAttribute('received_at'));
}
/** @return BelongsTo<Tenant, $this> */
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
/** @return BelongsTo<Project, $this> */
public function project(): BelongsTo
{
return $this->belongsTo(Project::class);
}
/** @return BelongsTo<User, $this> */
public function manager(): BelongsTo
{
return $this->belongsTo(User::class, 'manager_id');
}
}