/** * Meta Ads: vykon reklam na Facebooku a Instagramu. * * Sluzba: https://services.csbot.cz/apps/meta * Endpoint: GET /ads/insights/{object_id} * * Meta pocita **velke reporty asynchronne**. Tenhle krok je synchronni verze * pro bezne obdobi a uroven; kdyz Meta odpovi, ze uloha bezi, rekne se to * nahlas misto toho, aby krok predstiral prazdny vysledek. * * Utrata chodi v mene uctu jako text. Prevadi se na cislo tady, aby se s ni * v dalsim kroku dalo pocitat. */ export const manifest = { id: 'meta-ads.insights', name: 'Načíst výkon reklam', description: 'Stáhne útratu, zobrazení, prokliky a konverze za období. Objektem může být ' + 'reklamní účet, kampaň, sestava i jednotlivá reklama.', inputs: [ { id: 'objectId', label: 'ID objektu', type: 'string', required: true, hint: 'Reklamní účet jako act_123456789, nebo ID kampaně, sestavy či reklamy.', }, { id: 'level', label: 'Úroveň', type: 'string', required: false, default: 'campaign', options: [ { value: 'account', label: 'Účet' }, { value: 'campaign', label: 'Kampaň' }, { value: 'adset', label: 'Sestava' }, { value: 'ad', label: 'Reklama' }, ], }, { id: 'period', label: 'Období', type: 'string', required: false, default: 'last_7d', options: [ { value: 'today', label: 'Dnes' }, { value: 'yesterday', label: 'Včera' }, { value: 'last_7d', label: 'Posledních 7 dní' }, { value: 'last_30d', label: 'Posledních 30 dní' }, { value: 'this_month', label: 'Tento měsíc' }, { value: 'last_month', label: 'Minulý měsíc' }, ], hint: 'Použije se, když není vyplněné vlastní datum.', }, { id: 'dateFrom', label: 'Od', type: 'date', required: false, hint: 'Vyplněné datum od i do přebije volbu období.', }, { id: 'dateTo', label: 'Do', type: 'date', required: false }, { id: 'fields', label: 'Pole', type: 'string', required: false, default: 'campaign_name,impressions,clicks,spend,ctr,cpc,actions', hint: 'Oddělená čárkou, podle dokumentace Meta Marketing API.', }, ], outputs: [ { id: 'count', label: 'Počet řádků', type: 'number', required: true }, { id: 'rows', label: 'Řádky reportu', type: 'list', required: true }, { id: 'spend', label: 'Útrata celkem', type: 'number', required: true }, { id: 'clicks', label: 'Prokliky celkem', type: 'number', required: true }, { id: 'impressions', label: 'Zobrazení celkem', type: 'number', required: true }, ], timeoutMs: 60000, }; export async function run(inputs, ctx) { const { pick, num, round } = ctx.util; const query = { level: inputs.level, fields: inputs.fields }; if (inputs.dateFrom && inputs.dateTo) { // Meta chce rozsah jako JSON v query parametru, ne jako dva parametry. query.time_range = JSON.stringify({ since: inputs.dateFrom.slice(0, 10), until: inputs.dateTo.slice(0, 10), }); } else { if (inputs.dateFrom || inputs.dateTo) { ctx.log('Vyplněné je jen jedno datum, použije se zvolené období.'); } query.date_preset = inputs.period; } const { body } = await ctx.http.get(`/ads/insights/${inputs.objectId}`, { query }); const raw = pick(body, 'data', 'rows'); const items = Array.isArray(raw) ? raw : []; if (items.length === 0 && pick(body, 'report_run_id') !== undefined) { ctx.fail( 'Meta report počítá na pozadí, synchronní volání ho nestihlo. ' + 'Zkraťte období nebo zvolte vyšší úroveň.', body, ); } let spend = 0; let clicks = 0; let impressions = 0; const rows = items.map((row) => { // Meta vraci cisla jako text, vcetne utraty. const rowSpend = num(pick(row, 'spend'), 0); const rowClicks = num(pick(row, 'clicks'), 0); const rowImpressions = num(pick(row, 'impressions'), 0); spend += rowSpend; clicks += rowClicks; impressions += rowImpressions; return { ...row, spend: rowSpend, clicks: rowClicks, impressions: rowImpressions, }; }); if (ctx.util.bool(pick(body, 'truncated'))) { ctx.log('Meta vrátila jen část stránek, výsledek není úplný.'); } return { count: rows.length, rows, spend: round(spend, 2), clicks, impressions }; }