true, 'services.yandex_direct.base_url' => 'https://api-sandbox.direct.yandex.com', 'services.yandex_direct.token' => 'DIRTOKEN', ]); } /** * Кампания на модерации с набором баннеров, у каждого свой номер объявления. * * @param list $adIds * @return array{0: AdCampaign, 1: Collection} */ function makeModeratedCampaignWithBanners(array $adIds, int $yandexCampaignId = 222): array { $tenant = Tenant::factory()->create(); $campaign = AdCampaign::create([ 'tenant_id' => $tenant->id, 'name' => 'C', 'mode' => AdCampaign::MODE_MANUAL, 'audience_days' => 10, 'client_cpm_rub' => '120.00', 'status' => AdCampaign::STATUS_PENDING_MODERATION, 'yandex_campaign_id' => $yandexCampaignId, ]); $w = 300; $banners = collect($adIds)->map(function (int $adId) use ($campaign, &$w) { $w += 10; return AdCampaignBanner::create([ 'tenant_id' => $campaign->tenant_id, 'campaign_id' => $campaign->id, 'width' => $w, 'height' => 250, 'path' => "ad-banners/{$campaign->tenant_id}/{$campaign->id}/{$w}x250.jpg", 'bytes' => 1000, 'included' => true, 'yandex_creative_id' => 4000 + $adId, 'yandex_ad_id' => $adId, 'moderation_status' => AdCampaignBanner::MOD_MODERATION, ]); }); return [$campaign, $banners]; } it('keeps the campaign running when at least one banner ad is accepted', function () { configureYandexForModeration(); Http::fake(['*/json/v5/ads' => Http::response(['result' => ['Ads' => [ ['Id' => 5551, 'State' => 'ON', 'StatusClarification' => null, 'Status' => 'ACCEPTED'], ['Id' => 5552, 'State' => 'OFF', 'StatusClarification' => 'Текст на баннере', 'Status' => 'REJECTED'], ]]])]); [$campaign] = makeModeratedCampaignWithBanners([5551, 5552]); (new SyncCampaignModerationJob)->handle(); expect($campaign->fresh()->status)->toBe(AdCampaign::STATUS_RUNNING); $fresh = AdCampaignBanner::where('campaign_id', $campaign->id)->orderBy('yandex_ad_id')->get(); expect($fresh[0]->moderation_status)->toBe(AdCampaignBanner::MOD_ACCEPTED) ->and($fresh[1]->moderation_status)->toBe(AdCampaignBanner::MOD_REJECTED) ->and($fresh[1]->moderation_reason)->toBe('Текст на баннере'); }); it('rejects the campaign only when every banner ad is rejected', function () { configureYandexForModeration(); Http::fake(['*/json/v5/ads' => Http::response(['result' => ['Ads' => [ ['Id' => 5551, 'State' => 'OFF', 'StatusClarification' => 'Нельзя', 'Status' => 'REJECTED'], ['Id' => 5552, 'State' => 'OFF', 'StatusClarification' => 'Нельзя', 'Status' => 'REJECTED'], ]]])]); [$campaign] = makeModeratedCampaignWithBanners([5551, 5552]); (new SyncCampaignModerationJob)->handle(); expect($campaign->fresh()->status)->toBe(AdCampaign::STATUS_REJECTED); }); it('waits while at least one banner ad is still under moderation', function () { configureYandexForModeration(); Http::fake(['*/json/v5/ads' => Http::response(['result' => ['Ads' => [ ['Id' => 5551, 'State' => 'ON', 'StatusClarification' => null, 'Status' => 'ACCEPTED'], ['Id' => 5552, 'State' => 'OFF', 'StatusClarification' => null, 'Status' => 'MODERATION'], ]]])]); [$campaign] = makeModeratedCampaignWithBanners([5551, 5552]); (new SyncCampaignModerationJob)->handle(); expect($campaign->fresh()->status)->toBe(AdCampaign::STATUS_PENDING_MODERATION); }); // ВЫХОД 2 остаётся ровно один: разморозка зовётся только когда отклонены ВСЕ // объявления набора. Пока живо хоть одно — деньги остаются замороженными. it('не снимает заморозку, пока принято хотя бы одно объявление набора', function () { configureYandexForModeration(); Http::fake(['*/json/v5/ads' => Http::response(['result' => ['Ads' => [ ['Id' => 5561, 'State' => 'ON', 'StatusClarification' => null, 'Status' => 'ACCEPTED'], ['Id' => 5562, 'State' => 'OFF', 'StatusClarification' => 'Текст на баннере', 'Status' => 'REJECTED'], ]]])]); [$campaign] = makeModeratedCampaignWithBanners([5561, 5562], 229); $svc = app(AdWalletService::class); $svc->topup((int) $campaign->tenant_id, '3000.00', 'yandex', 'тест'); $svc->freeze((int) $campaign->tenant_id, 'yandex', 'campaign', (int) $campaign->id, '1200.00'); (new SyncCampaignModerationJob)->handle(); expect($campaign->fresh()->status)->toBe(AdCampaign::STATUS_RUNNING) ->and(AdWallet::where('tenant_id', $campaign->tenant_id)->first()->frozen_rub)->toBe('1200.00'); });