8e91be53c3
Часть 3b-1 из 6. Из одной картинки клиента генерируется и сохраняется полный набор баннеров кампании (15 размеров Яндекса). - Таблица ad_campaign_banners (RLS tenant_isolation, GRANT crm_app_user SELECT/INSERT/DELETE, клиентская — srv_bypass не нужен). Модель AdCampaignBanner. - CampaignBannerService::generate — прогон исходной картинки по BannerSizes через BannerGenerator, файлы на приватный диск local, строки в БД; перегенерация заменяет набор. - CHANGELOG_schema v8.97 + предупреждение для Части 4 (джоб под crm_supplier_worker потребует GRANT + srv_bypass re-run, иначе тихий ноль). Тесты: 9/9 зелёные (Storage::fake). rls-reviewer: PASS. Spec: docs/superpowers/specs/2026-07-25-yandex-reklama-medijnaya-pokazy-design.md §4 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
58 lines
2.1 KiB
PHP
58 lines
2.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\AdCampaign;
|
|
use App\Models\AdCampaignBanner;
|
|
use App\Models\Tenant;
|
|
use App\Services\Advertising\CampaignBannerService;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
function bannerSrcJpeg(int $w, int $h): string
|
|
{
|
|
$img = imagecreatetruecolor($w, $h);
|
|
imagefill($img, 0, 0, imagecolorallocate($img, 15, 110, 86));
|
|
ob_start();
|
|
imagejpeg($img, null, 90);
|
|
$bin = (string) ob_get_clean();
|
|
imagedestroy($img);
|
|
|
|
return $bin;
|
|
}
|
|
|
|
it('генерирует полный набор из 15 баннеров с файлами на диске', function () {
|
|
Storage::fake('local');
|
|
$tenant = Tenant::factory()->create();
|
|
$campaign = AdCampaign::create([
|
|
'tenant_id' => $tenant->id, 'name' => 'C', 'audience_days' => 10, 'use_uploaded_list' => false,
|
|
]);
|
|
|
|
$count = app(CampaignBannerService::class)->generate($campaign, bannerSrcJpeg(1500, 1500));
|
|
|
|
expect($count)->toBe(15)
|
|
->and(AdCampaignBanner::where('campaign_id', $campaign->id)->count())->toBe(15);
|
|
|
|
$b = AdCampaignBanner::where('campaign_id', $campaign->id)->where('width', 300)->where('height', 250)->first();
|
|
expect($b)->not->toBeNull();
|
|
Storage::disk('local')->assertExists($b->path);
|
|
$info = getimagesizefromstring((string) Storage::disk('local')->get($b->path));
|
|
expect($info[0])->toBe(300)->and($info[1])->toBe(250)->and($b->bytes)->toBeGreaterThan(0);
|
|
});
|
|
|
|
it('перегенерация заменяет прежний набор (снова 15, старые файлы удалены)', function () {
|
|
Storage::fake('local');
|
|
$tenant = Tenant::factory()->create();
|
|
$campaign = AdCampaign::create([
|
|
'tenant_id' => $tenant->id, 'name' => 'C', 'audience_days' => 10, 'use_uploaded_list' => false,
|
|
]);
|
|
$svc = app(CampaignBannerService::class);
|
|
|
|
$svc->generate($campaign, bannerSrcJpeg(1500, 1500));
|
|
$firstPaths = AdCampaignBanner::where('campaign_id', $campaign->id)->pluck('path')->all();
|
|
|
|
$svc->generate($campaign, bannerSrcJpeg(1200, 1200));
|
|
|
|
expect(AdCampaignBanner::where('campaign_id', $campaign->id)->count())->toBe(15);
|
|
expect(count($firstPaths))->toBe(15);
|
|
});
|