„Zcela absurdní,“ rozcupoval soud argumentaci finanční správy k ručení za DPH

30. 8. 2021
Doba čtení: 6 minut

Sdílet

Ilustrační obrázek
Autor: Depositphotos.com, podle licence: Rights Managed
Ilustrační obrázek
Pokud pošlete peníze na účet obchodního partnera, který nebyl zveřejněný, nezakládá vám to automaticky ručení za DPH, rozhodl Nejvyšší správní soud.

Argumentaci finanční správy, že existují postupy, kterými se firma mohla ručení vyhnout, pak soud označil za „zcela absurdní“. Soud rozsudkem navázal na svoji předešlou judikaturu ohledně ručitelského závazku. Už dříve totiž Nejvyšší správní soud (NSS) judikoval, že platba na zahraniční účet či obchodování s nespolehlivým plátcem nezakládají samy o sobě ručení za DPH a že musí být ještě splněn tzv. vědomostní test.

Co se dozvíte v článku
  1. Podle berňáku vzniká ručení automaticky
  2. Musí být splněn i vědomostní test, rozhodl soud
  3. Rozsudek, kterým argumentoval berňák, byl zrušen
  4. Argumentace finanční správy je „zcela absurdní“, řekl NSS
  5. Judikatura k ručení za DPH začíná být jasná

Podle berňáku vzniká ručení automaticky

Nejvyšší správní soud odmítl před několika dny kasační stížnost finanční správy, která se dožadovala zrušení rozsudku krajského soudu ohledně ručení za DPH při platbě na nezveřejněný účet. V roce 2018 vydal finanční úřad rozhodnutí, podle kterého měla firma ABC Kovopit-engineering doplatit skoro 1,1 milionu korun jakožto ručitelka za nezaplacenou daň firmou DZX potravinářská.

Ručení podle finanční správy vzniklo automaticky na základě § 109 odst. 2 písm. c) zákona o DPH, jelikož firma ABC Kovopit-engineering zaplatila za plnění na jiný účet než zveřejněný účet u správce daně a částka přesahovala dvojnásobek hranice podle zákona upravujícího omezení plateb v hotovosti, při jejímž překročení je stanovena povinnost provést platbu bezhotovostně (tedy 540 tisíc Kč).

§ 109 zákona o DPH

Ručení příjemce zdanitelného plnění

(1) Plátce, který přijme zdanitelné plnění s místem plnění v tuzemsku uskutečněné jiným plátcem nebo poskytne úplatu na takové plnění (dále jen „příjemce zdanitelného plnění“), ručí za nezaplacenou daň z tohoto plnění, pokud v okamžiku uskutečnění zdanitelného plnění nebo poskytnutí úplaty na takové plnění věděl nebo vědět měl a mohl, že

a) daň uvedená na daňovém dokladu nebude úmyslně zaplacena,

b) plátce, který uskutečňuje toto zdanitelné plnění nebo obdrží úplatu na takové plnění (dále jen „poskytovatel zdanitelného plnění“), se úmyslně dostal nebo dostane do postavení, kdy nemůže daň zaplatit, nebo

c) dojde ke zkrácení daně nebo vylákání daňové výhody.

(2) Příjemce zdanitelného plnění ručí také za nezaplacenou daň z tohoto plnění, pokud je úplata za toto plnění

a) bez ekonomického opodstatnění zcela zjevně odchylná od obvyklé ceny,

b) poskytnuta zcela nebo zčásti bezhotovostním převodem na účet vedený poskytovatelem platebních služeb mimo tuzemsko,

c) poskytnuta zcela nebo zčásti bezhotovostním převodem na jiný účet než účet poskytovatele zdanitelného plnění, který je správcem daně zveřejněn způsobem umožňujícím dálkový přístup, a pokud úplata za toto plnění překračuje dvojnásobek částky podle zákona upravujícího omezení plateb v hotovosti, při jejímž překročení je stanovena povinnost provést platbu bezhotovostně, nebo

d) poskytnuta zcela nebo zčásti virtuální měnou podle právního předpisu upravujícího některá opatření proti legalizaci výnosů z trestné činnosti a financování terorismu.

d) poskytnuta zcela nebo zčásti virtuálním aktivem podle právního předpisu upravujícího některá opatření proti legalizaci výnosů z trestné činnosti a financování terorismu.

