From f44e80bb6cb900c3ccd8fd2b29f13b7ae8d779d4 Mon Sep 17 00:00:00 2001 From: Ondrej Novak Date: Mon, 18 Jul 2016 22:07:22 +0200 Subject: [PATCH] Initial commit --- EETServiceSOAP.wsdl | 108 +++++++++++++++++++++++ EETXMLSchema.xsd | 200 +++++++++++++++++++++++++++++++++++++++++++ README.md | 15 ++++ eet.key | 28 ++++++ eet.pem | 23 +++++ example.php | 26 ++++++ lib/EETException.php | 7 ++ lib/Receipt.php | 173 +++++++++++++++++++++++++++++++++++++ lib/SoapClient.php | 33 +++++++ 9 files changed, 613 insertions(+) create mode 100644 EETServiceSOAP.wsdl create mode 100644 EETXMLSchema.xsd create mode 100644 README.md create mode 100644 eet.key create mode 100644 eet.pem create mode 100644 example.php create mode 100644 lib/EETException.php create mode 100644 lib/Receipt.php create mode 100644 lib/SoapClient.php diff --git a/EETServiceSOAP.wsdl b/EETServiceSOAP.wsdl new file mode 100644 index 0000000..5990c5e --- /dev/null +++ b/EETServiceSOAP.wsdl @@ -0,0 +1,108 @@ + + + + Ucel : Sluzba pro odeslani datove zpravy evidovane trzby + Verze : 2.0 + Vlastnik : Generalni financni reditelstvi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/EETXMLSchema.xsd b/EETXMLSchema.xsd new file mode 100644 index 0000000..53b4390 --- /dev/null +++ b/EETXMLSchema.xsd @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..3472378 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# Ukázka implementace EET v PHP. + +### Závislosti +Testováno na PHP 5.6 +V adresáří vendor se očekává knihovna https://github.com/robrichards/wse-php + +### Licence +Kód je poskytován tak jak stojí a leží, můžete s ním dělat co chcete, klidně použít i pro EET. Za chyby nezodpovídám. + +### Reklama +Komu se nechce do implementace, tak může použít on-line službu EETApp.cz, která má pokročilejší správu účtenek včetně tisku na tiskárnu. + +**Bitcoin Donate** +1LZuWFUHeVMrYvZWinxFjjkZtuq56TECot + diff --git a/eet.key b/eet.key new file mode 100644 index 0000000..cb5f1cd --- /dev/null +++ b/eet.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDgXC8qJcGllKal +yB3rNcp8eGcIMl7I24EmxnsFyhU/yiTlpnpmErN/oFaPVCh+Nzn1id3ksHRZtLF1 +G8OIGobRN+NHsGOUS4MPDciSzzeZBOpH2CgB0dyM0UTNx65RBWCX0Gu5K5KGDeph +iCFjZVWX8waoXxBRZTNywn3P5bZdSmsY6M2SVQAge5KnsOz05Q1rsCVE7o8hTGQ4 +1fQ48TukbyHCMpQr1WPZXc9a0AUt/5JPi1Xs7VHBP0zUE5CPiex6S+DrqgGbZq2q +XKSZwq1HQPe6DXSnYRGQFojh+Wj3x66uY+OuDxlJphfCwNLXedMheDZgmmlXT22t +TAuTKktTAgMBAAECggEAG3WM3Da0xaQ05TNh3gi+WI+P5KPtj921p95A7kt2YFFI +RMckUdvWFje0gGRHdHMj59ZQzw19oAEKew/D1aORfoe9jGedOGgpiS0hsD4mStcc +KWDePKLHwIBYUGsw/X+P++SpWodnrnqDhh5YH8cmO6ul0/OWlq+xJUmChnBR6obX +e2SYi/HZZctgDNItvGpmcyGfiohxgjjHY9x4NLdEUMJaAprqCwtXO6qHBIPNa01v +ORskmQF3gsjgpUlsq3pqlwyN9hzIZF4djFadZFqY8rQRzYypZD5gZGiDaplRmFoN +bwvg7xKnz/9QKRpC4NbOsW3IdAvTUPxhn0vD/acwMQKBgQDy6jOTLwUQVHb4KDqR +bzQygjugWtB+0x0lViTeoDe0DUJkkq1DZC149bDA6MiIeaeMuHzosEM3kk4LPElO +UL9XL57gPanAo05cUYAcfkLdlt4G5gm/ekSCcsy5h9JKfR6FArFRXXdaa6BV2bbX +Li/grQRKoZCyEZt+dAT9QhzsWQKBgQDschzMUtSyf0xzrne2Tg54Pe9gC9p2vDj1 +55RTYWYZgroineOz+hJA50Idgi9BwHoHGtOlgCIfaNuinO0lA1xPeeARem67TJfL +OH5Cf8fF0TpLlAH0RxEc3HgwmOiWyCokn/FBcM8wDaMx9HOYLNuIKpVfcq96KKMI +CG7xKerPiwKBgQDWO9UmnpZhs4yFCb21nBS14wPBRbaR05Dl59Z2fWkDI5qFZpLm +V4h/IHg1ele5fUlWozKOaT2u2hp4cD/akP5fX0FIVTnMCnrGkp5hAr3n/fFsth6s +v6GCRsrlabL+PODYv+owbzUfCsKKVIubtUFGbnDVfS5GzZ6MZLgtv8wQaQKBgDKi +wX4UYw6S6nl/rI1zK/AeO2xTPYbeCkjHPmGY4zelYl1VeNUrQct6exM8tQgcw0VQ +PnEb/rLBTwAFIVgi3xr6G71CfgJIhd10jL2LBepcQ2K6IK0CpyyKHocxx+W6miPb +yNvd39EHqqJhGnxFZwJDNFgLhH7hwwBOZgvpkSq/AoGBANokoUlgah4SlPv8d8LQ ++NAPix+98RC3MQlm6W8//Mx5vwQVxHzOMJc7zT5XjNdtLwdyh9NHfoOY+t49P1Is +TcC9GOhjuatj4X0J8gAXaMc0rNXJsPYdKnsbobUUll5stDA6UJ/0CnTuLByMvuHB +q/FlkWGSGyG5I93y789RSctM +-----END PRIVATE KEY----- diff --git a/eet.pem b/eet.pem new file mode 100644 index 0000000..1d869bf --- /dev/null +++ b/eet.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID6zCCAtOgAwIBAgIEAQAABTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJD +WjEaMBgGA1UEAwwRR0ZSIEVFVCB0ZXN0IENBIDExLTArBgNVBAoMJEdlbmVyw6Fs +bsOtIGZpbmFuxI1uw60gxZllZGl0ZWxzdHbDrTAeFw0xNjA1MTkxMjUxMzdaFw0x +ODA1MTkxMjUxMzdaMFMxCzAJBgNVBAYTAkNaMRQwEgYDVQQDDAtDWjY4MzU1NTEx +ODEYMBYGA1UECgwPxIzDrXNsbyBQbMOhdGNlMRQwEgYDVQQFEwtUMDAwMDAwMDAw +NTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOBcLyolwaWUpqXIHes1 +ynx4ZwgyXsjbgSbGewXKFT/KJOWmemYSs3+gVo9UKH43OfWJ3eSwdFm0sXUbw4ga +htE340ewY5RLgw8NyJLPN5kE6kfYKAHR3IzRRM3HrlEFYJfQa7krkoYN6mGIIWNl +VZfzBqhfEFFlM3LCfc/ltl1KaxjozZJVACB7kqew7PTlDWuwJUTujyFMZDjV9Djx +O6RvIcIylCvVY9ldz1rQBS3/kk+LVeztUcE/TNQTkI+J7HpL4OuqAZtmrapcpJnC +rUdA97oNdKdhEZAWiOH5aPfHrq5j464PGUmmF8LA0td50yF4NmCaaVdPba1MC5Mq +S1MCAwEAAaOBwTCBvjAeBgNVHREEFzAVgRNlcG9kcG9yYUBmcy5tZmNyLmN6MB8G +A1UdIwQYMBaAFHpa/A3L7DamDdppGWaMm++Cw6k0MB0GA1UdDgQWBBSJg2jzqct4 +XfLFxoKK3lucQpatUTBMBgNVHSAERTBDMEEGCmCGSAFlAwIBMAIwMzAxBggrBgEF +BQcCAjAlGiNUZW50byBjZXJ0aWZpa2F0IEpFIFBPVVpFIFRFU1RPVkFDSTAOBgNV +HQ8BAf8EBAMCBsAwDQYJKoZIhvcNAQELBQADggEBAFkTu819eKmotoiCSah7a0tl +WPN144iOY7zvoWuueXCEBcJBpurp37j/D3cufMinMZ6RAGfFAEsCkLCq+GzMeiPh +5N3kwk+1Ss4iw/FfkW19d6g9Yi+bU/NTNALgjj4kREgQO5Rr42BVFEoVz0K0Jvhl +XmQ0H3gzx/RlCwfqpwiSQkEVdI8wT2dPYt1lLNGkI0xukVdmjovYRDWMOl9r4r/H +LMuAesjTlTuKJ9CAawPJoyT0iEet/gFpAkrUnis5PZbdcVqfvnqbIs1d9C/i+8Of +MoyOmuoFQePCQjzIa4XETafvjVgZ4jKM/WaBTTY7lkd6d1K312Tz3MCQhlEL4hI= +-----END CERTIFICATE----- diff --git a/example.php b/example.php new file mode 100644 index 0000000..f3c64c6 --- /dev/null +++ b/example.php @@ -0,0 +1,26 @@ +uuid_zpravy = 'b3a09b52-7c87-4014-a496-4c7a53cf9120'; +$r->dic_popl = 'CZ72080043'; +$r->id_provoz = '181'; +$r->id_pokl = '1'; +$r->porad_cis = '1'; +$r->dat_trzby = new DateTime(); +$r->celk_trzba = 1000; +$fik = $r->send(); +var_dump($fik); + +// ukazka chyby +$r->dic_popl = 'x'; +try { + $fik = $r->send(); +} +catch (\eet\EETException $e) { + var_dump($e->getMessage()); +} \ No newline at end of file diff --git a/lib/EETException.php b/lib/EETException.php new file mode 100644 index 0000000..ba72c59 --- /dev/null +++ b/lib/EETException.php @@ -0,0 +1,7 @@ +key = $key; + $this->cert = $cert; + } + + public function check() + { + try { + return $this->send(TRUE); + } + catch (EETException $e) { + return FALSE; + } + } + + public function send($check = FALSE) + { + $hlavicka = [ + 'uuid_zpravy' => $this->uuid_zpravy, + 'dat_odesl' => time(), + 'prvni_zaslani' => $this->prvni_zaslani, + 'overeni' => $check + ]; + + $data = [ + 'dic_popl' => $this->dic_popl, + 'dic_poverujiciho' => $this->dic_poverujiciho, + 'id_provoz' => $this->id_provoz, + 'id_pokl' => $this->id_pokl, + 'porad_cis' => $this->porad_cis, + 'dat_trzby' => $this->dat_trzby->format('c'), + 'celk_trzba' => $this->priceFormat($this->celk_trzba), + 'zakl_nepodl_dph' => $this->priceFormat($this->zakl_nepodl_dph), + 'zakl_dan1' => $this->priceFormat($this->zakl_dan1), + 'dan1' => $this->priceFormat($this->dan1), + 'zakl_dan2' => $this->priceFormat($this->zakl_dan2), + 'dan2' => $this->priceFormat($this->dan2), + 'zakl_dan3' => $this->priceFormat($this->zakl_dan3), + 'dan3' => $this->priceFormat($this->dan3), + 'rezim' => $this->rezim + ]; + + + $soapClient = new \eet\SoapClient($this->key, $this->cert); + $response = $soapClient->OdeslaniTrzby([ + 'Hlavicka' => $hlavicka, + 'Data' => $data, + 'KontrolniKody' => $this->getCheckCodes() + ] + ); + if (isset($response->Chyba)) { + $this->processError($response->Chyba); + } + if ($check) { + return TRUE; + } + else { + return $response->Potvrzeni->fik; + } + } + + public function getCheckCodes() + { + $objKey = new \XMLSecurityKey(\XMLSecurityKey::RSA_SHA256, ['type' => 'private']); + $objKey->loadKey($this->key, TRUE); + + $arr = [ + $this->dic_popl, + $this->id_provoz, + $this->id_pokl, + $this->porad_cis, + $this->dat_trzby->format('c'), + $this->priceFormat($this->celk_trzba) + ]; + $sign = $objKey->signData(join('|', $arr)); + + return [ + 'pkp' => [ + '_' => $sign, + 'digest' => 'SHA256', + 'cipher' => 'RSA2048', + 'encoding' => 'base64' + ], + 'bkp' => [ + '_' => $this->formatBKB(sha1($sign)), + 'digest' => 'SHA1', + 'encoding' => 'base16' + ] + ]; + } + + private function formatBKB($code) { + $r = ''; + for ($i = 0; $i < 40; $i++) { + if ($i % 8 == 0 && $i != 0) { + $r.= '-'; + } + $r .= $code[$i]; + } + return $r; + } + + private function priceFormat($value) { + return number_format($value, 2, '.', ''); + } + + private function processError($error) { + if ($error->kod) { + $msgs = [ + -1 => 'Docasna technicka chyba zpracovani – odeslete prosim datovou zpravu pozdeji', + 2 => 'Kodovani XML neni platne', + 3 => 'XML zprava nevyhovela kontrole XML schematu', + 4 => 'Neplatny podpis SOAP zpravy', + 5 => 'Neplatny kontrolni bezpecnostni kod poplatnika (BKP)', + 6 => 'DIC poplatnika ma chybnou strukturu', + 7 => 'Datova zprava je prilis velka', + 8 => 'Datova zprava nebyla zpracovana kvuli technicke chybe nebo chybe dat', + ]; + $msg = isset($msgs[$error->kod]) ? $msgs[$error->kod] : ''; + throw new EETException($msg, $error->kod); + } + } + +} \ No newline at end of file diff --git a/lib/SoapClient.php b/lib/SoapClient.php new file mode 100644 index 0000000..d9b3df7 --- /dev/null +++ b/lib/SoapClient.php @@ -0,0 +1,33 @@ + 1]); + $this->key = $key; + $this->cert = $cert; + } + + public function __doRequest($request, $location, $saction, $version, $one_way = NULL) + { + $doc = new \DOMDocument('1.0'); + $doc->loadXML($request); + + $objWSSE = new \WSSESoap($doc); + $objWSSE->addTimestamp(); + + $objKey = new \XMLSecurityKey(\XMLSecurityKey::RSA_SHA256, ['type' => 'private']); + $objKey->loadKey($this->key, TRUE); + $objWSSE->signSoapDoc($objKey, ["algorithm" => \XMLSecurityDSig::SHA256]); + + $token = $objWSSE->addBinaryToken(file_get_contents($this->cert)); + $objWSSE->attachTokentoSig($token); + + return parent::__doRequest($objWSSE->saveXML(), $location, $saction, $version); + } +} \ No newline at end of file