1ba25e6b4e
Закрыты 4 TODO в Webhook PoC. Job теперь полностью реализует §5.5
narrative ТЗ за исключением DuplicateDetector (Биз-19) и
SendNewLeadNotificationJob (Биз-20) — отдельные ветви.
5 новых Eloquent-моделей:
- app/app/Models/BalanceTransaction.php — списание lead_charge -1,
type-константы (TYPE_LEAD_CHARGE и т.д.)
- app/app/Models/ActivityLog.php — event=deal.created с
context.source=webhook, event-константы
- app/app/Models/RejectedDealsLog.php — zero_balance ветка вместо
Log::info (payload сохраняется для возможного восстановления)
- app/app/Models/SupplierLeadCost.php — composite PK (id, received_at),
snapshot cost_rub из suppliers, supplier_id resolves через
project_suppliers m2m (первый активный по sort_order)
- app/app/Models/Supplier.php — минимальная для FK target
Job-структура реструктурирована: handle() оркестрирует, делегирует в
logRejection() / chargeNewLead() / resolveSupplierId() / upsertDeal().
Все INSERT'ы в одной DB::transaction — атомарность Ю-2 (deal +
balance_transaction + supplier_lead_cost появляются вместе).
Graceful skip SupplierLeadCost если у проекта нет активного supplier
через project_suppliers + Log::warning. TODO для production: SystemSetting
fallback.
6 новых Pest-тестов в ProcessWebhookJobTest:
- BalanceTransaction lead_charge -1 для новой сделки
- Дубль vid НЕ создаёт BalanceTransaction
- ActivityLog event=deal.created с context.source=webhook
- RejectedDealsLog reason=zero_balance при balance_leads=0
- SupplierLeadCost snapshot cost_rub (helper seedSupplierForProject)
- SupplierLeadCost graceful skip без активного supplier
Pest 37/37 зелёные за 3.9 сек. Pint + Larastan чисто (ide-helper:models
регенерирован для 5 новых моделей).
CLAUDE.md v1.12 → v1.13. Реестр Открытые_вопросы v1.21 → v1.22.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
55 lines
1.5 KiB
PHP
55 lines
1.5 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
/**
|
||
* Каталог поставщиков данных (B1/B2/B3 — суб-поставщики crm.bp-gr.ru).
|
||
*
|
||
* SaaS-уровневая (НЕ tenant-aware): один глобальный каталог на всю систему.
|
||
* Видна всем тенантам через project_suppliers (m2m с проектом).
|
||
*
|
||
* Источник: db/schema.sql v8.7 §2.3, table `suppliers`.
|
||
*
|
||
* @mixin IdeHelperSupplier
|
||
*/
|
||
class Supplier extends Model
|
||
{
|
||
protected $fillable = [
|
||
'code',
|
||
'name',
|
||
'description',
|
||
'accepts_types',
|
||
'cost_rub',
|
||
'settings_schema',
|
||
'channel',
|
||
'supports_sender_name',
|
||
'supports_keyword',
|
||
'supports_csv_upload',
|
||
'supports_domains_list',
|
||
'quality_score',
|
||
'is_active',
|
||
'sort_order',
|
||
];
|
||
|
||
protected function casts(): array
|
||
{
|
||
return [
|
||
'cost_rub' => 'decimal:2',
|
||
'quality_score' => 'decimal:2',
|
||
'supports_sender_name' => 'boolean',
|
||
'supports_keyword' => 'boolean',
|
||
'supports_csv_upload' => 'boolean',
|
||
'supports_domains_list' => 'boolean',
|
||
'is_active' => 'boolean',
|
||
'sort_order' => 'integer',
|
||
'settings_schema' => 'array',
|
||
'created_at' => 'datetime',
|
||
'updated_at' => 'datetime',
|
||
];
|
||
}
|
||
}
|