(3) Příjemce zdanitelného plnění ručí za nezaplacenou daň z tohoto plnění, pokud je v okamžiku jeho uskutečnění nebo poskytnutí úplaty na něj o poskytovateli zdanitelného plnění zveřejněna způsobem umožňujícím dálkový přístup skutečnost, že je nespolehlivým plátcem.

(4) Příjemce zdanitelného plnění, které spočívá v dodání pohonných hmot distributorem pohonných hmot podle zákona upravujícího pohonné hmoty, ručí za nezaplacenou daň z tohoto plnění, pokud v okamžiku jeho uskutečnění nebo poskytnutí úplaty na něj není o poskytovateli zdanitelného plnění zveřejněna způsobem umožňujícím dálkový přístup skutečnost, že je registrován jako distributor pohonných hmot podle zákona upravujícího pohonné hmoty.

Musí být splněn i vědomostní test, rozhodl soud

Krajský soud v Ostravě však rozhodnutí berňáku zrušil s tím, že pro vznik ručení dle zmíněného paragrafu musí být splněny také podmínky zakotvené v předcházejícím § 109 odst. 1 daného zákona. Podle soudu tak musí být pro vznik ručení splněn i tzv. vědomostní test, tedy že firma v okamžiku uskutečnění zdanitelného plnění nebo poskytnutí úplaty na takové plnění věděla nebo vědět měla a mohla, že by DPH zůstala nezaplacená. Soud dále odkázal na rozhodnutí NSS z roku 2018 (případ Kovář plus), podle kterého při platbě na zahraniční účet rovněž automaticky nevzniká ručení a musí být ještě splněn vědomostní test.

Finanční správa se s rozsudkem nesmířila a podala kasační stížnost. V ní uvedla, že vědomostní test je již zahrnut v samotné skutkové podstatě § 109 odst. 2 písm. c) zákona o DPH. Úřad rovněž odkázal na rozsudek Městského soudu v Praze z října 2018, který konstatoval značnou odlišnost skutkových podstat uvedených v § 109 odst. 2, 3 a 4 zákona o DPH, přičemž konkrétně v ohledu § 109 odst. 3 uvedeného zákona (nespolehlivý plátce) dospěl k závěru, že vědomostní test je obsažen přímo ve skutkové podstatě tohoto zákonného ustanovení.

Finanční správa v neposlední řadě upozornila, že existují postupy, jejichž využitím může firma vzniku ručení předejít. Platbu za zdanitelné plnění může svému dodavateli zaslat na správcem daně zveřejněný účet, nebo může využít zákonem nabízeného postupu dle § 109a ZDPH, tj. zaslat tu část úplaty za přijaté zdanitelné plnění, která odpovídá dani z přidané hodnoty, na účet správce daně, zatímco zbývající část (tj. kupní cenu, již bez DPH) zaslat třeba i na dodavatelův nezveřejněný účet.

Rozsudek, kterým argumentoval berňák, byl zrušen

Ani NSS však finanční správě nedal za pravdu. Jak upozornil NSS, odvolání se na rozsudek pražského soudu není relevantní, jelikož bylo toto rozhodnutí na začátku letošního roku zrušeno. NSS naopak konstatoval, že odkaz na případ Kovář plus byl přiléhavý a že aby ručení mohlo být uplatněno, musí k tomu navíc přistoupit další okolnosti, ze kterých bude zjevné, že takovýto příjemce plnění věděl či vědět mohl a měl, že záměrem takovéto platby je právě nezaplacení daně.

Nejvyšší správní soud nepochybuje o tom, že stejně jako nemůže pouhé poskytnutí úplaty příjemcem zdanitelného plnění zcela nebo zčásti bezhotovostním převodem na účet vedený poskytovatelem platebních služeb mimo tuzemsko založit bez dalšího ručitelský vztah, nemůže ručitelský vztah založit ani samotné naplnění předpokladů uvedených v § 109 odst. 2 písm. c) téhož zákona (poskytnutí alespoň částečné úplaty na jiný než „zveřejněný“ účet; kvalifikovaná výše úplaty), napsal v rozsudku NSS.

Argumentace finanční správy je „zcela absurdní“, řekl NSS

