'Chyba validace na straně přepravce', '4001' => "Hodnota '{field}' není platná", '4002' => "Nalezena duplicita - '{field}'", '4020' => "Chybí povinná položka '{field}'", '4021' => "Položka '{field}' nesmí být vyplněna", '4030' => "Položka '{field}' musí mít přesně danou hodnotu", '4031' => "Položka '{field}' není ze seznamu povolených hodnot", '4040' => "Neplatný formát položky '{field}'", '4041' => 'Neplatný email', '4060' => "Chybná číselná hodnota položky '{field}'", '4062' => "Chybná celočíselná hodnota položky '{field}'", '4080' => "Hodnota '{field}' není v platném rozsahu", '4100' => "Hodnota '{field}' musí mít přesný počet znaků", '4101' => "Hodnota '{field}' nesmí přesáhnout daný počet znaků", '4102' => "Hodnota '{field}' nesmí klesnout pod daný počet znaků", ]; protected $namefields = [ 'recipFirstname' => 'Jméno', 'recipSurname' => 'Přijmení', 'recipStreet' => 'Ulice', 'recipCity' => 'Město', 'recipPostalCode' => 'PSČ', 'recipState' => 'Stát', 'recipPhone' => 'Telefonní číslo', 'recipEmail' => 'Email', 'value' => 'Hodnota zásilky', 'packagesCount' => 'Počet balíků', 'currency' => 'Měna', 'weight' => 'Hmotnost', 'variableSymbol' => 'Variabilní symbol', 'deliveryType' => 'Typ zásilky', 'agent' => 'Přepravce', 'collectionPlace' => 'Svozové místo', 'cod' => 'Výše dobírky', 'extraServices' => 'Extra služby', ]; public $orders = []; public $IDs = []; /** * @param array $IDs */ public $response; protected $request_url; public function __construct() { $dbcfg = \Settings::getDefault(); $test_env = (!empty($dbcfg['balikonos']['testing']) && $dbcfg['balikonos']['testing'] == 'Y') || isDevelopment(); // $test_env = false; $this->request_url = $test_env ? 'https://test.rest.foxdeli.com' : 'https://rest.foxdeli.com'; if ($test_env) { $this->setTestMode(); } } public function sendDeliveries() { $this->getOrdersData(); $this->sendToBalikonos(); $this->saveToDB(); } public function deletePackage($id) { return $this->deleteSQL('balikonos', ['id' => $id]); } public function saveToDB() { try { $error = false; foreach ($this->orders as &$order) { if (!empty($order['response']->status)) { if ($order['response']->status == 'success') { sqlQuery('INSERT INTO balikonos (id_order,id_delivery) VALUES (:order_id, :package_id) ON DUPLICATE KEY UPDATE id_delivery=:package_id, close=0', [ 'order_id' => $order['id'], 'package_id' => $order['response']->data[0]->deliveryId, ] ); $order['error'] = 'OK'; } elseif ($order['response']->status == 'error') { sqlQuery('INSERT INTO balikonos (id_order) VALUES (:order_id) ON DUPLICATE KEY UPDATE id_delivery=NULL, close=0', ['order_id' => $order['id']] ); $order['error'] = $this->getErrorMessage($order['response']); $error = true; } } elseif ($error) { sqlQuery('INSERT INTO balikonos (id_order) VALUES (:order_id) ON DUPLICATE KEY UPDATE id_delivery=NULL, close=0', ['order_id' => $order['id']] ); $order['error'] = ''; } else { $order['error'] = $order['response']; } } $this->response = $error ? 3 : 4; } catch (\Doctrine\DBAL\DBALException $e) { echo $e->getMessage(); } } public function getErrorMessage($response) { if ($response->code == '422') { if (!empty($response->errors[0]->code)) { $msq = $this->errors_code[$response->errors[0]->code]; if (!empty($response->errors[0]->field)) { $msq = str_replace('{field}', $this->namefields[$response->errors[0]->field], $msq); } elseif (!empty($response->errors[0]->message)) { $msq = $response->errors[0]->message; } else { $msq = str_replace('{field}', '-', $msq); } logError(__FILE__, __LINE__, "Balikonos API error: {$msq} \n Response:".print_r($response, true)); return $msq; } } var_dump($response); logError(__FILE__, __LINE__, 'Balikonos API UNDEFINED error: '.print_r($response, true)); return 'Nedefinovaná chyba'; } public function setIDs(array $IDs) { $this->IDs = $IDs; } public function getOrdersData($complete = true) { $dbcfg = \Settings::getDefault(); foreach ($this->IDs as $ID => $data) { $orderCls = new \Order(); $orderCls->createFromDB($ID, true); $info = [ 'invoice_name' => !empty($orderCls->delivery_name) ? $orderCls->delivery_name : $orderCls->invoice_name, 'invoice_surname' => !empty($orderCls->delivery_surname) ? $orderCls->delivery_surname.(!empty($orderCls->delivery_firm) ? ' '.$orderCls->delivery_firm : '') : $orderCls->invoice_surname, 'invoice_street' => !empty($orderCls->delivery_street) ? $orderCls->delivery_street : $orderCls->invoice_street, 'invoice_city' => !empty($orderCls->delivery_city) ? $orderCls->delivery_city : $orderCls->invoice_city, 'invoice_zip' => !empty($orderCls->delivery_zip) ? $orderCls->delivery_zip : $orderCls->invoice_zip, 'invoice_country' => !empty($orderCls->delivery_country) ? $orderCls->delivery_country : $orderCls->delivery_country, 'order_no' => $orderCls->order_no, 'total_price' => $orderCls->total_price, 'id' => $ID, 'weight' => !empty($data['weights']) ? $data['weights'] : null, ]; if (!$this->isDeliverySupported($orderCls->getDeliveryType()->id_delivery)) { exit('Nesparovana doprava! Vyplnte v nastaveni -> Balikonos!'); } if ($complete) { $delivery = $orderCls->getDeliveryType()->getDelivery(); // doplnit spravnou ulici - balikonos jinak vraci chybu, ze neexistuje ulice if ($delivery instanceof \Balikovna && $info['invoice_street'] == 'BALÍKOVNA') { $deliveryInfo = $delivery->getInfo($this->getPostalCode($orderCls, $info['invoice_zip'])); if (!empty($deliveryInfo['address'])) { $parts = explode(', ', $deliveryInfo['address']); if (!empty($parts[0])) { $info['invoice_street'] = $parts[0]; } } } $order = [ 'balikonos_array' => [ 'recipFirstname' => $info['invoice_name'], 'recipSurname' => $info['invoice_surname'], 'recipStreet' => $info['invoice_street'], 'recipCity' => $info['invoice_city'], 'recipPostalCode' => $this->getPostalCode($orderCls, $info['invoice_zip']), 'recipState' => empty($info['invoice_country']) ? 'CZ' : $info['invoice_country'], 'recipPhone' => $orderCls->invoice_phone, 'recipEmail' => $orderCls->invoice_email, 'value' => \Decimal::max(toDecimal($orderCls->total_price), \DecimalConstants::one())->printFloatValue(0), 'packagesCount' => 1, 'currency' => $orderCls->currency ?: 'CZK', 'weight' => !empty($data['weights']) ? $data['weights'] : $dbcfg['balikonos']['weight'], 'variableSymbol' => intval($orderCls->order_no), 'deliveryType' => $dbcfg['balikonos']['delivery_type'][$orderCls->getDeliveryType()->id_delivery]['delivery_type'], 'agent' => $dbcfg['balikonos']['delivery_type'][$orderCls->getDeliveryType()->id_delivery]['deliver'], 'collectionPlace' => $dbcfg['balikonos']['collectionPlace'], 'id_order' => $ID, ], ]; // v pripade balikovny pridat ID odberneho mista if ($delivery instanceof \Balikovna) { $order['balikonos_array']['packmachine'] = $this->getPostalCode($orderCls, $info['invoice_zip']); } } else { $order = []; } $this->modifyOrderData($order); if (($remaining = $orderCls->getRemainingPayment()) != 0 && $complete) { if (!findModule('currencies') || $orderCls->currency == 'CZK') { $scale = 0; } else { $scale = 2; } if (findModule('currencies')) { changeCurrency($orderCls->currency); } $delivery_type = $orderCls->getDeliveryType($orderCls->getDeliveryId()); if (!empty($delivery_type->payment_class)) { $pay_method = $delivery_type->payment_class->getPayMethod(); } else { $pay_method = 0; } if ($pay_method == \Payment::METHOD_TRANSFER) { $order['balikonos_array']['cod'] = 0; } else { $order['balikonos_array']['cod'] = roundPrice(toDecimal($remaining))->printFloatValue($scale); } $order['balikonos_array']['codCurrency'] = $orderCls->currency; } if (!empty($data)) { $order = array_merge($order, $data); } $this->orders[] = array_merge($order, $info); } return $this->orders; } protected function modifyOrderData(&$order) { } private function getPostalCode($orderCls, $zip) { $dbcfg = \Settings::getDefault(); if ($dbcfg['balikonos']['delivery_type'][$orderCls->getDeliveryType()->id_delivery]['delivery_type'] == 'NP') { $delivery_data = $orderCls->getData('delivery_data'); return !empty($delivery_data['psc']) ? $delivery_data['psc'] : $zip; } else { return $zip; } } protected function sendToBalikonos() { foreach ($this->orders as &$order) { $stmt = sqlQuery('SELECT * FROM '.getTableName('balikonos')." WHERE id_order='{$order['id']}' AND id_delivery IS NOT NULL"); if (sqlNumRows($stmt) == 1) { $order['response'] = 'OK'; continue; } $body = ['deliveries' => $order['balikonos_array']]; $requestBody = json_encode($body, JSON_UNESCAPED_UNICODE); $encodedBody = gzencode($requestBody); logError(__FILE__, __LINE__, 'Balikonos odeslani baliku: '.print_r($requestBody, true)); $curl = $this->createCurl($encodedBody, 'POST'); curl_setopt($curl, CURLOPT_HTTPHEADER, [ 'Accept-Encoding: gzip', 'Accept: application/json', 'Authorization: Bearer '.$this->get_token(), // OAuth 2.0 access_token 'Content-Encoding: gzip', 'Content-Length: '.strlen($encodedBody), 'Content-Type: application/json', ]); $response = curl_exec($curl); if ($response) { $decodedResponse = gzdecode($response); $answr = json_decode($decodedResponse); // do what ever you want, for example json_decode and store somewhere $order['response'] = $answr; } else { $order['response'] = 'curl error: '.curl_error($curl); } if ($order['response']->status == 'error') { logError(__FILE__, __LINE__, 'Balikonos API UNDEFINED error sended_data: '.print_r($requestBody, true)); break; } } } // Opravi zasilky, ktere byli uzavrene v balikonosi ale v nasi databazi jsou stale neuzavrene public function repairClosedDeliveries() { $deliveryIds = []; foreach ($this->IDs as $package) { $deliveryIds[] = $package['id_delivery']; } $response = $this->getDetailPackage($deliveryIds); foreach ($response->data as $package) { if ($package->deliveryState >= 1) { sqlQuery('UPDATE balikonos AS b LEFT JOIN orders AS o ON o.id=b.id_order SET close = 1 WHERE o.order_no=:order_no', ['order_no' => $package->variableSymbol]); } } } public function closeDeliveries($id_deliver) { $batch_response = $this->closeBatch($id_deliver); for ($i = 0; !empty($batch_response->code) && $batch_response->code == 422 && $i < 20; $i++) { logError(__FILE__, __LINE__, 'Balikonos API Close Batch error - pokus o uzavreni uzavrene zasilky: '.print_r($batch_response, true)); $this->repairClosedDeliveries(); $batch_response = $this->closeBatch($id_deliver); } /* $cyklic = 0; while(!empty($batch_response->code) && $batch_response->code == 422){ if ($cyklic > 200){ logError(__FILE__, __LINE__, "Balikonos API Close Batch Cycling error: " . print_r($batch_response, true)); break; } preg_match('/delivery (\d+)/', $batch_response->message, $id_delivery); if (intval($id_delivery[1])){ $this->updateSQL("balikonos", ['close' => '1'], ['id_delivery' => $id_delivery[1]]); $batch_response = $this->closeBatch($id_deliver); } } */ if (!empty($batch_response->status) && $batch_response->status == 'success') { foreach ($this->orders as &$order) { $detail_response = $this->getDetailPackage($order['id_delivery']); if (!empty($detail_response->status) && $detail_response->status == 'success') { $this->updateSQL('balikonos', ['close' => '1'], ['id_order' => $order['id']]); } } $this->response = 2; } else { if ($batch_response !== false) { logError(__FILE__, __LINE__, 'Balikonos API Close Batch error: '.print_r($batch_response, true)); exit(print_r($batch_response)); } } } public function deleteDeliverBatch($deliver) { $SQL_send = sqlQuery('SELECT b.* FROM balikonos b JOIN orders o ON b.id_order=o.id LEFT JOIN delivery_type AS dtd ON dtd.id=o.id_delivery WHERE dtd.id_delivery=:id_delivery AND b.id_delivery IS NOT NULL AND b.close=1', ['id_delivery' => $deliver]); foreach ($SQL_send as $key => $order) { $package = $this->getDetailPackage($order['id_delivery']); if (findModule('currencies') && !empty($package->data[0]->currency)) { changeCurrency($package->data[0]->currency); } $delivery_number = !empty($package->data[0]->deliveryNumber) ? $package->data[0]->deliveryNumber : ''; $cod = !empty($package->data[0]->cod) ? $package->data[0]->cod : ''; $weight = !empty($package->data[0]->weight) ? $package->data[0]->weight : ''; $this->updateSQL('orders', ['package_id' => $delivery_number], ['id' => $order['id_order']]); $changeStatus = true; $cfg = Config::get(); if (array_key_exists('post_default_to', $cfg['Modules']['balikonos']) && $cfg['Modules']['balikonos']['post_default_to'] === null) { $changeStatus = false; } if ($changeStatus) { $this->ChangeStatus($order['id_order'], findModule('balikonos', 'post_default_to', 2), $delivery_number, $cod, $weight); } } $balikonosRowIDs = sqlQuery( 'SELECT b.id FROM balikonos b JOIN orders o ON b.id_order=o.id LEFT JOIN delivery_type AS dtd ON dtd.id=o.id_delivery WHERE dtd.id_delivery=:id_delivery AND b.id_delivery IS NOT NULL AND b.close=1', ['id_delivery' => $deliver] )->fetchAll(\PDO::FETCH_COLUMN); sqlQueryBuilder()->update('balikonos')->set('close', 2) ->andWhere(Operator::inIntArray($balikonosRowIDs, 'id')) ->execute(); $this->response = '1'; } public function getDetailPackage($id_order) { $url = $this->request_url.'/v2/deliveries?deliveryId='; if (is_array($id_order)) { $url .= join(',', $id_order); } else { $url .= $id_order; } $curl = $this->createCurl('', 'GET', $url); curl_setopt($curl, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer '.$this->get_token(), // OAuth 2.0 access_token 'Content-Type: application/json', ]); return json_decode(curl_exec($curl)); } public function closeBatch($id_deliver) { $stmt = sqlQuery("SELECT b.id_delivery, b.id_order FROM balikonos AS b LEFT JOIN orders AS o ON o.id=b.id_order LEFT JOIN delivery_type AS dtd ON dtd.id=o.id_delivery WHERE dtd.id_delivery={$id_deliver} AND b.close=0 AND b.id_delivery IS NOT NULL"); $data = []; foreach ($stmt as $package) { $data[] = ['deliveryId' => $package['id_delivery'], 'closed' => true]; $this->IDs[$package['id_order']] = ['id_delivery' => $package['id_delivery']]; } if (empty($data)) { return false; } $this->getOrdersData(false); $requestBody = json_encode(['deliveries' => $data], JSON_UNESCAPED_UNICODE); $encodedBody = gzencode($requestBody); $curl = $this->createCurl($encodedBody, 'PATCH'); curl_setopt($curl, CURLOPT_HTTPHEADER, [ 'Accept-Encoding: gzip', 'Accept: application/json', 'Authorization: Bearer '.$this->get_token(), // OAuth 2.0 access_token 'Content-Encoding: gzip', 'Content-Length: '.strlen($encodedBody), 'Content-Type: application/json', ]); $response = curl_exec($curl); if ($response) { $decodedResponse = gzdecode($response); return json_decode($decodedResponse); // do what ever you want, for example json_decode and store somewhere } else { return 'curl error: '.curl_error($curl); } } public function getDeliveryIDs() { $deliverIds = ''; foreach ($this->orders as $key => $order) { $deliverIds .= $key == 0 ? 'deliveryId='.$order['id_delivery'] : ','.$order['id_delivery']; } return $deliverIds; } // Print PDF public function printTickets($deliver_id, $position, $printFormat = 'default', $orderIds = []) { $url = $this->request_url.'/v2/deliveries/tickets?'; $qbResult = sqlQueryBuilder()->select('b.id_delivery, b.close, dtd.id_delivery AS delivery_type_delivery_id')->from('balikonos', 'b') ->leftJoin('b', 'orders', 'o', 'o.id=b.id_order') ->leftJoin('o', 'delivery_type', 'dtd', 'dtd.id=o.id_delivery') ->where('b.close < 2'); if ($orderIds) { $qbResult->andWhere(Operator::inIntArray($orderIds, 'o.id')); } elseif ($deliver_id) { $qbResult->andWhere('dtd.id_delivery=:delivery_id AND b.id_delivery IS NOT NULL') ->setParameter('delivery_id', $deliver_id); } $closeDeliveries = false; foreach ($qbResult->execute() as $key => $order) { $url .= $key == 0 ? 'deliveryId='.$order['id_delivery'] : ','.$order['id_delivery']; if (!$order['close']) { $closeDeliveries = $order['delivery_type_delivery_id']; } } if ($closeDeliveries) { $this->closeDeliveries($closeDeliveries); } if (!empty($position)) { $url .= '&position='.$position; } $url .= '&printFormat='.$printFormat; logError(__FILE__, __LINE__, 'Balikonos API PrintTicket url: '.print_r($url, true)); $curl = $this->createCurl('', 'GET', $url); curl_setopt($curl, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer '.$this->get_token(), // OAuth 2.0 access_token 'Content-Type: application/json', ]); $response = json_decode(curl_exec($curl)); if (empty($response->data->contents)) { logError(__FILE__, __LINE__, 'Balikonos API PrintTicket error: '.print_r($response, true)); echo '
';
            var_dump($response);
            echo '
'; exit; } $pdf = base64_decode($response->data->contents); header('Content-type: application/pdf'); // header('Content-Disposition: attachment; filename="Balikonos-'.date("Y-m-d_H-i").'.pdf"'); echo $pdf; } public function createCurl($encodedBody, $method, $url = null) { if (empty($url)) { $url = $this->request_url.'/v2/deliveries'; } $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_POSTFIELDS, $encodedBody); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); return $curl; } public function isDeliverySupported($id_delivery) { return !empty(\Settings::getDefault()['balikonos']['delivery_type'][$id_delivery]['delivery_type']); } }