Files
kupshop/bundles/KupShop/CeskaPostaBundle/CeskaPosta.php
2025-08-02 16:30:27 +02:00

381 lines
14 KiB
PHP

<?php
namespace KupShop\CeskaPostaBundle;
use Psr\Log\LoggerInterface;
class CeskaPosta
{
protected $idContract;
protected $customerID;
protected $postCode;
protected $locationNumber;
protected $idExtTransaction;
public $ns = 'https://b2b.postaonline.cz/schema/B2BCommon-v1';
public $ns2 = 'https://b2b.postaonline.cz/schema/POLServices-v1';
public $request_url;
public $request;
public $response;
public $error;
protected $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
$this->idContract = findModule(\Modules::CESKA_POSTA, 'idContract');
$this->customerID = findModule(\Modules::CESKA_POSTA, 'customerID');
$this->postCode = findModule(\Modules::CESKA_POSTA, 'postCode');
$this->locationNumber = findModule(\Modules::CESKA_POSTA, 'locationNumber');
}
public function configure($idContract, $customerID, $postCode, $locationNumber)
{
$this->idContract = $idContract;
$this->customerID = $customerID;
$this->postCode = $postCode;
$this->locationNumber = $locationNumber;
}
public function getHeader($type = '')
{
$this->idExtTransaction++;
$header = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<b2bRequest xmlns="'.$this->ns.'" xmlns:ns2="'.$this->ns2.'">
<header>
<idExtTransaction>'.$this->idExtTransaction.'</idExtTransaction>
<timeStamp>'.date('Y-m-d\TH:i:s.vP').'</timeStamp>
<idContract>'.$this->idContract.'</idContract>
</header>
';
if ($type == 'getParcelsPrinting') {
$header .= '<serviceData>
<ns2:getParcelsPrinting>
<ns2:doPrintingHeader>
<ns2:customerID>'.$this->customerID.'</ns2:customerID>
<ns2:contractNumber>'.$this->idContract.'</ns2:contractNumber>
<ns2:shiftHorizontal>0</ns2:shiftHorizontal>
<ns2:shiftVertical>0</ns2:shiftVertical>
</ns2:doPrintingHeader>
<ns2:doPrintingData></ns2:doPrintingData>
</ns2:getParcelsPrinting>
</serviceData>
';
}
if ($type == 'sendParcels') {
$header .= '<serviceData>
<ns2:sendParcels>
<ns2:doParcelHeader>
<ns2:transmissionDate>'.date('d.m.Y').'</ns2:transmissionDate>
<ns2:customerID>'.$this->customerID.'</ns2:customerID>
<ns2:postCode>'.$this->postCode.'</ns2:postCode>
<ns2:locationNumber>'.$this->locationNumber.'</ns2:locationNumber>
</ns2:doParcelHeader>
<ns2:doParcelData>
<ns2:doParcelParams></ns2:doParcelParams>
<ns2:doParcelAddress></ns2:doParcelAddress>
</ns2:doParcelData>
</ns2:sendParcels>
</serviceData>
';
}
$header .= '</b2bRequest>';
$simple_xml = simplexml_load_string($header);
return $simple_xml;
}
public function get_b2bRequest($order, $type = 'sendParcels')
{
$b2bRequest = $this->getHeader($type);
$serviceData = $b2bRequest->serviceData;
$doParcelParams = $serviceData->children('ns2', true)->sendParcels->doParcelData->doParcelParams;
$doParcelParams->addChild('ns2:recordID', $order->id, $this->ns2);
$doParcelParams->addChild('ns2:currency', $order->currency, $this->ns2);
$delivery_address = !empty($order->delivery_street); // true - use delivery address, false - use invoice address
// surname = name surname firm
// surname - string50
$surname = ($delivery_address ? $order->delivery_name : $order->invoice_name).' ';
$surname .= $delivery_address ? $order->delivery_surname.(!empty($order->delivery_firm) ? ' '.$order->delivery_firm : '') : $order->invoice_surname;
// street - string40
$street = $delivery_address ? $order->delivery_street : $order->invoice_street;
// firstName = custom_address (Address line 2 / Upřesnění adresy), if exists
// firstName - string50
$custom_address = ($delivery_address && !empty($order->delivery_custom_address)) ? ', '.$order->delivery_custom_address : (!$delivery_address && !empty($order->invoice_custom_address) ? ', '.$order->invoice_custom_address : '');
// city = city, state
// city - string40
$city = $delivery_address ? $order->delivery_city : $order->invoice_city;
$city .= ($delivery_address && !empty($order->delivery_state)) ? ', '.$order->delivery_state : (!$delivery_address && !empty($order->invoice_state) ? ', '.$order->invoice_state : '');
// zipCode - string25
$zip = $delivery_address ? $order->delivery_zip : $order->invoice_zip;
$country = $delivery_address ? $order->delivery_country : $order->invoice_country;
if ($transliterator = \Transliterator::create('Russian-Latin/BGN')) {
$surname = $transliterator->transliterate($surname);
$street = $transliterator->transliterate($street);
$custom_address = $transliterator->transliterate($custom_address);
$city = $transliterator->transliterate($city);
}
if (mb_strlen($surname) > 50) {
$surname = mb_substr($surname, 0, 50);
}
if (mb_strlen($city) > 40) {
$city = mb_substr($city, 0, 40);
}
$doParcelAddress = $serviceData->children('ns2', true)->sendParcels->doParcelData->doParcelAddress;
$doParcelAddress->addChild('ns2:surname', '', $this->ns2)[0] = trim($surname);
if (!empty($custom_address)) {
$doParcelAddress->addChild('ns2:firstName', '', $this->ns2)[0] = trim($custom_address);
}
$doParcelAddress->addChild('ns2:subject', 'F', $this->ns2);
$doParcelAddress->addChild('ns2:street', '', $this->ns2)[0] = trim($street);
$doParcelAddress->addChild('ns2:city', '', $this->ns2)[0] = trim($city);
$doParcelAddress->addChild('ns2:zipCode', '', $this->ns2)[0] = trim($zip);
$doParcelAddress->addChild('ns2:isoCountry', trim($country), $this->ns2);
if (in_array($country, ['US', 'MX', 'AU', 'BR', 'CA', 'ES'])) {
$state = ($delivery_address && !empty($order->delivery_state)) ? $order->delivery_state : $order->invoice_state;
$doParcelAddress->addChild('ns2:subIsoCountry', trim($state), $this->ns2);
}
$doParcelAddress->addChild('ns2:emailAddress', $order->invoice_email, $this->ns2);
$phone = trim($order->invoice_phone);
if (mb_strlen($phone) > 13) {
$phone = mb_substr($phone, mb_strlen($phone) - 13);
}
$doParcelAddress->addChild('ns2:mobileNumber', '', $this->ns2)[0] = trim($phone);
return $b2bRequest;
}
public function sendParcels($b2bRequest)
{
$this->request_url = 'https://b2b.postaonline.cz/services/POLService/v1/sendParcels';
$this->request = $b2bRequest->asXML();
if (!$this->sendToCeskaPosta($this->request, $this->request_url)) {
return false;
}
$parser = xml_parser_create();
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
if (!xml_parse_into_struct($parser, $this->response, $values, $index)) {
$this->error = 'xml_parse error: '.xml_error_string(xml_get_error_code($parser)).' at line '.xml_get_current_line_number($parser);
xml_parser_free($parser);
return false;
}
xml_parser_free($parser);
if (array_key_exists('v1:B2BFaultMessage', $index)) {
$i = $index['v1:errorDetail'][0];
$v = $values[$i]['value'];
$this->error = 'Error! B2BFaultMessage: '.$v;
return false;
}
if (!array_key_exists('v1:b2bASyncResponse', $index)) {
$this->error = 'Error! No b2bASyncResponse!';
return false;
}
if (!array_key_exists('v1:idTransaction', $index)) {
$this->error = 'Error! No idTransaction!';
return false;
}
$i = $index['v1:idTransaction'][0];
$idTransaction = $values[$i]['value'];
return $idTransaction;
}
public function getResultParcels($idTransaction)
{
$this->request_url = 'https://b2b.postaonline.cz/services/POLService/v1/getResultParcels';
$b2bRequest = $this->getHeader('getResultParcels');
$b2bRequest->addChild('idTransaction', $idTransaction);
$this->request = $b2bRequest->asXML();
if (!$this->sendToCeskaPosta($this->request, $this->request_url)) {
return false;
}
$parser = xml_parser_create();
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
if (!xml_parse_into_struct($parser, $this->response, $values, $index)) {
$this->error = 'xml_parse error: '.xml_error_string(xml_get_error_code($parser)).' at line '.xml_get_current_line_number($parser);
xml_parser_free($parser);
return false;
}
xml_parser_free($parser);
if (array_key_exists('v1:B2BFaultMessage', $index)) {
$i = $index['v1:errorDetail'][0];
$v = $values[$i]['value'];
$this->error = 'Error! B2BFaultMessage: '.$v;
$i = $index['v1:errorCode'][0];
$errorCode = $values[$i]['value'];
if ($errorCode == 10) {
// 10 = UNFINISHED_PROCESS = Zpracování není ještě ukončeno
sleep(1);
return $this->getResultParcels($idTransaction);
}
return false;
}
if (!array_key_exists('v1_1:responseCode', $index)) {
$this->error = 'Error! No responseCode!';
return false;
}
$i = $index['v1_1:responseCode'][0];
$responseCode = $values[$i]['value'];
if ($responseCode != '1') {
$this->error = 'Error! ';
foreach ($index['v1_1:responseCode'] as $key => $i) {
$responseCode = $values[$i]['value'];
$i = $index['v1_1:responseText'][$key];
$v = $values[$i]['value'];
$this->error .= $responseCode.': '.$v.'; ';
}
// ignore error
// 09.03.2018:
// getResultParcels vrati Error! 19: BATCH_INVALID, i kdyz je vsechno OK,
// a vrati take parcelCode
return false;
}
if (!array_key_exists('v1_1:parcelCode', $index)) {
$this->error .= 'Error! No parcelCode!';
return false;
}
$parcelCode = [];
foreach ($index['v1_1:parcelCode'] as $i) {
$parcelCode[] = $values[$i]['value'];
}
return array_unique($parcelCode);
}
public function getParcelsPrinting($parcelCode, $idForm, $print_position = null)
{
$this->request_url = 'https://b2b.postaonline.cz/services/POLService/v1/getParcelsPrinting';
$b2bRequest = $this->getHeader('getParcelsPrinting');
$serviceData = $b2bRequest->serviceData;
$doPrintingHeader = $serviceData->children('ns2', true)->getParcelsPrinting->doPrintingHeader;
$doPrintingHeader->addChild('ns2:idForm', $idForm, $this->ns2);
if ($print_position) {
$doPrintingHeader->addChild('ns2:position', $print_position, $this->ns2);
}
$doPrintingData = $serviceData->children('ns2', true)->getParcelsPrinting->doPrintingData;
foreach ($parcelCode as $code) {
$doPrintingData->addChild('ns2:parcelCode', $code, $this->ns2);
}
$this->request = $b2bRequest->asXML();
if (!$this->sendToCeskaPosta($this->request, $this->request_url)) {
return false;
}
$parser = xml_parser_create();
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
if (!xml_parse_into_struct($parser, $this->response, $values, $index)) {
$this->error = 'xml_parse error: '.xml_error_string(xml_get_error_code($parser)).' at line '.xml_get_current_line_number($parser);
xml_parser_free($parser);
return false;
}
xml_parser_free($parser);
if (array_key_exists('v1:B2BFaultMessage', $index)) {
$i = $index['v1:errorDetail'][0];
$v = $values[$i]['value'];
$this->error = 'Error! B2BFaultMessage: '.$v;
return false;
}
if (!array_key_exists('v1_1:responseCode', $index)) {
$this->error = 'Error! No responseCode!';
return false;
}
$i = $index['v1_1:responseCode'][0];
$responseCode = $values[$i]['value'];
if ($responseCode != '1') {
$i = $index['v1_1:responseText'][0];
$v = $values[$i]['value'];
$this->error = 'Error! '.$responseCode.': '.$v;
return false;
}
if (!array_key_exists('v1_1:file', $index)) {
$this->error = 'Error! No file!';
return false;
}
$i = $index['v1_1:file'][0];
$f = $values[$i]['value'];
$pdf = base64_decode($f);
return $pdf;
}
public function sendToCeskaPosta($request = '', $url = null)
{
$this->logger->notice('Ceska Posta Podani Online', ['request_url' => $url, 'request' => $request]);
$curl = $this->createCurl($request, $url);
$this->response = curl_exec($curl);
if ($this->response === false) {
$this->error = 'curl_error: '.curl_error($curl);
$this->logger->notice('Ceska Posta Podani Online', ['error' => $this->error]);
return false;
} else {
$this->error = '';
$this->logger->notice('Ceska Posta Podani Online', ['response' => $this->response]);
return true;
}
}
public function createCurl($encodedBody, $url = null)
{
if (empty($url)) {
$url = $this->request_url;
}
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
// curl_setopt($curl, CURLOPT_VERBOSE, true);
// curl_setopt($curl, CURLOPT_CERTINFO, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($curl, CURLOPT_CAINFO, __DIR__.DIRECTORY_SEPARATOR.'Resources/Certificates/postsignum_vca4.pem');
curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'P12');
curl_setopt($curl, CURLOPT_SSLCERT, __DIR__.DIRECTORY_SEPARATOR.'Resources/Certificates/post_2024.p12');
curl_setopt($curl, CURLOPT_SSLCERTPASSWD, 'wpj');
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($curl, CURLOPT_POSTFIELDS, $encodedBody);
return $curl;
}
}