NSS odmítl i tvrzení finanční správy, že firma mohla využít postupy, kterými se mohla ručení vyhnout. Soud dokonce označil argumentaci berňáku za “zcela absurdní”. Pokud tím snad stěžovatel (finanční správa) zamýšlel říci, že žalobkyně nemusela platit svému dodavateli DZX způsobem, kterým naplnila předpoklady § 109 odst. 2 písm. c) zákona o DPH, a pokud tak přesto učinila, zavinila si vznik ručení sama, Nejvyšší správní soud připomíná, že se žalobkyně předmětnými úhradami nedopustila ničeho protiprávního, a stěžovatel by jí tedy mohl stejně dobře vytknout, že nemusela provozovat podnikatelskou činnost [čímž by se také zaručeně vyhnula naplnění skutkové podstaty § 109 odst. 2 písm. c) ZDPH], podotkl soud.

Podle NSS je navíc nutné vzít v potaz judikaturu evropského soudu, podle které je požadováno zkoumání prvku zavinění příjemce plnění  (provedení vědomostního testu) v každém jednotlivém případě. Příjemci zdanitelného plnění by tak byla dokonce odepřena možnost s alespoň minimální šancí na úspěch v řízení o odvolání proti výzvě tvrdit, že v rozhodný okamžik o budoucím nezaplacení daně nevěděl a vědět nemohl, dodal NSS

Judikatura k ručení za DPH začíná být jasná

Jak již bylo uvedeno, nynější rozsudek doplňuje dosavadní judikaturu ohledně ručení za DPH. "První vlaštovkou” byl jim zmíněný případ Kovář plus, ve kterém NSS prvně konstatoval, že poskytnutí úplaty příjemcem zdanitelného plnění zcela nebo zčásti bezhotovostním převodem na účet vedený poskytovatelem platebních služeb mimo tuzemsko bez dalšího, nemůže samo o sobě založit ručitelský vztah. Aby ručení mohlo být uplatněno, musí k samotnému provedení platby přistoupit další okolnosti, ze kterých bude zjevné, že osoba povinná k dani, která úplatu na účet mimo tuzemsko uskutečnila, věděla či mohla vědět, že záměrem takto směrované platby mimo tuzemsko je právě nezaplacení daně.

MM25_Copy

Psali jsme: To, že pošlete peníze na zahraniční účet, samo o sobě nezakládá ručení za DPH

Letos v únoru pak NSS analogicky v případě firmy Legios Loco rozhodl, že skutečnost, že o poskytovateli zdanitelného plnění je způsobem umožňujícím dálkový přístup zveřejněna informace, že je nespolehlivým plátcem, nemůže bez dalšího založit ručitelský vztah. Aby tak ručitelský vztah vůbec vznikl, musí ke skutečnosti, že je v okamžiku uskutečnění zdanitelného plnění nebo poskytnutí úplaty za něj zveřejněn způsobem umožňujícím dálkový přístup status nespolehlivého plátce poskytovatele plnění, přistoupit další okolnosti, ze kterých bude zjevné, že příjemce zdanitelného plnění věděl, či vědět mohl a měl, že daň nebude uhrazena, uzavřel NSS.

Autor článku

Daniel Morávek píše o daních, zákonech a důchodech. Vysvětluje, jak legislativa ovlivňuje podnikatele a živnostníky. Profil autora →

