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