Elektronická evidence tržeb (EET) - SOAP komunikace rubrika: Programování: PHP
Zdravím,
s příchodem EET si ministerstvo vymyslelo nutnost elektronicky odesílat své tržby a to přes SOAP se kterým nemám žádné zkušenosti a vygooglit něco praktického je absolutně nemožné proto pokládám tento dotaz.
Ukázkový odeslaný a pozitivně přijatý dotaz vypadá následovně: http://www.etrzby.cz/assets/cs/prilohy/CZ00000019.valid.xml
Zpráva je v SOAP formátu a je tvořena obálkou, která obsahuje hlavičku pro meta data a body pro konkrétní data spojené s jednou tržbou.
Povedlo se mi vygenerovat tělo (soap:Body) zprávy pomocí jednoduchého kódu:
$result = $soap->OdeslaniTrzby([ "Hlavicka" => [ "dat_odesl" => "2016-09-19T19:06:37+01:00", "prvni_zaslani" => "false", "uuid_zpravy" => "9edeb22b-4234-4047-869c-3a76f86c20d3"], "Data" => [ "celk_trzba" => "34113.00", "cerp_zuct" => "679.00", "cest_sluz" => "5460.00", "dan1" => "-172.39", "dan2" => "-530.73", "dan3" => "975.65", "dat_trzby" => "2016-01-05T00:30:12+01:00", "dic_popl" => "CZ00000019", "id_pokl" => "/5546/RO24", "id_provoz" => "273", "porad_cis" => "0/6460/ZQ42", "pouzit_zboz1" => "784.00", "pouzit_zboz2" => "967.00", "pouzit_zboz3" => "189.00", "rezim" => "0", "urceno_cerp_zuct" => "324.00", "zakl_dan1" => "-820.92", "zakl_dan2" => "-3538.20", "zakl_dan3" => "9756.46", "zakl_nepodl_dph" => "3036.00" ], "KontrolniKody" => [ "pkp" => ["cipher" => "RSA2048", "digest" => "SHA256", "encoding" => "base64", "_" => $pkp], "bkp" => ["digest" => "SHA1", "encoding" => "base64", "_" => "1F1A2D90-4EAD34A8-411CFB0B-EB17616E-B2CE8114"] ] ]);
Problém je, že nedovedu vygenerovat hlavičku (SOAP-ENV:Header) zprávy. Respektive jak přidat dvojice atribut-hodnota. Vše programuji v php, nemáte s tímto někdo nějaké zkušenosti ?
Obecně lze řešení vytrollit přilepením html/xml textu namísto hlavičky ale určitě existuje nějaké lepší řešení, kde se přidávají dvojice atribut-hodnota jako to dělám v těle zprávy.
Předem děkuji za jakoukoliv pomoc.
Řeším EET v PHP
Žádné lepení xml stringu není potřeba! Na vše existují knihovny:
Soap klient: integrovaný v PHP (http://php.net/manual/en/class.soapclient.php)
umí sestavit XML na základě WSDL (akorát IDE nenašeptává metody, v tom je .NET dál)
Soap Header:
Podepsat tělo soapu umí knihovna https://github.com/robrichards/wse-php
má závislost na https://github.com/robrichards/xmlseclibs
v podstatě lze vyjít z tohoto examplu a jen vyměnit algoritmy dle specifikace EET https://github.com/robrichards/wse-php/blob/master/examples/ws-amazon.php
Vygenerovani PKP podpisu:
lze řešit rovněž přes xmlseclibs třídou XMLSecurityKey
Jsem velice mile překvapen, že statní správa zvolila dlouhodobě zavedené standardy SOAP/WSDL/XSD/WS-security. Je to nejlepší možné řešení a pro nás snadné na implementaci.
Dokumentace je skvělá, přestože je WSDL samo popisující, tak jej přepsali do lidské podoby a přidali ukázky volání a ukázky kódu.
Komentáře
- tdvorak : Bylo by případně možné publikovat tvou implementaci jako OSS? Určitě by to spoustě lidí pomohlo (a zlepšilo kvalitu dalších PHP implementací). — 14.7.2016
- michal.svojanovsky : Přimlouvám se za ukázku implementace, chápu že je to pracné a jsem ochoten i zaplatit (pokud to bude spolehlivě funkční). — 15.7.2016
- kajacx : Díky za odkazy na knihovny, určitě to pomůže. Jinak kde jsi prosím našel ty ukázky volání? "..., tak jej přepsali do lidské podoby a přidali ukázky volání a ukázky kódu." Já nikde na té jejich technické specifikaci nenašel jediný příklad, jak tu SOAP zprávu generovat (teda tělo je tam popsané dobře, ale k hlavičkám je pouze odkaz na officalní web soapu a WS-security, takže žádný ukázkový kód). — 16.7.2016
- harrison314 : @kajacx: pretoze ws-security a ws-adresing je standard, tak pouzijes standardne kniznice, uz len parsovat rucne o je o drzku, nie este skladat — 16.7.2016
- Teeto : také bych se přidal k prosbě upravit odkazovaný kód na ws-amazon pro potřeby EET, osobně se mi absolutně nedaří vygenerovat SOAP hlavičku a dle tohoto postu se to zdá být triviální záležitostí — 18.7.2016
- dzejkob : Když to tak čtu - tak v tom amazon requestu stačí vyhodit "$objWSSE->addTimestamp();" - potom změnit XMLSecurityKey::RSA_SHA1 na XMLSecurityKey::RSA_SHA256 a volání ->signSoapDoc upravit takto: ->signSoapDoc($objKey, array("algorithm" => XMLSecurityDSig::SHA256)) - potom by to mělo vyhovovat security policy eet. Potom je třeba tomu dodat pem klíč a pem certifikát + doplnit pkp a bkp dle specifikace (na to patrně openssl funkce v php). — 18.7.2016
- Teeto : děkuji za info, určitě se hodí, nicméně problém s generováním hlavičky stále přetrvává, abych nechodil kolem horké kaše tak tady je můj zdrojová soubor ve kterém se snažím napodobit volání amazon requestu upravené pro EET pastebin.com/CXq6tpY7 a výsledek (vygenerovaný request) je následovný pastebin.com/eFLgN7Ph bez SOAP hlavičky. Jediný problém snad může být v té závislosti použité knihovny na druhé, kterou uvádí autor příspěvku, nicméně se mi nikde při běhu neprojevila žádná chyba s chybějícím souborem takže to může být problém — 18.7.2016
- dzejkob : No ještě pro mne není aktuální to řešit v php - takže zcela přesně neporadím. Ovšem za prvé je třeba někam vložit jak vypadá výsledné soap XML - což patrně umí tato funkce: http://php.net/manual/en/soapclient.getlastrequest.php , za druhé jako PRIVATE_KEY je možné, že to nepobere pkcs - takže bych tam zkusil dát vyexportovaný klíč v pem - a CERT_FILE je určitě špatně - tam má být certifikát obchodníka, kterým se ten podpis ověřuje - ten je obsažen taktéž v balíčku pkcs (.p12) - takže bych zkusil buď na oboje místa dát 01000004.p12 - a pokud to podpis nevygeneruje, tak je nutný to zkonvertovat do pem. — 18.7.2016
- dzejkob : Tak přehlédnul jsem - ten request byl v druhém odkazu. Ve zdrojáku toho "loadKey" to používá http://php.net/manual/en/function.openssl-pkey-get-private.php nebo get_public - a obojí načítá PEM klíč. Je možný, že tahle funkce http://php.net/manual/en/function.openssl-pkcs12-read.php načte to pkcs a výsledný certifikát a klíč je PEM. Takže výsledek někam uložit a pak to nacpat do těch konstant (nebo upravit loadKey). — 18.7.2016
- dzejkob : Poslední dodatek - heslo toho pkcs klíče je "eet". — 18.7.2016
- Ondrejj : __getLastRequest() vraci xml bez hlavicky. Dumpni si $objWSSE->saveXML(), PRIVATE_KEY musi byt v PEM formatu (jde pres openssl zkonvertovat z pk12 do PEM) — 18.7.2016
- Ondrejj : Zveřejnuji můj example: https://github.com/ondrejnov/eet PKP/BKP je bez záruky, zdá se, že testovací prostředí příjme i evidentně chybný PKP/BKP — 18.7.2016
- dzejkob : Kontrolují jenom BKP - a neboť vychází z PKP, tak musí být taktéž správně. Možná by nezkontrolovali, kdyby nebylo pkp base64 kódované - ovšem to by pak nemuselo být validní xml. — 18.7.2016
- Ondrejj : pokud sestavim retezec k podpisu PKP z jinych hodnot nez jsou v sekci Data, tak bych ocekaval, ze mi zprava neprojde. — 18.7.2016
- dzejkob : Tak to jsem nezkoušel. Pokud ale bude bkp z jiného zdroje než je podepsané pkp, tak to vrátí "nesouhlasí kontrolní kód poplatníka (bkp)" nebo tak něco. Víc chybových stavů zatím specifikováno nemají (kromě těch ohledně komunikace a validace). — 18.7.2016
- tdvorak : @Ondrejj: Díky za zveřejnění a MIT licenci, vypadá to super! Ještě jeden dotaz - kontroluješ i podpis odpovědi (certifikát EET od I.CA, případně i oproti CRL)? — 20.7.2016
- Ondrejj : Podpis teď nekontroluji. Ve specifikaci je povinnost kontrolovat TLS certifikát, ale o kontrole soap response nic neříkají. Taky nevím, co bych dělal, když ti přijde zaevidovaný FIK s neplatným soap podpisem. Jestli to je duvod k nepredani FIK zakaznikovi nebo jestli odeslani uctenky opakovat, a kdyz opakovat jak jestli to povazovat na druhe odeslani nebo za prvni. — 20.7.2016
- ic : PHP to má docela podchycené, ale kromě SOAPu není ještě jiná možnost komunikace? Myslím třeba pro javascript žádný soap klient není :( to mají Javascripťáci v tomto směru smůlu ? — 6.9.2016
- dzejkob : No opět google potvrdil, že vše co člověka napadne hledat, tak najde: https://github.com/travist/jsencrypt, https://github.com/yaronn/xml-crypto — 6.9.2016
- david.macek3 : Diky moc, podarilo se mi to rozchodit v playground, ale dnes jsem si stahnul ostry certifikat z danovyho portalu a asi jsem uplne natvrdlej, ale nejak nechapu, proc mi to nefunguje. Muzu poprosit nekho, aby mi vysvetlil, co mam udelat se stazenymi soubory 318999283.crt, 318999283.p12, cacert.crt a current.crl? Pro Playground jsem pouzil soubory eet.key a eet.pem... Nebo musim pockat do listopadu nez rozjedou ostrej server? Stejne pak ale nebudu tusit, co s temi stazenymi soubory... Ps: muzu prispet nejak jinak nez pres bitcoin? — 7.9.2016
- Ondrejj : pres funkci openssl_pkcs12_read() muzes soubor .p12 rozlozit na verejny a soukromy klic. Prispet muzes i tak, ze podporu pk12 implementujes do knihovny a posles pull request ;) — 7.9.2016
- MartinK : Děkuji @Ondrejj za uveřejnění. Vše funkční, skvělé. Pro testovací certifikáty ok. Nyní ostrý certifikát .p12, ten když rozložím na CERTIFICATE a PRIVATEKEY, a nahradím načítání testovacího certifikátu, tak dostávám zpět odpověď "Neplatny podpis SOAP zpravy". Je potřeba posílat pro ostrý certifikát ve zprávě nějaké jiné údaje? Nebo v čem jiném by mohl být problém? — 9.9.2016
- ubuster : @MartinK: Ostré certifikáty, které jsou vydávány poplatníkům pro evidování tržeb, nejsou určeny pro použití na testovacím prostředí (Playground). V testovacím prostředí lze použít pouze certifikáty, které jsou zveřejněny na webu v sekci IT/Vývojář. — 15.9.2016
- ja13 : @Ondrejj: když jedu na PHP 5.5, tak mi ta tvoje knihovna nebude fungovat? — 2.10.2016
- ja13 : Teeto: Dzejkob: ostatní: Prosím, již někdo vyřešil to generování té hlavičky? Marně hledám v diskuzi, ale nenacházím. odkaz:http://pastebin.com/pbfiBtBD — 4.10.2016
- Anonym : nemohl by někdo udělat nějaké php řešení pro lamy? :-) že bych prostě jen někam nastavil cestu k mým certifikátům a do proměnných dosadil požadované hodnoty potřebné pro odeslání a zpět by mi přišel kód v proměnné, kterou bych si pak uložil do DB :-) jsem takový php amatér, ale to EET bych potřeboval rozchodit, mám pár svých systémů udělaných právě v php a bude to podléhat EET příští rok a popříští.... Jsem ochoten samozřejmě i pustit korunu, kdyby někdo to pro mne udělal a bylo by to funkční. Kdyžtak prosím na mail admin/zavináč/smhard.cz. — 22.10.2016
- k.korous : zkouším implementaci github.com/ondrejnov/eet a při volání testovacího případu se dostanu k tomuhle výstupu object(SoapFault)#23 (10) { ["message":protected]=> string(56) "Call to undefined function RobRichards\XMLSecLibs\hash()" instalovall jsem to přes composer RobRichards knihovna tam je. Díky edit: pro FreeBSD je PECL-Hash podporovaný pouze pro PHP4. Řeší to modul php56-hash-5.6.27 — 12.11.2016
- meca.petr : Děkuji @Ondrejj za uveřejnění, vše funguje. Opravdu mi to pomohlo. Jen upozornění, že na účtenku je třeba dát i BKP. Tvá funkce "send" vrací jen FIK. A také pokud by došlo k výpadku serveru finančáku, tak je třeba na účtenku dát PKP (protože FIK neexistuje) a to ta funkce taky nevrací. Vše už si tam doplním sám, ale dávám jen info i pro ostatní. — 26.11.2016
- Ondrejj : @meca.petr: kody BKP/PKP lze vypočítat offline před odesláním, proto se domnívám, že by nemělo být součástí metody send(), ale jiné public metody getCheckCodes(). — 26.11.2016
- lukame : Nemáte někdo kód jak pres funkci openssl_pkcs12_read() soubor .p12 rozlozit na verejny a soukromy klic? Stále mám prázdné soubory. — 28.11.2016
- Tom_as : Dobrý den Ondřeji, zajímalo by mě jak v php řešení řešíte vypočítání BKP/PKP offline? Musí se přeci vracet nejen v případě, že je výpadek serveru finančáku ale i případě, že je výpadek vašeho serveru. Děkuji :) — 30.11.2016
- Ondrejj : tom: k výpočtu bkp a pkp stačí údaje z účtenky a podpisový certifikát. Toto lze spočítat i bez připojení k internetu. Algoritmus je v EET dokumentaci. — 30.11.2016
- Tom_as : Ano ale co jsem koukal tak vše počítáte v php a to přeci při výpadku serveru na kterém to běží nepůjde. Jediné co mě napadlo je v takovém případě vracet výsledek v jiném jazyce. — 30.11.2016
- Ondrejj : Dal jsem k dispozici kód pro PHP. Je na každém jestli a kam ho nasadí. Jestli bude hostovat skript na sdíleném hostingu na Wedosu nebo použije nějaké HA řešení, kde výpadek serveru nebude znamenat komplikace. PHP lze spouštět i bez webserveru jako CLI. Lze mít skript na lokálním Raspberry PI... Kdo chce použít jiný jazyk, tak již existují alternativní knihovny https://github.com/todvora/eet-client#similar-projects — 30.11.2016
- michalj : Zdravím, zkouším implementaci ondrejnov/eet. Když se pokouším vypsat PKP tak jsou v něm netisknutelné znaky (otazníky). V některých případech se tiskne na účtenku. Můžete poradit co s tím? Díky — 12.2.2017
- jank : @michalj: použije se funkce base64_encode() a vytiskne se pak těch 344 znaků. — 13.2.2017
- michalj : díky moc! — 13.2.2017
Pro zobrazení všech 15 odpovědí se prosím přihlaste:
Nebo se přihlaste jménem a heslem:
Komentáře