'; document.getElementById('preroll-iframe').onload = function () { setupIframe(); } prerollContainer = document.getElementsByClassName('preroll-container-iframe')[0]; } function setupIframe() { prerollDocument = document.getElementById('preroll-iframe').contentWindow.document; let el = prerollDocument.createElement('style'); prerollDocument.head.appendChild(el); el.innerText = "#adContainer>div:nth-of-type(1),#adContainer>div:nth-of-type(1) > iframe { width: 99% !important;height: 99% !important;max-width: 100%;}#videoContent,body{ width:100vw;height:100vh}body{ font-family:'Helvetica Neue',Arial,sans-serif}#videoContent{ overflow:hidden;background:#000}#adMuteBtn{ width:35px;height:35px;border:0;background:0 0;display:none;position:absolute;fill:rgba(230,230,230,1);bottom:20px;right:25px}"; videoContent = prerollDocument.getElementById('contentElement'); videoContent.style.display = 'none'; videoContent.volume = 1; videoContent.muted = false; const playPromise = videoContent.play(); if (playPromise !== undefined) { playPromise.then(function () { console.log('PREROLL sound allowed'); // setUpIMA(true); videoContent.volume = 1; videoContent.muted = false; setUpIMA(); }).catch(function () { console.log('PREROLL sound forbidden'); videoContent.volume = 0; videoContent.muted = true; setUpIMA(); }); } } function setupDimensions() { prerollWidth = Math.min(iinfoPrerollPosition.offsetWidth, 480); prerollHeight = Math.min(iinfoPrerollPosition.offsetHeight, 320); } function setUpIMA() { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true); google.ima.settings.setLocale('cs'); google.ima.settings.setNumRedirects(10); // Create the ad display container. createAdDisplayContainer(); // Create ads loader. adsLoader = new google.ima.AdsLoader(adDisplayContainer); // Listen and respond to ads loaded and error events. adsLoader.addEventListener( google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded, false); adsLoader.addEventListener( google.ima.AdErrorEvent.Type.AD_ERROR, onAdError, false); // An event listener to tell the SDK that our content video // is completed so the SDK can play any post-roll ads. const contentEndedListener = function () { adsLoader.contentComplete(); }; videoContent.onended = contentEndedListener; // Request video ads. const adsRequest = new google.ima.AdsRequest(); adsRequest.adTagUrl = iinfoVastUrls[iinfoVastUrlIndex]; console.log('Preroll advert: ' + iinfoVastUrls[iinfoVastUrlIndex]); videoContent.muted = false; videoContent.volume = 1; // Specify the linear and nonlinear slot sizes. This helps the SDK to // select the correct creative if multiple are returned. // adsRequest.linearAdSlotWidth = prerollWidth; // adsRequest.linearAdSlotHeight = prerollHeight; adsRequest.nonLinearAdSlotWidth = 0; adsRequest.nonLinearAdSlotHeight = 0; adsLoader.requestAds(adsRequest); } function createAdDisplayContainer() { // We assume the adContainer is the DOM id of the element that will house // the ads. prerollDocument.getElementById('videoContent').style.display = 'none'; adDisplayContainer = new google.ima.AdDisplayContainer( prerollDocument.getElementById('adContainer'), videoContent); } function unmutePrerollAdvert() { adVolume = !adVolume; if (adVolume) { adsManager.setVolume(0.3); prerollDocument.getElementById('adMuteBtn').innerHTML = ''; } else { adsManager.setVolume(0); prerollDocument.getElementById('adMuteBtn').innerHTML = ''; } } function onAdsManagerLoaded(adsManagerLoadedEvent) { // Get the ads manager. const adsRenderingSettings = new google.ima.AdsRenderingSettings(); adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; adsRenderingSettings.loadVideoTimeout = 12000; // videoContent should be set to the content video element. adsManager = adsManagerLoadedEvent.getAdsManager(videoContent, adsRenderingSettings); // Add listeners to the required events. adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, onContentPauseRequested); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, onContentResumeRequested); adsManager.addEventListener( google.ima.AdEvent.Type.ALL_ADS_COMPLETED, onAdEvent); // Listen to any additional events, if necessary. adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, onAdEvent); playAds(); } function playAds() { // Initialize the container. Must be done through a user action on mobile // devices. videoContent.load(); adDisplayContainer.initialize(); // setupDimensions(); try { // Initialize the ads manager. Ad rules playlist will start at this time. adsManager.init(1920, 1080, google.ima.ViewMode.NORMAL); // Call play to start showing the ad. Single video and overlay ads will // start at this time; the call will be ignored for ad rules. adsManager.start(); // window.addEventListener('resize', function (event) { // if (adsManager) { // setupDimensions(); // adsManager.resize(prerollWidth, prerollHeight, google.ima.ViewMode.NORMAL); // } // }); } catch (adError) { // An error may be thrown if there was a problem with the VAST response. // videoContent.play(); } } function onAdEvent(adEvent) { const ad = adEvent.getAd(); console.log('Preroll event: ' + adEvent.type); switch (adEvent.type) { case google.ima.AdEvent.Type.LOADED: if (!ad.isLinear()) { videoContent.play(); } prerollDocument.getElementById('adContainer').style.width = '100%'; prerollDocument.getElementById('adContainer').style.maxWidth = '640px'; prerollDocument.getElementById('adContainer').style.height = '360px'; break; case google.ima.AdEvent.Type.STARTED: window.addEventListener('scroll', onActiveView); if (ad.isLinear()) { intervalTimer = setInterval( function () { // Example: const remainingTime = adsManager.getRemainingTime(); // adsManager.pause(); }, 300); // every 300ms } prerollDocument.getElementById('adMuteBtn').style.display = 'block'; break; case google.ima.AdEvent.Type.ALL_ADS_COMPLETED: if (ad.isLinear()) { clearInterval(intervalTimer); } if (prerollLastError === 303) { playYtVideo(); } break; case google.ima.AdEvent.Type.COMPLETE: if (ad.isLinear()) { clearInterval(intervalTimer); } playYtVideo(); break; } } function onAdError(adErrorEvent) { console.log(adErrorEvent.getError()); prerollLastError = adErrorEvent.getError().getErrorCode(); if (!loadNext()) { playYtVideo(); } } function loadNext() { iinfoVastUrlIndex++; if (iinfoVastUrlIndex < iinfoVastUrls.length) { iinfoPrerollPosition.remove(); playPrerollAd(); } else { return false; } adVolume = 1; return true; } function onContentPauseRequested() { videoContent.pause(); } function onContentResumeRequested() { videoContent.play(); } function onActiveView() { if (prerollContainer) { const containerOffset = prerollContainer.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight/1 && containerOffset.bottom > 0.0) { if (prerollPaused) { adsManager.resume(); prerollPaused = false; } return true; } else { if (!prerollPaused) { adsManager.pause(); prerollPaused = true; } } } return false; } function playYtVideo() { iinfoPrerollPosition.remove(); youtubeIframe.style.display = 'block'; youtubeIframe.src += '&autoplay=1&mute=1'; } }
Upozorníme vás na články, které by vám neměly uniknout (maximálně 2x týdně).
'; document.getElementById('outstream-iframe').onload = function () { setupIframe(); } replayScreen = document.getElementById('iinfoOutstreamReplay'); iinfoOutstreamPosition = document.getElementById('iinfoOutstreamPosition'); outstreamContainer = document.getElementsByClassName('outstream-container')[0]; setupReplayScreen(); } function setupIframe() { outstreamDocument = document.getElementById('outstream-iframe').contentWindow.document; let el = outstreamDocument.createElement('style'); outstreamDocument.head.appendChild(el); el.innerText = "#adContainer>div:nth-of-type(1),#adContainer>div:nth-of-type(1) > iframe { width: 99% !important;height: 99% !important;max-width: 100%;}#videoContent,body{ width:100vw;height:100vh}body{ font-family:'Helvetica Neue',Arial,sans-serif}#videoContent{ overflow:hidden;background:#000}#adMuteBtn{ width:35px;height:35px;border:0;background:0 0;display:none;position:absolute;fill:rgba(230,230,230,1);bottom:-5px;right:25px}"; videoContent = outstreamDocument.getElementById('contentElement'); videoContent.style.display = 'none'; videoContent.volume = 1; videoContent.muted = false; if ( location.href.indexOf('rejstriky.finance.cz') !== -1 || location.href.indexOf('finance-rejstrik') !== -1 || location.href.indexOf('firmy.euro.cz') !== -1 || location.href.indexOf('euro-rejstrik') !== -1 || location.href.indexOf('/rejstrik/') !== -1 || location.href.indexOf('/rejstrik-firem/') !== -1) { outstreamDirectPlayed = true; soundAllowed = true; iinfoVastUrlIndex = 0; } if (!outstreamDirectPlayed) { console.log('OUTSTREAM direct'); setUpIMA(true); } else { if (soundAllowed) { const playPromise = videoContent.play(); if (playPromise !== undefined) { playPromise.then(function () { console.log('OUTSTREAM sound allowed'); setUpIMA(false); }).catch(function () { console.log('OUTSTREAM sound forbidden'); renderBanner(); }); } } else { renderBanner(); } } } function getWrapper() { let articleWrapper = document.querySelector('.rs-outstream-placeholder'); // Outstream Placeholder from RedSys manipulation if (articleWrapper && articleWrapper.style.display !== 'block') { articleWrapper.innerHTML = ""; articleWrapper.style.display = 'block'; } // Don't render OutStream on homepages if (articleWrapper === null) { if (document.querySelector('body.p-index')) { return null; } } if (articleWrapper === null) { articleWrapper = document.getElementById('iinfo-outstream'); } if (articleWrapper === null) { articleWrapper = document.querySelector('.layout-main__content .detail__article p:nth-of-type(6)'); } if (articleWrapper === null) { // Euro, Autobible, Zdravi articleWrapper = document.querySelector('.o-article .o-article__text p:nth-of-type(6)'); } if (articleWrapper === null) { articleWrapper = document.getElementById('sidebar'); } if (!articleWrapper) { console.error("Outstream wrapper of article was not found."); } return articleWrapper; } function setupDimensions() { outstreamWidth = Math.min(iinfoOutstreamPosition.offsetWidth, 480); outstreamHeight = Math.min(iinfoOutstreamPosition.offsetHeight, 320); } /** * Sets up IMA ad display container, ads loader, and makes an ad request. */ function setUpIMA(direct) { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true); google.ima.settings.setLocale('cs'); google.ima.settings.setNumRedirects(10); // Create the ad display container. createAdDisplayContainer(); // Create ads loader. adsLoader = new google.ima.AdsLoader(adDisplayContainer); // Listen and respond to ads loaded and error events. adsLoader.addEventListener( google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded, false); adsLoader.addEventListener( google.ima.AdErrorEvent.Type.AD_ERROR, onAdError, false); // An event listener to tell the SDK that our content video // is completed so the SDK can play any post-roll ads. const contentEndedListener = function () { adsLoader.contentComplete(); }; videoContent.onended = contentEndedListener; // Request video ads. const adsRequest = new google.ima.AdsRequest(); if (direct) { adsRequest.adTagUrl = directVast; console.log('Outstream DIRECT CAMPAING advert: ' + directVast); videoContent.muted = true; videoContent.volume = 0; outstreamDirectPlayed = true; } else { adsRequest.adTagUrl = iinfoVastUrls[iinfoVastUrlIndex]; console.log('Outstream advert: ' + iinfoVastUrls[iinfoVastUrlIndex]); videoContent.muted = false; videoContent.volume = 1; } // Specify the linear and nonlinear slot sizes. This helps the SDK to // select the correct creative if multiple are returned. // adsRequest.linearAdSlotWidth = outstreamWidth; // adsRequest.linearAdSlotHeight = outstreamHeight; adsRequest.nonLinearAdSlotWidth = 0; adsRequest.nonLinearAdSlotHeight = 0; adsLoader.requestAds(adsRequest); } function setupReplayScreen() { replayScreen.addEventListener('click', function () { iinfoOutstreamPosition.remove(); iinfoVastUrlIndex = 0; outstreamInit(); }); } /** * Sets the 'adContainer' div as the IMA ad display container. */ function createAdDisplayContainer() { // We assume the adContainer is the DOM id of the element that will house // the ads. outstreamDocument.getElementById('videoContent').style.display = 'none'; adDisplayContainer = new google.ima.AdDisplayContainer( outstreamDocument.getElementById('adContainer'), videoContent); } function unmuteAdvert() { adVolume = !adVolume; if (adVolume) { adsManager.setVolume(0.3); outstreamDocument.getElementById('adMuteBtn').innerHTML = ''; } else { adsManager.setVolume(0); outstreamDocument.getElementById('adMuteBtn').innerHTML = ''; } } /** * Loads the video content and initializes IMA ad playback. */ function playAds() { // Initialize the container. Must be done through a user action on mobile // devices. videoContent.load(); adDisplayContainer.initialize(); // setupDimensions(); try { // Initialize the ads manager. Ad rules playlist will start at this time. adsManager.init(1920, 1080, google.ima.ViewMode.NORMAL); // Call play to start showing the ad. Single video and overlay ads will // start at this time; the call will be ignored for ad rules. adsManager.start(); // window.addEventListener('resize', function (event) { // if (adsManager) { // setupDimensions(); // adsManager.resize(outstreamWidth, outstreamHeight, google.ima.ViewMode.NORMAL); // } // }); } catch (adError) { // An error may be thrown if there was a problem with the VAST response. // videoContent.play(); } } /** * Handles the ad manager loading and sets ad event listeners. * @param { !google.ima.AdsManagerLoadedEvent } adsManagerLoadedEvent */ function onAdsManagerLoaded(adsManagerLoadedEvent) { // Get the ads manager. const adsRenderingSettings = new google.ima.AdsRenderingSettings(); adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; adsRenderingSettings.loadVideoTimeout = 12000; // videoContent should be set to the content video element. adsManager = adsManagerLoadedEvent.getAdsManager(videoContent, adsRenderingSettings); // Add listeners to the required events. adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, onContentPauseRequested); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, onContentResumeRequested); adsManager.addEventListener( google.ima.AdEvent.Type.ALL_ADS_COMPLETED, onAdEvent); // Listen to any additional events, if necessary. adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, onAdEvent); playAds(); } /** * Handles actions taken in response to ad events. * @param { !google.ima.AdEvent } adEvent */ function onAdEvent(adEvent) { // Retrieve the ad from the event. Some events (for example, // ALL_ADS_COMPLETED) don't have ad object associated. const ad = adEvent.getAd(); console.log('Outstream event: ' + adEvent.type); switch (adEvent.type) { case google.ima.AdEvent.Type.LOADED: // This is the first event sent for an ad - it is possible to // determine whether the ad is a video ad or an overlay. if (!ad.isLinear()) { // Position AdDisplayContainer correctly for overlay. // Use ad.width and ad.height. videoContent.play(); } outstreamDocument.getElementById('adContainer').style.width = '100%'; outstreamDocument.getElementById('adContainer').style.maxWidth = '640px'; outstreamDocument.getElementById('adContainer').style.height = '360px'; break; case google.ima.AdEvent.Type.STARTED: window.addEventListener('scroll', onActiveView); // This event indicates the ad has started - the video player // can adjust the UI, for example display a pause button and // remaining time. if (ad.isLinear()) { // For a linear ad, a timer can be started to poll for // the remaining time. intervalTimer = setInterval( function () { // Example: const remainingTime = adsManager.getRemainingTime(); // adsManager.pause(); }, 300); // every 300ms } outstreamDocument.getElementById('adMuteBtn').style.display = 'block'; break; case google.ima.AdEvent.Type.ALL_ADS_COMPLETED: if (ad.isLinear()) { clearInterval(intervalTimer); } if (outstreamLastError === 303) { if (isBanner) { renderBanner(); } else { replayScreen.style.display = 'flex'; } } break; case google.ima.AdEvent.Type.COMPLETE: // This event indicates the ad has finished - the video player // can perform appropriate UI actions, such as removing the timer for // remaining time detection. if (ad.isLinear()) { clearInterval(intervalTimer); } if (isBanner) { renderBanner(); } else { replayScreen.style.display = 'flex'; } break; } } /** * Handles ad errors. * @param { !google.ima.AdErrorEvent } adErrorEvent */ function onAdError(adErrorEvent) { // Handle the error logging. console.log(adErrorEvent.getError()); outstreamLastError = adErrorEvent.getError().getErrorCode(); if (!loadNext()) { renderBanner(); } } function renderBanner() { if (isBanner) { console.log('Outstream: Render Banner'); iinfoOutstreamPosition.innerHTML = ""; iinfoOutstreamPosition.style.height = "330px"; iinfoOutstreamPosition.appendChild(bannerDiv); } else { console.log('Outstream: Banner is not set'); } } function loadNext() { iinfoVastUrlIndex++; if (iinfoVastUrlIndex < iinfoVastUrls.length) { iinfoOutstreamPosition.remove(); outstreamInit(); } else { return false; } adVolume = 1; return true; } /** * Pauses video content and sets up ad UI. */ function onContentPauseRequested() { videoContent.pause(); // This function is where you should setup UI for showing ads (for example, // display ad timer countdown, disable seeking and more.) // setupUIForAds(); } /** * Resumes video content and removes ad UI. */ function onContentResumeRequested() { videoContent.play(); // This function is where you should ensure that your UI is ready // to play content. It is the responsibility of the Publisher to // implement this function when necessary. // setupUIForContent(); } function onActiveView() { if (outstreamContainer) { const containerOffset = outstreamContainer.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight/1 && containerOffset.bottom > 0.0) { if (outstreamPaused) { adsManager.resume(); outstreamPaused = false; } return true; } else { if (!outstreamPaused) { adsManager.pause(); outstreamPaused = true; } } } return false; } let outstreamInitInterval; if (typeof cpexPackage !== "undefined") { outstreamInitInterval = setInterval(tryToInitializeOutstream, 100); } else { const wrapper = getWrapper(); if (wrapper) { let outstreamInitialized = false; window.addEventListener('scroll', () => { if (!outstreamInitialized) { const containerOffset = wrapper.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight / 1 && containerOffset.bottom > 0.0) { outstreamInit(); outstreamInitialized = true; } } }); } } function tryToInitializeOutstream() { const wrapper = getWrapper(); if (wrapper) { const containerOffset = wrapper.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight / 1 && containerOffset.bottom > 0.0) { if (cpexPackage.adserver.displayed) { clearInterval(outstreamInitInterval); outstreamInit(); } } } else { clearInterval(outstreamInitInterval); } } }
OSZAR »