Files
portal/app/app/Models/PdSubjectRequest.php
T
Дмитрий f5482f415c fix(pd): PdSubjectRequest::$connection = pgsql_supplier (hole #4 prod fix)
crm_app_user (default pgsql connection) не имеет INSERT/UPDATE прав на
pd_subject_requests — это SaaS-уровневая таблица. На проде Eloquent
PdSubjectRequest::create() падал с Insufficient privilege.

Фикс: protected $connection = 'pgsql_supplier' (BYPASSRLS, crm_supplier_worker)
— симметрично существующему контроллеру и сервису. Альтернатива (GRANT для
crm_app_user) размывает границу tenant-уровня (db/00_create_roles.sql).

Smoke прод: create через tinker → row.id=1, deadline_at +30 дней auto-trigger
сработал. Cleanup row выполнен.

Tests: 12/12 passed (67 assertions, 2.5s).
2026-05-23 12:27:57 +03:00

90 lines
3.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\DB;
/**
* Обращение субъекта ПДн (152-ФЗ).
*
* SaaS-уровневая таблица — RLS не применяется. Доступ только из
* AdminPdSubjectRequestsController под saas-admin middleware.
*
* @property int $id
* @property string $received_at
* @property string|null $subject_email
* @property string|null $subject_phone
* @property string|null $subject_full_name
* @property string $request_type access|rectification|deletion|objection
* @property string|null $description
* @property string $status received|in_progress|completed|rejected
* @property int|null $tenant_id
* @property int|null $assigned_admin_id
* @property string|null $response_sent_at
* @property string|null $response_text
* @property string $deadline_at
* @property string|null $completed_at
* @property bool $processing_restricted
*/
class PdSubjectRequest extends Model
{
/**
* SaaS-уровневая таблица — crm_app_user (default) не имеет INSERT/UPDATE прав.
* Используем pgsql_supplier (BYPASSRLS / crm_supplier_worker), который имеет
* полный доступ. Альтернатива — GRANT для crm_app_user, но это размывает
* границу tenant-уровня (см. db/00_create_roles.sql).
*/
protected $connection = 'pgsql_supplier';
protected $table = 'pd_subject_requests';
public $timestamps = false;
/** @var list<string> */
protected $fillable = [
'received_at',
'subject_email',
'subject_phone',
'subject_full_name',
'request_type',
'description',
'status',
'tenant_id',
'assigned_admin_id',
'response_sent_at',
'response_text',
'deadline_at',
'completed_at',
'processing_restricted',
];
/** @var array<string, string> */
protected $casts = [
'received_at' => 'datetime',
'response_sent_at' => 'datetime',
'deadline_at' => 'datetime',
'completed_at' => 'datetime',
'processing_restricted' => 'boolean',
'tenant_id' => 'integer',
'assigned_admin_id' => 'integer',
];
/** Тенант, к которому относится обращение (nullable). */
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
/**
* SaaS-админ, назначенный исполнителем.
*
* NB: модель SaasAdminUser не создана — используем User как фиктивный базис.
* В реальном коде — DB::table('saas_admin_users') напрямую в контроллере.
*/
// assignedAdmin: нет Eloquent-модели SaasAdminUser — читается напрямую через DB
}