feat реклама показы: ядро переведено на набор креативов вместо одного адаптивного

Конструктор креативов Яндекса закрыт 01.06.2026 — адаптивного креатива на все
размеры не существует. Медийная кампания состоит из объявления на каждый размер
блока со своим креативом, поэтому строка баннера стала единицей
размер плюс файл плюс креатив плюс объявление.

Что сделано:
- у баннера появились номер креатива, номер объявления и статус модерации
- кап веса баннера поднят со 150 КБ до предела Яндекса 512 КБ
- слепок картиночных креативов аккаунта через creatives.get
- опознание своих креативов разницей слепков до и после загрузки по размеру
- запуск заводит объявление на каждый включённый баннер
- модерация считается по каждому объявлению: кампания работает, если принято
  хотя бы одно, а деньги возвращаются только когда отклонены все

Заморозка и возврат денег не тронуты, денежных выходов по-прежнему четыре.

После выката на прод ПЕРЕзапустить db/03_service_bypass_policies.sql, иначе
джоб модерации молча увидит ноль баннеров.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-07-27 14:33:02 +03:00
parent 1a00e215f5
commit c9406533bf
19 changed files with 749 additions and 89 deletions
@@ -183,3 +183,30 @@ it('returns null from creative preview when the creative is not found', function
expect($preview)->toBeNull();
});
it('lists image creative ids with their sizes and ignores video creatives', function () {
Http::fake([
'*/json/v5/creatives' => Http::response(['result' => ['Creatives' => [
['Id' => 1163441165, 'Type' => 'VIDEO_EXTENSION_CREATIVE', 'Width' => 1080, 'Height' => 1080],
['Id' => 1163586673, 'Type' => 'HTML5_CREATIVE', 'Width' => 300, 'Height' => 250],
['Id' => 1163586680, 'Type' => 'HTML5_CREATIVE', 'Width' => 728, 'Height' => 90],
]]]),
]);
$client = new YandexDirectClient('https://api.direct.yandex.com', 'T');
// Картиночные креативы Яндекс хранит типом HTML5_CREATIVE даже для загруженных JPG —
// проверено живым запросом 27.07.2026. Видео-креативы в набор попадать не должны.
expect($client->listImageCreativeIds())->toBe([
1163586673 => [300, 250],
1163586680 => [728, 90],
]);
});
it('returns an empty snapshot when the account has no creatives', function () {
Http::fake(['*/json/v5/creatives' => Http::response(['result' => []])]);
$client = new YandexDirectClient('https://api.direct.yandex.com', 'T');
expect($client->listImageCreativeIds())->toBe([]);
});