feat реклама за показы: правда про документ, экран «ждёт разбора» и разбор своих ошибок
Задача 16 закрыта решением владельца. Дороги «робот везёт документ в кабинет Яндекса» не существует — доказано двумя нарочными отказами, обычной тематикой и лицензируемой: в окне отказа ноль полей для файла, документы Яндекс принимает только снаружи кабинета. Приём документа оставлен, но портал больше не молчит: клиент приложил файл — в ленту сразу ложится отметка «документ у нас, передать его Яндексу автоматически нельзя, при необходимости отнесём сами и напишем здесь», а владельцу уходит письмо на адрес алертов. Без письма обещание было бы пустым: файл просто лёг бы на диск. Сам файл письмом не отправляем — это чужие бумаги. Обычный ответ без файла ни отметки, ни письма не даёт. Экран «ждёт разбора» в админке: ручка была, экрана не было. Третья карточка на странице «Реклама» — клиент, кампания, что робот делал человеческими словами, номер объявления и на чём споткнулся. В подписи прямо сказано, чего там НЕ будет: обычных отказов, их клиент разбирает сам. Дальше — разбор собственной работы этого дня. Найдено четыре ошибки, все исправлены. 1. ТЯЖЁЛАЯ. Доклад разведки на бою уронил бы очередь заданий целиком. Робот пишет в ленту под служебной ролью, а у неё на этой таблице было только чтение. Отказ по правам, 500 роботу, три повтора — и задание навсегда «в работе». Пока хоть одно задание в работе, выдача отвечает «работы нет» ВСЕМ клиентам. Лечение — запись схемы v9.17: право на запись плюс нумератор. В плане про это было написано прямым текстом, я прошёл мимо. Тесты поймать не могли: ходят суперпользователем. 2. Признак «набор создан» я выдумал: взял метку, которая в нашей же разметке описана как СКРЫТАЯ галочка. Проверка «видно ли её» не сработала бы никогда. Признак с экрана убран совсем: успех определяет портал слепком креативов, а «окно не закрылось» — это норма, так и есть живьём. 3. Сломал ленту для повторного отказа. Поменял защиту от дублей на «такой текст уже когда-либо был» — и клиент, починивший рекламу и получивший тот же отказ, не увидел бы ничего. Вернул сравнение с последним сообщением, а заглушку «причину выясняем» держит теперь сам джоб: показываем один раз, пока сказать нечего. 4. Мой собственный тест оказался пустышкой: оставался зелёным при вырезанной защите. В нём отклонялись ВСЕ объявления, а тогда кампания уходит в «отклонена» и обход её больше не берёт. Сценарий существует только при частичном отказе — тест переписан на два объявления и теперь вырезание защиты его роняет. Портал 391/391, админские экраны 9/9, фронт на затронутых наборах 52/52, робот 74/74, мест снятия заморозки денег по-прежнему четыре. На боевой не выкатывалось, рубильник Директа выключен, живьём разведка не гонялась. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -452,3 +452,73 @@ it('рубильник выключен — ни обращения к Янде
|
||||
expect(AdCreativeJob::where('campaign_id', $campaign->id)->count())->toBe(0)
|
||||
->and($campaign->banners()->first()->moderation_status)->toBe(AdCampaignBanner::MOD_MODERATION);
|
||||
});
|
||||
|
||||
/**
|
||||
* 🪤 Ловушка, вскрытая разведкой. Порядок в жизни такой: обход кладёт клиенту «Яндекс
|
||||
* причину не назвал, выясняем» → робот приносит НАСТОЯЩУЮ причину → следующий обход
|
||||
* снова кладёт заглушку, ведь последним в ленте лежит уже доклад робота.
|
||||
*
|
||||
* Клиент, только что прочитавший настоящую причину, получил бы поверх неё «причину
|
||||
* не назвали» и ещё одно письмо. Заглушку показываем ОДИН раз — пока сказать нечего.
|
||||
*
|
||||
* 🔴 Кампания тут с ДВУМЯ объявлениями: одно приняли, одно отклонили. Иначе сценария
|
||||
* не существует вовсе — при отказе ВСЕХ объявлений кампания уходит в «отклонена»,
|
||||
* и обход её больше не берёт. Первая версия этого теста была пустышкой ровно поэтому:
|
||||
* вырезание защиты её не роняло.
|
||||
*/
|
||||
it('после доклада разведки заглушка «причину выясняем» в ленту не возвращается', function () {
|
||||
configureYandexForModeration();
|
||||
|
||||
[$campaign, $banners] = makeModeratedCampaignWithBanners([9106, 9108]);
|
||||
$otkloneny = $banners->first();
|
||||
|
||||
$otvet = ['result' => ['Ads' => [
|
||||
['Id' => 9106, 'State' => 'OFF', 'Status' => 'REJECTED', 'StatusClarification' => '
|
||||
Отклонено на модерации.'],
|
||||
['Id' => 9108, 'State' => 'ON', 'Status' => 'ACCEPTED', 'StatusClarification' => 'Принято'],
|
||||
]]];
|
||||
|
||||
Http::fake(['*' => Http::response($otvet)]);
|
||||
|
||||
// Первый обход — заглушка. Кампания остаётся работающей: одно объявление принято.
|
||||
(new SyncCampaignModerationJob)->handle();
|
||||
expect($campaign->refresh()->status)->toBe(AdCampaign::STATUS_RUNNING);
|
||||
|
||||
// Робот сходил и принёс настоящую причину.
|
||||
app(CampaignMessageService::class)->postFromRobot(
|
||||
$campaign, (int) $otkloneny->id, 'Нет предупреждения: финансовые услуги',
|
||||
);
|
||||
|
||||
// Второй обход — заглушке в ленте больше не место.
|
||||
(new SyncCampaignModerationJob)->handle();
|
||||
|
||||
$bodies = AdCampaignMessage::where('campaign_id', $campaign->id)
|
||||
->where('banner_id', $otkloneny->id)
|
||||
->orderBy('id')->pluck('body')->all();
|
||||
|
||||
expect($bodies)->toHaveCount(2)
|
||||
->and($bodies[1])->toContain('финансовые услуги');
|
||||
});
|
||||
|
||||
/**
|
||||
* Обратная сторона: пока Яндекс молчит, а робот ещё не сходил, заглушка нужна —
|
||||
* иначе под ярлыком «Отклонено» у клиента будет пустота.
|
||||
*/
|
||||
it('пока разведка не сходила, заглушка клиенту всё-таки показывается', function () {
|
||||
configureYandexForModeration();
|
||||
|
||||
[$campaign] = makeModeratedCampaignWithBanners([9107]);
|
||||
|
||||
Http::fake(['*' => Http::response(['result' => ['Ads' => [[
|
||||
'Id' => 9107, 'State' => 'OFF', 'Status' => 'REJECTED',
|
||||
'StatusClarification' => '
|
||||
Отклонено на модерации.',
|
||||
]]]])]);
|
||||
|
||||
(new SyncCampaignModerationJob)->handle();
|
||||
|
||||
$first = AdCampaignMessage::where('campaign_id', $campaign->id)->first();
|
||||
|
||||
expect($first)->not->toBeNull()
|
||||
->and($first->body)->toContain('причину не назвал');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user